1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2025-03-28 02:40:31 +00:00

SO STUFF MUCH DOGE

This commit is contained in:
Steffo 2019-04-03 19:31:20 +02:00
parent 6ec151835d
commit 202e33bdf0
12 changed files with 118 additions and 16 deletions

View file

@ -3,14 +3,17 @@ import asyncio
from royalnet.bots import TelegramBot
from royalnet.commands import PingCommand, ShipCommand, SmecdsCommand, ColorCommand, CiaoruoziCommand, SyncCommand
from royalnet.commands.debug_create import DebugCreateCommand
from royalnet.commands.debug_author import DebugAuthorCommand
from royalnet.network import RoyalnetServer
from royalnet.database.tables import Royal, Telegram
loop = asyncio.get_event_loop()
commands = [PingCommand, ShipCommand, SmecdsCommand, ColorCommand, CiaoruoziCommand, DebugCreateCommand, SyncCommand]
commands = [PingCommand, ShipCommand, SmecdsCommand, ColorCommand, CiaoruoziCommand, DebugCreateCommand, SyncCommand,
DebugAuthorCommand]
master = RoyalnetServer("localhost", 1234, "sas")
tg_bot = TelegramBot(os.environ["TG_AK"], "localhost:1234", "sas", commands, os.environ["DB_PATH"])
tg_bot = TelegramBot(os.environ["TG_AK"], "localhost:1234", "sas", commands, os.environ["DB_PATH"], Royal, Telegram, "tg_id")
loop.create_task(master.run())
loop.create_task(tg_bot.run())
print("Starting loop...")

View file

@ -5,8 +5,7 @@ import logging as _logging
from ..commands import NullCommand
from ..utils import asyncify, Call, Command
from ..network import RoyalnetLink, Message
from ..database import Alchemy
from ..database import Alchemy, relationshiplinkchain
loop = asyncio.get_event_loop()
log = _logging.getLogger(__name__)
@ -24,6 +23,9 @@ class TelegramBot:
master_server_secret: str,
commands: typing.List[typing.Type[Command]],
database_uri: str,
master_table,
identity_table,
identity_column_name: str,
missing_command: Command = NullCommand,
error_command: Command = NullCommand):
self.bot: telegram.Bot = telegram.Bot(api_key)
@ -40,6 +42,10 @@ class TelegramBot:
required_tables = required_tables.union(command.require_alchemy_tables)
# Generate the Alchemy database
self.alchemy = Alchemy(database_uri, required_tables)
self.master_table = self.alchemy.__getattribute__(master_table.__name__)
self.identity_table = self.alchemy.__getattribute__(identity_table.__name__)
self.identity_column = self.identity_table.__getattribute__(self.identity_table, identity_column_name)
self.identity_chain = relationshiplinkchain(self.master_table, self.identity_table)
# noinspection PyMethodParameters
class TelegramCall(Call):
@ -54,6 +60,17 @@ class TelegramBot:
response = await self.network.request(message, destination)
return response
async def get_author(call):
update: telegram.Update = call.kwargs["update"]
user: telegram.User = update.effective_user
if user is None:
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)
self.Call = TelegramCall
async def run(self):

View file

@ -0,0 +1,16 @@
from ..utils import Command, CommandArgs, Call
from ..database.tables import Royal, Telegram
class DebugAuthorCommand(Command):
command_name = "debug_author"
command_title = "Ottieni informazioni sull'autore di questa chiamata."
require_alchemy_tables = {Royal, Telegram}
async def common(self, call: Call, args: CommandArgs):
author = await call.get_author()
if author is None:
await call.reply(f"☁️ L'autore di questa chiamata è sconosciuto.")
await call.reply(f"🌞 <code>{str(author)}</code> è l'autore di questa chiamata.")

View file

@ -1,5 +1,7 @@
from ..utils import Command, CommandArgs, Call
import re
import datetime
from ..utils import Command, CommandArgs, Call, InvalidInputError
from ..database.tables import Royal, Diario, Alias
class DiarioCommand(Command):
@ -7,9 +9,21 @@ class DiarioCommand(Command):
command_name = "diario"
command_title = "Aggiungi una citazione al Diario."
require_alchemy_tables = {Royal, Diario, Alias}
async def common(self, call: Call, args: CommandArgs):
# Recreate the full sentence
text = " ".join(args)
# Pass the sentence through the diario regex
match = re.match(r'["«‘“‛‟❛❝〝"`]([^"]+)["»’”❜❞〞"`] *(?:(?:-{1,2}|—) *(\w+))?(?:,? *([^ ].*))?', text)
# TODO
# Find the corresponding matches
if match is None:
raise InvalidInputError("No match found.")
text = match.group(1)
quoted = match.group(2)
context = match.group(3)
timestamp = datetime.datetime.now()
# Find if there's a Royalnet account associated with the quoted name
quoted_alias = call.session.query(call.alchemy.Alias).filter_by(alias=quoted).one_or_none()
quoted_account = quoted_alias.royal if quoted_alias is not None else None
# Find the creator of the quote

View file

@ -1,6 +1,6 @@
import typing
from telegram import Update, User
from ..utils import Command, CommandArgs, Call, asyncify
from ..utils import Command, CommandArgs, Call, asyncify, UnsupportedError
from ..database.tables import Royal, Telegram
@ -9,10 +9,10 @@ class SyncCommand(Command):
command_name = "sync"
command_title = "Connect your current account to Royalnet"
require_alchemy_tables = [Royal, Telegram]
require_alchemy_tables = {Royal, Telegram}
async def common(self, call: Call, args: CommandArgs):
raise NotImplementedError()
raise UnsupportedError()
async def telegram(self, call: Call, args: CommandArgs):
update: Update = args.kwargs["update"]
@ -24,6 +24,7 @@ class SyncCommand(Command):
royal = await asyncify(call.session.query(call.alchemy.Royal).filter_by(username=args[0]).one_or_none)
if royal is None:
await call.reply("⚠️ Non esiste alcun account Royalnet con quel nome.")
return
# Find if the user is already synced
telegram = await asyncify(call.session.query(call.alchemy.Telegram).filter_by(tg_id=user.id).one_or_none)
if telegram is None:

View file

@ -1,3 +1,4 @@
from .alchemy import Alchemy
from .relationshiplinkchain import relationshiplinkchain
__all__ = ["Alchemy"]
__all__ = ["Alchemy", "relationshiplinkchain"]

View file

@ -0,0 +1,22 @@
import typing
from sqlalchemy.inspection import inspect
def relationshiplinkchain(starting_class, ending_class) -> typing.Optional[tuple]:
"""Find the path to follow to get from the starting table to the ending table."""
inspected = set()
def search(_mapper, chain):
inspected.add(_mapper)
if _mapper.class_ == ending_class:
return chain
relationships = _mapper.relationships
for _relationship in set(relationships):
if _relationship.mapper in inspected:
continue
result = search(_relationship.mapper, chain + (_relationship,))
if len(result) == 0:
return result
return ()
return search(inspect(starting_class), tuple())

View file

@ -1,5 +1,6 @@
from .royals import Royal
from .telegram import Telegram
from .diario import Diario
from .aliases import Alias
__all__ = ["Royal", "Telegram", "Diario"]
__all__ = ["Royal", "Telegram", "Diario", "Alias"]

View file

@ -0,0 +1,23 @@
from sqlalchemy import Column, \
Integer, \
String, \
BigInteger, \
LargeBinary, \
ForeignKey
from sqlalchemy.orm import relationship
from .royals import Royal
class Alias:
__tablename__ = "aliases"
royal_id = Column(Integer, ForeignKey("royals.uid"))
alias = Column(String, primary_key=True)
royal = relationship("Royal", backref="aliases")
def __repr__(self):
return f"<Alias {str(self)}>"
def __str__(self):
return f"{self.alias}->{self.royal_id}"

View file

@ -14,9 +14,9 @@ class Diario:
diario_id = Column(Integer, primary_key=True)
creator_id = Column(Integer, ForeignKey("royals.id"))
quoted_id = Column(Integer, ForeignKey("royals.id"))
quoted_name = Column(String)
creator_id = Column(Integer, ForeignKey("royals.uid"))
quoted_account_id = Column(Integer, ForeignKey("royals.uid"))
quoted = Column(String)
text = Column(Text, nullable=False)
context = Column(Text)
timestamp = Column(DateTime, nullable=False)
@ -24,7 +24,7 @@ class Diario:
spoiler = Column(Boolean, default=False)
creator = relationship("Royal", foreign_keys=creator_id, backref="diario_created")
quoted = relationship("Royal", foreign_keys=quoted_id, backref="diario_quoted")
quoted_account = relationship("Royal", foreign_keys=quoted_account_id, backref="diario_quoted")
def __repr__(self):
return f"<Diario {self.diario_id}>"

View file

@ -17,7 +17,6 @@ class Telegram:
tg_last_name = Column(String)
tg_username = Column(String)
tg_avatar = Column(LargeBinary)
# TODO: Add an index? https://www.citusdata.com/blog/2016/10/12/count-performance/
royal = relationship("Royal", backref="telegram")

View file

@ -26,6 +26,11 @@ class Call:
The data must be pickleable."""
raise NotImplementedError()
async def get_author(self):
"""Try to find the universal identifier of the user that sent the message.
That probably means, the database row identifying the user."""
raise NotImplementedError()
# These parameters / methods should be left alone
def __init__(self, channel, command: Command, *args, **kwargs):
self.channel = channel