diff --git a/db.py b/db.py
index d201afe4..26892d30 100644
--- a/db.py
+++ b/db.py
@@ -19,6 +19,7 @@ import sql_queries
from flask import escape
import configparser
import typing
+import strings
if typing.TYPE_CHECKING:
# noinspection PyPackageRequirements
from discord import User as DiscordUser
@@ -835,6 +836,13 @@ class Diario(Base):
def __str__(self):
return f"{self.id} - {self.timestamp} - {self.author}: {self.text}"
+ def to_telegram(self):
+ return strings.safely_format_string(strings.DIARIO.ENTRY, words={
+ "id": self.id,
+ "author": self.author,
+ "text": self.text
+ })
+
def to_html(self):
return str(escape(self.text)).replace("\n", "
")
diff --git a/strings.py b/strings.py
index 9dddffb4..d9f80333 100644
--- a/strings.py
+++ b/strings.py
@@ -1,4 +1,5 @@
from db import MatchmakingStatus
+import typing
class SafeDict(dict):
@@ -6,8 +7,11 @@ class SafeDict(dict):
return key
-def safely_format_string(string, **kwargs):
- return string.format_map(SafeDict(**kwargs))
+def safely_format_string(string: str, words: typing.Dict[str, str]) -> str:
+ escaped = {}
+ for key in words:
+ escaped[key] = words[key].replace("<", "<").replace(">", ">")
+ return string.format_map(SafeDict(**escaped))
# Generic telegram errors
@@ -16,15 +20,46 @@ class TELEGRAM:
class ERRORS:
CRITICAL_ERROR = "☢ ERRORE CRITICO!\nIl bot ha ignorato il comando.\nUna segnalazione di errore è stata automaticamente mandata a @Steffo.\n\nDettagli dell'errore:\n
{exc_info}" - TELEGRAM_NOT_LINKED = "⚠ Il tuo account Telegram non è registrato a Royalnet! Registrati con
/register (NomeUtenteRoyalnet)
."
+ ROYALNET_NOT_LINKED = "⚠ Il tuo account Telegram non è connesso a Royalnet! Connettilo con /link (NomeUtenteRoyalnet)
."
+ UNAUTHORIZED_USER = "⚠ Non sono autorizzato a inviare messaggi a {mention}.\nPer piacere, {mention}, inviami un messaggio in privata!"
+ UNAUTHORIZED_GROUP = "⚠ Non sono autorizzato a inviare messaggi in {group}.\n@Steffo, aggiungimi al gruppo o concedimi i permessi!"
+ INACTIVE_BRIDGE = "⚠ Il collegamento tra Telegram e Discord non è attivo al momento."
PONG = "🏓 Pong!"
+# Diario
+class DIARIO:
+ SUCCESS = "✅ Riga aggiunta al diario:\n{diario}"
+ ENTRY = '#{id} di {author}\n{text}'
+
+ class ERRORS:
+ INVALID_SYNTAX = "⚠ Sintassi del comando errata.\nSintassi: /diario (frase)
, oppure rispondi a un messaggio con /diario
."
+ NO_TEXT = "⚠ Il messaggio a cui hai risposto non contiene testo."
+
+
+# Diario search
+class DIARIOSEARCH:
+ HEADER = "ℹ️ Risultati della ricerca di {term}:\n"
+
+ class ERRORS:
+ INVALID_SYNTAX = "⚠ Non hai specificato un termine da cercare!\nSintassi: /{command} (termine)
"
+ RESULTS_TOO_LONG = "⚠ Sono presenti troppi risultati da visualizzare! Prova a restringere la ricerca."
+
+
+# Eat!
+class EAT:
+ NORMAL = "🍗 Hai mangiato {food}!"
+ OUIJA = "👻 Il {food} che hai mangiato era posseduto.\nSpooky!"
+
+ class ERRORS:
+ INVALID_SYNTAX = "⚠ Non hai specificato cosa mangiare!\nSintassi: /eat (cibo)
"
+
+
# Royalnet linking
-class LINKING:
- SUCCESSFUL = "✅ Collegamento riuscito!"
+class LINK:
+ SUCCESS = "✅ Collegamento riuscito!"
class ERRORS:
INVALID_SYNTAX = "⚠ Non hai specificato un username!\nSintassi del comando: /register (NomeUtenteRoyalnet)
"
@@ -74,16 +109,15 @@ class MATCHMAKING:
INVALID_SYNTAX = "⚠ Sintassi del comando errata.\nSintassi: /mm [minplayers-][maxplayers] per (gamename) \\n[descrizione]" NOT_ADMIN = "⚠ Non sei il creatore di questo match!" MATCH_CLOSED = "⚠ Il matchmaking per questa partita è terminato!" - UNAUTHORIZED = "⚠ Non sono autorizzato a inviare messaggi a {mention}.\nPer piacere, {mention}, inviami un messaggio in privata!" -# Diario search -class DIARIOSEARCH: - HEADER = "ℹ️ Risultati della ricerca di {term}:\n" +# Ship creator +class SHIP: + RESULT = "💕 {one} + {two} = {result}" class ERRORS: - INVALID_SYNTAX = "⚠ Non hai specificato un termine da cercare!\nSintassi:
/{command} (termine)" - RESULTS_TOO_LONG = "⚠ Sono presenti troppi risultati da visualizzare! Prova a restringere la ricerca." + INVALID_SYNTAX = "⚠ Non hai specificato correttamente i due nomi!\nSintassi corretta:
/ship (nome) (nome)
"
+ INVALID_NAMES = "⚠ I nomi specificati non sono validi.\nRiprova con dei nomi diversi!"
# Wiki notifications
diff --git a/telegrambot.py b/telegrambot.py
index 3a1974eb..bf573f81 100644
--- a/telegrambot.py
+++ b/telegrambot.py
@@ -7,7 +7,9 @@ import stagismo
from sqlalchemy.sql import text
# python-telegram-bot has a different name
# noinspection PyPackageRequirements
-from telegram import Bot, Update, InlineKeyboardMarkup, InlineKeyboardButton
+import telegram
+IKMarkup = telegram.InlineKeyboardMarkup
+IKButton = telegram.InlineKeyboardButton
# noinspection PyPackageRequirements
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
from telegram.error import TimedOut, Unauthorized, BadRequest, TelegramError
@@ -22,7 +24,7 @@ import markovify
import raven
import coloredlogs
import strings
-s = strings.safely_format_string
+import time
# Markov model
try:
@@ -39,6 +41,7 @@ coloredlogs.install(level="DEBUG", logger=logger)
# Init the config reader
config = configparser.ConfigParser()
config.read("config.ini")
+main_group_id = int(config["Telegram"]["main_group"])
discord_connection = None
@@ -49,8 +52,30 @@ sentry = raven.Client(config["Sentry"]["token"],
hook_libraries=[])
+def reply_msg(bot: telegram.Bot, chat_id: int, string: str, **kwargs) -> telegram.Message:
+ return bot.send_message(chat_id, strings.safely_format_string(string, words=kwargs),
+ parse_mode="HTML",
+ disable_web_page_preview=True)
+
+
+def reply(bot: telegram.Bot, update: telegram.Update, string: str, **kwargs) -> telegram.Message:
+ while True:
+ try:
+ return reply_msg(bot, update.message.chat.id, string, **kwargs)
+ except Unauthorized:
+ if update.message.chat.type == telegram.Chat.PRIVATE:
+ return reply_msg(bot, main_group_id, strings.TELEGRAM.ERRORS.UNAUTHORIZED_USER,
+ mention=update.message.from_user.mention_html())
+ else:
+ return reply_msg(bot, main_group_id, strings.TELEGRAM.ERRORS.UNAUTHORIZED_GROUP,
+ group=(update.message.chat.title or update.message.chat.id))
+ except TimedOut:
+ time.sleep(1)
+ pass
+
+
def catch_and_report(func: "function"):
- def new_func(bot: Bot, update: Update):
+ def new_func(bot: telegram.Bot, update: telegram.Update):
# noinspection PyBroadException
try:
return func(bot, update)
@@ -62,9 +87,8 @@ def catch_and_report(func: "function"):
logger.error(f"Critical error: {sys.exc_info()}")
# noinspection PyBroadException
try:
- bot.send_message(int(config["Telegram"]["main_group"]),
- s(strings.TELEGRAM.ERRORS.CRITICAL_ERROR, exc_info=sys.exc_info()),
- parse_mode="HTML")
+ reply_msg(bot, main_group_id, strings.TELEGRAM.ERRORS.CRITICAL_ERROR,
+ exc_info=sys.exc_info())
except Exception:
logger.error(f"Double critical error: {sys.exc_info()}")
sentry.user_context({
@@ -83,19 +107,18 @@ def catch_and_report(func: "function"):
@catch_and_report
-def cmd_ping(bot: Bot, update: Update):
- bot.send_message(update.message.chat.id, s(strings.PONG))
+def cmd_ping(bot: telegram.Bot, update: telegram.Update):
+ reply(bot, update, strings.PONG)
@catch_and_report
-def cmd_register(bot: Bot, update: Update):
+def cmd_link(bot: telegram.Bot, update: telegram.Update):
session = db.Session()
try:
try:
username = update.message.text.split(" ", 1)[1]
except IndexError:
- bot.send_message(update.message.chat.id, s(strings.LINKING.ERRORS.INVALID_SYNTAX),
- parse_mode="HTML")
+ reply(bot, update, strings.LINK.ERRORS.INVALID_SYNTAX)
session.close()
return
try:
@@ -103,27 +126,24 @@ def cmd_register(bot: Bot, update: Update):
royal_username=username,
telegram_user=update.message.from_user)
except errors.NotFoundError:
- bot.send_message(update.message.chat.id, s(strings.LINKING.ERRORS.NOT_FOUND),
- parse_mode="HTML")
+ reply(bot, update, strings.LINK.ERRORS.NOT_FOUND)
session.close()
return
except errors.AlreadyExistingError:
- bot.send_message(update.message.chat.id, s(strings.LINKING.ERRORS.ALREADY_EXISTING),
- parse_mode="HTML")
+ reply(bot, update, strings.LINK.ERRORS.ALREADY_EXISTING)
session.close()
return
session.add(t)
session.commit()
- bot.send_message(update.message.chat.id, s(strings.LINKING.SUCCESSFUL),
- parse_mode="HTML")
+ reply(bot, update, strings.LINK.SUCCESS)
finally:
session.close()
@catch_and_report
-def cmd_discord(bot: Bot, update: Update):
+def cmd_cv(bot: telegram.Bot, update: telegram.Update):
if discord_connection is None:
- bot.send_message(update.message.chat.id, "⚠ Il bot non è collegato a Discord al momento.")
+ reply(bot, update, strings.TELEGRAM.ERRORS.INACTIVE_BRIDGE)
return
# dirty hack as usual
if update.message.text.endswith("full"):
@@ -135,7 +155,7 @@ def cmd_discord(bot: Bot, update: Update):
@catch_and_report
-def cmd_cast(bot: Bot, update: Update):
+def cmd_cast(bot: telegram.Bot, update: telegram.Update):
try:
spell: str = update.message.text.split(" ", 1)[1]
except IndexError:
@@ -156,19 +176,19 @@ def cmd_cast(bot: Bot, update: Update):
@catch_and_report
-def cmd_color(bot: Bot, update: Update):
+def cmd_color(bot: telegram.Bot, update: telegram.Update):
bot.send_message(update.message.chat.id, "I am sorry, unknown error occured during working with your request,"
" Admin were notified")
@catch_and_report
-def cmd_smecds(bot: Bot, update: Update):
+def cmd_smecds(bot: telegram.Bot, update: telegram.Update):
ds = random.sample(stagismo.listona, 1)[0]
bot.send_message(update.message.chat.id, f"Secondo me, è colpa {ds}.")
@catch_and_report
-def cmd_ciaoruozi(bot: Bot, update: Update):
+def cmd_ciaoruozi(bot: telegram.Bot, update: telegram.Update):
if update.message.from_user.username.lstrip("@") == "MeStakes":
bot.send_message(update.message.chat.id, "Ciao me!")
else:
@@ -176,7 +196,7 @@ def cmd_ciaoruozi(bot: Bot, update: Update):
@catch_and_report
-def cmd_ahnonlosoio(bot: Bot, update: Update):
+def cmd_ahnonlosoio(bot: telegram.Bot, update: telegram.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!", "Ah, non lo so neppure io!"
]:
@@ -186,7 +206,7 @@ def cmd_ahnonlosoio(bot: Bot, update: Update):
@catch_and_report
-def cmd_balurage(bot: Bot, update: Update):
+def cmd_balurage(bot: telegram.Bot, update: telegram.Update):
session = db.Session()
try:
user = session.query(db.Telegram).filter_by(telegram_id=update.message.from_user.id).one_or_none()
@@ -211,14 +231,12 @@ def cmd_balurage(bot: Bot, update: Update):
@catch_and_report
-def cmd_diario(bot: Bot, update: Update):
+def cmd_diario(bot: telegram.Bot, update: telegram.Update):
session = db.Session()
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 {query}
", entries), parse_mode="HTML")
except (BadRequest, TelegramError):
- bot.send_message(update.message.chat.id, s(strings.DIARIOSEARCH.ERRORS.RESULTS_TOO_LONG))
+ reply(bot, update, strings.DIARIOSEARCH.ERRORS.RESULTS_TOO_LONG)
finally:
session.close()
@catch_and_report
-def cmd_mm(bot: Bot, update: Update):
+def cmd_mm(bot: telegram.Bot, update: telegram.Update):
session = db.Session()
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, s(strings.TELEGRAM.ERRORS.TELEGRAM_NOT_LINKED), parse_mode="Markdown")
+ reply(bot, update, strings.TELEGRAM.ERRORS.ROYALNET_NOT_LINKED)
return
match = re.match(r"/(?:mm|matchmaking)(?:@royalgamesbot)?(?: (?:([0-9]+)-)?([0-9]+))? (?:per )?([A-Za-z0-9!\-_\. ]+)(?:.*\n(.+))?",
update.message.text)
if match is None:
- bot.send_message(update.message.chat.id,
- "")
+ reply(bot, update, strings.MATCHMAKING.ERRORS.INVALID_SYNTAX)
return
min_players, max_players, match_name, match_desc = match.group(1, 2, 3, 4)
db_match = db.Match(timestamp=datetime.datetime.now(),
@@ -376,9 +389,7 @@ def cmd_mm(bot: Bot, update: Update):
creator=user)
session.add(db_match)
session.flush()
- inline_keyboard = InlineKeyboardMarkup([([InlineKeyboardButton(s(strings.MATCHMAKING.BUTTONS[key]),
- callback_data=key)])
- for key in strings.MATCHMAKING.BUTTONS])
+ inline_keyboard = IKMarkup([([IKButton(strings.MATCHMAKING.BUTTONS[key], callback_data=key)]) for key in strings.MATCHMAKING.BUTTONS])
message = bot.send_message(config["Telegram"]["announcement_group"], db_match.generate_text(session=session),
parse_mode="HTML",
reply_markup=inline_keyboard)
@@ -389,7 +400,7 @@ def cmd_mm(bot: Bot, update: Update):
@catch_and_report
-def on_callback_query(bot: Bot, update: Update):
+def on_callback_query(bot: telegram.Bot, update: telegram.Update):
if update.callback_query.data.startswith("vote_"):
if update.callback_query.data == "vote_yes":
status = db.VoteChoices.YES
@@ -407,7 +418,7 @@ def on_callback_query(bot: Bot, update: Update):
user = session.query(db.Telegram).filter_by(telegram_id=update.callback_query.from_user.id).one_or_none()
if user is None:
bot.answer_callback_query(update.callback_query.id, show_alert=True,
- text=s(strings.TELEGRAM.ERRORS.TELEGRAM_NOT_LINKED),
+ text=strings.TELEGRAM.ERRORS.ROYALNET_NOT_LINKED,
parse_mode="Markdown")
return
question = session.query(db.VoteQuestion)\
@@ -426,12 +437,9 @@ 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")]])
+ inline_keyboard = IKMarkup([[IKButton("🔵 Sì", callback_data="vote_yes")],
+ [IKButton("🔴 No", callback_data="vote_no")],
+ [IKButton("⚫️ 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),
@@ -446,7 +454,7 @@ def on_callback_query(bot: Bot, update: Update):
if user is None:
bot.answer_callback_query(update.callback_query.id,
show_alert=True,
- text=strings.TELEGRAM.ERRORS.TELEGRAM_NOT_LINKED,
+ text=strings.TELEGRAM.ERRORS.ROYALNET_NOT_LINKED,
parse_mode="Markdown")
return
match = session.query(db.Match).filter_by(message_id=update.callback_query.message.message_id).one()
@@ -457,20 +465,9 @@ def on_callback_query(bot: Bot, update: Update):
text=strings.MATCHMAKING.ERRORS.NOT_ADMIN)
return
match.closed = True
- failed_send = []
for player in match.players:
if player.status >= 1:
- try:
- bot.send_message(player.user.telegram_id,
- s(strings.MATCHMAKING.GAME_START[player.status],
- **match.format_dict()),
- parse_mode="HTML")
- except Unauthorized:
- failed_send.append(player)
- if failed_send:
- for player in failed_send:
- bot.send_message(int(config["Telegram"]["main_group"]),
- s(strings.MATCHMAKING.ERRORS.UNAUTHORIZED, mention=player.user.mention()))
+ reply_msg(bot, player.user.telegram_id, strings.MATCHMAKING.GAME_START[player.status], **match.format_dict())
elif update.callback_query.data == "match_cancel":
if not (match.creator == user or user.telegram_id == 25167391):
bot.answer_callback_query(update.callback_query.id,
@@ -504,9 +501,7 @@ def on_callback_query(bot: Bot, update: Update):
text=strings.MATCHMAKING.TICKER_TEXT[update.callback_query.data],
cache_time=1)
if not match.closed:
- inline_keyboard = InlineKeyboardMarkup([([InlineKeyboardButton(strings.MATCHMAKING.BUTTONS[key],
- callback_data=key)])
- for key in strings.MATCHMAKING.BUTTONS])
+ inline_keyboard = IKMarkup([([IKButton(strings.MATCHMAKING.BUTTONS[key], callback_data=key)]) for key in strings.MATCHMAKING.BUTTONS])
else:
inline_keyboard = None
try:
@@ -522,48 +517,41 @@ def on_callback_query(bot: Bot, update: Update):
@catch_and_report
-def cmd_eat(bot: Bot, update: Update):
+def cmd_eat(bot: telegram.Bot, update: telegram.Update):
try:
food: str = update.message.text.split(" ", 1)[1].capitalize()
except IndexError:
- bot.send_message(update.message.chat.id, "⚠️ Non hai specificato cosa mangiare!\n"
- "Sintassi corretta: `/eat