1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +00:00

Start porting to 5.11 (sigh)

This commit is contained in:
Steffo 2020-08-20 03:20:53 +02:00
parent c1145550dd
commit 3f1c8a57d3
30 changed files with 746 additions and 1045 deletions

779
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
[tool.poetry] [tool.poetry]
name = "royalpack" name = "royalpack"
version = "5.13.9" version = "5.14.0"
description = "A Royalnet command pack for the Royal Games community" description = "A Royalnet command pack for the Royal Games community"
authors = ["Stefano Pigozzi <ste.pigozzi@gmail.com>"] authors = ["Stefano Pigozzi <ste.pigozzi@gmail.com>"]
license = "AGPL-3.0+" license = "AGPL-3.0+"
@ -28,13 +28,12 @@
itsdangerous = "^1.1.0" itsdangerous = "^1.1.0"
[tool.poetry.dependencies.royalnet] [tool.poetry.dependencies.royalnet]
version = "~5.10.4" version = "~5.11.0"
# Maybe... there is a way to make these selectable? # Maybe... there is a way to make these selectable?
extras = [ extras = [
"telegram", "telegram",
"discord", "discord",
"alchemy_easy", "alchemy_easy",
"bard",
"constellation", "constellation",
"sentry", "sentry",
"herald", "herald",

View file

@ -23,7 +23,6 @@ from .leagueoflegends import LeagueoflegendsCommand
from .magickfiorygi import MagickfiorygiCommand from .magickfiorygi import MagickfiorygiCommand
from .magicktreasure import MagicktreasureCommand from .magicktreasure import MagicktreasureCommand
from .matchmaking import MatchmakingCommand from .matchmaking import MatchmakingCommand
from .peertubeupdates import PeertubeUpdatesCommand
from .ping import PingCommand from .ping import PingCommand
from .pmots import PmotsCommand from .pmots import PmotsCommand
from .dog import DogCommand from .dog import DogCommand
@ -37,7 +36,6 @@ from .steammatch import SteammatchCommand
from .steampowered import SteampoweredCommand from .steampowered import SteampoweredCommand
from .treasure import TreasureCommand from .treasure import TreasureCommand
from .trivia import TriviaCommand from .trivia import TriviaCommand
from .userinfo import UserinfoCommand
from .osu import OsuCommand from .osu import OsuCommand
# Enter the commands of your Pack here! # Enter the commands of your Pack here!
@ -66,7 +64,6 @@ available_commands = [
MagickfiorygiCommand, MagickfiorygiCommand,
MagicktreasureCommand, MagicktreasureCommand,
MatchmakingCommand, MatchmakingCommand,
PeertubeUpdatesCommand,
PingCommand, PingCommand,
PmotsCommand, PmotsCommand,
DogCommand, DogCommand,
@ -80,7 +77,6 @@ available_commands = [
SteampoweredCommand, SteampoweredCommand,
TreasureCommand, TreasureCommand,
TriviaCommand, TriviaCommand,
UserinfoCommand,
OsuCommand, OsuCommand,
] ]

View file

@ -14,37 +14,37 @@ log = logging.getLogger(__name__)
class LinkerCommand(rc.Command, metaclass=abc.ABCMeta): class LinkerCommand(rc.Command, metaclass=abc.ABCMeta):
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf, config)
self.updater_task = None self.updater_task = None
if self.enabled(): if self.enabled():
self.updater_task = self.loop.create_task(self.run_updater()) self.updater_task = self.loop.create_task(self.run_updater())
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
author = await data.get_author(error_if_none=True) author = await data.get_author(error_if_none=True)
if len(args) == 0: async with data.session_acm() as session:
message = [] if len(args) == 0:
for obj in await self.get_updatables_of_user(session=data.session, user=author): message = []
async def change(attribute: str, value: Any): for obj in await self.get_updatables_of_user(session=session, user=author):
"""A shortcut for self.__change.""" async def change(attribute: str, value: Any):
await self._change(session=data.session, """A shortcut for self.__change."""
obj=obj, await self._change(session=session,
attribute=attribute, obj=obj,
new=value) attribute=attribute,
new=value)
await self.update(session=data.session, obj=obj, change=change) await self.update(session=session, obj=obj, change=change)
message.append(self.describe(obj)) message.append(self.describe(obj))
if len(message) == 0: if len(message) == 0:
raise rc.UserError("Nessun account connesso.") raise rc.UserError("Nessun account connesso.")
await data.session_commit() await ru.asyncify(session.commit)
await data.reply("\n".join(message))
else:
created = await self.create(session=data.session, user=author, args=args, data=data)
await data.session_commit()
if created is not None:
message = ["🔗 Account collegato!", "", self.describe(created)]
await data.reply("\n".join(message)) await data.reply("\n".join(message))
else:
created = await self.create(session=session, user=author, args=args, data=data)
await ru.asyncify(session.commit)
if created is not None:
message = ["🔗 Account collegato!", "", self.describe(created)]
await data.reply("\n".join(message))
def describe(self, obj: Updatable) -> str: def describe(self, obj: Updatable) -> str:
"""The text that should be appended to the report message for a given Updatable.""" """The text that should be appended to the report message for a given Updatable."""
@ -143,7 +143,7 @@ class LinkerCommand(rc.Command, metaclass=abc.ABCMeta):
def enabled(self) -> bool: def enabled(self) -> bool:
"""Whether the updater is enabled or not.""" """Whether the updater is enabled or not."""
return self.config[self.name]["updater"]["enabled"] and self.interface.name == "telegram" return self.config[self.name]["updater"]["enabled"] and isinstance(self.serf, rst.TelegramSerf)
def period(self) -> int: def period(self) -> int:
"""The time between two updater cycles.""" """The time between two updater cycles."""

View file

@ -1,15 +1,16 @@
from typing import * from typing import *
import telegram import telegram
from royalnet.commands import * import royalnet.commands as rc
import royalnet.serf.telegram as rst
class CiaoruoziCommand(Command): class CiaoruoziCommand(rc.Command):
name: str = "ciaoruozi" name: str = "ciaoruozi"
description: str = "Saluta Ruozi, un leggendario essere che è tornato in Royal Games." description: str = "Saluta Ruozi, un leggendario essere che è tornato in Royal Games."
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "telegram": if isinstance(self.serf, rst.TelegramSerf):
user: telegram.User = data.message.from_user user: telegram.User = data.message.from_user
# Se sei Ruozi, salutati da solo! # Se sei Ruozi, salutati da solo!
if user.id == 112437036: if user.id == 112437036:

View file

@ -9,9 +9,6 @@ class CvCommand(Command):
syntax: str = "[a][o][n][d][h]" syntax: str = "[a][o][n][d][h]"
def __init__(self, interface: CommandInterface):
super().__init__(interface)
def _render_member(self, def _render_member(self,
member, member,
display_nick: bool, display_nick: bool,
@ -92,7 +89,7 @@ class CvCommand(Command):
return f"{status}{voice} {name}{activity}\n" return f"{status}{voice} {name}{activity}\n"
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: CommandArgs, data: CommandData) -> None:
response: Dict[str, Any] = await self.interface.call_herald_event("discord", "discord_cv") response: Dict[str, Any] = await self.serf.call_herald_event("discord", "discord_cv")
flags = args.optional(0, default="") flags = args.optional(0, default="")
display_nicks = "n" in flags display_nicks = "n" in flags

View file

@ -4,6 +4,7 @@ import asyncio
import datetime import datetime
import royalnet.commands as rc import royalnet.commands as rc
import royalnet.utils as ru import royalnet.utils as ru
import royalnet.serf.discord as rsd
from ..tables import Cvstats from ..tables import Cvstats
@ -18,14 +19,14 @@ class CvstatsCommand(rc.Command):
syntax: str = "" syntax: str = ""
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf=serf, config=config)
if self.interface.name == "discord": if isinstance(self.serf, rsd.DiscordSerf):
self.loop.create_task(self._updater(1800)) self.loop.create_task(self._updater(1800))
def _is_ryg_member(self, member: dict): def _is_ryg_member(self, member: dict):
for role in member["roles"]: for role in member["roles"]:
if role["id"] == self.interface.config["Cv"]["displayed_role_id"]: if role["id"] == self.config["Cv"]["displayed_role_id"]:
return True return True
return False return False
@ -33,7 +34,7 @@ class CvstatsCommand(rc.Command):
log.info(f"Gathering Cvstats...") log.info(f"Gathering Cvstats...")
while True: while True:
try: try:
response: Dict[str, Any] = await self.interface.call_herald_event("discord", "discord_cv") response: Dict[str, Any] = await self.serf.call_herald_event("discord", "discord_cv")
except rc.ConfigurationError: except rc.ConfigurationError:
await asyncio.sleep(10) await asyncio.sleep(10)
continue continue
@ -118,7 +119,8 @@ class CvstatsCommand(rc.Command):
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
CvstatsT = self.alchemy.get(Cvstats) CvstatsT = self.alchemy.get(Cvstats)
cvstats = data.session.query(CvstatsT).order_by(CvstatsT.timestamp.desc()).first() async with data.session_acm() as session:
cvstats = session.query(CvstatsT).order_by(CvstatsT.timestamp.desc()).first()
message = [ message = [
f" [b]Statistiche[/b]", f" [b]Statistiche[/b]",

View file

@ -6,6 +6,7 @@ import aiohttp
import royalnet.commands as rc import royalnet.commands as rc
import royalnet.utils as ru import royalnet.utils as ru
import royalnet.backpack.tables as rbt import royalnet.backpack.tables as rbt
import royalnet.serf.telegram as rst
from ..tables import * from ..tables import *
@ -38,169 +39,166 @@ class DiarioCommand(rc.Command):
syntax = "[!] \"{testo}\" --[autore], [contesto]" syntax = "[!] \"{testo}\" --[autore], [contesto]"
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name == "telegram": async with data.session_acm() as session:
message: telegram.Message = data.message if isinstance(self.serf, rst.TelegramSerf):
reply: telegram.Message = message.reply_to_message message: telegram.Message = data.message
creator = await data.get_author() reply: telegram.Message = message.reply_to_message
# noinspection PyUnusedLocal creator = await data.get_author()
quoted: Optional[str] # noinspection PyUnusedLocal
# noinspection PyUnusedLocal quoted: Optional[str]
text: Optional[str] # noinspection PyUnusedLocal
# noinspection PyUnusedLocal text: Optional[str]
context: Optional[str] # noinspection PyUnusedLocal
# noinspection PyUnusedLocal context: Optional[str]
timestamp: datetime.datetime # noinspection PyUnusedLocal
# noinspection PyUnusedLocal timestamp: datetime.datetime
media_url: Optional[str] # noinspection PyUnusedLocal
# noinspection PyUnusedLocal media_url: Optional[str]
spoiler: bool # noinspection PyUnusedLocal
if creator is None: spoiler: bool
await data.reply("⚠️ Devi essere registrato a Royalnet per usare questo comando!") if creator is None:
return await data.reply("⚠️ Devi essere registrato a Royalnet per usare questo comando!")
if reply is not None: return
# Get the message text if reply is not None:
text = reply.text # Get the message text
# Check if there's an image associated with the reply text = reply.text
photosizes: Optional[List[telegram.PhotoSize]] = reply.photo # Check if there's an image associated with the reply
if photosizes: photosizes: Optional[List[telegram.PhotoSize]] = reply.photo
# Text is a caption if photosizes:
text = reply.caption # Text is a caption
media_url = await to_imgur(self.interface.config["Imgur"]["token"], text = reply.caption
photosizes, text if text is not None else "") media_url = await to_imgur(self.config["Imgur"]["token"],
else: photosizes, text if text is not None else "")
media_url = None
# Ensure there is a text or an image
if not (text or media_url):
raise rc.InvalidInputError("Il messaggio a cui hai risposto non contiene testo o immagini.")
# Find the Royalnet account associated with the sender
quoted_tg = await ru.asyncify(data.session.query(self.alchemy.get(rbt.Telegram))
.filter_by(tg_id=reply.from_user.id)
.one_or_none)
quoted_account = quoted_tg.user if quoted_tg is not None else None
# Find the quoted name to assign
quoted_user: telegram.User = reply.from_user
quoted = quoted_user.full_name
# Get the timestamp
timestamp = reply.date
# Set the other properties
spoiler = False
context = None
else:
# Get the current timestamp
timestamp = datetime.datetime.now()
# Get the message text
raw_text = " ".join(args)
# Check if there's an image associated with the reply
photosizes: Optional[List[telegram.PhotoSize]] = message.photo
if photosizes:
media_url = await to_imgur(self.interface.config["Imgur"]["token"],
photosizes, raw_text if raw_text is not None else "")
else:
media_url = None
# Parse the text, if it exists
if raw_text:
# Pass the sentence through the diario regex
match = re.match(
r'(!)? *["«‘“‛‟❛❝〝"`]([^"]+)["»’”❜❞〞"`] *(?:(?:-{1,2}|—) *([^,]+))?(?:, *([^ ].*))?',
raw_text)
# Find the corresponding matches
if match is not None:
spoiler = bool(match.group(1))
text = match.group(2)
quoted = match.group(3)
context = match.group(4)
# Otherwise, consider everything part of the text
else: else:
spoiler = False media_url = None
text = raw_text # Ensure there is a text or an image
quoted = None if not (text or media_url):
context = None raise rc.InvalidInputError("Il messaggio a cui hai risposto non contiene testo o immagini.")
# Ensure there's a quoted # Find the Royalnet account associated with the sender
if not quoted: quoted_tg = await ru.asyncify(session.query(self.alchemy.get(rbt.Telegram))
quoted = None .filter_by(tg_id=reply.from_user.id)
if not context: .one_or_none)
context = None quoted_account = quoted_tg.user if quoted_tg is not None else None
# Find if there's a Royalnet account associated with the quoted name # Find the quoted name to assign
if quoted is not None: quoted_user: telegram.User = reply.from_user
quoted_alias = await ru.asyncify( quoted = quoted_user.full_name
data.session.query(self.alchemy.get(rbt.Alias)) # Get the timestamp
.filter_by(alias=quoted.lower()).one_or_none timestamp = reply.date
) # Set the other properties
else:
quoted_alias = None
quoted_account = quoted_alias.user if quoted_alias is not None else None
else:
text = None
quoted = None
quoted_account = None
spoiler = False spoiler = False
context = None context = None
# Ensure there is a text or an image else:
if not (text or media_url): # Get the current timestamp
timestamp = datetime.datetime.now()
# Get the message text
raw_text = " ".join(args)
# Check if there's an image associated with the reply
photosizes: Optional[List[telegram.PhotoSize]] = message.photo
if photosizes:
media_url = await to_imgur(self.config["Imgur"]["token"],
photosizes, raw_text if raw_text is not None else "")
else:
media_url = None
# Parse the text, if it exists
if raw_text:
# Pass the sentence through the diario regex
match = re.match(
r'(!)? *["«‘“‛‟❛❝〝"`]([^"]+)["»’”❜❞〞"`] *(?:(?:-{1,2}|—) *([^,]+))?(?:, *([^ ].*))?',
raw_text)
# Find the corresponding matches
if match is not None:
spoiler = bool(match.group(1))
text = match.group(2)
quoted = match.group(3)
context = match.group(4)
# Otherwise, consider everything part of the text
else:
spoiler = False
text = raw_text
quoted = None
context = None
# Ensure there's a quoted
if not quoted:
quoted = None
if not context:
context = None
# Find if there's a Royalnet account associated with the quoted name
if quoted is not None:
quoted_alias = await ru.asyncify(
session.query(self.alchemy.get(rbt.Alias))
.filter_by(alias=quoted.lower()).one_or_none
)
else:
quoted_alias = None
quoted_account = quoted_alias.user if quoted_alias is not None else None
else:
text = None
quoted = None
quoted_account = None
spoiler = False
context = None
# Ensure there is a text or an image
if not (text or media_url):
raise rc.InvalidInputError("Manca il testo o l'immagine da inserire nel diario.")
# Create the diario quote
diario = self.alchemy.get(Diario)(creator=creator,
quoted_account=quoted_account,
quoted=quoted,
text=text,
context=context,
timestamp=timestamp,
media_url=media_url,
spoiler=spoiler)
session.add(diario)
await ru.asyncify(session.commit)
await data.reply(f"{str(diario)}")
else:
# Find the creator of the quotes
creator = await data.get_author(error_if_none=True)
# Recreate the full sentence
raw_text = " ".join(args)
# Pass the sentence through the diario regex
match = re.match(r'(!)? *["«‘“‛‟❛❝〝"`]([^"]+)["»’”❜❞〞"`] *(?:(?:-{1,2}|—) *([^,]+))?(?:, *([^ ].*))?',
raw_text)
# Find the corresponding matches
if match is not None:
spoiler = bool(match.group(1))
text = match.group(2)
quoted = match.group(3)
context = match.group(4)
# Otherwise, consider everything part of the text
else:
spoiler = False
text = raw_text
quoted = None
context = None
timestamp = datetime.datetime.now()
# Ensure there is some text
if not text:
raise rc.InvalidInputError("Manca il testo o l'immagine da inserire nel diario.") raise rc.InvalidInputError("Manca il testo o l'immagine da inserire nel diario.")
# Create the diario quote # Or a quoted
diario = self.alchemy.get(Diario)(creator=creator, if not quoted:
quoted_account=quoted_account, quoted = None
quoted=quoted, if not context:
text=text, context = None
context=context, # Find if there's a Royalnet account associated with the quoted name
timestamp=timestamp, if quoted is not None:
media_url=media_url, quoted_account = await rbt.User.find(self.alchemy, session, quoted)
spoiler=spoiler) else:
data.session.add(diario) quoted_account = None
await ru.asyncify(data.session.commit) if quoted_account is None:
await data.reply(f"{str(diario)}") raise rc.UserError("Il nome dell'autore è ambiguo, quindi la riga non è stata aggiunta.\n"
else: "Per piacere, ripeti il comando con un nome più specifico!")
# Find the creator of the quotes # Create the diario quote
creator = await data.get_author(error_if_none=True) DiarioT = self.alchemy.get(Diario)
# Recreate the full sentence diario = DiarioT(creator=creator,
raw_text = " ".join(args) quoted_account=quoted_account,
# Pass the sentence through the diario regex quoted=quoted,
match = re.match(r'(!)? *["«‘“‛‟❛❝〝"`]([^"]+)["»’”❜❞〞"`] *(?:(?:-{1,2}|—) *([^,]+))?(?:, *([^ ].*))?', text=text,
raw_text) context=context,
# Find the corresponding matches timestamp=timestamp,
if match is not None: media_url=None,
spoiler = bool(match.group(1)) spoiler=spoiler)
text = match.group(2) session.add(diario)
quoted = match.group(3) await ru.asyncify(session.commit)
context = match.group(4) await data.reply(f"{str(diario)}")
# Otherwise, consider everything part of the text
else:
spoiler = False
text = raw_text
quoted = None
context = None
timestamp = datetime.datetime.now()
# Ensure there is some text
if not text:
raise rc.InvalidInputError("Manca il testo o l'immagine da inserire nel diario.")
# Or a quoted
if not quoted:
quoted = None
if not context:
context = None
# Find if there's a Royalnet account associated with the quoted name
if quoted is not None:
quoted_alias = await ru.asyncify(
data.session.query(self.alchemy.get(rbt.Alias))
.filter_by(alias=quoted.lower())
.one_or_none
)
else:
quoted_alias = None
quoted_account = quoted_alias.user if quoted_alias is not None else None
if quoted_alias is not None and quoted_account is None:
raise rc.UserError("Il nome dell'autore è ambiguo, quindi la riga non è stata aggiunta.\n"
"Per piacere, ripeti il comando con un nome più specifico!")
# Create the diario quote
diario = self.alchemy.Diario(creator=creator,
quoted_account=quoted_account,
quoted=quoted,
text=text,
context=context,
timestamp=timestamp,
media_url=None,
spoiler=spoiler)
data.session.add(diario)
await ru.asyncify(data.session.commit)
await data.reply(f"{str(diario)}")

View file

@ -19,7 +19,8 @@ class DiarioquoteCommand(rc.Command):
entry_id = int(args[0].lstrip("#")) entry_id = int(args[0].lstrip("#"))
except ValueError: except ValueError:
raise rc.CommandError("L'id che hai specificato non è valido.") raise rc.CommandError("L'id che hai specificato non è valido.")
entry: Diario = await ru.asyncify(data.session.query(self.alchemy.get(Diario)).get, entry_id) async with data.session_acm() as session:
entry: Diario = await ru.asyncify(session.query(self.alchemy.get(Diario)).get, entry_id)
if entry is None: if entry is None:
raise rc.CommandError("Nessuna riga con quell'id trovata.") raise rc.CommandError("Nessuna riga con quell'id trovata.")
await data.reply(f" {entry}") await data.reply(f" {entry}")

View file

@ -16,14 +16,11 @@ class DiarioshuffleCommand(rc.Command):
syntax = "" syntax = ""
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
DiarioT = self.alchemy.get(Diario) async with data.session_acm() as session:
entry: List[Diario] = await ru.asyncify( DiarioT = self.alchemy.get(Diario)
data.session entry: List[Diario] = await ru.asyncify(
.query(DiarioT) session.query(DiarioT).order_by(func.random()).limit(1).one_or_none
.order_by(func.random()) )
.limit(1) if entry is None:
.one_or_none raise rc.CommandError("Nessuna riga del diario trovata.")
) await data.reply(f" {entry}")
if entry is None:
raise rc.CommandError("Nessuna riga del diario trovata.")
await data.reply(f" {entry}")

View file

@ -15,7 +15,7 @@ class EvalCommand(rc.Command):
user: rbt.User = await data.get_author(error_if_none=True) user: rbt.User = await data.get_author(error_if_none=True)
if "admin" not in user.roles: if "admin" not in user.roles:
raise rc.CommandError("Non sei autorizzato a eseguire codice arbitrario!\n" raise rc.CommandError("Non sei autorizzato a eseguire codice arbitrario!\n"
"(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)") "(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)")
try: try:
result = eval(args.joined(require_at_least=1)) result = eval(args.joined(require_at_least=1))
except Exception as e: except Exception as e:

View file

@ -15,7 +15,7 @@ class ExecCommand(rc.Command):
user: rbt.User = await data.get_author(error_if_none=True) user: rbt.User = await data.get_author(error_if_none=True)
if "admin" not in user.roles: if "admin" not in user.roles:
raise rc.CommandError("Non sei autorizzato a eseguire codice arbitrario!\n" raise rc.CommandError("Non sei autorizzato a eseguire codice arbitrario!\n"
"(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)") "(Sarebbe un po' pericoloso se te lo lasciassi eseguire, non trovi?)")
try: try:
exec(args.joined(require_at_least=1)) exec(args.joined(require_at_least=1))
except Exception as e: except Exception as e:

View file

@ -20,7 +20,8 @@ class GivefiorygiCommand(rc.Command):
if user_arg is None: if user_arg is None:
raise rc.InvalidInputError("Non hai specificato un destinatario!") raise rc.InvalidInputError("Non hai specificato un destinatario!")
user = await rbt.User.find(self.alchemy, data.session, user_arg) async with data.session_acm() as session:
user = await rbt.User.find(self.alchemy, session, user_arg)
if user is None: if user is None:
raise rc.InvalidInputError("L'utente specificato non esiste!") raise rc.InvalidInputError("L'utente specificato non esiste!")
if user.uid == author.uid: if user.uid == author.uid:

View file

@ -13,14 +13,14 @@ class GivetreasureCommand(MagicktreasureCommand):
syntax: str = "{codice} {valore}" syntax: str = "{codice} {valore}"
async def _permission_check(self, author, code, value, data): async def _permission_check(self, author, code, value, data, session):
if author.fiorygi.fiorygi < value: if author.fiorygi.fiorygi < value:
raise rc.UserError("Non hai abbastanza fiorygi per creare questo Treasure.") raise rc.UserError("Non hai abbastanza fiorygi per creare questo Treasure.")
async def _create_treasure(self, author, code, value, data): async def _create_treasure(self, author, code, value, data, session):
TreasureT = self.alchemy.get(Treasure) TreasureT = self.alchemy.get(Treasure)
treasure = await ru.asyncify(data.session.query(TreasureT).get, code) treasure = await ru.asyncify(session.query(TreasureT).get, code)
if treasure is not None: if treasure is not None:
raise rc.UserError("Esiste già un Treasure con quel codice.") raise rc.UserError("Esiste già un Treasure con quel codice.")

View file

@ -17,19 +17,19 @@ class HelpCommand(rc.Command):
] ]
for command in sorted(list(set(self.serf.commands.values())), key=lambda c: c.name): for command in sorted(list(set(self.serf.commands.values())), key=lambda c: c.name):
message.append(f"- [c]{self.interface.prefix}{command.name}[/c]") message.append(f"- [c]{self.serf.prefix}{command.name}[/c]")
await data.reply("\n".join(message)) await data.reply("\n".join(message))
else: else:
name: str = args[0].lstrip(self.interface.prefix) name: str = args[0].lstrip(self.serf.prefix)
try: try:
command: rc.Command = self.serf.commands[f"{self.interface.prefix}{name}"] command: rc.Command = self.serf.commands[f"{self.serf.prefix}{name}"]
except KeyError: except KeyError:
raise rc.InvalidInputError("Il comando richiesto non esiste.") raise rc.InvalidInputError("Il comando richiesto non esiste.")
message = [ message = [
f" [c]{self.interface.prefix}{command.name} {command.syntax}[/c]", f" [c]{self.serf.prefix}{command.name} {command.syntax}[/c]",
"", "",
f"{command.description}" f"{command.description}"
] ]

View file

@ -29,8 +29,8 @@ class LeagueoflegendsCommand(LinkerCommand):
"rank_flexq": "Flex", "rank_flexq": "Flex",
} }
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf, config)
self._lolwatcher: Optional[riotwatcher.RiotWatcher] = None self._lolwatcher: Optional[riotwatcher.RiotWatcher] = None
self._tftwatcher: Optional[riotwatcher.RiotWatcher] = None self._tftwatcher: Optional[riotwatcher.RiotWatcher] = None
if self.enabled(): if self.enabled():

View file

@ -23,7 +23,8 @@ class MagickfiorygiCommand(rc.Command):
if user_arg is None: if user_arg is None:
raise rc.InvalidInputError("Non hai specificato un destinatario!") raise rc.InvalidInputError("Non hai specificato un destinatario!")
user = await rbt.User.find(self.alchemy, data.session, user_arg) async with data.session_acm() as session:
user = await rbt.User.find(self.alchemy, session, user_arg)
if user is None: if user is None:
raise rc.InvalidInputError("L'utente specificato non esiste!") raise rc.InvalidInputError("L'utente specificato non esiste!")

View file

@ -12,15 +12,15 @@ class MagicktreasureCommand(rc.Command):
syntax: str = "{codice} {valore}" syntax: str = "{codice} {valore}"
async def _permission_check(self, author, code, value, data): async def _permission_check(self, author, code, value, data, session):
if "banker" not in author.roles: if "banker" not in author.roles:
raise rc.UserError("Non hai permessi sufficienti per eseguire questo comando.") raise rc.UserError("Non hai permessi sufficienti per eseguire questo comando.")
return author return author
async def _create_treasure(self, author, code, value, data): async def _create_treasure(self, author, code, value, data, session):
TreasureT = self.alchemy.get(Treasure) TreasureT = self.alchemy.get(Treasure)
treasure = await ru.asyncify(data.session.query(TreasureT).get, code) treasure = await ru.asyncify(session.query(TreasureT).get, code)
if treasure is not None: if treasure is not None:
raise rc.UserError("Esiste già un Treasure con quel codice.") raise rc.UserError("Esiste già un Treasure con quel codice.")
@ -44,10 +44,10 @@ class MagicktreasureCommand(rc.Command):
if value < 0: if value < 0:
raise rc.InvalidInputError("Il valore deve essere maggiore o uguale a 0.") raise rc.InvalidInputError("Il valore deve essere maggiore o uguale a 0.")
await self._permission_check(author, code, value, data) async with data.session_acm() as session:
treasure = await self._create_treasure(author, code, value, data) await self._permission_check(author, code, value, data, session)
treasure = await self._create_treasure(author, code, value, data, session)
data.session.add(treasure) session.add(treasure)
await data.session_commit() await ru.asyncify(session.commit)
await data.reply("✅ Treasure creato!") await data.reply("✅ Treasure creato!")

View file

@ -3,7 +3,9 @@ import datetime
import re import re
import dateparser import dateparser
import typing import typing
import royalnet.utils as ru
import royalnet.commands as rc import royalnet.commands as rc
import royalnet.serf.telegram as rst
from ..tables import MMEvent from ..tables import MMEvent
from ..utils import MMTask from ..utils import MMTask
@ -18,20 +20,20 @@ class MatchmakingCommand(rc.Command):
aliases = ["mm", "lfg"] aliases = ["mm", "lfg"]
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf, config)
# Find all active MMEvents and run the tasks for them # Find all active MMEvents and run the tasks for them
session = self.alchemy.Session() session = self.alchemy.Session()
# Create a new MMEvent and run it # Create a new MMEvent and run it
if self.interface.name == "telegram": if isinstance(self.serf, rst.TelegramSerf):
MMEventT = self.alchemy.get(MMEvent) MMEventT = self.alchemy.get(MMEvent)
active_mmevents = ( active_mmevents = (
session session
.query(MMEventT) .query(MMEventT)
.filter( .filter(
MMEventT.interface == self.interface.name, MMEventT.interface == self.serf.interface_name,
MMEventT.interrupted == False MMEventT.interrupted == False
) )
.all() .all()
@ -74,13 +76,14 @@ class MatchmakingCommand(rc.Command):
dt, title, description = self._parse_args(args) dt, title, description = self._parse_args(args)
# Add the MMEvent to the database # Add the MMEvent to the database
mmevent: MMEvent = self.alchemy.get(MMEvent)(creator=author, async with data.session_acm() as session:
datetime=dt, mmevent: MMEvent = self.alchemy.get(MMEvent)(creator=author,
title=title, datetime=dt,
description=description, title=title,
interface=self.interface.name) description=description,
data.session.add(mmevent) interface=self.serf.interface_name)
await data.session_commit() session.add(mmevent)
await ru.asyncify(session.commit)
# Create and run a task for the newly created MMEvent # Create and run a task for the newly created MMEvent
task = MMTask(mmevent.mmid, command=self) task = MMTask(mmevent.mmid, command=self)

View file

@ -7,7 +7,6 @@ import royalnet.commands as rc
import royalnet.utils as ru import royalnet.utils as ru
from .abstract.linker import LinkerCommand from .abstract.linker import LinkerCommand
from ..types import Updatable
from ..tables import Osu from ..tables import Osu
from ..stars.api_auth_login_osu import ApiAuthLoginOsuStar from ..stars.api_auth_login_osu import ApiAuthLoginOsuStar

View file

@ -1,81 +0,0 @@
from typing import *
import aiohttp
import asyncio
import datetime
import logging
import dateparser
import royalnet.commands as rc
import royalnet.serf.telegram as rst
log = logging.getLogger(__name__)
class PeertubeUpdatesCommand(rc.Command):
name: str = "peertubeupdates"
description: str = "Guarda quando è uscito l'ultimo video su PeerTube."
aliases = ["ptu"]
_ready = asyncio.Event()
_latest_date: datetime.datetime = None
def __init__(self, interface: rc.CommandInterface):
super().__init__(interface)
if self.interface.name == "telegram":
self.loop.create_task(self._ready_up())
self.loop.create_task(self._update())
async def _get_json(self):
log.debug("Getting jsonfeed")
async with aiohttp.ClientSession() as session:
async with session.get(self.config["Peertube"]["instance_url"] +
"/feeds/videos.json?sort=-publishedAt&filter=local") as response:
log.debug("Parsing jsonfeed")
if response.status != 200:
raise rc.ExternalError("Peertube is unavailable")
j = await response.json()
log.debug("Jsonfeed parsed successfully")
return j
async def _send(self, message):
client = self.interface.bot.client
await self.interface.bot.safe_api_call(client.send_message,
chat_id=self.config["Telegram"]["main_group_id"],
text=rst.escape(message),
parse_mode="HTML",
disable_webpage_preview=True)
async def _ready_up(self):
j = await self._get_json()
if j["version"] != "https://jsonfeed.org/version/1":
raise rc.ConfigurationError("url is not a jsonfeed")
videos = j["items"]
for video in reversed(videos):
date_modified = dateparser.parse(video["date_modified"])
if self._latest_date is None or date_modified > self._latest_date:
log.debug(f"Found newer video: {date_modified}")
self._latest_date = date_modified
self._ready.set()
async def _update(self):
await self._ready.wait()
while True:
j = await self._get_json()
videos = j["items"]
for video in reversed(videos):
date_modified = dateparser.parse(video["date_modified"])
if date_modified > self._latest_date:
log.debug(f"Found newer video: {date_modified}")
self._latest_date = date_modified
await self._send(f"🆕 Nuovo video su RoyalTube!\n"
f"[b]{video['title']}[/b]\n"
f"{video['url']}")
await asyncio.sleep(self.config["Peertube"]["feed_update_timeout"])
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if self.interface.name != "telegram":
raise rc.UnsupportedError()
await data.reply(f" Ultimo video caricato il: [b]{self._latest_date.isoformat()}[/b]")

View file

@ -12,7 +12,7 @@ class PingCommand(rc.Command):
syntax: str = "" syntax: str = ""
_targets = ["telegram", "discord", "matrix", "constellation"] _targets = ["telegram", "discord", "constellation"]
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
await data.reply("📶 Ping...") await data.reply("📶 Ping...")
@ -21,7 +21,7 @@ class PingCommand(rc.Command):
start = datetime.datetime.now() start = datetime.datetime.now()
for target in self._targets: for target in self._targets:
tasks[target] = self.loop.create_task(self.interface.call_herald_event(target, "pong")) tasks[target] = self.loop.create_task(self.serf.call_herald_event(target, "pong"))
await asyncio.sleep(10) await asyncio.sleep(10)

View file

@ -7,8 +7,8 @@ import discord
from sqlalchemy import and_ from sqlalchemy import and_
import royalnet.commands as rc import royalnet.commands as rc
import royalnet.utils as ru import royalnet.utils as ru
from royalnet.serf.telegram import escape as telegram_escape import royalnet.serf.telegram as rst
from royalnet.serf.discord import escape as discord_escape import royalnet.serf.discord as rsd
from ..tables import Reminder from ..tables import Reminder
@ -22,34 +22,35 @@ class ReminderCommand(rc.Command):
syntax: str = "[ {data} ] {messaggio}" syntax: str = "[ {data} ] {messaggio}"
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf, config)
session = interface.alchemy.Session()
session = self.alchemy.Session()
reminders = ( reminders = (
session.query(interface.alchemy.get(Reminder)) session.query(self.alchemy.get(Reminder))
.filter(and_( .filter(and_(
interface.alchemy.get(Reminder).datetime >= datetime.datetime.now(), self.alchemy.get(Reminder).datetime >= datetime.datetime.now(),
interface.alchemy.get(Reminder).interface_name == interface.name)) self.alchemy.get(Reminder).interface_name == self.serf.interface_name))
.all() .all()
) )
for reminder in reminders: for reminder in reminders:
interface.loop.create_task(self._remind(reminder)) self.loop.create_task(self._remind(reminder))
async def _remind(self, reminder): async def _remind(self, reminder):
await ru.sleep_until(reminder.datetime) await ru.sleep_until(reminder.datetime)
if self.interface.name == "telegram": if isinstance(self.serf, rst.TelegramSerf):
chat_id: int = pickle.loads(reminder.interface_data) chat_id: int = pickle.loads(reminder.interface_data)
client: telegram.Bot = self.serf.client client: telegram.Bot = self.serf.client
await self.serf.api_call(client.send_message, await self.serf.api_call(client.send_message,
chat_id=chat_id, chat_id=chat_id,
text=telegram_escape(f"❗️ {reminder.message}"), text=rst.escape(f"❗️ {reminder.message}"),
parse_mode="HTML", parse_mode="HTML",
disable_web_page_preview=True) disable_web_page_preview=True)
elif self.interface.name == "discord": elif isinstance(self.serf, rsd.DiscordSerf):
channel_id: int = pickle.loads(reminder.interface_data) channel_id: int = pickle.loads(reminder.interface_data)
client: discord.Client = self.serf.client client: discord.Client = self.serf.client
channel = client.get_channel(channel_id) channel = client.get_channel(channel_id)
await channel.send(discord_escape(f"❗️ {reminder.message}")) await channel.send(rsd.escape(f"❗️ {reminder.message}"))
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
try: try:
@ -70,18 +71,19 @@ class ReminderCommand(rc.Command):
await data.reply("⚠️ La data che hai specificato è nel passato.") await data.reply("⚠️ La data che hai specificato è nel passato.")
return 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 isinstance(self.serf, rst.TelegramSerf):
interface_data = pickle.dumps(data.message.chat.id) interface_data = pickle.dumps(data.message.chat.id)
elif self.interface.name == "discord": elif isinstance(self.serf, rsd.DiscordSerf):
interface_data = pickle.dumps(data.message.channel.id) interface_data = pickle.dumps(data.message.channel.id)
else: else:
raise rc.UnsupportedError("This command does not support the current interface.") raise rc.UnsupportedError("This command does not support the current interface.")
creator = await data.get_author() creator = await data.get_author()
reminder = self.interface.alchemy.get(Reminder)(creator=creator, async with data.session_acm() as session:
interface_name=self.interface.name, reminder = self.alchemy.get(Reminder)(creator=creator,
interface_data=interface_data, interface_name=self.serf.interface_name,
datetime=date, interface_data=interface_data,
message=reminder_text) datetime=date,
self.interface.loop.create_task(self._remind(reminder)) message=reminder_text)
data.session.add(reminder) self.loop.create_task(self._remind(reminder))
await ru.asyncify(data.session.commit) session.add(reminder)
await ru.asyncify(session.commit)

View file

@ -16,10 +16,7 @@ class RoyalpackCommand(rc.Command):
return pkg_resources.get_distribution("royalpack").version return pkg_resources.get_distribution("royalpack").version
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
if __debug__: message = f" Royalpack [url=https://github.com/Steffo99/royalpack/releases/tag/{self.royalpack_version}]{self.royalpack_version}[/url]\n"
message = f" Royalpack [url=https://github.com/Steffo99/royalpack/]Unreleased[/url]\n"
else:
message = f" Royalpack [url=https://github.com/Steffo99/royalpack/releases/tag/{self.royalpack_version}]{self.royalpack_version}[/url]\n"
if "69" in self.royalpack_version: if "69" in self.royalpack_version:
message += "(Nice.)" message += "(Nice.)"
await data.reply(message) await data.reply(message)

View file

@ -53,8 +53,8 @@ class SteammatchCommand(rc.Command):
syntax: str = "{royalnet_username}+" syntax: str = "{royalnet_username}+"
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf, config)
self._api = steam.webapi.WebAPI(self.config["steampowered"]["token"]) self._api = steam.webapi.WebAPI(self.config["steampowered"]["token"])
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
@ -64,7 +64,8 @@ class SteammatchCommand(rc.Command):
users.append(author) users.append(author)
for arg in args: for arg in args:
user = await rbt.User.find(self.alchemy, data.session, arg) async with data.session_acm() as session:
user = await rbt.User.find(self.alchemy, session, arg)
users.append(user) users.append(user)
if len(users) < 2: if len(users) < 2:

View file

@ -22,8 +22,8 @@ class SteampoweredCommand(LinkerCommand):
syntax: str = "{url_profilo}" syntax: str = "{url_profilo}"
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf, config)
self._api = steam.webapi.WebAPI(self.token()) self._api = steam.webapi.WebAPI(self.token())
def token(self): def token(self):

View file

@ -16,16 +16,17 @@ class TreasureCommand(rc.Command):
author = await data.get_author(error_if_none=True) author = await data.get_author(error_if_none=True)
code = args[0].lower() code = args[0].lower()
TreasureT = self.alchemy.get(Treasure) async with data.session_acm() as session:
TreasureT = self.alchemy.get(Treasure)
treasure = await ru.asyncify(data.session.query(TreasureT).get, code) treasure = await ru.asyncify(session.query(TreasureT).get, code)
if treasure is None: if treasure is None:
raise rc.UserError("Non esiste nessun Treasure con quel codice.") raise rc.UserError("Non esiste nessun Treasure con quel codice.")
if treasure.redeemed_by is not None: if treasure.redeemed_by is not None:
raise rc.UserError(f"Quel tesoro è già stato riscattato da {treasure.redeemed_by}.") raise rc.UserError(f"Quel tesoro è già stato riscattato da {treasure.redeemed_by}.")
treasure.redeemed_by = author treasure.redeemed_by = author
await data.session_commit() await ru.asyncify(session.commit)
await FiorygiTransaction.spawn_fiorygi(data, await FiorygiTransaction.spawn_fiorygi(data,
author, author,
treasure.value, treasure.value,

View file

@ -31,117 +31,116 @@ class TriviaCommand(rc.Command):
# _question_lock: bool = False # _question_lock: bool = False
def __init__(self, interface: rc.CommandInterface): def __init__(self, serf, config):
super().__init__(interface) super().__init__(serf, config)
self._answerers: Dict[uuid.UUID, Dict[str, bool]] = {} self._answerers: Dict[uuid.UUID, Dict[str, bool]] = {}
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None: async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
arg = args.optional(0) arg = args.optional(0)
if arg == "credits": async with data.session_acm() as session:
await data.reply(f" [c]{self.interface.prefix}{self.name}[/c] di [i]Steffo[/i]\n" if arg == "credits":
f"\n" await data.reply(f" [c]{self.serf.prefix}{self.name}[/c] di [i]Steffo[/i]\n"
f"Tutte le domande vengono dall'[b]Open Trivia Database[/b] di [i]Pixeltail Games[/i]," f"\n"
f" creatori di Tower Unite, e sono rilasciate sotto la licenza [b]CC BY-SA 4.0[/b].") f"Tutte le domande vengono dall'[b]Open Trivia Database[/b] di [i]Pixeltail Games[/i],"
return f" creatori di Tower Unite, e sono rilasciate sotto la licenza [b]CC BY-SA 4.0[/b].")
elif arg == "scores": return
trivia_scores = await ru.asyncify(data.session.query(self.alchemy.get(TriviaScore)).all) elif arg == "scores":
strings = ["🏆 [b]Trivia Leaderboards[/b]\n"] trivia_scores = await ru.asyncify(session.query(self.alchemy.get(TriviaScore)).all)
for index, ts in enumerate(sorted(trivia_scores, key=lambda ts: -ts.score)): strings = ["🏆 [b]Trivia Leaderboards[/b]\n"]
if index > 3: for index, ts in enumerate(sorted(trivia_scores, key=lambda ts: -ts.score)):
index = 3 if index > 3:
strings.append(f"{self._medal_emojis[index]} {ts.user.username}: [b]{ts.score:.0f}p[/b]" index = 3
f" ({ts.correct_answers}/{ts.total_answers})") strings.append(f"{self._medal_emojis[index]} {ts.user.username}: [b]{ts.score:.0f}p[/b]"
await data.reply("\n".join(strings)) f" ({ts.correct_answers}/{ts.total_answers})")
return await data.reply("\n".join(strings))
# if self._question_lock: return
# raise rc.CommandError("C'è già un'altra domanda attiva!") # if self._question_lock:
# self._question_lock = True # raise rc.CommandError("C'è già un'altra domanda attiva!")
# Fetch the question # self._question_lock = True
async with aiohttp.ClientSession() as session: # Fetch the question
async with session.get("https://opentdb.com/api.php?amount=1") as response: async with aiohttp.ClientSession() as ws:
j = await response.json() async with ws.get("https://opentdb.com/api.php?amount=1") as response:
# Parse the question j = await response.json()
if j["response_code"] != 0: # Parse the question
raise rc.CommandError(f"OpenTDB returned an error response_code ({j['response_code']}).") if j["response_code"] != 0:
question = j["results"][0] raise rc.CommandError(f"OpenTDB returned an error response_code ({j['response_code']}).")
text = f'❓ [b]{question["category"]}[/b]\n' \ question = j["results"][0]
f'{html.unescape(question["question"])}' text = f'❓ [b]{question["category"]}[/b]\n' \
# Prepare answers f'{html.unescape(question["question"])}'
correct_answer: str = question["correct_answer"] # Prepare answers
wrong_answers: List[str] = question["incorrect_answers"] correct_answer: str = question["correct_answer"]
answers: List[str] = [correct_answer, *wrong_answers] wrong_answers: List[str] = question["incorrect_answers"]
if question["type"] == "multiple": answers: List[str] = [correct_answer, *wrong_answers]
random.shuffle(answers) if question["type"] == "multiple":
elif question["type"] == "boolean": random.shuffle(answers)
answers.sort(key=lambda a: a) elif question["type"] == "boolean":
answers.reverse() answers.sort(key=lambda a: a)
else: answers.reverse()
raise NotImplementedError("Unknown question type")
# Find the correct index
for index, answer in enumerate(answers):
if answer == correct_answer:
correct_index = index
break
else:
raise ValueError("correct_index not found")
# Add emojis
for index, answer in enumerate(answers):
answers[index] = f"{self._letter_emojis[index]} {html.unescape(answers[index])}"
# Create the question id
question_id = uuid.uuid4()
self._answerers[question_id] = {}
# Create the correct and wrong functions
async def correct(data: rc.CommandData):
answerer_ = await data.get_author(error_if_none=True)
try:
self._answerers[question_id][answerer_.uid] = True
except KeyError:
raise rc.UserError("Tempo scaduto!")
await data.reply("🆗 Hai risposto alla domanda. Ora aspetta un attimo per i risultati!")
async def wrong(data: rc.CommandData):
answerer_ = await data.get_author(error_if_none=True)
try:
self._answerers[question_id][answerer_.uid] = False
except KeyError:
raise rc.UserError("Tempo scaduto!")
await data.reply("🆗 Hai risposto alla domanda. Ora aspetta un attimo per i risultati!")
# Add question
keyboard: List[rc.KeyboardKey] = []
for index, answer in enumerate(answers):
if index == correct_index:
keyboard.append(rc.KeyboardKey(interface=self.interface,
short=self._letter_emojis[index],
text=answers[index],
callback=correct))
else: else:
keyboard.append(rc.KeyboardKey(interface=self.interface, raise NotImplementedError("Unknown question type")
short=self._letter_emojis[index], # Find the correct index
text=answers[index], for index, answer in enumerate(answers):
callback=wrong)) if answer == correct_answer:
async with data.keyboard(text=text, keys=keyboard): correct_index = index
await asyncio.sleep(self._answer_time) break
results = f"❗️ Tempo scaduto!\n" \
f"La risposta corretta era [b]{answers[correct_index]}[/b]!\n\n"
for answerer_id in self._answerers[question_id]:
answerer = data.session.query(self.alchemy.get(rbt.users.User)).get(answerer_id)
if answerer.trivia_score is None:
ts = self.interface.alchemy.get(TriviaScore)(user=answerer)
data.session.add(ts)
await ru.asyncify(data.session.commit)
previous_score = answerer.trivia_score.score
if self._answerers[question_id][answerer_id]:
results += self._correct_emoji
answerer.trivia_score.correct_answers += 1
else: else:
results += self._wrong_emoji raise ValueError("correct_index not found")
answerer.trivia_score.wrong_answers += 1 # Add emojis
current_score = answerer.trivia_score.score for index, answer in enumerate(answers):
score_difference = current_score - previous_score answers[index] = f"{self._letter_emojis[index]} {html.unescape(answers[index])}"
results += f" {answerer}: [b]{current_score:.0f}p[/b] ({score_difference:+.0f}p)\n" # Create the question id
await data.reply(results) question_id = uuid.uuid4()
del self._answerers[question_id] self._answerers[question_id] = {}
await ru.asyncify(data.session.commit)
# self._question_lock = False # Create the correct and wrong functions
async def correct(data: rc.CommandData):
answerer_ = await data.get_author(error_if_none=True)
try:
self._answerers[question_id][answerer_.uid] = True
except KeyError:
raise rc.UserError("Tempo scaduto!")
await data.reply("🆗 Hai risposto alla domanda. Ora aspetta un attimo per i risultati!")
async def wrong(data: rc.CommandData):
answerer_ = await data.get_author(error_if_none=True)
try:
self._answerers[question_id][answerer_.uid] = False
except KeyError:
raise rc.UserError("Tempo scaduto!")
await data.reply("🆗 Hai risposto alla domanda. Ora aspetta un attimo per i risultati!")
# Add question
keyboard: List[rc.KeyboardKey] = []
for index, answer in enumerate(answers):
if index == correct_index:
keyboard.append(rc.KeyboardKey(short=self._letter_emojis[index],
text=answers[index],
callback=correct))
else:
keyboard.append(rc.KeyboardKey(short=self._letter_emojis[index],
text=answers[index],
callback=wrong))
async with data.keyboard(text=text, keys=keyboard):
await asyncio.sleep(self._answer_time)
results = f"❗️ Tempo scaduto!\n" \
f"La risposta corretta era [b]{answers[correct_index]}[/b]!\n\n"
for answerer_id in self._answerers[question_id]:
answerer = session.query(self.alchemy.get(rbt.users.User)).get(answerer_id)
if answerer.trivia_score is None:
ts = self.alchemy.get(TriviaScore)(user=answerer)
session.add(ts)
await ru.asyncify(session.commit)
previous_score = answerer.trivia_score.score
if self._answerers[question_id][answerer_id]:
results += self._correct_emoji
answerer.trivia_score.correct_answers += 1
else:
results += self._wrong_emoji
answerer.trivia_score.wrong_answers += 1
current_score = answerer.trivia_score.score
score_difference = current_score - previous_score
results += f" {answerer}: [b]{current_score:.0f}p[/b] ({score_difference:+.0f}p)\n"
await data.reply(results)
del self._answerers[question_id]
await ru.asyncify(session.commit)
# self._question_lock = False

View file

@ -1,74 +0,0 @@
from typing import *
import royalnet.commands as rc
import royalnet.backpack.tables as rbt
class UserinfoCommand(rc.Command):
name: str = "userinfo"
aliases = ["uinfo", "ui", "useri"]
description: str = "Visualizza informazioni su un utente."
syntax = "[username]"
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
username = args.optional(0)
if username is None:
user: rbt.User = await data.get_author(error_if_none=True)
else:
found: Optional[rbt.User] = await rbt.User.find(self.alchemy, data.session, username)
if not found:
raise rc.InvalidInputError("Utente non trovato.")
else:
user = found
r = [
f" [url=https://ryg.steffo.eu/#/user/{user.uid}]{user.username}[/url]",
f"{', '.join(user.roles)}",
]
if user.email:
r.append(f"{user.email}")
r.append("")
# Bios are a bit too long
# if user.bio:
# r.append(f"{user.bio}")
for account in user.telegram:
r.append(f"{account}")
for account in user.discord:
r.append(f"{account}")
for account in user.steam:
r.append(f"{account}")
if account.dota is not None:
r.append(f"{account.dota}")
if account.brawlhalla is not None:
r.append(f"{account.brawlhalla}")
for account in user.leagueoflegends:
r.append(f"{account}")
r.append("")
r.append(f"Ha creato [b]{len(user.diario_created)}[/b] righe di "
f"[url=https://ryg.steffo.eu/#/diario]Diario[/url], e vi compare in"
f" [b]{len(user.diario_quoted)}[/b] righe.")
r.append("")
if user.trivia_score:
r.append(f"Ha [b]{user.trivia_score.score:.0f}[/b] punti Trivia, avendo risposto correttamente a"
f" [b]{user.trivia_score.correct_answers}[/b] domande su"
f" [b]{user.trivia_score.total_answers}[/b].")
r.append("")
if user.fiorygi:
r.append(f"Ha [b]{user.fiorygi}[/b].")
r.append("")
await data.reply("\n".join(r))

View file

@ -4,6 +4,7 @@ import datetime
from sqlalchemy import * from sqlalchemy import *
from sqlalchemy.orm import * from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.declarative import declared_attr
import royalnet.utils as ru
from .fiorygi import Fiorygi from .fiorygi import Fiorygi
@ -48,35 +49,38 @@ class FiorygiTransaction:
@classmethod @classmethod
async def spawn_fiorygi(cls, data: "CommandData", user, qty: int, reason: str): async def spawn_fiorygi(cls, data: "CommandData", user, qty: int, reason: str):
if user.fiorygi is None: if user.fiorygi is None:
data.session.add(data._interface.alchemy.get(Fiorygi)( async with data.session_acm() as session:
session.add(data.alchemy.get(Fiorygi)(
user_id=user.uid,
fiorygi=0
))
await ru.asyncify(session.commit)
async with data.session_acm() as session:
transaction = data.alchemy.get(FiorygiTransaction)(
user_id=user.uid, user_id=user.uid,
fiorygi=0 change=qty,
)) reason=reason,
await data.session_commit() timestamp=datetime.datetime.now()
)
session.add(transaction)
transaction = data._interface.alchemy.get(FiorygiTransaction)( user.fiorygi.fiorygi += qty
user_id=user.uid, await ru.asyncify(session.commit)
change=qty,
reason=reason,
timestamp=datetime.datetime.now()
)
data.session.add(transaction)
user.fiorygi.fiorygi += qty if len(user.telegram) > 0:
await data.session_commit() user_str = user.telegram[0].mention()
else:
user_str = user.username
if len(user.telegram) > 0: if qty > 0:
user_str = user.telegram[0].mention() msg = f"💰 [b]{user_str}[/b] ha ottenuto [b]{qty}[/b] fioryg{'i' if qty != 1 else ''} per [i]{reason}[/i]!"
else: elif qty == 0:
user_str = user.username msg = f"❓ [b]{user_str}[/b] ha mantenuto i suoi fiorygi attuali per [i]{reason}[/i].\nWait, cosa?"
else:
msg = f"💸 [b]{user_str}[/b] ha perso [b]{-qty}[/b] fioryg{'i' if qty != -1 else ''} per [i]{reason}[/i]."
if qty > 0: await data.command.serf.call_herald_event(
msg = f"💰 [b]{user_str}[/b] ha ottenuto [b]{qty}[/b] fioryg{'i' if qty != 1 else ''} per [i]{reason}[/i]!" "telegram", "telegram_message",
elif qty == 0: chat_id=data.command.config["Telegram"]["main_group_id"],
msg = f"❓ [b]{user_str}[/b] ha mantenuto i suoi fiorygi attuali per [i]{reason}[/i].\nWait, cosa?" text=msg)
else:
msg = f"💸 [b]{user_str}[/b] ha perso [b]{-qty}[/b] fioryg{'i' if qty != -1 else ''} per [i]{reason}[/i]."
await data._interface.call_herald_event("telegram", "telegram_message",
chat_id=data._interface.config["Telegram"]["main_group_id"],
text=msg)