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."""