mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Merge remote-tracking branch 'origin/unity' into unity
# Conflicts: # requirements.txt
This commit is contained in:
commit
7047bcf230
20 changed files with 104 additions and 29 deletions
|
@ -4,3 +4,5 @@ pytest>=4.3.1
|
|||
psycopg2-binary>=2.8
|
||||
aiohttp>=3.5.4
|
||||
sqlalchemy>=1.3.2
|
||||
Markdown>=3.1
|
||||
dateparser>=0.7.1
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import os
|
||||
import asyncio
|
||||
from royalnet.bots import TelegramBot
|
||||
from royalnet.commands import PingCommand, ShipCommand, SmecdsCommand, ColorCommand, CiaoruoziCommand, SyncCommand, DiarioCommand, RageCommand
|
||||
from royalnet.commands import *
|
||||
from royalnet.commands.debug_create import DebugCreateCommand
|
||||
from royalnet.commands.debug_author import DebugAuthorCommand
|
||||
from royalnet.commands.error_handler import ErrorHandlerCommand
|
||||
from royalnet.network import RoyalnetServer
|
||||
from royalnet.database.tables import Royal, Telegram
|
||||
|
@ -11,7 +10,7 @@ from royalnet.database.tables import Royal, Telegram
|
|||
loop = asyncio.get_event_loop()
|
||||
|
||||
commands = [PingCommand, ShipCommand, SmecdsCommand, ColorCommand, CiaoruoziCommand, DebugCreateCommand, SyncCommand,
|
||||
DebugAuthorCommand, DiarioCommand, RageCommand]
|
||||
AuthorCommand, DiarioCommand, RageCommand, DateparserCommand, ReminderCommand]
|
||||
|
||||
master = RoyalnetServer("localhost", 1234, "sas")
|
||||
tg_bot = TelegramBot(os.environ["TG_AK"], "localhost:1234", "sas", commands, os.environ["DB_PATH"], Royal, Telegram, "tg_id", error_command=ErrorHandlerCommand)
|
||||
|
|
|
@ -4,7 +4,7 @@ import typing
|
|||
import logging as _logging
|
||||
import sys
|
||||
from ..commands import NullCommand
|
||||
from ..utils import asyncify, Call, Command
|
||||
from ..utils import asyncify, Call, Command, UnregisteredError
|
||||
from ..network import RoyalnetLink, Message
|
||||
from ..database import Alchemy, relationshiplinkchain
|
||||
|
||||
|
@ -71,16 +71,21 @@ class TelegramBot:
|
|||
response = await self.network.request(message, destination)
|
||||
return response
|
||||
|
||||
async def get_author(call):
|
||||
async def get_author(call, error_if_none=False):
|
||||
update: telegram.Update = call.kwargs["update"]
|
||||
user: telegram.User = update.effective_user
|
||||
if user is None:
|
||||
if error_if_none:
|
||||
raise UnregisteredError("Author is not registered!")
|
||||
return None
|
||||
query = call.session.query(self.master_table)
|
||||
for link in self.identity_chain:
|
||||
query = query.join(link.mapper.class_)
|
||||
query = query.filter(self.identity_column == user.id)
|
||||
return await asyncify(query.one_or_none)
|
||||
result = await asyncify(query.one_or_none)
|
||||
if result is None and error_if_none:
|
||||
raise UnregisteredError("Author is not registered!")
|
||||
return result
|
||||
|
||||
self.TelegramCall = TelegramCall
|
||||
|
||||
|
|
|
@ -7,7 +7,10 @@ from .color import ColorCommand
|
|||
from .sync import SyncCommand
|
||||
from .diario import DiarioCommand
|
||||
from .rage import RageCommand
|
||||
from .dateparser import DateparserCommand
|
||||
from .author import AuthorCommand
|
||||
from .reminder import ReminderCommand
|
||||
|
||||
|
||||
__all__ = ["NullCommand", "PingCommand", "ShipCommand", "SmecdsCommand", "CiaoruoziCommand", "ColorCommand",
|
||||
"SyncCommand", "DiarioCommand", "RageCommand"]
|
||||
"SyncCommand", "DiarioCommand", "RageCommand", "DateparserCommand", "AuthorCommand", "ReminderCommand"]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from ..utils import Command, CommandArgs, Call
|
||||
from ..utils import Command, Call
|
||||
from ..database.tables import Royal, Telegram
|
||||
|
||||
|
||||
class DebugAuthorCommand(Command):
|
||||
class AuthorCommand(Command):
|
||||
|
||||
command_name = "debug_author"
|
||||
command_name = "author"
|
||||
command_description = "Ottieni informazioni sull'autore di questa chiamata."
|
||||
command_syntax = ""
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ..utils import Command, CommandArgs, Call
|
||||
from ..utils import Command, Call
|
||||
|
||||
|
||||
class ColorCommand(Command):
|
||||
|
|
21
royalnet/commands/dateparser.py
Normal file
21
royalnet/commands/dateparser.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
import datetime
|
||||
import dateparser
|
||||
from ..utils import Command, Call, InvalidInputError
|
||||
|
||||
|
||||
class DateparserCommand(Command):
|
||||
|
||||
command_name = "dateparser"
|
||||
command_description = "Legge e comprende la data inserita."
|
||||
command_syntax = "(data)"
|
||||
|
||||
@classmethod
|
||||
async def common(cls, call: Call):
|
||||
if len(call.args) == 0:
|
||||
raise InvalidInputError("Missing arg")
|
||||
text = " ".join(call.args)
|
||||
date: datetime.datetime = dateparser.parse(text)
|
||||
if date is None:
|
||||
await call.reply("🕕 La data inserita non è valida.")
|
||||
return
|
||||
await call.reply(f"🕐 La data inserita è {date.isoformat()}")
|
|
@ -1,4 +1,4 @@
|
|||
from ..utils import Command, CommandArgs, Call, asyncify
|
||||
from ..utils import Command, Call, asyncify
|
||||
from ..database.tables import Royal, Alias
|
||||
|
||||
|
||||
|
|
|
@ -45,10 +45,7 @@ class DiarioCommand(Command):
|
|||
@classmethod
|
||||
async def common(cls, 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
|
||||
creator = await call.get_author(error_if_none=True)
|
||||
# Recreate the full sentence
|
||||
raw_text = " ".join(call.args)
|
||||
# Pass the sentence through the diario regex
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import traceback
|
||||
from logging import Logger
|
||||
from ..utils import Command, CommandArgs, Call, InvalidInputError, UnsupportedError
|
||||
from ..utils import Command, CommandArgs, Call, InvalidInputError, UnsupportedError, UnregisteredError
|
||||
|
||||
|
||||
class ErrorHandlerCommand(Command):
|
||||
|
@ -24,6 +24,9 @@ class ErrorHandlerCommand(Command):
|
|||
command = call.kwargs["previous_command"]
|
||||
await call.reply(f"⚠️ Sintassi non valida.\nSintassi corretta: [c]/{command.command_name} {command.command_syntax}[/c]")
|
||||
return
|
||||
if e_type == UnregisteredError:
|
||||
await call.reply("⚠️ Devi essere registrato a Royalnet per usare questo comando!")
|
||||
return
|
||||
await call.reply(f"❌ Eccezione non gestita durante l'esecuzione del comando:\n[b]{e_type.__name__}[/b]\n{e_value}")
|
||||
formatted_tb: str = '\n'.join(traceback.format_tb(e_tb))
|
||||
call.logger.error(f"Unhandled exception - {e_type.__name__}: {e_value}\n{formatted_tb}")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from ..utils import Command, CommandArgs, Call
|
||||
from ..utils import Command, Call
|
||||
|
||||
|
||||
class NullCommand(Command):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import asyncio
|
||||
from ..utils import Command, CommandArgs, Call, InvalidInputError
|
||||
from ..utils import Command, Call, InvalidInputError
|
||||
|
||||
|
||||
class PingCommand(Command):
|
||||
|
|
28
royalnet/commands/reminder.py
Normal file
28
royalnet/commands/reminder.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import datetime
|
||||
import dateparser
|
||||
import typing
|
||||
from ..utils import Command, Call, sleep_until
|
||||
|
||||
|
||||
class ReminderCommand(Command):
|
||||
|
||||
command_name = "reminder"
|
||||
command_description = "Ripete quello che gli avevi chiesto dopo un po' di tempo."
|
||||
command_syntax = "[ (data) ] (testo)"
|
||||
|
||||
@classmethod
|
||||
async def common(cls, call: Call):
|
||||
match = call.args.match(r"\[ *(.+?) *] *(.+?) *$")
|
||||
date_str = match.group(1)
|
||||
reminder_text = match.group(2)
|
||||
date: typing.Optional[datetime.datetime]
|
||||
try:
|
||||
date = dateparser.parse(date_str)
|
||||
except OverflowError:
|
||||
date = None
|
||||
if date is None:
|
||||
await call.reply("⚠️ La data che hai inserito non è valida.")
|
||||
return
|
||||
await call.reply(f"✅ Promemoria impostato per [b]{date.strftime('%Y-%m-%d %H:%M:%S')}[/b]")
|
||||
await sleep_until(date)
|
||||
await call.reply(f"❗️ Promemoria: [b]{reminder_text}[/b]")
|
|
@ -1,5 +1,5 @@
|
|||
import re
|
||||
from ..utils import Command, CommandArgs, Call, safeformat
|
||||
from ..utils import Command, Call, safeformat
|
||||
|
||||
|
||||
SHIP_RESULT = "💕 {one} + {two} = [b]{result}[/b]"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import random
|
||||
from ..utils import Command, CommandArgs, Call, safeformat
|
||||
from ..utils import Command, Call, safeformat
|
||||
|
||||
|
||||
DS_LIST = ["della secca", "del seccatore", "del secchiello", "del secchio", "del secchione", "del secondino",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import typing
|
||||
from telegram import Update, User
|
||||
from ..utils import Command, CommandArgs, Call, asyncify, UnsupportedError
|
||||
from ..utils import Command, Call, asyncify, UnsupportedError
|
||||
from ..database.tables import Royal, Telegram
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
from sqlalchemy import Column, \
|
||||
Integer, \
|
||||
String, \
|
||||
BigInteger, \
|
||||
LargeBinary, \
|
||||
ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from .royals import Royal
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from .asyncify import asyncify
|
||||
from .call import Call
|
||||
from .call import Call, UnregisteredError
|
||||
from .command import Command, CommandArgs, InvalidInputError, UnsupportedError, InvalidConfigError, ExternalError
|
||||
from .safeformat import safeformat
|
||||
from .classdictjanitor import cdj
|
||||
from .sleepuntil import sleep_until
|
||||
|
||||
__all__ = ["asyncify", "Call", "Command", "safeformat", "InvalidInputError", "UnsupportedError", "CommandArgs",
|
||||
"cdj", "InvalidConfigError", "ExternalError"]
|
||||
"cdj", "InvalidConfigError", "ExternalError", "sleep_until", "UnregisteredError"]
|
||||
|
|
|
@ -10,6 +10,10 @@ if typing.TYPE_CHECKING:
|
|||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
||||
class UnregisteredError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Call:
|
||||
"""A command call. Still an abstract class, subbots should create a new call from this."""
|
||||
|
||||
|
@ -27,9 +31,10 @@ class Call:
|
|||
The data must be pickleable."""
|
||||
raise NotImplementedError()
|
||||
|
||||
async def get_author(self):
|
||||
async def get_author(self, error_if_none=False):
|
||||
"""Try to find the universal identifier of the user that sent the message.
|
||||
That probably means, the database row identifying the user."""
|
||||
That probably means, the database row identifying the user.
|
||||
Raise a UnregisteredError if error_if_none is set to True and no author is found."""
|
||||
raise NotImplementedError()
|
||||
|
||||
# These parameters / methods should be left alone
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import re
|
||||
import typing
|
||||
if typing.TYPE_CHECKING:
|
||||
from .call import Call
|
||||
|
@ -35,6 +36,18 @@ class CommandArgs(list):
|
|||
raise InvalidInputError(f'Tried to get invalid [{item}] slice from CommandArgs')
|
||||
raise ValueError(f"Invalid type passed to CommandArgs.__getattr__: {type(item)}")
|
||||
|
||||
def match(self, pattern: typing.Pattern) -> typing.Match:
|
||||
text = " ".join(self)
|
||||
match = re.match(pattern, text)
|
||||
if match is None:
|
||||
raise InvalidInputError("Pattern didn't match")
|
||||
return match
|
||||
|
||||
def optional(self, index: int) -> typing.Optional:
|
||||
try:
|
||||
return self[index]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
class Command:
|
||||
"""A generic command, called from any source."""
|
||||
|
|
Loading…
Reference in a new issue