From cce7bb409303e9ad27ef4e5617d0bc9068810f13 Mon Sep 17 00:00:00 2001 From: Romain J Date: Tue, 4 Feb 2020 18:47:11 +0100 Subject: [PATCH] =?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