mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Add mm command (VERY WIP; PROBABLY HAS 9001 RACE CONDITIONS)
This commit is contained in:
parent
e7b98880e0
commit
e63086393b
11 changed files with 481 additions and 5 deletions
|
@ -127,6 +127,8 @@ class DiscordBot(GenericBot):
|
||||||
error_message += '\n'.join(e.args)
|
error_message += '\n'.join(e.args)
|
||||||
log.error(f"Error in {command.name}: {error_message}")
|
log.error(f"Error in {command.name}: {error_message}")
|
||||||
await data.reply(f"⛔️ {error_message}")
|
await data.reply(f"⛔️ {error_message}")
|
||||||
|
if __debug__:
|
||||||
|
raise
|
||||||
|
|
||||||
async def on_ready(cli):
|
async def on_ready(cli):
|
||||||
log.debug("Connection successful, client is ready")
|
log.debug("Connection successful, client is ready")
|
||||||
|
|
|
@ -154,6 +154,8 @@ class GenericBot:
|
||||||
self._init_royalnet(royalnet_config=royalnet_config)
|
self._init_royalnet(royalnet_config=royalnet_config)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sentry_sdk.capture_exception(e)
|
sentry_sdk.capture_exception(e)
|
||||||
|
log.error(f"{e.__class__.__name__} while initializing Royalnet: {' | '.join(e.args)}")
|
||||||
|
raise
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
"""A blocking coroutine that should make the bot start listening to commands and requests."""
|
"""A blocking coroutine that should make the bot start listening to commands and requests."""
|
||||||
|
|
|
@ -67,7 +67,12 @@ class TelegramBot(GenericBot):
|
||||||
disable_web_page_preview=True)
|
disable_web_page_preview=True)
|
||||||
|
|
||||||
async def get_author(data, error_if_none=False):
|
async def get_author(data, error_if_none=False):
|
||||||
user: telegram.User = data.update.effective_user
|
if data.update.message is not None:
|
||||||
|
user: telegram.User = data.update.message.from_user
|
||||||
|
elif data.update.callback_query is not None:
|
||||||
|
user: telegram.user = data.update.callback_query.from_user
|
||||||
|
else:
|
||||||
|
raise UnregisteredError("Author can not be determined")
|
||||||
if user is None:
|
if user is None:
|
||||||
if error_if_none:
|
if error_if_none:
|
||||||
raise UnregisteredError("No author for this message")
|
raise UnregisteredError("No author for this message")
|
||||||
|
@ -148,6 +153,8 @@ class TelegramBot(GenericBot):
|
||||||
error_message = f"⛔️ [b]{e.__class__.__name__}[/b]\n"
|
error_message = f"⛔️ [b]{e.__class__.__name__}[/b]\n"
|
||||||
error_message += '\n'.join(e.args)
|
error_message += '\n'.join(e.args)
|
||||||
await data.reply(error_message)
|
await data.reply(error_message)
|
||||||
|
if __debug__:
|
||||||
|
raise
|
||||||
|
|
||||||
async def _handle_callback_query(self, update: telegram.Update):
|
async def _handle_callback_query(self, update: telegram.Update):
|
||||||
query: telegram.CallbackQuery = update.callback_query
|
query: telegram.CallbackQuery = update.callback_query
|
||||||
|
|
|
@ -23,6 +23,7 @@ from .videochannel import VideochannelCommand
|
||||||
from .dnditem import DnditemCommand
|
from .dnditem import DnditemCommand
|
||||||
from .dndspell import DndspellCommand
|
from .dndspell import DndspellCommand
|
||||||
from .trivia import TriviaCommand
|
from .trivia import TriviaCommand
|
||||||
|
from .mm import MmCommand
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"CiaoruoziCommand",
|
"CiaoruoziCommand",
|
||||||
|
@ -44,5 +45,6 @@ __all__ = [
|
||||||
"VideochannelCommand",
|
"VideochannelCommand",
|
||||||
"DnditemCommand",
|
"DnditemCommand",
|
||||||
"DndspellCommand",
|
"DndspellCommand",
|
||||||
"TriviaCommand"
|
"TriviaCommand",
|
||||||
|
"MmCommand"
|
||||||
]
|
]
|
||||||
|
|
271
royalnet/commands/royalgames/mm.py
Normal file
271
royalnet/commands/royalgames/mm.py
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
import typing
|
||||||
|
import datetime
|
||||||
|
import dateparser
|
||||||
|
import os
|
||||||
|
import telegram
|
||||||
|
import asyncio
|
||||||
|
from ..command import Command
|
||||||
|
from ..commandargs import CommandArgs
|
||||||
|
from ..commanddata import CommandData
|
||||||
|
from ...database.tables import MMEvent, MMDecision, MMResponse
|
||||||
|
from ...error import *
|
||||||
|
from ...utils import asyncify, telegram_escape, sleep_until
|
||||||
|
|
||||||
|
|
||||||
|
class MmCommand(Command):
|
||||||
|
"""Matchmaking command.
|
||||||
|
|
||||||
|
Requires the MM_CHANNEL_ID envvar to be set."""
|
||||||
|
name: str = "mm"
|
||||||
|
|
||||||
|
description: str = "Trova giocatori per una partita a qualcosa."
|
||||||
|
|
||||||
|
syntax: str = "[ (data) ] (nomegioco)\n[descrizione]"
|
||||||
|
|
||||||
|
require_alchemy_tables = {MMEvent, MMDecision, MMResponse}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _decision_string(mmevent: MMEvent) -> str:
|
||||||
|
return f"⚫️ Hai detto che forse parteciperai a [b]{mmevent.title}[/b] alle [b]{mmevent.datetime.strftime('%H:%M')}[/b].\n" \
|
||||||
|
f"Confermi di volerci essere?"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _decision_keyboard(mmevent: MMEvent) -> telegram.InlineKeyboardMarkup:
|
||||||
|
return telegram.InlineKeyboardMarkup([
|
||||||
|
[telegram.InlineKeyboardButton("🔵 Ci sarò!", callback_data=f"mm_{mmevent.mmid}_d_YES"),
|
||||||
|
telegram.InlineKeyboardButton("🔴 Non mi interessa...", callback_data=f"mm_{mmevent.mmid}_d_NO")]
|
||||||
|
])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _response_string(mmevent: MMEvent, count: int = 0) -> str:
|
||||||
|
if count == 0:
|
||||||
|
return f"🚩 E' ora di [b]{mmevent.title}[/b]!\n" \
|
||||||
|
f"Sei pronto?"
|
||||||
|
else:
|
||||||
|
return f"🕒 Sei in ritardo di [b]{count * 5}[/b] minuti per [b]{mmevent.title}[/b]...\n" \
|
||||||
|
f"Sei pronto?"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _response_keyboard(mmevent: MMEvent) -> telegram.InlineKeyboardMarkup:
|
||||||
|
return telegram.InlineKeyboardMarkup([
|
||||||
|
[telegram.InlineKeyboardButton("✅ Ci sono!", callback_data=f"mm_{mmevent.mmid}_r_YES")],
|
||||||
|
[telegram.InlineKeyboardButton("🕒 Aspettatemi 5 minuti!", callback_data=f"mm_{mmevent.mmid}_r_LATER")],
|
||||||
|
[telegram.InlineKeyboardButton("❌ Non ci sono più, mi spiace.", callback_data=f"mm_{mmevent.mmid}_r_NO")]
|
||||||
|
])
|
||||||
|
|
||||||
|
async def _update_message(self, mmevent: MMEvent) -> None:
|
||||||
|
client: telegram.Bot = self.interface.bot.client
|
||||||
|
try:
|
||||||
|
await asyncify(client.edit_message_text,
|
||||||
|
text=telegram_escape(str(mmevent)),
|
||||||
|
chat_id=os.environ["MM_CHANNEL_ID"],
|
||||||
|
message_id=mmevent.message_id,
|
||||||
|
parse_mode="HTML",
|
||||||
|
disable_web_page_preview=True,
|
||||||
|
reply_markup=mmevent.main_keyboard())
|
||||||
|
except telegram.error.BadRequest:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def run(self, args: CommandArgs, data: CommandData) -> None:
|
||||||
|
if self.interface.name != "telegram":
|
||||||
|
raise UnsupportedError("mm is supported only on Telegram")
|
||||||
|
client: telegram.Bot = self.interface.bot.client
|
||||||
|
creator = await data.get_author(error_if_none=True)
|
||||||
|
timestring, title, description = args.match(r"\[\s*([^]]+)\s*]\s*([^\n]+)\s*\n?\s*(.+)?\s*")
|
||||||
|
|
||||||
|
try:
|
||||||
|
dt: typing.Optional[datetime.datetime] = dateparser.parse(timestring)
|
||||||
|
except OverflowError:
|
||||||
|
dt = None
|
||||||
|
if dt is None:
|
||||||
|
await data.reply("⚠️ La data che hai specificato non è valida.")
|
||||||
|
return
|
||||||
|
if dt <= datetime.datetime.now():
|
||||||
|
await data.reply("⚠️ La data che hai specificato è nel passato.")
|
||||||
|
return
|
||||||
|
|
||||||
|
mmevent: MMEvent = self.interface.alchemy.MMEvent(creator=creator,
|
||||||
|
datetime=dt,
|
||||||
|
title=title,
|
||||||
|
description=description,
|
||||||
|
state="WAITING")
|
||||||
|
self.interface.session.add(mmevent)
|
||||||
|
await asyncify(self.interface.session.commit)
|
||||||
|
|
||||||
|
async def decision_yes(data: CommandData):
|
||||||
|
royal = await data.get_author()
|
||||||
|
mmdecision: MMDecision = await asyncify(self.interface.session.query(self.interface.alchemy.MMDecision).filter_by(mmevent=mmevent, royal=royal).one_or_none)
|
||||||
|
if mmdecision is None:
|
||||||
|
mmdecision: MMDecision = self.interface.alchemy.MMDecision(royal=royal,
|
||||||
|
mmevent=mmevent,
|
||||||
|
decision="YES")
|
||||||
|
self.interface.session.add(mmdecision)
|
||||||
|
else:
|
||||||
|
mmdecision.decision = "YES"
|
||||||
|
# Can't asyncify this
|
||||||
|
self.interface.session.commit()
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
return "🔵 Hai detto che ci sarai!"
|
||||||
|
|
||||||
|
async def decision_maybe(data: CommandData):
|
||||||
|
royal = await data.get_author()
|
||||||
|
mmdecision: MMDecision = await asyncify(self.interface.session.query(self.interface.alchemy.MMDecision).filter_by(mmevent=mmevent, royal=royal).one_or_none)
|
||||||
|
if mmdecision is None:
|
||||||
|
mmdecision: MMDecision = self.interface.alchemy.MMDecision(royal=royal,
|
||||||
|
mmevent=mmevent,
|
||||||
|
decision="MAYBE")
|
||||||
|
self.interface.session.add(mmdecision)
|
||||||
|
else:
|
||||||
|
mmdecision.decision = "MAYBE"
|
||||||
|
# Can't asyncify this
|
||||||
|
self.interface.session.commit()
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
return "⚫️ Hai detto che forse ci sarai. Rispondi al messaggio di conferma 5 minuti prima dell'inizio!"
|
||||||
|
|
||||||
|
async def decision_no(data: CommandData):
|
||||||
|
royal = await data.get_author()
|
||||||
|
mmdecision: MMDecision = await asyncify(self.interface.session.query(self.interface.alchemy.MMDecision).filter_by(mmevent=mmevent, royal=royal).one_or_none)
|
||||||
|
if mmdecision is None:
|
||||||
|
mmdecision: MMDecision = self.interface.alchemy.MMDecision(royal=royal,
|
||||||
|
mmevent=mmevent,
|
||||||
|
decision="NO")
|
||||||
|
self.interface.session.add(mmdecision)
|
||||||
|
else:
|
||||||
|
mmdecision.decision = "NO"
|
||||||
|
# Can't asyncify this
|
||||||
|
self.interface.session.commit()
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
return "🔴 Hai detto che non ti interessa."
|
||||||
|
|
||||||
|
self.interface.register_keyboard_key(f"mm_{mmevent.mmid}_d_YES", decision_yes)
|
||||||
|
self.interface.register_keyboard_key(f"mm_{mmevent.mmid}_d_MAYBE", decision_maybe)
|
||||||
|
self.interface.register_keyboard_key(f"mm_{mmevent.mmid}_d_NO", decision_no)
|
||||||
|
|
||||||
|
message: telegram.Message = await asyncify(client.send_message,
|
||||||
|
chat_id=os.environ["MM_CHANNEL_ID"],
|
||||||
|
text=telegram_escape(str(mmevent)),
|
||||||
|
parse_mode="HTML",
|
||||||
|
disable_webpage_preview=True,
|
||||||
|
reply_markup=mmevent.main_keyboard())
|
||||||
|
|
||||||
|
mmevent.message_id = message.message_id
|
||||||
|
# Can't asyncify this
|
||||||
|
self.interface.session.commit()
|
||||||
|
|
||||||
|
await sleep_until(dt - datetime.timedelta(minutes=10))
|
||||||
|
|
||||||
|
mmevent.state = "DECISION"
|
||||||
|
await asyncify(self.interface.session.commit)
|
||||||
|
for mmdecision in mmevent.decisions:
|
||||||
|
mmdecision: MMDecision
|
||||||
|
if mmdecision.decision == "MAYBE":
|
||||||
|
await asyncify(client.send_message,
|
||||||
|
chat_id=mmdecision.royal.telegram[0].tg_id,
|
||||||
|
text=telegram_escape(self._decision_string(mmevent)),
|
||||||
|
parse_mode="HTML",
|
||||||
|
disable_webpage_preview=True,
|
||||||
|
reply_markup=self._decision_keyboard(mmevent))
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
|
||||||
|
await sleep_until(dt)
|
||||||
|
|
||||||
|
async def response_yes(data: CommandData):
|
||||||
|
royal = await data.get_author()
|
||||||
|
mmresponse: MMResponse = await asyncify(
|
||||||
|
self.interface.session.query(self.interface.alchemy.MMResponse).filter_by(mmevent=mmevent, royal=royal).one_or_none)
|
||||||
|
mmresponse.response = "YES"
|
||||||
|
# Can't asyncify this
|
||||||
|
self.interface.session.commit()
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
return "✅ Sei pronto!"
|
||||||
|
|
||||||
|
async def response_later(data: CommandData):
|
||||||
|
royal = await data.get_author()
|
||||||
|
mmresponse: MMResponse = await asyncify(
|
||||||
|
self.interface.session.query(self.interface.alchemy.MMResponse).filter_by(mmevent=mmevent, royal=royal).one_or_none)
|
||||||
|
mmresponse.response = "LATER"
|
||||||
|
# Can't asyncify this
|
||||||
|
self.interface.session.commit()
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
return "🕒 Hai chiesto agli altri di aspettarti 5 minuti."
|
||||||
|
|
||||||
|
async def response_no(data: CommandData):
|
||||||
|
royal = await data.get_author()
|
||||||
|
mmresponse: MMResponse = await asyncify(
|
||||||
|
self.interface.session.query(self.interface.alchemy.MMResponse).filter_by(mmevent=mmevent, royal=royal).one_or_none)
|
||||||
|
mmresponse.response = "NO"
|
||||||
|
# Can't asyncify this
|
||||||
|
self.interface.session.commit()
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
return "❌ Hai detto che non ci sarai."
|
||||||
|
|
||||||
|
async def start_now():
|
||||||
|
mmevent.state = "STARTED"
|
||||||
|
for mmresponse in mmevent.responses:
|
||||||
|
if mmresponse.response is None:
|
||||||
|
mmresponse.response = "NO"
|
||||||
|
if mmresponse.response == "LATER":
|
||||||
|
mmresponse.response = "NO"
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
await asyncify(self.interface.session.commit)
|
||||||
|
self.interface.unregister_keyboard_key(f"mm_{mmevent.mmid}_r_YES")
|
||||||
|
self.interface.unregister_keyboard_key(f"mm_{mmevent.mmid}_r_LATER")
|
||||||
|
self.interface.unregister_keyboard_key(f"mm_{mmevent.mmid}_r_NO")
|
||||||
|
self.interface.unregister_keyboard_key(f"mm_{mmevent.mmid}_start")
|
||||||
|
|
||||||
|
async def start_key(data: CommandData):
|
||||||
|
royal = await data.get_author()
|
||||||
|
if royal == creator:
|
||||||
|
await start_now()
|
||||||
|
|
||||||
|
mmevent.state = "READY_CHECK"
|
||||||
|
|
||||||
|
self.interface.unregister_keyboard_key(f"mm_{mmevent.mmid}_d_YES")
|
||||||
|
self.interface.unregister_keyboard_key(f"mm_{mmevent.mmid}_d_MAYBE")
|
||||||
|
self.interface.unregister_keyboard_key(f"mm_{mmevent.mmid}_d_NO")
|
||||||
|
|
||||||
|
for mmdecision in mmevent.decisions:
|
||||||
|
if mmdecision.decision == "MAYBE":
|
||||||
|
mmdecision.decision = "NO"
|
||||||
|
elif mmdecision.decision == "YES":
|
||||||
|
mmresponse: MMResponse = self.interface.alchemy.MMResponse(royal=mmdecision.royal, mmevent=mmevent)
|
||||||
|
self.interface.session.add(mmresponse)
|
||||||
|
await asyncify(self.interface.session.commit)
|
||||||
|
|
||||||
|
self.interface.register_keyboard_key(f"mm_{mmevent.mmid}_r_YES", response_yes)
|
||||||
|
self.interface.register_keyboard_key(f"mm_{mmevent.mmid}_r_LATER", response_later)
|
||||||
|
self.interface.register_keyboard_key(f"mm_{mmevent.mmid}_r_NO", response_no)
|
||||||
|
self.interface.register_keyboard_key(f"mm_{mmevent.mmid}_start", start_key)
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
while True:
|
||||||
|
for mmresponse in mmevent.responses:
|
||||||
|
# Send messages
|
||||||
|
if mmresponse.response is None:
|
||||||
|
await asyncify(client.send_message,
|
||||||
|
chat_id=mmresponse.royal.telegram[0].tg_id,
|
||||||
|
text=telegram_escape(self._response_string(mmevent, count=count)),
|
||||||
|
parse_mode="HTML",
|
||||||
|
disable_webpage_preview=True,
|
||||||
|
reply_markup=self._response_keyboard(mmevent))
|
||||||
|
await self._update_message(mmevent)
|
||||||
|
# Wait
|
||||||
|
await asyncio.sleep(300)
|
||||||
|
|
||||||
|
# Advance cycle
|
||||||
|
for mmresponse in mmevent.responses:
|
||||||
|
if mmresponse.response is None:
|
||||||
|
mmresponse.response = "NO"
|
||||||
|
if mmresponse.response == "LATER":
|
||||||
|
mmresponse.response = None
|
||||||
|
|
||||||
|
# Check if the event can start
|
||||||
|
for mmresponse in mmevent.responses:
|
||||||
|
if mmresponse.response is None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
await start_now()
|
|
@ -61,6 +61,9 @@ class ReminderCommand(Command):
|
||||||
if date is None:
|
if date is None:
|
||||||
await data.reply("⚠️ La data che hai inserito non è valida.")
|
await data.reply("⚠️ La data che hai inserito non è valida.")
|
||||||
return
|
return
|
||||||
|
if date <= datetime.datetime.now():
|
||||||
|
await data.reply("⚠️ La data che hai specificato è nel passato.")
|
||||||
|
return
|
||||||
await data.reply(f"✅ Promemoria impostato per [b]{date.strftime('%Y-%m-%d %H:%M:%S')}[/b]")
|
await data.reply(f"✅ Promemoria impostato per [b]{date.strftime('%Y-%m-%d %H:%M:%S')}[/b]")
|
||||||
if self.interface.name == "telegram":
|
if self.interface.name == "telegram":
|
||||||
interface_data = pickle.dumps(data.update.effective_chat.id)
|
interface_data = pickle.dumps(data.update.effective_chat.id)
|
||||||
|
|
|
@ -13,6 +13,10 @@ from .medalawards import MedalAward
|
||||||
from .bios import Bio
|
from .bios import Bio
|
||||||
from .reminders import Reminder
|
from .reminders import Reminder
|
||||||
from .triviascores import TriviaScore
|
from .triviascores import TriviaScore
|
||||||
|
from .mmdecisions import MMDecision
|
||||||
|
from .mmevents import MMEvent
|
||||||
|
from .mmresponse import MMResponse
|
||||||
|
|
||||||
__all__ = ["Royal", "Telegram", "Diario", "Alias", "ActiveKvGroup", "Keyvalue", "Keygroup", "Discord", "WikiPage",
|
__all__ = ["Royal", "Telegram", "Diario", "Alias", "ActiveKvGroup", "Keyvalue", "Keygroup", "Discord", "WikiPage",
|
||||||
"WikiRevision", "Medal", "MedalAward", "Bio", "Reminder", "TriviaScore"]
|
"WikiRevision", "Medal", "MedalAward", "Bio", "Reminder", "TriviaScore", "MMDecision", "MMEvent",
|
||||||
|
"MMResponse"]
|
||||||
|
|
36
royalnet/database/tables/mmdecisions.py
Normal file
36
royalnet/database/tables/mmdecisions.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from sqlalchemy import Column, \
|
||||||
|
Integer, \
|
||||||
|
String, \
|
||||||
|
ForeignKey
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
from .royals import Royal
|
||||||
|
from .mmevents import MMEvent
|
||||||
|
|
||||||
|
|
||||||
|
class MMDecision:
|
||||||
|
__tablename__ = "mmdecisions"
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal_id(self):
|
||||||
|
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal(self):
|
||||||
|
return relationship("Royal", backref="mmdecisions_taken")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def mmevent_id(self):
|
||||||
|
return Column(Integer, ForeignKey("mmevents.mmid"), primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def mmevent(self):
|
||||||
|
return relationship("MMEvent", backref="decisions")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def decision(self):
|
||||||
|
# Valid decisions are YES, MAYBE or NO
|
||||||
|
return Column(String, nullable=False)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<MMDecision of {self.royal}: {self.decision}>"
|
113
royalnet/database/tables/mmevents.py
Normal file
113
royalnet/database/tables/mmevents.py
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import telegram
|
||||||
|
import typing
|
||||||
|
from sqlalchemy import Column, \
|
||||||
|
Integer, \
|
||||||
|
DateTime, \
|
||||||
|
String, \
|
||||||
|
Text, \
|
||||||
|
ForeignKey, \
|
||||||
|
BigInteger
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
from .royals import Royal
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from .mmdecisions import MMDecision
|
||||||
|
from .mmresponse import MMResponse
|
||||||
|
|
||||||
|
|
||||||
|
class MMEvent:
|
||||||
|
__tablename__ = "mmevents"
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def creator_id(self):
|
||||||
|
return Column(Integer, ForeignKey("royals.uid"), nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def creator(self):
|
||||||
|
return relationship("Royal", backref="mmevents_created")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def mmid(self):
|
||||||
|
return Column(Integer, primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def datetime(self):
|
||||||
|
return Column(DateTime, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def title(self):
|
||||||
|
return Column(String, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def description(self):
|
||||||
|
return Column(Text, nullable=False, default="")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def state(self):
|
||||||
|
# Valid states are WAITING, DECISION, READY_CHECK, STARTED
|
||||||
|
return Column(String, nullable=False, default="WAITING")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def message_id(self):
|
||||||
|
return Column(BigInteger)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<MMEvent {self.mmid}: {self.title}>"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
text = f"🌐 [b]{self.title}[/b] - [b]{self.datetime.strftime('%Y-%m-%d %H:%M')}[/b]\n"
|
||||||
|
if self.description:
|
||||||
|
text += f"{self.description}\n"
|
||||||
|
text += "\n"
|
||||||
|
if self.state == "WAITING" or self.state == "DECISION":
|
||||||
|
for mmdecision in self.decisions:
|
||||||
|
mmdecision: "MMDecision"
|
||||||
|
if mmdecision.decision == "YES":
|
||||||
|
text += "🔵 "
|
||||||
|
elif mmdecision.decision == "MAYBE":
|
||||||
|
text += "⚫️ "
|
||||||
|
elif mmdecision.decision == "NO":
|
||||||
|
text += "🔴 "
|
||||||
|
else:
|
||||||
|
raise ValueError(f"decision is of an unknown value ({mmdecision.decision})")
|
||||||
|
text += f"{mmdecision.royal}\n"
|
||||||
|
elif self.state == "READY_CHECK":
|
||||||
|
for mmresponse in self.responses:
|
||||||
|
mmresponse: "MMResponse"
|
||||||
|
if mmresponse.response is None:
|
||||||
|
text += "❔ "
|
||||||
|
elif mmresponse.response == "YES":
|
||||||
|
text += "✅ "
|
||||||
|
elif mmresponse.response == "LATER":
|
||||||
|
text += "🕒 "
|
||||||
|
elif mmresponse.response == "NO":
|
||||||
|
text += "❌ "
|
||||||
|
else:
|
||||||
|
raise ValueError(f"response is of an unknown value ({mmresponse.response})")
|
||||||
|
text += f"{mmresponse.royal}\n"
|
||||||
|
elif self.state == "STARTED":
|
||||||
|
for mmresponse in self.responses:
|
||||||
|
if mmresponse.response == "YES":
|
||||||
|
text += f"✅ {mmresponse.royal}\n"
|
||||||
|
return text
|
||||||
|
|
||||||
|
def main_keyboard(self) -> typing.Optional[telegram.InlineKeyboardMarkup]:
|
||||||
|
if self.state == "WAITING":
|
||||||
|
return telegram.InlineKeyboardMarkup([
|
||||||
|
[telegram.InlineKeyboardButton("🔵 Ci sarò!", callback_data=f"mm_{self.mmid}_d_YES")],
|
||||||
|
[telegram.InlineKeyboardButton("⚫️ Forse...", callback_data=f"mm_{self.mmid}_d_MAYBE")],
|
||||||
|
[telegram.InlineKeyboardButton("🔴 Non mi interessa.", callback_data=f"mm_{self.mmid}_d_NO")]
|
||||||
|
])
|
||||||
|
elif self.state == "DECISION":
|
||||||
|
return telegram.InlineKeyboardMarkup([
|
||||||
|
[telegram.InlineKeyboardButton("🔵 Ci sarò!", callback_data=f"mm_{self.mmid}_d_YES"),
|
||||||
|
telegram.InlineKeyboardButton("🔴 Non mi interessa...", callback_data=f"mm_{self.mmid}_d_NO")]
|
||||||
|
])
|
||||||
|
elif self.state == "READY_CHECK":
|
||||||
|
return telegram.InlineKeyboardMarkup([
|
||||||
|
[telegram.InlineKeyboardButton("🚩 Avvia la partita", callback_data=f"mm_{self.mmid}_start")]
|
||||||
|
])
|
||||||
|
elif self.state == "STARTED":
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
raise ValueError(f"state is of an unknown value ({self.state})")
|
36
royalnet/database/tables/mmresponse.py
Normal file
36
royalnet/database/tables/mmresponse.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from sqlalchemy import Column, \
|
||||||
|
Integer, \
|
||||||
|
String, \
|
||||||
|
ForeignKey
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
from .royals import Royal
|
||||||
|
from .mmevents import MMEvent
|
||||||
|
|
||||||
|
|
||||||
|
class MMResponse:
|
||||||
|
__tablename__ = "mmresponse"
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal_id(self):
|
||||||
|
return Column(Integer, ForeignKey("royals.uid"), primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def royal(self):
|
||||||
|
return relationship("Royal", backref="mmresponses_given")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def mmevent_id(self):
|
||||||
|
return Column(Integer, ForeignKey("mmevents.mmid"), primary_key=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def mmevent(self):
|
||||||
|
return relationship("MMEvent", backref="responses")
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def response(self):
|
||||||
|
# Valid decisions are YES, LATER or NO
|
||||||
|
return Column(String)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<MMResponse of {self.royal}: {self.response}>"
|
|
@ -24,7 +24,6 @@ sentry_dsn = os.environ.get("SENTRY_DSN")
|
||||||
# noinspection PyUnreachableCode
|
# noinspection PyUnreachableCode
|
||||||
if __debug__:
|
if __debug__:
|
||||||
commands = [
|
commands = [
|
||||||
|
|
||||||
]
|
]
|
||||||
log.setLevel(logging.DEBUG)
|
log.setLevel(logging.DEBUG)
|
||||||
else:
|
else:
|
||||||
|
@ -48,7 +47,8 @@ else:
|
||||||
VideochannelCommand,
|
VideochannelCommand,
|
||||||
DnditemCommand,
|
DnditemCommand,
|
||||||
DndspellCommand,
|
DndspellCommand,
|
||||||
TriviaCommand
|
TriviaCommand,
|
||||||
|
MmCommand
|
||||||
]
|
]
|
||||||
log.setLevel(logging.INFO)
|
log.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue