mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 11:34:18 +00:00
Start work on 5.5
This commit is contained in:
parent
cdfd6c3e49
commit
c3e77fa5e6
14 changed files with 173 additions and 85 deletions
41
poetry.lock
generated
41
poetry.lock
generated
|
@ -66,6 +66,21 @@ version = "2.8.0"
|
|||
[package.dependencies]
|
||||
pytz = ">=2015.7"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Modern password hashing for your software and your servers"
|
||||
name = "bcrypt"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "3.1.7"
|
||||
|
||||
[package.dependencies]
|
||||
cffi = ">=1.1"
|
||||
six = ">=1.4.1"
|
||||
|
||||
[package.extras]
|
||||
tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
|
@ -913,8 +928,8 @@ python-versions = "*"
|
|||
version = "2020.1.24"
|
||||
|
||||
[extras]
|
||||
alchemy_easy = ["sqlalchemy", "psycopg2_binary"]
|
||||
alchemy_hard = ["sqlalchemy", "psycopg2"]
|
||||
alchemy_easy = ["sqlalchemy", "psycopg2_binary", "bcrypt"]
|
||||
alchemy_hard = ["sqlalchemy", "psycopg2", "bcrypt"]
|
||||
bard = ["ffmpeg_python", "youtube_dl", "eyed3"]
|
||||
coloredlogs = ["coloredlogs"]
|
||||
constellation = ["starlette", "uvicorn", "python-multipart"]
|
||||
|
@ -925,7 +940,7 @@ sentry = ["sentry_sdk"]
|
|||
telegram = ["python_telegram_bot"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "f275cd948fe28423a90d37d2825eabfec97e8ac0cdf52ee2d20f803d61987b40"
|
||||
content-hash = "218f4a253a7ef17bb871abf541ae7182f1626cd43d55417de12f9561c58ca0e9"
|
||||
python-versions = "^3.8"
|
||||
|
||||
[metadata.files]
|
||||
|
@ -963,6 +978,26 @@ babel = [
|
|||
{file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"},
|
||||
{file = "Babel-2.8.0.tar.gz", hash = "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38"},
|
||||
]
|
||||
bcrypt = [
|
||||
{file = "bcrypt-3.1.7-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7"},
|
||||
{file = "bcrypt-3.1.7-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31"},
|
||||
{file = "bcrypt-3.1.7-cp27-cp27m-win32.whl", hash = "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161"},
|
||||
{file = "bcrypt-3.1.7-cp27-cp27m-win_amd64.whl", hash = "sha256:9fe92406c857409b70a38729dbdf6578caf9228de0aef5bc44f859ffe971a39e"},
|
||||
{file = "bcrypt-3.1.7-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:763669a367869786bb4c8fcf731f4175775a5b43f070f50f46f0b59da45375d0"},
|
||||
{file = "bcrypt-3.1.7-cp34-abi3-macosx_10_6_intel.whl", hash = "sha256:a190f2a5dbbdbff4b74e3103cef44344bc30e61255beb27310e2aec407766052"},
|
||||
{file = "bcrypt-3.1.7-cp34-abi3-manylinux1_x86_64.whl", hash = "sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105"},
|
||||
{file = "bcrypt-3.1.7-cp34-cp34m-win32.whl", hash = "sha256:8b10acde4e1919d6015e1df86d4c217d3b5b01bb7744c36113ea43d529e1c3de"},
|
||||
{file = "bcrypt-3.1.7-cp34-cp34m-win_amd64.whl", hash = "sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133"},
|
||||
{file = "bcrypt-3.1.7-cp35-cp35m-win32.whl", hash = "sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5"},
|
||||
{file = "bcrypt-3.1.7-cp35-cp35m-win_amd64.whl", hash = "sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09"},
|
||||
{file = "bcrypt-3.1.7-cp36-cp36m-win32.whl", hash = "sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c"},
|
||||
{file = "bcrypt-3.1.7-cp36-cp36m-win_amd64.whl", hash = "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89"},
|
||||
{file = "bcrypt-3.1.7-cp37-cp37m-win32.whl", hash = "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294"},
|
||||
{file = "bcrypt-3.1.7-cp37-cp37m-win_amd64.whl", hash = "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc"},
|
||||
{file = "bcrypt-3.1.7-cp38-cp38-win32.whl", hash = "sha256:ce4e4f0deb51d38b1611a27f330426154f2980e66582dc5f438aad38b5f24fc1"},
|
||||
{file = "bcrypt-3.1.7-cp38-cp38-win_amd64.whl", hash = "sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752"},
|
||||
{file = "bcrypt-3.1.7.tar.gz", hash = "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"},
|
||||
{file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"},
|
||||
|
|
|
@ -3,6 +3,7 @@ from sqlalchemy.orm import *
|
|||
from sqlalchemy.ext.declarative import declared_attr
|
||||
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
#set($CAPITALIZED_NAME = $NAME.substring(0,1).toUpperCase() + $NAME.substring(1))
|
||||
class ${CAPITALIZED_NAME}:
|
||||
__tablename__ = "${NAME}"
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
sqlalchemy = {version="^1.3.10", optional=true}
|
||||
psycopg2 = {version="^2.8.4", optional=true} # Requires quite a bit of stuff http://initd.org/psycopg/docs/install.html#install-from-source
|
||||
psycopg2_binary = {version="^2.8.4", optional=true} # Prebuilt alternative to psycopg2, not recommended
|
||||
bcrypt = {version="^3.1.7", optional=true}
|
||||
|
||||
# constellation
|
||||
starlette = {version="^0.12.13", optional=true}
|
||||
|
@ -71,8 +72,8 @@
|
|||
telegram = ["python_telegram_bot"]
|
||||
discord = ["discord.py", "pynacl"]
|
||||
matrix = ["matrix-nio"]
|
||||
alchemy_easy = ["sqlalchemy", "psycopg2_binary"]
|
||||
alchemy_hard = ["sqlalchemy", "psycopg2"]
|
||||
alchemy_easy = ["sqlalchemy", "psycopg2_binary", "bcrypt"]
|
||||
alchemy_hard = ["sqlalchemy", "psycopg2", "bcrypt"]
|
||||
bard = ["ffmpeg_python", "youtube_dl", "eyed3"]
|
||||
constellation = ["starlette", "uvicorn", "python-multipart"]
|
||||
sentry = ["sentry_sdk"]
|
||||
|
|
|
@ -1,22 +1,10 @@
|
|||
# Imports go here!
|
||||
from .version import VersionCommand
|
||||
from .exception import ExceptionCommand
|
||||
from .excevent import ExceventCommand
|
||||
from .keyboardtest import KeyboardtestCommand
|
||||
|
||||
# Enter the commands of your Pack here!
|
||||
available_commands = [
|
||||
VersionCommand,
|
||||
]
|
||||
|
||||
# noinspection PyUnreachableCode
|
||||
if __debug__:
|
||||
available_commands = [
|
||||
*available_commands,
|
||||
ExceptionCommand,
|
||||
ExceventCommand,
|
||||
KeyboardtestCommand,
|
||||
]
|
||||
|
||||
# Don't change this, it should automatically generate __all__
|
||||
__all__ = [command.__name__ for command in available_commands]
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import royalnet
|
||||
from royalnet.commands import *
|
||||
|
||||
|
||||
class ExceptionCommand(Command):
|
||||
name: str = "exception"
|
||||
|
||||
description: str = "Raise an exception in the command."
|
||||
|
||||
async def run(self, args: CommandArgs, data: CommandData) -> None:
|
||||
raise Exception(f"{self.interface.prefix}{self.name} was called")
|
|
@ -1,12 +0,0 @@
|
|||
import royalnet
|
||||
from royalnet.commands import *
|
||||
|
||||
|
||||
class ExceventCommand(Command):
|
||||
name: str = "excevent"
|
||||
|
||||
description: str = "Call an event that raises an exception."
|
||||
|
||||
async def run(self, args: CommandArgs, data: CommandData) -> None:
|
||||
await self.interface.call_herald_event(self.interface.name, "exception")
|
||||
await data.reply("✅ Event called!")
|
|
@ -1,28 +0,0 @@
|
|||
from typing import *
|
||||
from royalnet.commands import *
|
||||
import functools
|
||||
import asyncio
|
||||
|
||||
|
||||
class KeyboardtestCommand(Command):
|
||||
name: str = "keyboardtest"
|
||||
|
||||
description: str = "Create a new keyboard with the specified keys."
|
||||
|
||||
syntax: str = "{keys}+"
|
||||
|
||||
@staticmethod
|
||||
async def echo(data: CommandData, echo: str):
|
||||
await data.reply(echo)
|
||||
|
||||
async def run(self, args: CommandArgs, data: CommandData) -> None:
|
||||
keys = []
|
||||
for arg in args:
|
||||
# noinspection PyTypeChecker
|
||||
keys.append(KeyboardKey(interface=self.interface,
|
||||
short=arg[0],
|
||||
text=arg,
|
||||
callback=functools.partial(self.echo, echo=arg)))
|
||||
async with data.keyboard("This is a test keyboard.", keys):
|
||||
await asyncio.sleep(10)
|
||||
await data.reply("The keyboard is no longer in scope.")
|
86
royalnet/backpack/commands/link.py
Normal file
86
royalnet/backpack/commands/link.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
from typing import *
|
||||
import royalnet
|
||||
import royalnet.commands as rc
|
||||
import royalnet.utils as ru
|
||||
from ..tables.telegram import Telegram
|
||||
from ..tables.discord import Discord
|
||||
|
||||
|
||||
class SyncCommand(rc.Command):
|
||||
name: str = "sync"
|
||||
|
||||
description: str = "Connect your chat account to Royalnet!"
|
||||
|
||||
syntax: str = "{username} {password}"
|
||||
|
||||
async def run(self, args: rc.CommandArgs, data: rc.CommandData) -> None:
|
||||
username = args[0]
|
||||
password = " ".join(args[1:])
|
||||
|
||||
author = await data.get_author(error_if_none=True)
|
||||
|
||||
user = await data.find_user(username)
|
||||
try:
|
||||
successful = user.test_password(password)
|
||||
except ValueError:
|
||||
raise rc.UserError(f"User {user} has no password set!")
|
||||
if not successful:
|
||||
raise rc.InvalidInputError(f"Invalid password!")
|
||||
|
||||
if self.interface.name == "telegram":
|
||||
import telegram
|
||||
message: telegram.Message = data.message
|
||||
from_user: telegram.User = message.from_user
|
||||
TelegramT = self.alchemy.get(Telegram)
|
||||
tg_user: Telegram = await ru.asyncify(
|
||||
data.session.query(TelegramT).filter_by(tg_id=from_user.id).one_or_none
|
||||
)
|
||||
if tg_user is None:
|
||||
# Create
|
||||
tg_user = TelegramT(
|
||||
user=author,
|
||||
tg_id=from_user.id,
|
||||
first_name=from_user.first_name,
|
||||
last_name=from_user.last_name,
|
||||
username=from_user.username
|
||||
)
|
||||
data.session.add(tg_user)
|
||||
else:
|
||||
# Edit
|
||||
tg_user.first_name = from_user.first_name
|
||||
tg_user.last_name = from_user.last_name
|
||||
tg_user.username = from_user.username
|
||||
await data.session_commit()
|
||||
await data.reply(f"↔️ Account {tg_user} synced to {author}!")
|
||||
|
||||
elif self.interface.name == "discord":
|
||||
import discord
|
||||
message: discord.Message = data.message
|
||||
author: discord.User = message.author
|
||||
DiscordT = self.alchemy.get(Discord)
|
||||
ds_user: Discord = await ru.asyncify(
|
||||
data.session.query(DiscordT).filter_by(discord_id=author.id).one_or_none
|
||||
)
|
||||
if ds_user is None:
|
||||
# Create
|
||||
ds_user = DiscordT(
|
||||
user=author,
|
||||
discord_id=author.id,
|
||||
username=author.name,
|
||||
discriminator=author.discriminator,
|
||||
avatar_url=author.avatar_url
|
||||
)
|
||||
data.session.add(ds_user)
|
||||
else:
|
||||
# Edit
|
||||
ds_user.username = author.name
|
||||
ds_user.discriminator = author.discriminator
|
||||
ds_user.avatar_url = author.avatar_url
|
||||
await data.session_commit()
|
||||
await data.reply(f"↔️ Account {ds_user} synced to {author}!")
|
||||
|
||||
elif self.interface.name == "matrix":
|
||||
raise rc.UnsupportedError(f"{self} hasn't been implemented for Matrix yet")
|
||||
|
||||
else:
|
||||
raise rc.UnsupportedError(f"Unknown interface: {self.interface.name}")
|
|
@ -10,26 +10,30 @@ class Alias:
|
|||
__tablename__ = "aliases"
|
||||
|
||||
@declared_attr
|
||||
def royal_id(self):
|
||||
return Column(Integer, ForeignKey("users.uid"))
|
||||
def user_id(self):
|
||||
return Column(Integer, ForeignKey("users.uid"), primary_key=True)
|
||||
|
||||
@declared_attr
|
||||
def alias(self):
|
||||
return Column(String, primary_key=True)
|
||||
|
||||
@declared_attr
|
||||
def royal(self):
|
||||
def user(self):
|
||||
return relationship("User", backref="aliases")
|
||||
|
||||
@classmethod
|
||||
def find_by_alias(cls, alchemy, session, alias: str):
|
||||
def find_user(cls, alchemy, session, alias: str):
|
||||
result = session.query(alchemy.get(cls)).filter_by(alias=alias.lower()).one_or_none()
|
||||
if result is not None:
|
||||
result = result.royal
|
||||
return result
|
||||
|
||||
def __init__(self, user: str, alias: str):
|
||||
self.user = user
|
||||
self.alias = alias.lower()
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Alias {str(self)}>"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.alias}->{self.royal_id}"
|
||||
return f"{self.alias}->{self.user_id}"
|
||||
|
|
|
@ -13,9 +13,13 @@ class Discord:
|
|||
__tablename__ = "discord"
|
||||
|
||||
@declared_attr
|
||||
def royal_id(self):
|
||||
def user_id(self):
|
||||
return Column(Integer, ForeignKey("users.uid"))
|
||||
|
||||
@declared_attr
|
||||
def user(self):
|
||||
return relationship("User", backref="discord")
|
||||
|
||||
@declared_attr
|
||||
def discord_id(self):
|
||||
return Column(BigInteger, primary_key=True)
|
||||
|
@ -29,13 +33,9 @@ class Discord:
|
|||
return Column(String)
|
||||
|
||||
@declared_attr
|
||||
def avatar_hash(self):
|
||||
def avatar_url(self):
|
||||
return Column(String)
|
||||
|
||||
@declared_attr
|
||||
def royal(self):
|
||||
return relationship("User", backref="discord")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Discord {str(self)}>"
|
||||
|
||||
|
|
|
@ -13,9 +13,13 @@ class Telegram:
|
|||
__tablename__ = "telegram"
|
||||
|
||||
@declared_attr
|
||||
def royal_id(self):
|
||||
def user_id(self):
|
||||
return Column(Integer, ForeignKey("users.uid"))
|
||||
|
||||
@declared_attr
|
||||
def user(self):
|
||||
return relationship("User", backref="telegram")
|
||||
|
||||
@declared_attr
|
||||
def tg_id(self):
|
||||
return Column(BigInteger, primary_key=True)
|
||||
|
@ -32,10 +36,6 @@ class Telegram:
|
|||
def username(self):
|
||||
return Column(String)
|
||||
|
||||
@declared_attr
|
||||
def royal(self):
|
||||
return relationship("User", backref="telegram")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Telegram {str(self)}>"
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import bcrypt
|
||||
from sqlalchemy import Column, \
|
||||
Integer, \
|
||||
String, \
|
||||
|
@ -5,6 +6,7 @@ from sqlalchemy import Column, \
|
|||
from sqlalchemy.ext.declarative import declared_attr
|
||||
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
class User:
|
||||
__tablename__ = "users"
|
||||
|
||||
|
@ -36,6 +38,16 @@ class User:
|
|||
"avatar": self.avatar
|
||||
}
|
||||
|
||||
def set_password(self, password: str):
|
||||
byte_password: bytes = bytes(password, encoding="UTF8")
|
||||
self.password = bcrypt.hashpw(byte_password, bcrypt.gensalt(14))
|
||||
|
||||
def test_password(self, password: str):
|
||||
if self.password is None:
|
||||
raise ValueError("No password is set")
|
||||
byte_password: bytes = bytes(password, encoding="UTF8")
|
||||
return bcrypt.checkpw(byte_password, self.password)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__qualname__} {self.username}>"
|
||||
|
||||
|
|
|
@ -5,9 +5,11 @@ import asyncio as aio
|
|||
import royalnet.utils as ru
|
||||
from .errors import UnsupportedError
|
||||
from .commandinterface import CommandInterface
|
||||
from royalnet.backpack.tables.aliases import Alias
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .keyboardkey import KeyboardKey
|
||||
from royalnet.backpack.tables.users import User
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -64,6 +66,16 @@ class CommandData:
|
|||
if error_if_unavailable:
|
||||
raise UnsupportedError(f"'{self.delete_invoking.__name__}' is not supported")
|
||||
|
||||
async def find_user(self, alias: str) -> Optional["User"]:
|
||||
"""Find the User having a specific Alias.
|
||||
|
||||
Parameters:
|
||||
alias: the Alias to search for."""
|
||||
return await ru.asyncify(
|
||||
Alias.find_user(self._interface.alchemy, self.session, alias)
|
||||
)
|
||||
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def keyboard(self, text, keys: List["KeyboardKey"]):
|
||||
yield
|
||||
|
|
|
@ -1 +1 @@
|
|||
semantic = "5.4"
|
||||
semantic = "5.5"
|
||||
|
|
Loading…
Reference in a new issue