diff --git a/db.py b/db.py index 9b96994e..a5627e05 100644 --- a/db.py +++ b/db.py @@ -6,15 +6,20 @@ import coloredlogs from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.ext.hybrid import hybrid_property -from sqlalchemy import Column, BigInteger, Integer, String, DateTime, ForeignKey, Float, Enum, create_engine, UniqueConstraint, PrimaryKeyConstraint, Boolean, or_, LargeBinary, Text, Date, func, desc +from sqlalchemy import Column, BigInteger, Integer, String, DateTime, ForeignKey, Float, Enum, create_engine, \ + UniqueConstraint, PrimaryKeyConstraint, Boolean, LargeBinary, Text, Date import requests from errors import NotFoundError, AlreadyExistingError, PrivateError import re import enum +# Both packages have different pip names +# noinspection PyPackageRequirements from discord import User as DiscordUser +# noinspection PyPackageRequirements from telegram import User as TelegramUser import loldata from dirty import Dirty +import query_discord_music # Init the config reader import configparser @@ -126,14 +131,16 @@ class Steam(Base): return f"https://steamcdn-a.akamaihd.net/steam/apps/{self.most_played_game_id}/header.jpg" def avatar_url(self): - return f"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/{self.avatar_hex[0:2]}/{self.avatar_hex}.jpg" + return f"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/{self.avatar_hex[0:2]}/"\ + f"{self.avatar_hex}.jpg" @staticmethod def create(session: Session, royal_id: int, steam_id: str): s = session.query(Steam).get(steam_id) if s is not None: raise AlreadyExistingError(repr(s)) - r = requests.get(f"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key={config['Steam']['api_key']}&steamids={steam_id}") + r = requests.get(f"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/" + f"?key={config['Steam']['api_key']}&steamids={steam_id}") r.raise_for_status() j = r.json() if len(j) == 0: @@ -141,12 +148,14 @@ class Steam(Base): s = Steam(royal_id=royal_id, steam_id=steam_id, persona_name=j["response"]["players"][0]["personaname"], - avatar_hex=re.search(r"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/../(.+).jpg", j["response"]["players"][0]["avatar"]).group(1)) + avatar_hex=re.search(r"https://steamcdn-a\.akamaihd\.net/steamcommunity/public/images/avatars/../" + r"(.+).jpg", j["response"]["players"][0]["avatar"]).group(1)) return s @staticmethod def find_trade_token(trade_url): - return re.search(r"https://steamcommunity\.com/tradeoffer/new/\?partner=[0-9]+&token=(.{8})", trade_url).group(1) + return re.search(r"https://steamcommunity\.com/tradeoffer/new/\?partner=[0-9]+&token=(.{8})", trade_url)\ + .group(1) @staticmethod def to_steam_id_2(steam_id): @@ -163,13 +172,17 @@ class Steam(Base): else: return f"{int(steam_id) - 76561197960265728}" + # noinspection PyUnusedLocal def update(self, session=None, raise_if_private: bool=False): - r = requests.get(f"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key={config['Steam']['api_key']}&steamids={self.steam_id}") + r = requests.get(f"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/" + f"?key={config['Steam']['api_key']}&steamids={self.steam_id}") r.raise_for_status() j = r.json() self.persona_name = j["response"]["players"][0]["personaname"] - self.avatar_hex = re.search(r"https://steamcdn-a\.akamaihd\.net/steamcommunity/public/images/avatars/../(.+).jpg", j["response"]["players"][0]["avatar"]).group(1) - r = requests.get(f"http://api.steampowered.com/IPlayerService/GetRecentlyPlayedGames/v0001/?key={config['Steam']['api_key']}&steamid={self.steam_id}&format=json") + self.avatar_hex = re.search(r"https://steamcdn-a\.akamaihd\.net/steamcommunity/public/images/avatars/../" + r"(.+).jpg", j["response"]["players"][0]["avatar"]).group(1) + r = requests.get(f"http://api.steampowered.com/IPlayerService/GetRecentlyPlayedGames/v0001/" + f"?key={config['Steam']['api_key']}&steamid={self.steam_id}&format=json") r.raise_for_status() j = r.json() if "response" not in j or "games" not in j["response"] or len(j["response"]["games"]) < 1: @@ -258,7 +271,9 @@ class Dota(Base): def get_rank_icon_url(self): # Rank icon is determined by the first digit of the rank tier - return f"https://www.opendota.com/assets/images/dota2/rank_icons/rank_icon_{str(self.rank_tier)[0] if self.rank_tier is not None else '0'}.png" + if self.rank_tier is None: + return f"https://www.opendota.com/assets/images/dota2/rank_icons/rank_icon_0.png" + return f"https://www.opendota.com/assets/images/dota2/rank_icons/rank_icon_{str(self.rank_tier)[0]}.png" def get_rank_stars_url(self): # Rank stars are determined by the second digit of the rank tier @@ -305,6 +320,7 @@ class Dota(Base): new_record.update() return new_record + # noinspection PyUnusedLocal def update(self, session=None) -> bool: r = requests.get(f"https://api.opendota.com/api/players/{Steam.to_steam_id_3(self.steam_id)}") r.raise_for_status() @@ -376,7 +392,8 @@ class LeagueOfLegends(Base): @staticmethod def create(royal_id, summoner_name) -> "LeagueOfLegends": - r = requests.get(f"https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-name/{summoner_name}?api_key={config['League of Legends']['riot_api_key']}") + r = requests.get(f"https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-name/{summoner_name}" + f"?api_key={config['League of Legends']['riot_api_key']}") r.raise_for_status() data = r.json() lol = LeagueOfLegends() @@ -389,14 +406,18 @@ class LeagueOfLegends(Base): lol.update() return lol + # noinspection PyUnusedLocal def update(self, session=None): - r = requests.get(f"https://euw1.api.riotgames.com/lol/summoner/v4/summoners/{self.summoner_id}?api_key={config['League of Legends']['riot_api_key']}") + r = requests.get(f"https://euw1.api.riotgames.com/lol/summoner/v4/summoners/" + f"{self.summoner_id}?api_key={config['League of Legends']['riot_api_key']}") r.raise_for_status() data = r.json() - r = requests.get(f"https://euw1.api.riotgames.com/lol/league/v4/positions/by-summoner/{self.summoner_id}?api_key={config['League of Legends']['riot_api_key']}") + r = requests.get(f"https://euw1.api.riotgames.com/lol/league/v4/positions/by-summoner/" + f"{self.summoner_id}?api_key={config['League of Legends']['riot_api_key']}") r.raise_for_status() rank = r.json() - r = requests.get(f"https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-summoner/{self.summoner_id}?api_key={config['League of Legends']['riot_api_key']}") + r = requests.get(f"https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-summoner/" + f"{self.summoner_id}?api_key={config['League of Legends']['riot_api_key']}") r.raise_for_status() mastery = r.json() solo_q = None @@ -416,9 +437,12 @@ class LeagueOfLegends(Base): solo = Dirty((self.solo_division, self.solo_rank)) flex = Dirty((self.flex_division, self.flex_rank)) twtr = Dirty((self.twtr_division, self.twtr_rank)) - solo.value = (None, None) if solo_q is None else (LeagueOfLegendsRanks[solo_q["tier"]], RomanNumerals[solo_q["rank"]]) - flex.value = (None, None) if flex_q is None else (LeagueOfLegendsRanks[flex_q["tier"]], RomanNumerals[flex_q["rank"]]) - twtr.value = (None, None) if twtr_q is None else (LeagueOfLegendsRanks[twtr_q["tier"]], RomanNumerals[twtr_q["rank"]]) + solo.value = (None, None) if solo_q is None else (LeagueOfLegendsRanks[solo_q["tier"]], + RomanNumerals[solo_q["rank"]]) + flex.value = (None, None) if flex_q is None else (LeagueOfLegendsRanks[flex_q["tier"]], + RomanNumerals[flex_q["rank"]]) + twtr.value = (None, None) if twtr_q is None else (LeagueOfLegendsRanks[twtr_q["tier"]], + RomanNumerals[twtr_q["rank"]]) self.highest_mastery_champ = mastery[0]["championId"] self.solo_division = solo.value[0] self.solo_rank = solo.value[1] @@ -477,6 +501,7 @@ class Osu(Base): mania_pp=j3["pp_raw"]) return new_record + # noinspection PyUnusedLocal def update(self, session=None): r0 = requests.get(f"https://osu.ppy.sh/api/get_user?k={config['Osu!']['ppy_api_key']}&u={self.osu_name}&m=0") r0.raise_for_status() @@ -582,6 +607,7 @@ class Overwatch(Base): def icon_url(self): return f"https://d1u1mce87gyfbn.cloudfront.net/game/unlocks/{self.icon}.png" + # noinspection PyUnusedLocal def update(self, session=None): r = requests.get(f"https://owapi.net/api/v3/u/{self.battletag}-{self.discriminator}/stats", headers={ "User-Agent": "Royal-Bot/4.1", @@ -724,7 +750,7 @@ class VoteQuestion(Base): text = f"{self.question}\n\n" none, yes, no, abstain = 0, 0, 0, 0 if self.message_id is not None: - query = session.execute("SELECT * FROM telegram LEFT JOIN (SELECT voteanswer.question_id, voteanswer.user_id, voteanswer.choice FROM votequestion JOIN voteanswer ON votequestion.id = voteanswer.question_id WHERE votequestion.message_id = " + str(self.message_id) + ") answer ON telegram.telegram_id = answer.user_id ORDER BY answer.choice;") + query = session.execute(query_discord_music.vote_answers, {"message_id": self.message_id}) for record in query: if record["username"] == "royalgamesbot": continue diff --git a/query_discord_music.py b/query_discord_music.py index 37827996..3e57d21e 100644 --- a/query_discord_music.py +++ b/query_discord_music.py @@ -129,3 +129,15 @@ FROM playedmusic WHERE playedmusic.enqueuer_id = :discordid GROUP BY playedmusic.filename ORDER BY c DESC;""" + +vote_answers = """SELECT * +FROM telegram +LEFT JOIN + ( + SELECT voteanswer.question_id, voteanswer.user_id, voteanswer.choice + FROM votequestion + JOIN voteanswer + ON votequestion.id = voteanswer.question_id + WHERE votequestion.message_id = :message_id + ) answer ON telegram.telegram_id = answer.user_id +ORDER BY answer.choice;""" diff --git a/redditbot.py b/redditbot.py index 8f9f7893..4ee74afe 100644 --- a/redditbot.py +++ b/redditbot.py @@ -2,6 +2,8 @@ import praw import configparser import db import logging +# python-telegram-bot has a different name +# noinspection PyPackageRequirements import telegram import time import raven @@ -61,7 +63,8 @@ def process(): try: telegram_bot.send_message(config["Telegram"]["main_group"], f'ℹ️ Nuovo post su r/RoyalGames:\n' - f'{submission.title}\n' + f'' + f'{submission.title}\n' f'da u/{submission.author}', parse_mode="HTML", disable_notification=True) except telegram.error.TimedOut: diff --git a/statsupdate.py b/statsupdate.py index 4477f80b..2dd0ef6a 100644 --- a/statsupdate.py +++ b/statsupdate.py @@ -5,6 +5,8 @@ import raven import configparser import os import typing +# python-telegram-bot has a different name +# noinspection PyPackageRequirements import telegram import sys import coloredlogs @@ -53,7 +55,7 @@ def update_block(session: db.Session, block: list, delay: float=0, change_callba }) sentry.captureException() continue - except Exception as e: + except Exception: logger.warning(f"Error {sys.exc_info()} while updating {repr(item)}.") sentry.extra_context({ "item": repr(item) @@ -66,6 +68,7 @@ def update_block(session: db.Session, block: list, delay: float=0, change_callba time.sleep(sleep_time if sleep_time > 0 else 0) +# noinspection PyUnusedLocal def new_dota_rank(item: db.Dota, change): try: telegram_bot.send_message(config["Telegram"]["main_group"], @@ -77,22 +80,30 @@ def new_dota_rank(item: db.Dota, change): def new_lol_rank(item, change: typing.Tuple[Dirty]): # It always gets called, even when there is no change + # Assignment inspection is wrong + # noinspection PyTupleAssignmentBalance solo, flex, twtr = change try: if solo: telegram_bot.send_message(config["Telegram"]["main_group"], - f"✳️ {item.royal.username} ha un nuovo rank in **SOLO/DUO** su League of Legends!\n" - f"{solo.initial_value[0]} {solo.initial_value[1]} -> **{solo.value[0]} {solo.value[1]}**", + f"✳️ {item.royal.username} ha un nuovo rank in **SOLO/DUO**" + f" su League of Legends!\n" + f"{solo.initial_value[0]} {solo.initial_value[1]} ->" + f" **{solo.value[0]} {solo.value[1]}**", parse_mode="Markdown") if flex: telegram_bot.send_message(config["Telegram"]["main_group"], - f"✳️ {item.royal.username} ha un nuovo rank in **FLEX** su League of Legends!\n" - f"{flex.initial_value[0]} {flex.initial_value[1]} -> **{flex.value[0]} {flex.value[1]}**", + f"✳️ {item.royal.username} ha un nuovo rank in **FLEX**" + f" su League of Legends!\n" + f"{flex.initial_value[0]} {flex.initial_value[1]} ->" + f" **{flex.value[0]} {flex.value[1]}**", parse_mode="Markdown") if twtr: telegram_bot.send_message(config["Telegram"]["main_group"], - f"✳️ {item.royal.username} ha un nuovo rank in **3V3** su League of Legends!\n" - f"{twtr.initial_value[0]} {twtr.initial_value[1]} -> **{twtr.value[0]} {twtr.value[1]}**", + f"✳️ {item.royal.username} ha un nuovo rank in **3V3**" + f" su League of Legends!\n" + f"{twtr.initial_value[0]} {twtr.initial_value[1]} ->" + f" **{twtr.value[0]} {twtr.value[1]}**", parse_mode="Markdown") except Exception: logger.warning(f"Couldn't notify on Telegram: {item}") @@ -101,7 +112,6 @@ def new_lol_rank(item, change: typing.Tuple[Dirty]): def process(): while True: session = db.Session() - logger.info("Now updating Steam data.") update_block(session, session.query(db.Steam).all()) session.commit() diff --git a/telegrambot.py b/telegrambot.py index 95060f26..26fa0d0d 100644 --- a/telegrambot.py +++ b/telegrambot.py @@ -4,7 +4,10 @@ import typing import db import errors import stagismo +# python-telegram-bot has a different name +# noinspection PyPackageRequirements from telegram import Bot, Update, InlineKeyboardMarkup, InlineKeyboardButton +# noinspection PyPackageRequirements from telegram.ext import Updater, CommandHandler, CallbackQueryHandler import dice import sys @@ -159,7 +162,9 @@ def cmd_ciaoruozi(bot: Bot, update: Update): @catch_and_report def cmd_ahnonlosoio(bot: Bot, update: Update): - if update.message.reply_to_message is not None and update.message.reply_to_message.text in ["/ahnonlosoio", "/ahnonlosoio@royalgamesbot", "Ah, non lo so io!"]: + if update.message.reply_to_message is not None and update.message.reply_to_message.text in [ + "/ahnonlosoio", "/ahnonlosoio@royalgamesbot", "Ah, non lo so io!", "Ah, non lo so neppure io!" + ]: bot.send_message(update.message.chat.id, "Ah, non lo so neppure io!") else: bot.send_message(update.message.chat.id, "Ah, non lo so io!") @@ -171,7 +176,10 @@ def cmd_balurage(bot: Bot, update: Update): try: user = session.query(db.Telegram).filter_by(telegram_id=update.message.from_user.id).one_or_none() if user is None: - bot.send_message(update.message.chat.id, "⚠ Il tuo account Telegram non è registrato al RYGdb! Registrati con `/register@royalgamesbot `.", parse_mode="Markdown") + bot.send_message(update.message.chat.id, + "⚠ Il tuo account Telegram non è registrato al RYGdb!\n\n" + "Registrati con `/register@royalgamesbot `.", + parse_mode="Markdown") return try: reason = update.message.text.split(" ", 1)[1] @@ -203,10 +211,17 @@ def cmd_diario(bot: Bot, update: Update): saver = author except IndexError: if update.message.reply_to_message is None: - bot.send_message(update.message.chat.id, f"⚠ Non hai specificato cosa aggiungere al diario! Puoi rispondere `/diario@royalgamesbot` al messaggio che vuoi salvare nel diario oppure scrivere `/diario@royalgamesbot ` per aggiungere quel messaggio nel diario.", parse_mode="Markdown") + bot.send_message(update.message.chat.id, + f"⚠ Non hai specificato cosa aggiungere al diario!\n\n" + f"Puoi rispondere `/diario@royalgamesbot` al messaggio che vuoi salvare nel diario" + f" oppure scrivere `/diario@royalgamesbot `" + f" per aggiungere quel messaggio nel diario.", + parse_mode="Markdown") return text = update.message.reply_to_message.text - author = session.query(db.Telegram).filter_by(telegram_id=update.message.reply_to_message.from_user.id).one_or_none() + author = session.query(db.Telegram)\ + .filter_by(telegram_id=update.message.reply_to_message.from_user.id)\ + .one_or_none() saver = session.query(db.Telegram).filter_by(telegram_id=update.message.from_user.id).one_or_none() if text is None: bot.send_message(update.message.chat.id, f"⚠ Il messaggio a cui hai risposto non contiene testo.") @@ -257,7 +272,8 @@ def cmd_vote(bot: Bot, update: Update): inline_keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("🔵 Sì", callback_data="vote_yes")], [InlineKeyboardButton("🔴 No", callback_data="vote_no")], [InlineKeyboardButton("⚫️ Astieniti", callback_data="vote_abstain")]]) - message = bot.send_message(update.message.chat.id, vote.generate_text(session=session), reply_markup=inline_keyboard, + message = bot.send_message(update.message.chat.id, vote.generate_text(session=session), + reply_markup=inline_keyboard, parse_mode="HTML") vote.message_id = message.message_id session.commit() @@ -290,7 +306,9 @@ def on_callback_query(bot: Bot, update: Update): " Registrati con `/register@royalgamesbot `.", parse_mode="Markdown") return - question = session.query(db.VoteQuestion).filter_by(message_id=update.callback_query.message.message_id).one() + question = session.query(db.VoteQuestion)\ + .filter_by(message_id=update.callback_query.message.message_id)\ + .one() answer = session.query(db.VoteAnswer).filter_by(question=question, user=user).one_or_none() if answer is None: answer = db.VoteAnswer(question=question, choice=choice, user=user) @@ -304,11 +322,16 @@ def on_callback_query(bot: Bot, update: Update): bot.answer_callback_query(update.callback_query.id, text=f"Hai cambiato il tuo voto in {emoji}.", cache_time=1) session.commit() - inline_keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("🔵 Sì", callback_data="vote_yes")], - [InlineKeyboardButton("🔴 No", callback_data="vote_no")], - [InlineKeyboardButton("⚫️ Astieniti", callback_data="vote_abstain")]]) - bot.edit_message_text(message_id=update.callback_query.message.message_id, chat_id=update.callback_query.message.chat.id, - text=question.generate_text(session), reply_markup=inline_keyboard, + inline_keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("🔵 Sì", + callback_data="vote_yes")], + [InlineKeyboardButton("🔴 No", + callback_data="vote_no")], + [InlineKeyboardButton("⚫️ Astieniti", + callback_data="vote_abstain")]]) + bot.edit_message_text(message_id=update.callback_query.message.message_id, + chat_id=update.callback_query.message.chat.id, + text=question.generate_text(session), + reply_markup=inline_keyboard, parse_mode="HTML") except Exception: raise @@ -345,7 +368,7 @@ def cmd_ship(bot: Bot, update: Update): part_two = re.search(r"[^aeiouAEIOU]*[aeiouAEIOU]?[A-Za-z]$", name_two) try: mixed = part_one.group(0) + part_two.group(0) - except: + except Exception: bot.send_message(update.message.chat.id, "⚠ I nomi specificati non sono validi.\n" "Riprova con dei nomi diversi!") return @@ -377,8 +400,10 @@ def cmd_bridge(bot: Bot, update: Update): try: data = update.message.text.split(" ", 1)[1] except IndexError: - bot.send_message(update.message.chat.id, "⚠ Non hai specificato un comando!\n" - "Sintassi corretta: `/bridge `", parse_mode="Markdown") + bot.send_message(update.message.chat.id, + "⚠ Non hai specificato un comando!\n" + "Sintassi corretta: `/bridge `", + parse_mode="Markdown") return discord_connection.send(f"!{data}") result = discord_connection.recv() @@ -464,7 +489,10 @@ def cmd_newevent(bot: Bot, update: Update): return # Create the event session = db.Session() - telegram_user = session.query(db.Telegram).filter_by(telegram_id=update.message.from_user.id).join(db.Royal).one_or_none() + telegram_user = session.query(db.Telegram)\ + .filter_by(telegram_id=update.message.from_user.id)\ + .join(db.Royal)\ + .one_or_none() event = db.Event(author=telegram_user.royal, name=name, description=description,