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)
|
||||
log.error(f"Error in {command.name}: {error_message}")
|
||||
await data.reply(f"⛔️ {error_message}")
|
||||
if __debug__:
|
||||
raise
|
||||
|
||||
async def on_ready(cli):
|
||||
log.debug("Connection successful, client is ready")
|
||||
|
|
|
@ -154,6 +154,8 @@ class GenericBot:
|
|||
self._init_royalnet(royalnet_config=royalnet_config)
|
||||
except Exception as e:
|
||||
sentry_sdk.capture_exception(e)
|
||||
log.error(f"{e.__class__.__name__} while initializing Royalnet: {' | '.join(e.args)}")
|
||||
raise
|
||||
|
||||
async def run(self):
|
||||
"""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)
|
||||
|
||||
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 error_if_none:
|
||||
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 += '\n'.join(e.args)
|
||||
await data.reply(error_message)
|
||||
if __debug__:
|
||||
raise
|
||||
|
||||
async def _handle_callback_query(self, update: telegram.Update):
|
||||
query: telegram.CallbackQuery = update.callback_query
|
||||
|
|
|
@ -23,6 +23,7 @@ from .videochannel import VideochannelCommand
|
|||
from .dnditem import DnditemCommand
|
||||
from .dndspell import DndspellCommand
|
||||
from .trivia import TriviaCommand
|
||||
from .mm import MmCommand
|
||||
|
||||
__all__ = [
|
||||
"CiaoruoziCommand",
|
||||
|
@ -44,5 +45,6 @@ __all__ = [
|
|||
"VideochannelCommand",
|
||||
"DnditemCommand",
|
||||
"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:
|
||||
await data.reply("⚠️ La data che hai inserito non è valida.")
|
||||
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]")
|
||||
if self.interface.name == "telegram":
|
||||
interface_data = pickle.dumps(data.update.effective_chat.id)
|
||||
|
|
|
@ -13,6 +13,10 @@ from .medalawards import MedalAward
|
|||
from .bios import Bio
|
||||
from .reminders import Reminder
|
||||
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",
|
||||
"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
|
||||
if __debug__:
|
||||
commands = [
|
||||
|
||||
]
|
||||
log.setLevel(logging.DEBUG)
|
||||
else:
|
||||
|
@ -48,7 +47,8 @@ else:
|
|||
VideochannelCommand,
|
||||
DnditemCommand,
|
||||
DndspellCommand,
|
||||
TriviaCommand
|
||||
TriviaCommand,
|
||||
MmCommand
|
||||
]
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
|
|
Loading…
Reference in a new issue