From d4e2b2b8d8898f2db32b9d5f67d0b6c683881b22 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 26 Oct 2019 14:35:05 +0200 Subject: [PATCH] Some more progress on mm --- royalnet/packs/royal/commands/__init__.py | 4 +- royalnet/packs/royal/commands/matchmaking.py | 124 +++++++++++++++---- royalnet/packs/royal/tables/mmresponse.py | 6 +- 3 files changed, 108 insertions(+), 26 deletions(-) diff --git a/royalnet/packs/royal/commands/__init__.py b/royalnet/packs/royal/commands/__init__.py index b85fe503..cf068492 100644 --- a/royalnet/packs/royal/commands/__init__.py +++ b/royalnet/packs/royal/commands/__init__.py @@ -11,7 +11,7 @@ from .videochannel import VideochannelCommand from .dnditem import DnditemCommand from .dndspell import DndspellCommand from .trivia import TriviaCommand -from .matchmaking import MmCommand +from .matchmaking import MatchmakingCommand from .pause import PauseCommand from .play import PlayCommand from .playmode import PlaymodeCommand @@ -37,7 +37,7 @@ available_commands = [ DnditemCommand, DndspellCommand, TriviaCommand, - MmCommand, + MatchmakingCommand, PauseCommand, PlayCommand, PlaymodeCommand, diff --git a/royalnet/packs/royal/commands/matchmaking.py b/royalnet/packs/royal/commands/matchmaking.py index 7faf28d7..d903c4cf 100644 --- a/royalnet/packs/royal/commands/matchmaking.py +++ b/royalnet/packs/royal/commands/matchmaking.py @@ -1,13 +1,13 @@ -import pickle +import datetime from telegram import Bot as PTBBot from telegram import Message as PTBMessage -from telegram.error import BadRequest +from telegram.error import BadRequest, Unauthorized from telegram import InlineKeyboardMarkup as IKM from telegram import InlineKeyboardButton as IKB from royalnet.commands import * from royalnet.bots import TelegramBot -from royalnet.utils import telegram_escape, asyncify -from ..tables import MMEvent, MMResponse +from royalnet.utils import telegram_escape, asyncify, sleep_until +from ..tables import MMEvent, MMResponse, User, Telegram from ..utils import MMChoice, MMInterfaceData, MMInterfaceDataTelegram @@ -25,14 +25,27 @@ class MatchmakingCommand(Command): def __init__(self, interface: CommandInterface): super().__init__(interface) # Find all relevant MMEvents and run them - ... + session = self.interface.Session() + mmevents = await asyncify( + session.query(self.alchemy.MMEvent) + .filter(self.alchemy.MMEvent.interface == self.interface.name, + self.alchemy.MMEvent.datetime > datetime.datetime.now()) + .all + ) + for mmevent in mmevents: + self._run_mmevent(mmevent.mmid) async def run(self, args: CommandArgs, data: CommandData) -> None: # Create a new MMEvent and run it + if self.interface.name != "telegram": + raise UnsupportedError(f"{self.interface.prefix}matchmaking funziona solo su Telegram. Per ora.") + author = await data.get_author(error_if_none=True) ... _mm_chat_id = -1001224004974 + _mm_error_chat_id = -1001153723135 + def _gen_mm_message(self, mmevent: MMEvent) -> str: text = f"🌐 [{mmevent.datetime.strftime('%Y-%m-%d %H:%M')}] [b]{mmevent.title}[/b]\n" if mmevent.description: @@ -40,7 +53,7 @@ class MatchmakingCommand(Command): text += "\n" for response in mmevent.responses: response: MMResponse - text += f"{response.choice.value} {response.royal}\n" + text += f"{response.choice.value} {response.user}\n" return text def _gen_telegram_keyboard(self, mmevent: MMEvent): @@ -48,7 +61,8 @@ class MatchmakingCommand(Command): [IKB(f"{MMChoice.YES.value} Ci sarò!", callback_data=f"mm{mmevent.mmid}_YES")], [IKB(f"{MMChoice.MAYBE.value} (Forse.)", callback_data=f"mm{mmevent.mmid}_MAYBE")], [IKB(f"{MMChoice.LATE_SHORT.value} Arrivo dopo 5-10 min.", callback_data=f"mm{mmevent.mmid}_LATE_SHORT")], - [IKB(f"{MMChoice.LATE_MEDIUM.value} Arrivo dopo 15-35 min.", callback_data=f"mm{mmevent.mmid}_LATE_MEDIUM")], + [IKB(f"{MMChoice.LATE_MEDIUM.value} Arrivo dopo 15-35 min.", + callback_data=f"mm{mmevent.mmid}_LATE_MEDIUM")], [IKB(f"{MMChoice.LATE_LONG.value} Arrivo dopo 40+ min.", callback_data=f"mm{mmevent.mmid}_LATE_LONG")], [IKB(f"{MMChoice.NO_TIME} Non posso a quell'ora...", callback_data=f"mm{mmevent.mmid}_NO_TIME")], [IKB(f"{MMChoice.NO_INTEREST} Non mi interessa.", callback_data=f"mm{mmevent.mmid}_NO_INTEREST")], @@ -72,17 +86,33 @@ class MatchmakingCommand(Command): author = await data.get_author(error_if_none=True) # Find the MMEvent with the current session mmevent: MMEvent = await asyncify(data.session.query(self.alchemy.MMEvent).get, mmid) - mmresponse: MMResponse = await asyncify(data.session.query(self.alchemy.MMResponse).filter_by(royal=author, mmevent=mmevent).one_or_none) + mmresponse: MMResponse = await asyncify( + data.session.query(self.alchemy.MMResponse).filter_by(user=author, mmevent=mmevent).one_or_none) if mmresponse is None: - mmresponse = self.alchemy.MMResponse(royal=author, mmevent=mmevent, choice=choice) + mmresponse = self.alchemy.MMResponse(user=author, mmevent=mmevent, choice=choice) data.session.add(mmresponse) else: mmresponse.choice = choice await data.session_commit() await self._update_telegram_mm_message(client, mmevent) return f"✅ Messaggio ricevuto!" + return callback + def _gen_event_start_message(self, mmevent: MMEvent): + text = f"🚩 L'evento [b]{mmevent.title}[/b] è iniziato!\n\n" \ + f"Partecipano:\n" + for mmresponse in sorted(mmevent.responses, key=lambda mmr: mmr.user.username): + if mmresponse.response == "YES": + text += f"✅ {mmresponse.user}\n" + elif mmresponse.response == "NO": + text += f"❌ {mmresponse.user}\n" + return text + + def _gen_unauth_message(self, user: User): + return f"⚠️ Non sono autorizzato a mandare messaggi a [b]{user.username}[/b]!\n" \ + f"{user.telegram.mention()}, apri una chat privata con me e mandami un messaggio!" + async def _run_mmevent(self, mmid: int): """Run a MMEvent.""" # Open a new Alchemy Session @@ -91,6 +121,9 @@ class MatchmakingCommand(Command): mmevent: MMEvent = await asyncify(session.query(self.alchemy.MMEvent).get, mmid) if mmevent is None: raise ValueError("Invalid mmid.") + # Ensure the MMEvent hasn't already started + if mmevent.datetime <= datetime.datetime.now(): + raise ValueError("MMEvent has already started.") # Ensure the MMEvent interface matches the current one if mmevent.interface != self.interface.name: raise ValueError("Invalid interface.") @@ -103,27 +136,76 @@ class MatchmakingCommand(Command): # Send the keyboard message: PTBMessage = await self.interface.bot.safe_api_call(client.send_message, chat_id=self._mm_chat_id, - text=telegram_escape(self._gen_mm_message(mmevent)), + text=telegram_escape( + self._gen_mm_message(mmevent)), parse_mode="HTML", disable_webpage_preview=True, - reply_markup=self._gen_telegram_keyboard(mmevent.mmid)) + reply_markup=self._gen_telegram_keyboard( + mmevent.mmid)) # Store message data in the interface data object - mmevent.interface_data = MMInterfaceDataTelegram(chat_id=self._mm_chat_id, message_id=message.message_id) + mmevent.interface_data = MMInterfaceDataTelegram(chat_id=self._mm_chat_id, + message_id=message.message_id) + await asyncify(session.commit) else: raise UnsupportedError() # Register handlers for the keyboard events if self.interface.name == "telegram": bot: TelegramBot = self.interface.bot client: PTBBot = bot.client - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_YES", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.YES)) - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_MAYBE", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.MAYBE)) - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_LATE_SHORT", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.LATE_SHORT)) - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_LATE_MEDIUM", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.LATE_MEDIUM)) - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_LATE_LONG", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.LATE_LONG)) - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_NO_TIME", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.NO_TIME)) - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_NO_INTEREST", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.NO_INTEREST)) - self.interface.register_keyboard_key(f"mm{mmevent.mmid}_NO_TECH", callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.NO_TECH)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_YES", + callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.YES)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_MAYBE", + callback=self._gen_mm_telegram_callback(client, mmid, MMChoice.MAYBE)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_LATE_SHORT", + callback=self._gen_mm_telegram_callback(client, mmid, + MMChoice.LATE_SHORT)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_LATE_MEDIUM", + callback=self._gen_mm_telegram_callback(client, mmid, + MMChoice.LATE_MEDIUM)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_LATE_LONG", + callback=self._gen_mm_telegram_callback(client, mmid, + MMChoice.LATE_LONG)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_NO_TIME", + callback=self._gen_mm_telegram_callback(client, mmid, + MMChoice.NO_TIME)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_NO_INTEREST", + callback=self._gen_mm_telegram_callback(client, mmid, + MMChoice.NO_INTEREST)) + self.interface.register_keyboard_key(f"mm{mmevent.mmid}_NO_TECH", + callback=self._gen_mm_telegram_callback(client, mmid, + MMChoice.NO_TECH)) else: raise UnsupportedError() # Sleep until the time of the event - ... + await sleep_until(mmevent.datetime) + # Notify the positive answers of the event start + if self.interface.name == "telegram": + bot: TelegramBot = self.interface.bot + client: PTBBot = bot.client + for response in mmevent.responses: + if response.choice == MMChoice.NO_INTEREST or response.choice == MMChoice.NO_TIME: + return + try: + await self.interface.bot.safe_api_call(client.send_message, + chat_id=response.user.telegram.tg_id, + text=telegram_escape(self._gen_event_start_message(mmevent)), + parse_mode="HTML", + disable_webpage_preview=True) + except Unauthorized: + await self.interface.bot.safe_api_call(client.send_message, + chat_id=self._mm_error_chat_id, + text=telegram_escape( + self._gen_unauth_message(response.user)), + parse_mode="HTML", + disable_webpage_preview=True) + else: + raise UnsupportedError() + # Delete the event message + if self.interface.name == "telegram": + await self.interface.bot.safe_api_call(client.delete_message, + chat_id=mmevent.interface_data.chat_id, + message_id=mmevent.interface_data.message_id, + parse_mode="HTML", + disable_webpage_preview=True) + # The end! + await asyncify(session.close) diff --git a/royalnet/packs/royal/tables/mmresponse.py b/royalnet/packs/royal/tables/mmresponse.py index 37b0b845..4d04931a 100644 --- a/royalnet/packs/royal/tables/mmresponse.py +++ b/royalnet/packs/royal/tables/mmresponse.py @@ -8,11 +8,11 @@ class MMResponse: __tablename__ = "mmresponse" @declared_attr - def royal_id(self): + def user_id(self): return Column(Integer, ForeignKey("users.uid"), primary_key=True) @declared_attr - def royal(self): + def user(self): return relationship("User", backref="mmresponses_given") @declared_attr @@ -28,4 +28,4 @@ class MMResponse: return Column(Enum(MMChoice), nullable=False) def __repr__(self): - return f"" + return f""