From 96618fa5025b957da8623194507ac8bf3d0a4481 Mon Sep 17 00:00:00 2001 From: Romain J Date: Wed, 15 Jan 2020 21:40:12 +0100 Subject: [PATCH 1/3] fix(token): fix all possible flaw of leaked token --- bot.py | 6 +++++- utils/functions/extra.py | 25 ++++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/bot.py b/bot.py index f06583f..e7b3bc0 100755 --- a/bot.py +++ b/bot.py @@ -14,6 +14,7 @@ from utils import Config from utils import Database from utils import Texts from utils import Version +from utils import ContextPlus description = """ Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) @@ -95,6 +96,9 @@ class TuxBot(commands.AutoShardedBot): return str(user.id) in self.config.get("permissions", "Owners").split( ', ') + async def get_context(self, message, *, cls=None): + return await super().get_context(message, cls=cls or ContextPlus) + async def on_socket_response(self, msg): self._prev_events.append(msg) @@ -112,7 +116,7 @@ class TuxBot(commands.AutoShardedBot): ) async def process_commands(self, message: discord.message): - ctx = await self.get_context(message) + ctx: commands.Context = await self.get_context(message) if ctx.command is None: return diff --git a/utils/functions/extra.py b/utils/functions/extra.py index 318ab04..d2779f6 100644 --- a/utils/functions/extra.py +++ b/utils/functions/extra.py @@ -1,20 +1,35 @@ from discord.ext import commands +from utils import Config -class commandsPlus(commands.Command): +class CommandsPlus(commands.Command): def __init__(self, func, **kwargs): super().__init__(func, **kwargs) self.category = kwargs.get("category", 'other') -def commandExtra(*args, **kwargs): - return commands.command(*args, **kwargs, cls=commandsPlus) - - class GroupPlus(commands.Group): def __init__(self, func, **kwargs): super().__init__(func, **kwargs) self.category = kwargs.get("category", 'other') + +class ContextPlus(commands.Context): + async def send(self, **kwargs): + config = Config('./configs/config.cfg') + content = kwargs.pop('content') + + content = content.replace(config.get("bot", "Token"), 'Whoops! leaked token') + content = content.replace(config.get("webhook", "Token"), 'Whoops! leaked token') + + kwargs['content'] = content + + return await super().send(**kwargs) + + +def commandExtra(*args, **kwargs): + return commands.command(*args, **kwargs, cls=CommandsPlus) + + def groupExtra(*args, **kwargs): return commands.group(*args, **kwargs, cls=GroupPlus) From be1e6d24e40e9be342afa91adb9bdb16deda9289 Mon Sep 17 00:00:00 2001 From: Romain J Date: Wed, 15 Jan 2020 22:56:54 +0100 Subject: [PATCH 2/3] breaking change ! update(database): change database ORM todo: update Admin, Poll and User cogs --- bot.py | 51 ++++++++++++++++++------------------- cogs/Admin.py | 2 +- cogs/Useful.py | 7 ----- configs/langs.json | 5 ++++ database.py | 19 ++++---------- requirements.txt | 3 ++- utils/__init__.py | 2 -- utils/functions/__init__.py | 6 +++++ utils/functions/database.py | 11 ++++---- utils/functions/extra.py | 2 +- utils/functions/lang.py | 21 +++++---------- utils/models/__init__.py | 14 +++++++--- utils/models/alias.py | 34 ++++++++----------------- utils/models/lang.py | 12 --------- utils/models/poll.py | 46 +++++++++++++++++---------------- utils/models/warn.py | 25 ++++++++---------- 16 files changed, 111 insertions(+), 149 deletions(-) create mode 100644 configs/langs.json delete mode 100644 utils/models/lang.py diff --git a/bot.py b/bot.py index e7b3bc0..4efe24d 100755 --- a/bot.py +++ b/bot.py @@ -10,11 +10,11 @@ import discord import git from discord.ext import commands -from utils import Config -from utils import Database -from utils import Texts -from utils import Version -from utils import ContextPlus +from utils.functions import Config +from utils.functions import Database +from utils.functions import Texts +from utils.functions import Version +from utils.functions import ContextPlus description = """ Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) @@ -52,7 +52,7 @@ async def _prefix_callable(bot, message: discord.message) -> list: class TuxBot(commands.AutoShardedBot): - def __init__(self, database): + def __init__(self,): super().__init__(command_prefix=_prefix_callable, pm_help=None, help_command=None, description=description, help_attrs=dict(hidden=True), @@ -63,20 +63,20 @@ class TuxBot(commands.AutoShardedBot): self.socket_stats = Counter() self.command_stats = Counter() - self.uptime: datetime = datetime.datetime.utcnow() - self._prev_events = deque(maxlen=10) - self.session = aiohttp.ClientSession(loop=self.loop) - self.database = database - self.config = Config('./configs/config.cfg') self.prefixes = Config('./configs/prefixes.cfg') self.blacklist = Config('./configs/blacklist.cfg') self.fallbacks = Config('./configs/fallbacks.cfg') self.cluster = self.fallbacks.find('True', key='This', first=True) + self.uptime: datetime = datetime.datetime.utcnow() + self._prev_events = deque(maxlen=10) + self.session = aiohttp.ClientSession(loop=self.loop) + self.database = Database(self.config) + self.version = Version(*version, pre_release='rc2', build=build) - self.owner: discord.User = discord.User - self.owners: List[discord.User] = [] + self.owner_ids = self.config.get('permissions', 'Owners').split(', ') + self.owner_id = int(self.owner_ids[0]) for extension in l_extensions: try: @@ -93,8 +93,7 @@ class TuxBot(commands.AutoShardedBot): + extension, exc_info=e) async def is_owner(self, user: discord.User) -> bool: - return str(user.id) in self.config.get("permissions", "Owners").split( - ', ') + return str(user.id) in self.owner_ids async def get_context(self, message, *, cls=None): return await super().get_context(message, cls=cls or ContextPlus) @@ -114,6 +113,8 @@ class TuxBot(commands.AutoShardedBot): "Sorry. This command is disabled and cannot be used." ) ) + elif isinstance(error, commands.CommandOnCooldown): + await ctx.send(str(error)) async def process_commands(self, message: discord.message): ctx: commands.Context = await self.get_context(message) @@ -193,13 +194,13 @@ class TuxBot(commands.AutoShardedBot): @contextlib.contextmanager def setup_logging(): + logging.getLogger('discord').setLevel(logging.INFO) + logging.getLogger('discord.http').setLevel(logging.WARNING) + + log = logging.getLogger() + log.setLevel(logging.INFO) + try: - logging.getLogger('discord').setLevel(logging.INFO) - logging.getLogger('discord.http').setLevel(logging.WARNING) - - log = logging.getLogger() - log.setLevel(logging.INFO) - handler = logging.FileHandler(filename='logs/tuxbot.log', encoding='utf-8', mode='w') fmt = logging.Formatter('[{levelname:<7}] [{asctime}]' @@ -218,14 +219,12 @@ def setup_logging(): if __name__ == "__main__": - log = logging.getLogger() - print(Texts().get('Starting...')) - bot = TuxBot(Database(Config("./configs/config.cfg"))) + app = TuxBot() try: with setup_logging(): - bot.run() + app.run() except KeyboardInterrupt: - bot.close() + app.close() diff --git a/cogs/Admin.py b/cogs/Admin.py index b9dd6a3..80510eb 100644 --- a/cogs/Admin.py +++ b/cogs/Admin.py @@ -9,7 +9,7 @@ from discord.ext import commands from bot import TuxBot from utils import Texts -from utils import WarnModel, LangModel +from utils.models import WarnModel from utils import commandExtra, groupExtra log = logging.getLogger(__name__) diff --git a/cogs/Useful.py b/cogs/Useful.py index 6cdafd3..56506c1 100644 --- a/cogs/Useful.py +++ b/cogs/Useful.py @@ -150,13 +150,6 @@ class Useful(commands.Cog): ########################################################################### - @commands.Cog.listener() - async def on_command_error(self, ctx, error): - if isinstance(error, commands.CommandOnCooldown): - await ctx.send(error) - - ########################################################################### - @commandExtra(name='getheaders', category='network') async def _getheaders(self, ctx: commands.Context, addr: str): if (addr.startswith('http') or addr.startswith('ftp')) is not True: diff --git a/configs/langs.json b/configs/langs.json new file mode 100644 index 0000000..f7b1b6f --- /dev/null +++ b/configs/langs.json @@ -0,0 +1,5 @@ +{ + "default": "fr", + "available": ["en", "fr"], + "280805240977227776": "fr" +} \ No newline at end of file diff --git a/database.py b/database.py index 57a83e8..49127d5 100644 --- a/database.py +++ b/database.py @@ -1,7 +1,5 @@ -from utils import Config -from utils.models import Base -from utils import Database -from utils.models.lang import LangModel +import sqlalchemy +from utils.models import database, metadata import argparse parser = argparse.ArgumentParser() @@ -9,20 +7,13 @@ parser.add_argument("-m", "--migrate", action="store_true") parser.add_argument("-s", "--seed", action="store_true") args = parser.parse_args() -database = Database(Config("./configs/config.cfg")) - if args.migrate: print("Migrate...") - Base.metadata.create_all(database.engine) + engine = sqlalchemy.create_engine(str(database.url)) + metadata.create_all(engine) print("Done!") if args.seed: print('Seeding...') - default = LangModel(key="default", value="fr") - available = LangModel(key="available", value="fr,en") - - database.session.add(default) - database.session.add(available) - - database.session.commit() + # todo: add seeding print("Done!") diff --git a/requirements.txt b/requirements.txt index 41b86e1..442102d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,8 @@ humanize git+https://github.com/Rapptz/discord.py@master jishaku gitpython -sqlalchemy +orm +asyncpg psycopg2 configparser psutil diff --git a/utils/__init__.py b/utils/__init__.py index a60b691..ff23e97 100755 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,5 +1,3 @@ -from .models import * - from utils.functions.config import * from utils.functions.lang import * from utils.functions.version import * diff --git a/utils/functions/__init__.py b/utils/functions/__init__.py index e69de29..171e8cc 100644 --- a/utils/functions/__init__.py +++ b/utils/functions/__init__.py @@ -0,0 +1,6 @@ +from .config import Config +from .database import Database +from .extra import * +from .lang import Texts +from .paginator import * +from .version import Version diff --git a/utils/functions/database.py b/utils/functions/database.py index 9a7e7a3..20388f0 100644 --- a/utils/functions/database.py +++ b/utils/functions/database.py @@ -1,7 +1,7 @@ from .config import Config -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker, session +import sqlalchemy +import databases class Database: @@ -10,8 +10,7 @@ class Database: postgresql = 'postgresql://{}:{}@{}/{}'.format( conf_postgresql.get("Username"), conf_postgresql.get("Password"), conf_postgresql.get("Host"), conf_postgresql.get("DBName")) - self.engine = create_engine(postgresql, echo=False) - Session = sessionmaker() - Session.configure(bind=self.engine) - self.session: session = Session() + self.database = databases.Database(postgresql) + self.metadata = sqlalchemy.MetaData() + self.engine = sqlalchemy.create_engine(str(self.database.url)) diff --git a/utils/functions/extra.py b/utils/functions/extra.py index d2779f6..26b7d05 100644 --- a/utils/functions/extra.py +++ b/utils/functions/extra.py @@ -1,5 +1,5 @@ from discord.ext import commands -from utils import Config +from utils.functions import Config class CommandsPlus(commands.Command): diff --git a/utils/functions/lang.py b/utils/functions/lang.py index 4be303b..64f2648 100644 --- a/utils/functions/lang.py +++ b/utils/functions/lang.py @@ -1,8 +1,6 @@ import gettext -from .config import Config -from .database import Database +import json -from utils.models.lang import LangModel from discord.ext import commands @@ -22,17 +20,10 @@ class Texts: @staticmethod def get_locale(ctx): - database = Database(Config("./configs/config.cfg")) + with open('./configs/langs.json') as f: + data = json.load(f) if ctx is not None: - current = database.session\ - .query(LangModel.value)\ - .filter(LangModel.key == str(ctx.guild.id)) - if current.count() > 0: - return current.one()[0] - - default = database.session\ - .query(LangModel.value)\ - .filter(LangModel.key == 'default')\ - .one()[0] - return default + return data.get(str(ctx.guild.id), data['default']) + else: + return data['default'] diff --git a/utils/models/__init__.py b/utils/models/__init__.py index 8407711..e3a855a 100644 --- a/utils/models/__init__.py +++ b/utils/models/__init__.py @@ -1,7 +1,15 @@ -from sqlalchemy.ext.declarative import declarative_base -Base = declarative_base() +import databases +import sqlalchemy +from utils.functions import Config + +conf_postgresql = Config('./configs/config.cfg')["postgresql"] +postgresql = 'postgresql://{}:{}@{}/{}'.format( + conf_postgresql.get("Username"), conf_postgresql.get("Password"), + conf_postgresql.get("Host"), conf_postgresql.get("DBName")) + +database = databases.Database(postgresql) +metadata = sqlalchemy.MetaData() -from .lang import LangModel from .warn import WarnModel from .poll import PollModel, ResponsesModel from .alias import AliasesModel diff --git a/utils/models/alias.py b/utils/models/alias.py index 7ab63df..4a1a96c 100644 --- a/utils/models/alias.py +++ b/utils/models/alias.py @@ -1,28 +1,14 @@ -from sqlalchemy import Column, String, BigInteger, Integer - -from . import Base +import orm +from . import database, metadata -class AliasesModel(Base): +class AliasesModel(orm.Model): __tablename__ = 'aliases' + __database__ = database + __metadata__ = metadata - id = Column(Integer, primary_key=True) - user_id = Column(BigInteger) - alias = Column(String) - command = Column(String) - guild = Column(String) - - def __repr__(self): - return "" % ( - self.id, - self.user_id, - self.alias, - self.command, - self.guild - ) + id = orm.Integer(primary_key=True) + user_id = orm.String(max_length=18) + alias = orm.String(max_length=255) + command = orm.String(max_length=255) + guild = orm.String(max_length=255) diff --git a/utils/models/lang.py b/utils/models/lang.py deleted file mode 100644 index 2ceb555..0000000 --- a/utils/models/lang.py +++ /dev/null @@ -1,12 +0,0 @@ -from . import Base -from sqlalchemy import Column, String - - -class LangModel(Base): - __tablename__ = 'langs' - - key = Column(String, primary_key=True) - value = Column(String) - - def __repr__(self): - return "" % (self.key, self.value) diff --git a/utils/models/poll.py b/utils/models/poll.py index 2d3d69e..a2f793e 100644 --- a/utils/models/poll.py +++ b/utils/models/poll.py @@ -1,27 +1,29 @@ -from . import Base -from sqlalchemy import Column, Integer, BigInteger, JSON, ForeignKey, Boolean -from sqlalchemy.orm import relationship +import orm +from . import database, metadata -class PollModel(Base): - __tablename__ = 'polls' - - id = Column(Integer, primary_key=True, autoincrement=True) - channel_id = Column(BigInteger) - message_id = Column(BigInteger) - - content = Column(JSON) - is_anonymous = Column(Boolean) - - available_choices = Column(Integer) - choice = relationship("ResponsesModel") - - -class ResponsesModel(Base): +class ResponsesModel(orm.Model): __tablename__ = 'responses' + __database__ = database + __metadata__ = metadata - id = Column(Integer, primary_key=True, autoincrement=True) - user = Column(BigInteger) + id = orm.Integer(primary_key=True) + user = orm.String(max_length=18) - poll_id = Column(Integer, ForeignKey('polls.id')) - choice = Column(Integer) + choice = orm.Integer() + + +class PollModel(orm.Model): + __tablename__ = 'polls' + __database__ = database + __metadata__ = metadata + + id = orm.Integer(primary_key=True) + channel_id = orm.String(max_length=18) + message_id = orm.String(max_length=18) + + content = orm.JSON() + is_anonymous = orm.Boolean() + + available_choices = orm.Integer() + choice = orm.ForeignKey(ResponsesModel) diff --git a/utils/models/warn.py b/utils/models/warn.py index b9d4674..77f8833 100644 --- a/utils/models/warn.py +++ b/utils/models/warn.py @@ -1,19 +1,14 @@ -import datetime - -from . import Base -from sqlalchemy import Column, Integer, String, BIGINT, TIMESTAMP +import orm +from . import database, metadata -class WarnModel(Base): +class WarnModel(orm.Model): __tablename__ = 'warns' + __database__ = database + __metadata__ = metadata - id = Column(Integer, primary_key=True) - server_id = Column(BIGINT) - user_id = Column(BIGINT) - reason = Column(String) - created_at = Column(TIMESTAMP, default=datetime.datetime.now()) - - def __repr__(self): - return "" \ - % (self.server_id, self.user_id, self.reason, self.created_at) + id = orm.Integer(primary_key=True) + server_id = orm.String(max_length=18) + user_id = orm.String(max_length=18) + reason = orm.String(max_length=255) + created_at = orm.DateTime() From cce7bb409303e9ad27ef4e5617d0bc9068810f13 Mon Sep 17 00:00:00 2001 From: Romain J Date: Tue, 4 Feb 2020 18:47:11 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=E2=A0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.py | 53 +++++++++++++++++++++--------------- cogs/API.py | 56 ++++++++++++++++++++++++++++++++++++++ cogs/Admin.py | 48 +++++++++++++++----------------- cogs/Logs.py | 8 +++--- cogs/Poll.py | 4 +-- cogs/Useful.py | 18 ++++++------ cogs/User.py | 4 +-- configs/config.cfg.example | 6 +++- configs/langs.json | 5 ---- configs/prefixes.cfg | 18 ------------ utils/functions/extra.py | 11 +++----- utils/functions/lang.py | 19 ++++++++----- utils/models/__init__.py | 3 ++ 13 files changed, 150 insertions(+), 103 deletions(-) create mode 100644 cogs/API.py delete mode 100644 configs/langs.json delete mode 100644 configs/prefixes.cfg diff --git a/bot.py b/bot.py index 4efe24d..5c384bf 100755 --- a/bot.py +++ b/bot.py @@ -1,5 +1,6 @@ import contextlib import datetime +import json import logging import sys from collections import deque, Counter @@ -8,14 +9,16 @@ from typing import List import aiohttp import discord import git +import sqlalchemy from discord.ext import commands from utils.functions import Config -from utils.functions import Database from utils.functions import Texts from utils.functions import Version from utils.functions import ContextPlus +from utils.models import metadata, database + description = """ Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) """ @@ -27,6 +30,7 @@ log = logging.getLogger(__name__) l_extensions: List[str] = [ 'cogs.Admin', + 'cogs.API', 'cogs.Help', 'cogs.Logs', # 'cogs.Monitoring', @@ -38,21 +42,23 @@ l_extensions: List[str] = [ async def _prefix_callable(bot, message: discord.message) -> list: - extras = [bot.cluster.get('Name') + '.', '.'] - if message.guild is not None: - if str(message.guild.id) in bot.prefixes: - extras.extend( - bot.prefixes.get(str(message.guild.id), "prefixes").split( - bot.config.get("misc", "Separator") - ) - ) + try: + with open(f'./configs/guilds/{message.guild.id}.json', 'r') as f: + data = json.load(f) + + custom_prefix = data['prefixes'] + except FileNotFoundError: + custom_prefix = [''] + + extras = [bot.cluster.get('Name') + '.'] + extras.extend(custom_prefix) return commands.when_mentioned_or(*extras)(bot, message) class TuxBot(commands.AutoShardedBot): - def __init__(self,): + def __init__(self, ): super().__init__(command_prefix=_prefix_callable, pm_help=None, help_command=None, description=description, help_attrs=dict(hidden=True), @@ -64,7 +70,6 @@ class TuxBot(commands.AutoShardedBot): self.command_stats = Counter() self.config = Config('./configs/config.cfg') - self.prefixes = Config('./configs/prefixes.cfg') self.blacklist = Config('./configs/blacklist.cfg') self.fallbacks = Config('./configs/fallbacks.cfg') self.cluster = self.fallbacks.find('True', key='This', first=True) @@ -72,11 +77,14 @@ class TuxBot(commands.AutoShardedBot): self.uptime: datetime = datetime.datetime.utcnow() self._prev_events = deque(maxlen=10) self.session = aiohttp.ClientSession(loop=self.loop) - self.database = Database(self.config) + + self.database, self.metadata = database, metadata + self.engine = sqlalchemy.create_engine(str(self.database.url)) + self.metadata.create_all(self.engine) self.version = Version(*version, pre_release='rc2', build=build) - self.owner_ids = self.config.get('permissions', 'Owners').split(', ') - self.owner_id = int(self.owner_ids[0]) + self.owners_id = [int(owner_id) for owner_id in self.config.get('permissions', 'Owners').split(', ')] + self.owner_id = int(self.owners_id[0]) for extension in l_extensions: try: @@ -92,8 +100,16 @@ class TuxBot(commands.AutoShardedBot): log.error(Texts().get("Failed to load extension : ") + extension, exc_info=e) + @property + def owner(self): + return self.get_user(self.owner_id) + + @property + def owners(self): + return [self.get_user(owner_id) for owner_id in self.owners_id] + async def is_owner(self, user: discord.User) -> bool: - return str(user.id) in self.owner_ids + return user in self.owners async def get_context(self, message, *, cls=None): return await super().get_context(message, cls=cls or ContextPlus) @@ -156,13 +172,6 @@ class TuxBot(commands.AutoShardedBot): print('-' * 60) await self.change_presence(**presence) - self.owner = await self.fetch_user( - int(self.config.get('permissions', 'Owners').split(', ')[0]) - ) - for owner in self.config.get('permissions', 'Owners').split(', '): - self.owners.append( - await self.fetch_user(int(owner)) - ) @staticmethod async def on_resumed(): diff --git a/cogs/API.py b/cogs/API.py new file mode 100644 index 0000000..a483b25 --- /dev/null +++ b/cogs/API.py @@ -0,0 +1,56 @@ +import logging + +import discord +from aiohttp import web +from discord.ext import commands + +from bot import TuxBot + +log = logging.getLogger(__name__) + + +class API(commands.Cog): + + def __init__(self, bot: TuxBot): + self.bot = bot + self.site = web.TCPSite + + app = web.Application() + app.add_routes([web.get('/users/{user_id}', self.users)]) + + self.runner = web.AppRunner(app) + self.bot.loop.create_task(self.start_HTTPMonitoring_server()) + + async def start_HTTPMonitoring_server(self): + host = self.bot.config.get('API', 'Host') + port = self.bot.config.get('API', 'Port') + + print(f"Starting API server on {host}:{port}") + + await self.runner.setup() + self.site = web.TCPSite(self.runner, host, port) + await self.site.start() + + async def users(self, request): + try: + user = await self.bot.fetch_user(request.match_info['user_id']) + except discord.NotFound: + return web.Response(status=404) + + json = { + 'id': user.id, + 'username': user.name, + 'discriminator': user.discriminator, + 'avatar': user.avatar, + 'default_avatar': user.default_avatar.value, + 'bot': user.bot, + 'system': user.system, + } + + return web.json_response( + json + ) + + +def setup(bot: TuxBot): + bot.add_cog(API(bot)) diff --git a/cogs/Admin.py b/cogs/Admin.py index 80510eb..0fa400d 100644 --- a/cogs/Admin.py +++ b/cogs/Admin.py @@ -10,7 +10,7 @@ from discord.ext import commands from bot import TuxBot from utils import Texts from utils.models import WarnModel -from utils import commandExtra, groupExtra +from utils import command_extra, group_extra log = logging.getLogger(__name__) @@ -65,7 +65,7 @@ class Admin(commands.Cog): ########################################################################### - @groupExtra(name='say', invoke_without_command=True, category='text') + @group_extra(name='say', invoke_without_command=True, category='text') async def _say(self, ctx: commands.Context, *, content: str): if ctx.invoked_subcommand is None: try: @@ -105,7 +105,7 @@ class Admin(commands.Cog): ########################################################################### - @commandExtra(name='ban', category='administration') + @command_extra(name='ban', category='administration') async def _ban(self, ctx: commands.Context, user: discord.Member, *, reason=""): try: @@ -132,7 +132,7 @@ class Admin(commands.Cog): ########################################################################### - @commandExtra(name='kick', category='administration') + @command_extra(name='kick', category='administration') async def _kick(self, ctx: commands.Context, user: discord.Member, *, reason=""): try: @@ -159,7 +159,7 @@ class Admin(commands.Cog): ########################################################################### - @commandExtra(name='clear', category='text') + @command_extra(name='clear', category='text') async def _clear(self, ctx: commands.Context, count: int): try: await ctx.message.delete() @@ -169,7 +169,7 @@ class Admin(commands.Cog): ########################################################################### - @groupExtra(name='react', category='text') + @group_extra(name='react', category='text') async def _react(self, ctx: commands.Context): if ctx.invoked_subcommand is None: await ctx.send_help('react') @@ -203,7 +203,7 @@ class Admin(commands.Cog): ########################################################################### - @groupExtra(name='delete', invoke_without_command=True, category='text') + @group_extra(name='delete', invoke_without_command=True, category='text') async def _delete(self, ctx: commands.Context, message_id: int): try: await ctx.message.delete() @@ -229,12 +229,14 @@ class Admin(commands.Cog): try: message: discord.Message = await channel.fetch_message( - message_id) + message_id + ) await message.delete() except (discord.errors.NotFound, discord.errors.Forbidden): await ctx.send( Texts('utils', ctx).get("Unable to find the message"), - delete_after=5) + delete_after=5 + ) ########################################################################### @@ -242,24 +244,18 @@ class Admin(commands.Cog): member: discord.Member = False): await ctx.trigger_typing() - week_ago = datetime.datetime.now() - datetime.timedelta(weeks=6) - if member: - warns = self.bot.database.session \ - .query(WarnModel) \ - .filter(WarnModel.user_id == member.id, - WarnModel.created_at > week_ago, - WarnModel.server_id == ctx.guild.id) \ - .order_by(WarnModel.created_at.desc()) + warns = WarnModel.objects.filter( + server_id=str(ctx.guild.id), + user_id=member.id + ) else: - warns = self.bot.database.session \ - .query(WarnModel) \ - .filter(WarnModel.created_at > week_ago, - WarnModel.server_id == ctx.guild.id) \ - .order_by(WarnModel.created_at.desc()) + warns = WarnModel.objects.filter( + server_id=str(ctx.guild.id) + ) warns_list = '' - for warn in warns: + for warn in await warns.all(): row_id = warn.id user_id = warn.user_id user = await self.bot.fetch_user(user_id) @@ -283,7 +279,7 @@ class Admin(commands.Cog): self.bot.database.session.add(warn) self.bot.database.session.commit() - @groupExtra(name='warn', aliases=['warns'], category='administration') + @group_extra(name='warn', aliases=['warns'], category='administration') async def _warn(self, ctx: commands.Context): await ctx.trigger_typing() if ctx.invoked_subcommand is None: @@ -412,7 +408,7 @@ class Admin(commands.Cog): ########################################################################### - @commandExtra(name='language', aliases=['lang', 'langue', 'langage'], category='server') + @command_extra(name='language', aliases=['lang', 'langue', 'langage'], category='server') async def _language(self, ctx: commands.Context, locale: str): available = self.bot.database.session \ .query(LangModel.value) \ @@ -443,7 +439,7 @@ class Admin(commands.Cog): ########################################################################### - @groupExtra(name='prefix', aliases=['prefixes'], category='server') + @group_extra(name='prefix', aliases=['prefixes'], category='server') async def _prefix(self, ctx: commands.Context): if ctx.invoked_subcommand is None: await ctx.send_help('prefix') diff --git a/cogs/Logs.py b/cogs/Logs.py index 3642367..7caa4ec 100644 --- a/cogs/Logs.py +++ b/cogs/Logs.py @@ -20,7 +20,7 @@ from discord.ext import commands, tasks from bot import TuxBot from utils import Texts -from utils import commandExtra +from utils import command_extra log = logging.getLogger(__name__) @@ -243,7 +243,7 @@ class Logs(commands.Cog): msg = f'{emoji} `[{dt:%Y-%m-%d %H:%M:%S}] {record.message}`' await self.webhook.send(msg) - @commandExtra(name='commandstats', hidden=True, category='misc') + @command_extra(name='commandstats', hidden=True, category='misc') @commands.is_owner() async def _commandstats(self, ctx, limit=20): counter = self.bot.command_stats @@ -258,7 +258,7 @@ class Logs(commands.Cog): await ctx.send(f'```\n{output}\n```') - @commandExtra(name='socketstats', hidden=True, category='misc') + @command_extra(name='socketstats', hidden=True, category='misc') @commands.is_owner() async def _socketstats(self, ctx): delta = datetime.datetime.utcnow() - self.bot.uptime @@ -268,7 +268,7 @@ class Logs(commands.Cog): await ctx.send( f'{total} socket events observed ({cpm:.2f}/minute):\n{self.bot.socket_stats}') - @commandExtra(name='uptime', category='misc') + @command_extra(name='uptime', category='misc') async def _uptime(self, ctx): uptime = humanize.naturaltime( datetime.datetime.utcnow() - self.bot.uptime) diff --git a/cogs/Poll.py b/cogs/Poll.py index 62beac7..44dd1eb 100644 --- a/cogs/Poll.py +++ b/cogs/Poll.py @@ -10,7 +10,7 @@ from bot import TuxBot from utils import PollModel, ResponsesModel from utils import Texts from utils.functions import emotes as utils_emotes -from utils import groupExtra +from utils import group_extra log = logging.getLogger(__name__) @@ -205,7 +205,7 @@ class Poll(commands.Cog): poll.content = json.dumps(content) self.bot.database.session.commit() - @groupExtra(name='poll', aliases=['sondage'], category='poll') + @group_extra(name='poll', aliases=['sondage'], category='poll') async def _poll(self, ctx: commands.Context): if ctx.invoked_subcommand is None: await ctx.send_help('poll') diff --git a/cogs/Useful.py b/cogs/Useful.py index 56506c1..a79b60c 100644 --- a/cogs/Useful.py +++ b/cogs/Useful.py @@ -23,7 +23,7 @@ from tcp_latency import measure_latency from bot import TuxBot from utils import Texts -from utils import commandExtra, groupExtra +from utils import command_extra, group_extra log = logging.getLogger(__name__) @@ -86,7 +86,7 @@ class Useful(commands.Cog): ########################################################################### - @commandExtra(name='iplocalise', category='network') + @command_extra(name='iplocalise', category='network') async def _iplocalise(self, ctx: commands.Context, addr, ip_type=''): addr = re.sub(r'http(s?)://', '', addr) addr = addr[:-1] if addr.endswith('/') else addr @@ -150,7 +150,7 @@ class Useful(commands.Cog): ########################################################################### - @commandExtra(name='getheaders', category='network') + @command_extra(name='getheaders', category='network') async def _getheaders(self, ctx: commands.Context, addr: str): if (addr.startswith('http') or addr.startswith('ftp')) is not True: addr = f"http://{addr}" @@ -180,7 +180,7 @@ class Useful(commands.Cog): ########################################################################### - @commandExtra(name='git', aliases=['sources', 'source', 'github'], category='misc') + @command_extra(name='git', aliases=['sources', 'source', 'github'], category='misc') async def _git(self, ctx): e = discord.Embed( title=Texts('useful', ctx).get('git repo'), @@ -195,7 +195,7 @@ class Useful(commands.Cog): ########################################################################### - @commandExtra(name='quote', category='misc') + @command_extra(name='quote', category='misc') async def _quote(self, ctx, message_id: discord.Message): e = discord.Embed( colour=message_id.author.colour, @@ -217,7 +217,7 @@ class Useful(commands.Cog): ########################################################################### - @commandExtra(name='ping', category='network') + @command_extra(name='ping', category='network') async def _ping(self, ctx: commands.Context): start = time.perf_counter() await ctx.trigger_typing() @@ -235,7 +235,7 @@ class Useful(commands.Cog): ########################################################################### - @commandExtra(name='info', aliases=['about'], category='misc') + @command_extra(name='info', aliases=['about'], category='misc') async def _info(self, ctx: commands.Context): proc = psutil.Process() total, python = self.fetch_info() @@ -318,7 +318,7 @@ class Useful(commands.Cog): ########################################################################### - @commandExtra(name='credits', aliases=['contributors', 'authors'], category='misc') + @command_extra(name='credits', aliases=['contributors', 'authors'], category='misc') async def _credits(self, ctx: commands.Context): e = discord.Embed( title=Texts('useful', ctx).get('Contributors'), @@ -342,7 +342,7 @@ class Useful(commands.Cog): await ctx.send(embed=e) ########################################################################### - @groupExtra(name='cb', aliases=['cc'], category='misc') + @group_extra(name='cb', aliases=['cc'], category='misc') @commands.cooldown(1, 5, type=commands.BucketType.user) async def _cb(self, ctx: commands.Context): if ctx.invoked_subcommand is None: diff --git a/cogs/User.py b/cogs/User.py index c883b63..ac0c830 100644 --- a/cogs/User.py +++ b/cogs/User.py @@ -5,7 +5,7 @@ from discord.ext import commands from bot import TuxBot from utils import AliasesModel from utils import Texts -from utils import groupExtra +from utils import group_extra log = logging.getLogger(__name__) @@ -19,7 +19,7 @@ class User(commands.Cog): ########################################################################### - @groupExtra(name='alias', aliases=['aliases'], category='alias') + @group_extra(name='alias', aliases=['aliases'], category='alias') async def _alias(self, ctx: commands.Context): if ctx.invoked_subcommand is None: await ctx.send_help('alias') diff --git a/configs/config.cfg.example b/configs/config.cfg.example index 6bc3eb2..e156f5d 100644 --- a/configs/config.cfg.example +++ b/configs/config.cfg.example @@ -17,4 +17,8 @@ ID = Token = [misc] -Separator = \ No newline at end of file +Separator = + +[API] +Host = +Port = \ No newline at end of file diff --git a/configs/langs.json b/configs/langs.json deleted file mode 100644 index f7b1b6f..0000000 --- a/configs/langs.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "default": "fr", - "available": ["en", "fr"], - "280805240977227776": "fr" -} \ No newline at end of file diff --git a/configs/prefixes.cfg b/configs/prefixes.cfg deleted file mode 100644 index 1924607..0000000 --- a/configs/prefixes.cfg +++ /dev/null @@ -1,18 +0,0 @@ -[280805240977227776] -prefixes = b1. - -[303633056944881686] -prefixes = b1. - -[373881878471770112] -prefixes = b1. - -[336642139381301249] -prefixes = ba. - -[274247231534792704] -prefixes = test. - -[528679953399676938] -prefixes = test. - diff --git a/utils/functions/extra.py b/utils/functions/extra.py index 26b7d05..b07ad88 100644 --- a/utils/functions/extra.py +++ b/utils/functions/extra.py @@ -15,21 +15,18 @@ class GroupPlus(commands.Group): class ContextPlus(commands.Context): - async def send(self, **kwargs): + async def send(self, content=None, **kwargs): config = Config('./configs/config.cfg') - content = kwargs.pop('content') content = content.replace(config.get("bot", "Token"), 'Whoops! leaked token') content = content.replace(config.get("webhook", "Token"), 'Whoops! leaked token') - kwargs['content'] = content - - return await super().send(**kwargs) + return await super().send(content, **kwargs) -def commandExtra(*args, **kwargs): +def command_extra(*args, **kwargs): return commands.command(*args, **kwargs, cls=CommandsPlus) -def groupExtra(*args, **kwargs): +def group_extra(*args, **kwargs): return commands.group(*args, **kwargs, cls=GroupPlus) diff --git a/utils/functions/lang.py b/utils/functions/lang.py index 64f2648..fd3330b 100644 --- a/utils/functions/lang.py +++ b/utils/functions/lang.py @@ -19,11 +19,16 @@ class Texts: self.locale = lang @staticmethod - def get_locale(ctx): - with open('./configs/langs.json') as f: - data = json.load(f) - + def get_locale(ctx: commands.Context): + lang = 'fr' if ctx is not None: - return data.get(str(ctx.guild.id), data['default']) - else: - return data['default'] + try: + with open(f'./configs/guilds/{ctx.guild.id}.json', 'r') as f: + data = json.load(f) + + lang = data['lang'] + + except FileNotFoundError: + pass + + return lang diff --git a/utils/models/__init__.py b/utils/models/__init__.py index e3a855a..36ba5cc 100644 --- a/utils/models/__init__.py +++ b/utils/models/__init__.py @@ -10,6 +10,9 @@ postgresql = 'postgresql://{}:{}@{}/{}'.format( database = databases.Database(postgresql) metadata = sqlalchemy.MetaData() +engine = sqlalchemy.create_engine(str(database.url)) +metadata.create_all(engine) + from .warn import WarnModel from .poll import PollModel, ResponsesModel from .alias import AliasesModel