diff --git a/.idea/dictionaries/romain.xml b/.idea/dictionaries/romain.xml index b11d467..4def97a 100644 --- a/.idea/dictionaries/romain.xml +++ b/.idea/dictionaries/romain.xml @@ -22,6 +22,7 @@ localiseip octobre pacman + postgre postgresql pred pylint @@ -32,6 +33,7 @@ splt suivante systemd + tablename tldr tutux tuxbot @@ -40,6 +42,7 @@ venv webhook webhooks + youtrack écrite diff --git a/.idea/misc.xml b/.idea/misc.xml index 4941e09..a24750f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index dd59735..f8da336 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/.idea/tuxbot-bot-rewrite.iml b/.idea/tuxbot-bot.iml similarity index 85% rename from .idea/tuxbot-bot-rewrite.iml rename to .idea/tuxbot-bot.iml index d728f09..24523bc 100644 --- a/.idea/tuxbot-bot-rewrite.iml +++ b/.idea/tuxbot-bot.iml @@ -6,7 +6,7 @@ - + diff --git a/Makefile b/Makefile index da03d39..30a6922 100644 --- a/Makefile +++ b/Makefile @@ -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 . diff --git a/dev.requirements.txt b/dev.requirements.txt new file mode 100644 index 0000000..dd71093 --- /dev/null +++ b/dev.requirements.txt @@ -0,0 +1,3 @@ +youtrack +pylint==2.6.0 +black==20.8b1 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 6ee8527..2b717cf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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 = diff --git a/tuxbot/__main__.py b/tuxbot/__main__.py index fdf4ebe..a49981b 100644 --- a/tuxbot/__main__.py +++ b/tuxbot/__main__.py @@ -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) diff --git a/tuxbot/__run__.py b/tuxbot/__run__.py index 9039a54..5057b79 100644 --- a/tuxbot/__run__.py +++ b/tuxbot/__run__.py @@ -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: diff --git a/tuxbot/cogs/admin/__init__.py b/tuxbot/cogs/admin/__init__.py index 11565d1..491897f 100644 --- a/tuxbot/cogs/admin/__init__.py +++ b/tuxbot/cogs/admin/__init__.py @@ -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") diff --git a/tuxbot/cogs/admin/admin.py b/tuxbot/cogs/admin/admin.py index 585c1e3..eec7423 100644 --- a/tuxbot/cogs/admin/admin.py +++ b/tuxbot/cogs/admin/admin.py @@ -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 diff --git a/tuxbot/cogs/admin/config.py b/tuxbot/cogs/admin/config.py index ff6762b..0d23ddb 100644 --- a/tuxbot/cogs/admin/config.py +++ b/tuxbot/cogs/admin/config.py @@ -1,5 +1,7 @@ from structured_config import Structure +HAS_MODELS = True + class AdminConfig(Structure): pass diff --git a/tuxbot/cogs/admin/models/__init__.py b/tuxbot/cogs/admin/models/__init__.py new file mode 100644 index 0000000..f21a8b3 --- /dev/null +++ b/tuxbot/cogs/admin/models/__init__.py @@ -0,0 +1,2 @@ +from .alias import * +from .warn import * diff --git a/tuxbot/cogs/admin/models/alias.py b/tuxbot/cogs/admin/models/alias.py new file mode 100644 index 0000000..eb306db --- /dev/null +++ b/tuxbot/cogs/admin/models/alias.py @@ -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"" + + __repr__ = __str__ diff --git a/tuxbot/cogs/admin/models/warn.py b/tuxbot/cogs/admin/models/warn.py new file mode 100644 index 0000000..c1d408a --- /dev/null +++ b/tuxbot/cogs/admin/models/warn.py @@ -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"" + + __repr__ = __str__ diff --git a/tuxbot/cogs/dev/__init__.py b/tuxbot/cogs/dev/__init__.py new file mode 100644 index 0000000..64b60ac --- /dev/null +++ b/tuxbot/cogs/dev/__init__.py @@ -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) diff --git a/tuxbot/cogs/dev/config.py b/tuxbot/cogs/dev/config.py new file mode 100644 index 0000000..f2ac023 --- /dev/null +++ b/tuxbot/cogs/dev/config.py @@ -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", + }, +} diff --git a/tuxbot/cogs/dev/dev.py b/tuxbot/cogs/dev/dev.py new file mode 100644 index 0000000..8833ac1 --- /dev/null +++ b/tuxbot/cogs/dev/dev.py @@ -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 diff --git a/tuxbot/cogs/dev/locales/en-US.po b/tuxbot/cogs/dev/locales/en-US.po new file mode 100644 index 0000000..d7bc028 --- /dev/null +++ b/tuxbot/cogs/dev/locales/en-US.po @@ -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" diff --git a/tuxbot/cogs/dev/locales/fr-FR.po b/tuxbot/cogs/dev/locales/fr-FR.po new file mode 100644 index 0000000..3562511 --- /dev/null +++ b/tuxbot/cogs/dev/locales/fr-FR.po @@ -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" diff --git a/tuxbot/cogs/dev/locales/messages.pot b/tuxbot/cogs/dev/locales/messages.pot new file mode 100644 index 0000000..9c11528 --- /dev/null +++ b/tuxbot/cogs/dev/locales/messages.pot @@ -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 , 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 \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" diff --git a/tuxbot/cogs/dev/models/__init__.py b/tuxbot/cogs/dev/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tuxbot/cogs/logs/__init__.py b/tuxbot/cogs/logs/__init__.py index 85eaf19..0cb5625 100644 --- a/tuxbot/cogs/logs/__init__.py +++ b/tuxbot/cogs/logs/__init__.py @@ -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") diff --git a/tuxbot/cogs/logs/config.py b/tuxbot/cogs/logs/config.py index e1f7802..366efdf 100644 --- a/tuxbot/cogs/logs/config.py +++ b/tuxbot/cogs/logs/config.py @@ -1,5 +1,7 @@ from structured_config import Structure, StrField +HAS_MODELS = False + class LogsConfig(Structure): dm: str = StrField("") diff --git a/tuxbot/cogs/logs/logs.py b/tuxbot/cogs/logs/logs.py index 9f53163..bb27f0c 100644 --- a/tuxbot/cogs/logs/logs.py +++ b/tuxbot/cogs/logs/logs.py @@ -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__) diff --git a/tuxbot/cogs/logs/models/__init__.py b/tuxbot/cogs/logs/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tuxbot/core/bot.py b/tuxbot/core/bot.py index 9541075..4d728c6 100644 --- a/tuxbot/core/bot.py +++ b/tuxbot/core/bot.py @@ -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" diff --git a/tuxbot/core/config.py b/tuxbot/core/config.py index 9ea992c..e96baa0 100644 --- a/tuxbot/core/config.py +++ b/tuxbot/core/config.py @@ -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("") diff --git a/tuxbot/core/utils/__init__.py b/tuxbot/core/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tuxbot/core/checks.py b/tuxbot/core/utils/checks.py similarity index 100% rename from tuxbot/core/checks.py rename to tuxbot/core/utils/checks.py diff --git a/tuxbot/core/data_manager.py b/tuxbot/core/utils/data_manager.py similarity index 100% rename from tuxbot/core/data_manager.py rename to tuxbot/core/utils/data_manager.py diff --git a/tuxbot/core/utils/functions/extra.py b/tuxbot/core/utils/functions/extra.py index 0fe7915..1b79911 100644 --- a/tuxbot/core/utils/functions/extra.py +++ b/tuxbot/core/utils/functions/extra.py @@ -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) diff --git a/tuxbot/setup.py b/tuxbot/setup.py index 0dd3801..7a42ca6 100644 --- a/tuxbot/setup.py +++ b/tuxbot/setup.py @@ -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."""