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

View file

@ -3,5 +3,5 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</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>

View file

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<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>
</component>
</project>

View file

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

View file

@ -9,6 +9,8 @@ main:
$(VENV)/bin/pip install -U pip setuptools
install:
$(VENV)/bin/pip install .
install-dev:
$(VENV)/bin/pip install -r dev.requirements.txt
update:
$(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
install_requires =
appdirs>=1.4.4
asyncpg>=0.21.0
Babel>=2.8.0
black==20.8b1
discord.py==1.5.1
discord_flags==2.1.1
humanize==2.6.0
discord.py>=1.5.1
discord_flags>=2.1.1
humanize>=2.6.0
jishaku>=1.19.1.200
psutil>=5.7.2
pylint==2.6.0
rich>=6.0.0
structured_config>=4.12
tortoise-orm>=0.16.17
[options.entry_points]
console_scripts =

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@ import logging
import discord
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.config import set_for_key
from tuxbot.core.config import Config

View file

@ -1,5 +1,7 @@
from structured_config import Structure
HAS_MODELS = True
class AdminConfig(Structure):
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 .logs import Logs, on_error, GatewayHandler
from .config import LogsConfig
from .config import LogsConfig, HAS_MODELS
from ...core.bot import Tux
VersionInfo = namedtuple("VersionInfo", "major minor micro release_level")

View file

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

View file

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

View file

View file

@ -1,5 +1,6 @@
import asyncio
import datetime
import importlib
import logging
from collections import Counter
from typing import List, Union
@ -13,10 +14,14 @@ from rich.console import Console
from rich.panel import Panel
from rich.progress import Progress, TextColumn, BarColumn
from rich.table import Table
from rich.traceback import install
from tortoise import Tortoise
from tuxbot import version_info
from tuxbot.core.utils.data_manager import (
logs_data_path,
data_path,
config_dir,
)
from .config import (
Config,
ConfigFile,
@ -24,8 +29,6 @@ from .config import (
AppConfig,
set_for_key,
)
from .data_manager import logs_data_path, data_path, config_dir
from . import __version__, ExitCodes
from . import exceptions
from .utils.functions.extra import ContextPlus
@ -33,9 +36,13 @@ from .utils.functions.prefix import get_prefixes
log = logging.getLogger("tuxbot")
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):
@ -140,7 +147,7 @@ class Tux(commands.AutoShardedBot):
)
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.add_column(
@ -240,6 +247,43 @@ class Tux(commands.AutoShardedBot):
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:
task_id = self._progress.get("tasks")[
"connecting"

View file

@ -8,7 +8,6 @@ from structured_config import (
ConfigFile,
)
__all__ = [
"Config",
"ConfigFile",
@ -47,6 +46,13 @@ class Config(Structure):
Cogs: Dict[str, Cog] = {}
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] = []
prefixes: List[str] = []
token: str = StrField("")

View file

View file

@ -9,6 +9,7 @@ from rich.console import Console
console = Console()
TOKEN_REPLACEMENT = "whoops, leaked token"
PASSWORD_REPLACEMENT = "whoops, leaked password"
class ContextPlus(commands.Context):
@ -28,6 +29,8 @@ class ContextPlus(commands.Context):
if content:
content = content.replace(
self.bot.config.Core.token, TOKEN_REPLACEMENT
).replace(
self.bot.config.Core.Database.password, PASSWORD_REPLACEMENT
)
if embed:
e = embed.to_dict()
@ -35,6 +38,9 @@ class ContextPlus(commands.Context):
if isinstance(value, (str, bytes)):
e[key] = value.replace(
self.bot.config.Core.token, TOKEN_REPLACEMENT
).replace(
self.bot.config.Core.Database.password,
PASSWORD_REPLACEMENT,
)
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.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
console = Console()
@ -300,6 +300,34 @@ def finish_setup(data_dir: Path) -> None:
"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(
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.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:
"""Configs who refer to instances."""