mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-12-17 23:24:20 +00:00
Many more improvements
This commit is contained in:
parent
a564e33efc
commit
6666331a15
16 changed files with 96 additions and 54 deletions
|
@ -2,6 +2,7 @@ import telegram
|
||||||
import asyncio
|
import asyncio
|
||||||
import typing
|
import typing
|
||||||
import logging as _logging
|
import logging as _logging
|
||||||
|
import sys
|
||||||
from ..commands import NullCommand
|
from ..commands import NullCommand
|
||||||
from ..utils import asyncify, Call, Command
|
from ..utils import asyncify, Call, Command
|
||||||
from ..network import RoyalnetLink, Message
|
from ..network import RoyalnetLink, Message
|
||||||
|
@ -120,9 +121,17 @@ class TelegramBot:
|
||||||
command = self.missing_command
|
command = self.missing_command
|
||||||
# Call the command
|
# Call the command
|
||||||
try:
|
try:
|
||||||
return await self.Call(message.chat, command, *parameters, update=update).run()
|
return await self.Call(message.chat, command, parameters,
|
||||||
|
update=update).run()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return await self.Call(message.chat, self.error_command, *parameters, update=update, exception=exc, previous_command=command).run()
|
try:
|
||||||
|
return await self.Call(message.chat, self.error_command, parameters,
|
||||||
|
update=update,
|
||||||
|
exception_info=sys.exc_info(),
|
||||||
|
previous_command=command,
|
||||||
|
log=log).run()
|
||||||
|
except Exception as exc2:
|
||||||
|
log.error(f"Exception in error handler command: {exc2}")
|
||||||
|
|
||||||
async def handle_net_request(self, message: Message):
|
async def handle_net_request(self, message: Message):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -8,8 +8,8 @@ class CiaoruoziCommand(Command):
|
||||||
command_title = "Saluta Ruozi, anche se non è più in RYG."
|
command_title = "Saluta Ruozi, anche se non è più in RYG."
|
||||||
command_syntax = ""
|
command_syntax = ""
|
||||||
|
|
||||||
async def telegram(self, call: Call, args: CommandArgs):
|
async def telegram(self, call: Call):
|
||||||
update: Update = args.kwargs["update"]
|
update: Update = call.kwargs["update"]
|
||||||
user: User = update.effective_user
|
user: User = update.effective_user
|
||||||
if user.id == 112437036:
|
if user.id == 112437036:
|
||||||
await call.reply("👋 Ciao me!")
|
await call.reply("👋 Ciao me!")
|
||||||
|
|
|
@ -7,7 +7,7 @@ class ColorCommand(Command):
|
||||||
command_title = "Invia un colore in chat...?"
|
command_title = "Invia un colore in chat...?"
|
||||||
command_syntax = ""
|
command_syntax = ""
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
await call.reply("""
|
await call.reply("""
|
||||||
[i]I am sorry, unknown error occured during working with your request, Admin were notified[/i]
|
[i]I am sorry, unknown error occured during working with your request, Admin were notified[/i]
|
||||||
""")
|
""")
|
||||||
|
|
|
@ -10,7 +10,7 @@ class DebugAuthorCommand(Command):
|
||||||
|
|
||||||
require_alchemy_tables = {Royal, Telegram}
|
require_alchemy_tables = {Royal, Telegram}
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
author = await call.get_author()
|
author = await call.get_author()
|
||||||
if author is None:
|
if author is None:
|
||||||
await call.reply(f"☁️ L'autore di questa chiamata è sconosciuto.")
|
await call.reply(f"☁️ L'autore di questa chiamata è sconosciuto.")
|
||||||
|
|
|
@ -10,10 +10,10 @@ class DebugCreateCommand(Command):
|
||||||
|
|
||||||
require_alchemy_tables = {Royal, Alias}
|
require_alchemy_tables = {Royal, Alias}
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
royal = call.alchemy.Royal(username=args[0], role="Member")
|
royal = call.alchemy.Royal(username=call.args[0], role="Member")
|
||||||
call.session.add(royal)
|
call.session.add(royal)
|
||||||
alias = call.alchemy.Alias(royal=royal, alias=royal.username)
|
alias = call.alchemy.Alias(royal=royal, alias=royal.username)
|
||||||
call.session.add(alias)
|
call.session.add(alias)
|
||||||
await asyncify(call.session.commit)
|
await asyncify(call.session.commit)
|
||||||
await call.reply(f"✅ Utente <code>{royal}</code> creato!")
|
await call.reply(f"✅ Utente [c]{royal}[/c] creato!")
|
||||||
|
|
|
@ -13,18 +13,28 @@ class DiarioCommand(Command):
|
||||||
|
|
||||||
require_alchemy_tables = {Royal, Diario, Alias}
|
require_alchemy_tables = {Royal, Diario, Alias}
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
|
# Find the creator of the quotes
|
||||||
|
creator = await call.get_author()
|
||||||
|
if creator is None:
|
||||||
|
await call.reply("⚠️ Devi essere registrato a Royalnet per usare questo comando!")
|
||||||
|
return
|
||||||
# Recreate the full sentence
|
# Recreate the full sentence
|
||||||
text = " ".join(args.args)
|
raw_text = " ".join(call.args)
|
||||||
# Pass the sentence through the diario regex
|
# Pass the sentence through the diario regex
|
||||||
match = re.match(r'(!)? *["«‘“‛‟❛❝〝"`]([^"]+)["»’”❜❞〞"`] *(?:(?:-{1,2}|—) *([\w ]+))?(?:, *([^ ].*))?', text)
|
match = re.match(r'(!)? *["«‘“‛‟❛❝〝"`]([^"]+)["»’”❜❞〞"`] *(?:(?:-{1,2}|—) *([\w ]+))?(?:, *([^ ].*))?', raw_text)
|
||||||
# Find the corresponding matches
|
# Find the corresponding matches
|
||||||
if match is None:
|
if match is not None:
|
||||||
raise InvalidInputError("No match found.")
|
spoiler = bool(match.group(1))
|
||||||
spoiler = bool(match.group(1))
|
text = match.group(2)
|
||||||
text = match.group(2)
|
quoted = match.group(3)
|
||||||
quoted = match.group(3)
|
context = match.group(4)
|
||||||
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()
|
timestamp = datetime.datetime.now()
|
||||||
# Find if there's a Royalnet account associated with the quoted name
|
# Find if there's a Royalnet account associated with the quoted name
|
||||||
if quoted is not None:
|
if quoted is not None:
|
||||||
|
@ -32,8 +42,6 @@ class DiarioCommand(Command):
|
||||||
else:
|
else:
|
||||||
quoted_alias = None
|
quoted_alias = None
|
||||||
quoted_account = quoted_alias.royal if quoted_alias is not None else None
|
quoted_account = quoted_alias.royal if quoted_alias is not None else None
|
||||||
# Find the creator of the quotes
|
|
||||||
creator = await call.get_author()
|
|
||||||
# Create the diario quote
|
# Create the diario quote
|
||||||
diario = call.alchemy.Diario(creator=creator,
|
diario = call.alchemy.Diario(creator=creator,
|
||||||
quoted_account=quoted_account,
|
quoted_account=quoted_account,
|
||||||
|
@ -45,4 +53,4 @@ class DiarioCommand(Command):
|
||||||
spoiler=spoiler)
|
spoiler=spoiler)
|
||||||
call.session.add(diario)
|
call.session.add(diario)
|
||||||
await asyncify(call.session.commit)
|
await asyncify(call.session.commit)
|
||||||
await call.reply(f"✅ Aggiunto al diario!")
|
await call.reply(f"✅ {str(diario)}")
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from ..utils import Command, CommandArgs, Call, InvalidInputError
|
import traceback
|
||||||
|
from logging import Logger
|
||||||
|
from ..utils import Command, CommandArgs, Call, InvalidInputError, UnsupportedError
|
||||||
|
|
||||||
class ErrorHandlerCommand(Command):
|
class ErrorHandlerCommand(Command):
|
||||||
|
|
||||||
|
@ -7,14 +8,20 @@ class ErrorHandlerCommand(Command):
|
||||||
command_title = "Gestisce gli errori causati dagli altri comandi."
|
command_title = "Gestisce gli errori causati dagli altri comandi."
|
||||||
command_syntax = ""
|
command_syntax = ""
|
||||||
|
|
||||||
async def telegram(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
|
raise UnsupportedError()
|
||||||
|
|
||||||
|
async def telegram(self, call: Call):
|
||||||
try:
|
try:
|
||||||
exc = args.kwargs["exception"]
|
e_type, e_value, e_tb = call.kwargs["exception_info"]
|
||||||
except InvalidInputError:
|
except InvalidInputError:
|
||||||
await call.reply("⚠️ Questo comando non può essere chiamato da solo.")
|
await call.reply("⚠️ Questo comando non può essere chiamato da solo.")
|
||||||
return
|
return
|
||||||
if isinstance(exc, InvalidInputError):
|
if e_type == InvalidInputError:
|
||||||
command = args.kwargs["previous_command"]
|
command = call.kwargs["previous_command"]
|
||||||
await call.reply(f"⚠️ Sintassi non valida.\nSintassi corretta:[c]/{command.command_name} {command.command_syntax}[/c]")
|
await call.reply(f"⚠️ Sintassi non valida.\nSintassi corretta:[c]/{command.command_name} {command.command_syntax}[/c]")
|
||||||
return
|
return
|
||||||
await call.reply("❌ Eccezione non gestita durante l'esecuzione del comando.")
|
await call.reply(f"❌ Eccezione non gestita durante l'esecuzione del comando:\n[b]{e_type.__name__}[/b]\n{e_value}")
|
||||||
|
log: Logger = call.kwargs["log"]
|
||||||
|
formatted_tb: str = '\n'.join(traceback.format_tb(e_tb))
|
||||||
|
log.error(f"Unhandled exception - {e_type.__name__}: {e_value}\n{formatted_tb}")
|
||||||
|
|
|
@ -7,5 +7,5 @@ class NullCommand(Command):
|
||||||
command_title = "Non fa nulla."
|
command_title = "Non fa nulla."
|
||||||
command_syntax = ""
|
command_syntax = ""
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -7,5 +7,5 @@ class PingCommand(Command):
|
||||||
command_title = "Ping pong!"
|
command_title = "Ping pong!"
|
||||||
command_syntax = ""
|
command_syntax = ""
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
await call.reply("🏓 Pong!")
|
await call.reply("🏓 Pong!")
|
||||||
|
|
|
@ -11,11 +11,11 @@ class ShipCommand(Command):
|
||||||
command_title = "Crea una ship tra due cose."
|
command_title = "Crea una ship tra due cose."
|
||||||
command_syntax = "(uno) (due)"
|
command_syntax = "(uno) (due)"
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
name_one = args[0]
|
name_one = call.args[0]
|
||||||
name_two = args[1]
|
name_two = call.args[1]
|
||||||
if name_two == "+":
|
if name_two == "+":
|
||||||
name_two = args[2]
|
name_two = call.args[2]
|
||||||
name_one = name_one.lower()
|
name_one = name_one.lower()
|
||||||
name_two = name_two.lower()
|
name_two = name_two.lower()
|
||||||
# Get all letters until the first vowel, included
|
# Get all letters until the first vowel, included
|
||||||
|
|
|
@ -57,6 +57,6 @@ class SmecdsCommand(Command):
|
||||||
command_title = "Secondo me, è colpa dello stagista..."
|
command_title = "Secondo me, è colpa dello stagista..."
|
||||||
command_syntax = ""
|
command_syntax = ""
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
ds = random.sample(DS_LIST, 1)[0]
|
ds = random.sample(DS_LIST, 1)[0]
|
||||||
return await call.reply(safeformat(SMECDS, ds=ds))
|
return await call.reply(safeformat(SMECDS, ds=ds))
|
||||||
|
|
|
@ -12,17 +12,17 @@ class SyncCommand(Command):
|
||||||
|
|
||||||
require_alchemy_tables = {Royal, Telegram}
|
require_alchemy_tables = {Royal, Telegram}
|
||||||
|
|
||||||
async def common(self, call: Call, args: CommandArgs):
|
async def common(self, call: Call):
|
||||||
raise UnsupportedError()
|
raise UnsupportedError()
|
||||||
|
|
||||||
async def telegram(self, call: Call, args: CommandArgs):
|
async def telegram(self, call: Call):
|
||||||
update: Update = args.kwargs["update"]
|
update: Update = call.kwargs["update"]
|
||||||
# Find the user
|
# Find the user
|
||||||
user: typing.Optional[User] = update.effective_user
|
user: typing.Optional[User] = update.effective_user
|
||||||
if user is None:
|
if user is None:
|
||||||
raise ValueError("Trying to sync a None user.")
|
raise ValueError("Trying to sync a None user.")
|
||||||
# Find the Royal
|
# Find the Royal
|
||||||
royal = await asyncify(call.session.query(call.alchemy.Royal).filter_by(username=args[0]).one_or_none)
|
royal = await asyncify(call.session.query(call.alchemy.Royal).filter_by(username=call.args[0]).one_or_none)
|
||||||
if royal is None:
|
if royal is None:
|
||||||
await call.reply("⚠️ Non esiste alcun account Royalnet con quel nome.")
|
await call.reply("⚠️ Non esiste alcun account Royalnet con quel nome.")
|
||||||
return
|
return
|
||||||
|
@ -46,4 +46,4 @@ class SyncCommand(Command):
|
||||||
telegram.tg_username = user.username
|
telegram.tg_username = user.username
|
||||||
await call.reply(f"✅ Dati di [c]{str(telegram)}[/c] aggiornati.")
|
await call.reply(f"✅ Dati di [c]{str(telegram)}[/c] aggiornati.")
|
||||||
# Commit the session
|
# Commit the session
|
||||||
await asyncify(call.session.commit())
|
await asyncify(call.session.commit)
|
||||||
|
|
|
@ -15,7 +15,7 @@ def relationshiplinkchain(starting_class, ending_class) -> typing.Optional[tuple
|
||||||
if _relationship.mapper in inspected:
|
if _relationship.mapper in inspected:
|
||||||
continue
|
continue
|
||||||
result = search(_relationship.mapper, chain + (_relationship,))
|
result = search(_relationship.mapper, chain + (_relationship,))
|
||||||
if len(result) == 0:
|
if len(result) != 0:
|
||||||
return result
|
return result
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import re
|
||||||
from sqlalchemy import Column, \
|
from sqlalchemy import Column, \
|
||||||
Integer, \
|
Integer, \
|
||||||
Text, \
|
Text, \
|
||||||
|
@ -13,7 +14,7 @@ class Diario:
|
||||||
__tablename__ = "diario"
|
__tablename__ = "diario"
|
||||||
|
|
||||||
diario_id = Column(Integer, primary_key=True)
|
diario_id = Column(Integer, primary_key=True)
|
||||||
creator_id = Column(Integer, ForeignKey("royals.uid"))
|
creator_id = Column(Integer, ForeignKey("royals.uid"), nullable=False)
|
||||||
quoted_account_id = Column(Integer, ForeignKey("royals.uid"))
|
quoted_account_id = Column(Integer, ForeignKey("royals.uid"))
|
||||||
quoted = Column(String)
|
quoted = Column(String)
|
||||||
text = Column(Text, nullable=False)
|
text = Column(Text, nullable=False)
|
||||||
|
@ -27,3 +28,23 @@ class Diario:
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Diario diario_id={self.diario_id} creator_id={self.creator_id} quoted_account_id={self.quoted_account_id} quoted={self.quoted} text={self.text} context={self.context} timestamp={self.timestamp} media_url={self.media_url} spoiler={self.spoiler}>"
|
return f"<Diario diario_id={self.diario_id} creator_id={self.creator_id} quoted_account_id={self.quoted_account_id} quoted={self.quoted} text={self.text} context={self.context} timestamp={self.timestamp} media_url={self.media_url} spoiler={self.spoiler}>"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
# TODO: support media_url
|
||||||
|
text = f"Riga #{self.diario_id}"
|
||||||
|
text += f" (salvata da {self.creator.username}"
|
||||||
|
text += f" alle {self.timestamp.strftime('%Y-%m-%d %H:%M')}):\n"
|
||||||
|
if self.spoiler:
|
||||||
|
hidden = re.sub("\w", "█", self.text)
|
||||||
|
text += f"\"{hidden}\"\n"
|
||||||
|
else:
|
||||||
|
text += f"[b]\"{self.text}\"[/b]\n"
|
||||||
|
if self.quoted_account is not None:
|
||||||
|
text += f" —{self.quoted_account.username}"
|
||||||
|
elif self.quoted is not None:
|
||||||
|
text += f" —{self.quoted}"
|
||||||
|
else:
|
||||||
|
text += f" —Anonimo"
|
||||||
|
if self.context:
|
||||||
|
text += f", [i]{self.context}[/i]"
|
||||||
|
return text
|
||||||
|
|
|
@ -32,10 +32,10 @@ class Call:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
# These parameters / methods should be left alone
|
# These parameters / methods should be left alone
|
||||||
def __init__(self, channel, command: Command, *args, **kwargs):
|
def __init__(self, channel, command: typing.Type[Command], command_args: list, **kwargs):
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.command = command
|
self.command = command
|
||||||
self.args = args
|
self.args = CommandArgs(command_args)
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self.session = None
|
self.session = None
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class Call:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
coroutine = getattr(self.command, "common")
|
coroutine = getattr(self.command, "common")
|
||||||
try:
|
try:
|
||||||
result = await coroutine(self.command, self, CommandArgs(*self.args, **self.kwargs))
|
result = await coroutine(self.command, self)
|
||||||
finally:
|
finally:
|
||||||
await self.session_end()
|
await self.session_end()
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -13,23 +13,20 @@ class InvalidInputError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CommandArgs:
|
class CommandArgs(list):
|
||||||
"""The arguments of a command. Raises InvalidInputError if the requested argument does not exist."""
|
"""The arguments of a command. Raises InvalidInputError if the requested argument does not exist."""
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.args = args
|
|
||||||
self.kwargs = kwargs
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
if isinstance(item, int):
|
if isinstance(item, int):
|
||||||
try:
|
try:
|
||||||
return self.args[item]
|
return super().__getitem__(item)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise InvalidInputError(f'Tried to get missing [{item}] arg from CommandArgs')
|
raise InvalidInputError(f'Tried to get missing [{item}] arg from CommandArgs')
|
||||||
elif isinstance(item, str):
|
if isinstance(item, slice):
|
||||||
try:
|
try:
|
||||||
return self.kwargs[item]
|
return super().__getitem__(item)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise InvalidInputError(f'Tried to get missing ["{item}"] kwarg from CommandArgs')
|
raise InvalidInputError(f'Tried to get invalid [{item}] slice from CommandArgs')
|
||||||
raise ValueError(f"Invalid type passed to CommandArgs.__getattr__: {type(item)}")
|
raise ValueError(f"Invalid type passed to CommandArgs.__getattr__: {type(item)}")
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,5 +39,5 @@ class Command:
|
||||||
|
|
||||||
require_alchemy_tables: typing.Set = set()
|
require_alchemy_tables: typing.Set = set()
|
||||||
|
|
||||||
async def common(self, call: "Call", args: CommandArgs):
|
async def common(self, call: "Call"):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
Loading…
Reference in a new issue