feat(database): add models loader in core

This commit is contained in:
Romain J 2020-11-08 01:07:27 +01:00
parent 71335de878
commit e38823e5be
33 changed files with 320 additions and 29 deletions

View file

@ -22,6 +22,7 @@
<w>localiseip</w> <w>localiseip</w>
<w>octobre</w> <w>octobre</w>
<w>pacman</w> <w>pacman</w>
<w>postgre</w>
<w>postgresql</w> <w>postgresql</w>
<w>pred</w> <w>pred</w>
<w>pylint</w> <w>pylint</w>
@ -32,6 +33,7 @@
<w>splt</w> <w>splt</w>
<w>suivante</w> <w>suivante</w>
<w>systemd</w> <w>systemd</w>
<w>tablename</w>
<w>tldr</w> <w>tldr</w>
<w>tutux</w> <w>tutux</w>
<w>tuxbot</w> <w>tuxbot</w>
@ -40,6 +42,7 @@
<w>venv</w> <w>venv</w>
<w>webhook</w> <w>webhook</w>
<w>webhooks</w> <w>webhooks</w>
<w>youtrack</w>
<w>écrite</w> <w>écrite</w>
</words> </words>
</dictionary> </dictionary>

View file

@ -3,5 +3,5 @@
<component name="JavaScriptSettings"> <component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" /> <option name="languageLevel" value="ES6" />
</component> </component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (tuxbot-bot-rewrite)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (tuxbot-bot)" project-jdk-type="Python SDK" />
</project> </project>

View file

@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/.idea/tuxbot-bot-rewrite.iml" filepath="$PROJECT_DIR$/.idea/tuxbot-bot-rewrite.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/tuxbot-bot.iml" filepath="$PROJECT_DIR$/.idea/tuxbot-bot.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View file

@ -6,7 +6,7 @@
<excludeFolder url="file://$MODULE_DIR$/dist" /> <excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/venv" /> <excludeFolder url="file://$MODULE_DIR$/venv" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="Python 3.8 (tuxbot-bot)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">

View file

@ -9,6 +9,8 @@ main:
$(VENV)/bin/pip install -U pip setuptools $(VENV)/bin/pip install -U pip setuptools
install: install:
$(VENV)/bin/pip install . $(VENV)/bin/pip install .
install-dev:
$(VENV)/bin/pip install -r dev.requirements.txt
update: update:
$(VENV)/bin/pip install -U . $(VENV)/bin/pip install -U .

3
dev.requirements.txt Normal file
View file

@ -0,0 +1,3 @@
youtrack
pylint==2.6.0
black==20.8b1

View file

@ -16,16 +16,16 @@ packages = find_namespace:
python_requires = >=3.7 python_requires = >=3.7
install_requires = install_requires =
appdirs>=1.4.4 appdirs>=1.4.4
asyncpg>=0.21.0
Babel>=2.8.0 Babel>=2.8.0
black==20.8b1 discord.py>=1.5.1
discord.py==1.5.1 discord_flags>=2.1.1
discord_flags==2.1.1 humanize>=2.6.0
humanize==2.6.0
jishaku>=1.19.1.200 jishaku>=1.19.1.200
psutil>=5.7.2 psutil>=5.7.2
pylint==2.6.0
rich>=6.0.0 rich>=6.0.0
structured_config>=4.12 structured_config>=4.12
tortoise-orm>=0.16.17
[options.entry_points] [options.entry_points]
console_scripts = console_scripts =

View file

@ -3,7 +3,7 @@ from rich.traceback import install
from tuxbot import ExitCodes from tuxbot import ExitCodes
console = Console() console = Console()
install(console=console) install(console=console, show_locals=True)
def main() -> None: def main() -> None:
@ -20,11 +20,11 @@ def main() -> None:
else: else:
raise exc raise exc
except Exception: except Exception:
console.print_exception() console.print_exception(show_locals=True)
if __name__ == "__main__": if __name__ == "__main__":
try: try:
main() main()
except Exception: except Exception:
console.print_exception() console.print_exception(show_locals=True)

View file

@ -4,7 +4,6 @@ import logging
import signal import signal
import sys import sys
import os import os
import tracemalloc
from argparse import Namespace from argparse import Namespace
from datetime import datetime from datetime import datetime
@ -21,15 +20,14 @@ from rich import print as rprint
import tuxbot.logging import tuxbot.logging
from tuxbot.core.bot import Tux from tuxbot.core.bot import Tux
from tuxbot.core import data_manager
from tuxbot.core import config from tuxbot.core import config
from .core.utils import data_manager
from . import __version__, version_info, ExitCodes from . import __version__, version_info, ExitCodes
log = logging.getLogger("tuxbot.main") log = logging.getLogger("tuxbot.main")
console = Console() console = Console()
install(console=console) install(console=console, show_locals=True)
tracemalloc.start()
BORDER_STYLE = "not dim" BORDER_STYLE = "not dim"
@ -295,7 +293,7 @@ def run() -> None:
raise raise
except Exception as exc: except Exception as exc:
log.error("Unexpected exception (%s): ", type(exc)) log.error("Unexpected exception (%s): ", type(exc))
console.print_exception() console.print_exception(show_locals=True)
if tux is not None: if tux is not None:
loop.run_until_complete(shutdown_handler(tux, None, 1)) loop.run_until_complete(shutdown_handler(tux, None, 1))
finally: finally:

View file

@ -1,7 +1,7 @@
from collections import namedtuple from collections import namedtuple
from .admin import Admin from .admin import Admin
from .config import AdminConfig from .config import AdminConfig, HAS_MODELS
from ...core.bot import Tux from ...core.bot import Tux
VersionInfo = namedtuple("VersionInfo", "major minor micro release_level") VersionInfo = namedtuple("VersionInfo", "major minor micro release_level")

View file

@ -3,7 +3,7 @@ import logging
import discord import discord
from discord.ext import commands from discord.ext import commands
from tuxbot.core import checks from tuxbot.core.utils import checks
from tuxbot.core.bot import Tux from tuxbot.core.bot import Tux
from tuxbot.core.config import set_for_key from tuxbot.core.config import set_for_key
from tuxbot.core.config import Config from tuxbot.core.config import Config

View file

@ -1,5 +1,7 @@
from structured_config import Structure from structured_config import Structure
HAS_MODELS = True
class AdminConfig(Structure): class AdminConfig(Structure):
pass pass

View file

@ -0,0 +1,2 @@
from .alias import *
from .warn import *

View file

@ -0,0 +1,22 @@
import tortoise
from tortoise import fields
class AliasesModel(tortoise.Model):
id = fields.BigIntField(pk=True)
user_id = fields.BigIntField()
alias = fields.TextField(max_length=255)
command = fields.TextField(max_length=255)
guild = fields.BigIntField()
class Meta:
table = "aliases"
def __str__(self):
return f"<AliasesModel id={self.id} " \
f"user_id={self.user_id} " \
f"alias='{self.alias}' " \
f"command='{self.command}' " \
f"guild={self.guild}>"
__repr__ = __str__

View file

@ -0,0 +1,22 @@
import tortoise
from tortoise import fields
class WarnsModel(tortoise.Model):
id = fields.BigIntField(pk=True)
server_id = fields.BigIntField()
user_id = fields.BigIntField()
reason = fields.TextField(max_length=255)
created_at = fields.DatetimeField()
class Meta:
table = "warns"
def __str__(self):
return f"<WarnsModel id={self.id} " \
f"server_id={self.server_id} " \
f"user_id={self.user_id} " \
f"reason='{self.reason}' " \
f"created_at={self.created_at}>"
__repr__ = __str__

View file

@ -0,0 +1,20 @@
from collections import namedtuple
from .dev import Dev
from .config import DevConfig, HAS_MODELS
from ...core.bot import Tux
VersionInfo = namedtuple("VersionInfo", "major minor micro release_level")
version_info = VersionInfo(major=0, minor=1, micro=0, release_level="alpha")
__version__ = "v{}.{}.{}-{}".format(
version_info.major,
version_info.minor,
version_info.micro,
version_info.release_level,
).replace("\n", "")
def setup(bot: Tux):
cog = Dev(bot)
bot.add_cog(cog)

25
tuxbot/cogs/dev/config.py Normal file
View file

@ -0,0 +1,25 @@
from structured_config import Structure, StrField
HAS_MODELS = False
class DevConfig(Structure):
url: str = StrField("")
login: str = StrField("")
password: str = StrField("")
extra = {
"url": {
"type": str,
"description": "URL of the YouTrack instance (without /youtrack/)"
},
"login": {
"type": str,
"description": "Login for YouTrack instance"
},
"password": {
"type": str,
"description": "Password for YouTrack instance",
},
}

45
tuxbot/cogs/dev/dev.py Normal file
View file

@ -0,0 +1,45 @@
import logging
from discord.ext import commands
from youtrack.connection import Connection as YouTrack
from structured_config import ConfigFile
from tuxbot.core.bot import Tux
from tuxbot.core.i18n import (
Translator,
)
from tuxbot.core.utils.data_manager import cogs_data_path
from .config import DevConfig
from ...core.utils import checks
from ...core.utils.functions.extra import group_extra, ContextPlus
log = logging.getLogger("tuxbot.cogs.dev")
_ = Translator("Dev", __file__)
class Dev(commands.Cog, name="Dev"):
yt: YouTrack # pylint: disable=invalid-name
def __init__(self, bot: Tux):
self.bot = bot
self.config: DevConfig = ConfigFile(
str(
cogs_data_path(self.bot.instance_name, "dev") / "config.yaml"
),
DevConfig,
).config
# pylint: disable=invalid-name
self.yt = YouTrack(
self.config.url.rstrip('/') + '/youtrack/',
login=self.config.login,
password=self.config.password
)
@group_extra(name="issue", aliases=["issues"], deletable=True)
@checks.is_owner()
async def _issue(self, ctx: ContextPlus):
"""Manage bot issues."""
@_issue.command(name="list", aliases=["liste", "all", "view"])
async def _lang_list(self, ctx: ContextPlus):
pass

View file

@ -0,0 +1,18 @@
# English translations for Tuxbot-bot package.
# Copyright (C) 2020 THE Tuxbot-bot'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Tuxbot-bot package.
# Automatically generated, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2020-10-21 01:15+0200\n"
"PO-Revision-Date: 2020-10-21 01:15+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View file

@ -0,0 +1,19 @@
# French translations for Tuxbot-bot package
# Traductions françaises du paquet Tuxbot-bot.
# Copyright (C) 2020 THE Tuxbot-bot'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Tuxbot-bot package.
# Automatically generated, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2020-10-21 01:15+0200\n"
"PO-Revision-Date: 2020-10-21 01:15+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

View file

@ -0,0 +1,18 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Tuxbot-bot package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2020-10-21 01:15+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

View file

View file

@ -4,7 +4,7 @@ from collections import namedtuple
from discord.ext import commands from discord.ext import commands
from .logs import Logs, on_error, GatewayHandler from .logs import Logs, on_error, GatewayHandler
from .config import LogsConfig from .config import LogsConfig, HAS_MODELS
from ...core.bot import Tux from ...core.bot import Tux
VersionInfo = namedtuple("VersionInfo", "major minor micro release_level") VersionInfo = namedtuple("VersionInfo", "major minor micro release_level")

View file

@ -1,5 +1,7 @@
from structured_config import Structure, StrField from structured_config import Structure, StrField
HAS_MODELS = False
class LogsConfig(Structure): class LogsConfig(Structure):
dm: str = StrField("") dm: str = StrField("")

View file

@ -21,8 +21,8 @@ from tuxbot.core.utils.functions.extra import (
command_extra, command_extra,
ContextPlus, ContextPlus,
) )
from tuxbot.core.utils.data_manager import cogs_data_path
from .config import LogsConfig from .config import LogsConfig
from ...core.data_manager import cogs_data_path
log = logging.getLogger("tuxbot.cogs.logs") log = logging.getLogger("tuxbot.cogs.logs")
_ = Translator("Logs", __file__) _ = Translator("Logs", __file__)

View file

View file

@ -1,5 +1,6 @@
import asyncio import asyncio
import datetime import datetime
import importlib
import logging import logging
from collections import Counter from collections import Counter
from typing import List, Union from typing import List, Union
@ -13,10 +14,14 @@ from rich.console import Console
from rich.panel import Panel from rich.panel import Panel
from rich.progress import Progress, TextColumn, BarColumn from rich.progress import Progress, TextColumn, BarColumn
from rich.table import Table from rich.table import Table
from rich.traceback import install from tortoise import Tortoise
from tuxbot import version_info from tuxbot import version_info
from tuxbot.core.utils.data_manager import (
logs_data_path,
data_path,
config_dir,
)
from .config import ( from .config import (
Config, Config,
ConfigFile, ConfigFile,
@ -24,8 +29,6 @@ from .config import (
AppConfig, AppConfig,
set_for_key, set_for_key,
) )
from .data_manager import logs_data_path, data_path, config_dir
from . import __version__, ExitCodes from . import __version__, ExitCodes
from . import exceptions from . import exceptions
from .utils.functions.extra import ContextPlus from .utils.functions.extra import ContextPlus
@ -33,9 +36,13 @@ from .utils.functions.prefix import get_prefixes
log = logging.getLogger("tuxbot") log = logging.getLogger("tuxbot")
console = Console() console = Console()
install(console=console)
packages: List[str] = ["jishaku", "tuxbot.cogs.admin", "tuxbot.cogs.logs"] packages: List[str] = [
"jishaku",
"tuxbot.cogs.admin",
"tuxbot.cogs.logs",
"tuxbot.cogs.dev",
]
class Tux(commands.AutoShardedBot): class Tux(commands.AutoShardedBot):
@ -140,7 +147,7 @@ class Tux(commands.AutoShardedBot):
) )
console.print() console.print()
columns = Columns(expand=True, padding=2, align="center") columns = Columns(expand=True, align="center")
table = Table(style="dim", border_style="not dim", box=box.HEAVY_HEAD) table = Table(style="dim", border_style="not dim", box=box.HEAVY_HEAD)
table.add_column( table.add_column(
@ -240,6 +247,43 @@ class Tux(commands.AutoShardedBot):
Todo: add postgresql connect here Todo: add postgresql connect here
""" """
with self._progress.get("main") as progress:
task_id = self._progress.get("tasks")[
"connecting"
] = progress.add_task(
"connecting",
task_name="Connecting to PostgreSQL...",
start=False,
)
models = []
for extension, _ in self.extensions.items():
if extension == "jishaku":
continue
if importlib.import_module(extension).HAS_MODELS:
models.append(f"{extension}.models.__init__")
progress.update(task_id)
await Tortoise.init(
db_url="postgres://{}:{}@{}:{}/{}".format(
self.config.Core.Database.username,
self.config.Core.Database.password,
self.config.Core.Database.domain,
self.config.Core.Database.port,
self.config.Core.Database.db_name,
),
modules={"models": models},
)
await Tortoise.generate_schemas()
self._progress["main"].stop_task(self._progress["tasks"]["connecting"])
self._progress["main"].remove_task(
self._progress["tasks"]["connecting"]
)
self._progress["tasks"].pop("connecting")
with self._progress.get("main") as progress: with self._progress.get("main") as progress:
task_id = self._progress.get("tasks")[ task_id = self._progress.get("tasks")[
"connecting" "connecting"

View file

@ -8,7 +8,6 @@ from structured_config import (
ConfigFile, ConfigFile,
) )
__all__ = [ __all__ = [
"Config", "Config",
"ConfigFile", "ConfigFile",
@ -47,6 +46,13 @@ class Config(Structure):
Cogs: Dict[str, Cog] = {} Cogs: Dict[str, Cog] = {}
class Core(Structure): class Core(Structure):
class Database(Structure):
username: str = StrField("")
password: str = StrField("")
domain: str = StrField("")
port: str = IntField(5432)
db_name: str = StrField("")
owners_id: List[int] = [] owners_id: List[int] = []
prefixes: List[str] = [] prefixes: List[str] = []
token: str = StrField("") token: str = StrField("")

View file

View file

@ -9,6 +9,7 @@ from rich.console import Console
console = Console() console = Console()
TOKEN_REPLACEMENT = "whoops, leaked token" TOKEN_REPLACEMENT = "whoops, leaked token"
PASSWORD_REPLACEMENT = "whoops, leaked password"
class ContextPlus(commands.Context): class ContextPlus(commands.Context):
@ -28,6 +29,8 @@ class ContextPlus(commands.Context):
if content: if content:
content = content.replace( content = content.replace(
self.bot.config.Core.token, TOKEN_REPLACEMENT self.bot.config.Core.token, TOKEN_REPLACEMENT
).replace(
self.bot.config.Core.Database.password, PASSWORD_REPLACEMENT
) )
if embed: if embed:
e = embed.to_dict() e = embed.to_dict()
@ -35,6 +38,9 @@ class ContextPlus(commands.Context):
if isinstance(value, (str, bytes)): if isinstance(value, (str, bytes)):
e[key] = value.replace( e[key] = value.replace(
self.bot.config.Core.token, TOKEN_REPLACEMENT self.bot.config.Core.token, TOKEN_REPLACEMENT
).replace(
self.bot.config.Core.Database.password,
PASSWORD_REPLACEMENT,
) )
embed = Embed.from_dict(e) embed = Embed.from_dict(e)

View file

@ -15,7 +15,7 @@ from rich.traceback import install
from tuxbot.core.config import set_for, set_for_key from tuxbot.core.config import set_for, set_for_key
from tuxbot.logging import formatter from tuxbot.logging import formatter
from tuxbot.core.data_manager import config_dir, app_dir, cogs_data_path from tuxbot.core.utils.data_manager import config_dir, app_dir, cogs_data_path
from tuxbot.core import config from tuxbot.core import config
console = Console() console = Console()
@ -300,6 +300,34 @@ def finish_setup(data_dir: Path) -> None:
"Give the owner id of this bot", "Add another owner ?", int "Give the owner id of this bot", "Add another owner ?", int
) )
console.print("\n" * 4)
console.print(Rule("\nAnd to finish, the configuration for PostgreSQL"))
console.print()
database = {
"username": Prompt.ask(
"Please enter the username for PostgreSQL",
console=console,
),
"password": Prompt.ask(
"Please enter the password for PostgreSQL",
console=console,
),
"domain": Prompt.ask(
"Please enter the domain for PostgreSQL",
console=console,
default="localhost",
),
"port": IntPrompt.ask(
"Please enter the port for PostgreSQL",
console=console,
default="5432",
),
"db_name": Prompt.ask(
"Please enter the database name for PostgreSQL", console=console
),
}
instance_config = config.ConfigFile( instance_config = config.ConfigFile(
str(data_dir / "config.yaml"), config.Config str(data_dir / "config.yaml"), config.Config
) )
@ -310,6 +338,12 @@ def finish_setup(data_dir: Path) -> None:
instance_config.config.Core.mentionable = mentionable instance_config.config.Core.mentionable = mentionable
instance_config.config.Core.locale = "en-US" instance_config.config.Core.locale = "en-US"
instance_config.config.Core.Database.username = database["username"]
instance_config.config.Core.Database.password = database["password"]
instance_config.config.Core.Database.domain = database["domain"]
instance_config.config.Core.Database.port = database["port"]
instance_config.config.Core.Database.db_name = database["db_name"]
def basic_setup() -> None: def basic_setup() -> None:
"""Configs who refer to instances.""" """Configs who refer to instances."""