diff --git a/bot.py b/bot.py index 0a179a4..b5fb74d 100755 --- a/bot.py +++ b/bot.py @@ -11,12 +11,13 @@ from discord.ext import commands import config from cogs.utils.config import Config -from cogs.utils.lang import gettext +from cogs.utils.lang import Texts from cogs.utils.version import Version description = """ Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) """ +build = git.Repo(search_parent_directories=True).head.object.hexsha log = logging.getLogger(__name__) @@ -38,7 +39,10 @@ class TuxBot(commands.AutoShardedBot): __slots__ = ('uptime', 'config', 'session') def __init__(self, unload: list): - super().__init__(command_prefix=_prefix_callable, description=description, pm_help=None, help_command=None, help_attrs=dict(hidden=True)) + super().__init__(command_prefix=_prefix_callable, pm_help=None, + help_command=None, description=description, + help_attrs=dict(hidden=True), + activity=discord.Game(name=Texts().get('Stating...'))) self.uptime: datetime = datetime.datetime.utcnow() self.config = config @@ -48,15 +52,17 @@ class TuxBot(commands.AutoShardedBot): self.prefixes = Config('prefixes.json') self.blacklist = Config('blacklist.json') - self.version = Version(10, 0, 0, pre_release='a20', build=git.Repo(search_parent_directories=True).head.object.hexsha) + self.version = Version(10, 0, 0, pre_release='a20', build=build) for extension in l_extensions: if extension not in unload: try: self.load_extension(extension) except Exception as e: - print(gettext("Failed to load extension : ") + extension, file=sys.stderr) - log.error(gettext("Failed to load extension : ") + extension, exc_info=e) + print(Texts().get("Failed to load extension : ") + + extension, file=sys.stderr) + log.error(Texts().get("Failed to load extension : ") + + extension, exc_info=e) async def is_owner(self, user: discord.User) -> bool: return user.id in config.authorized_id @@ -66,15 +72,21 @@ class TuxBot(commands.AutoShardedBot): async def on_command_error(self, ctx: discord.ext.commands.Context, error): if isinstance(error, commands.NoPrivateMessage): - await ctx.author.send(gettext('This command cannot be used in private messages.')) + await ctx.author.send( + Texts().get("This command cannot be used in private messages.") + ) elif isinstance(error, commands.DisabledCommand): - await ctx.author.send(gettext('Sorry. This command is disabled and cannot be used.')) + await ctx.author.send( + Texts().get("Sorry. This command is disabled and cannot be used.") + ) elif isinstance(error, commands.CommandInvokeError): - print(gettext('In ') + f'{ctx.command.qualified_name}:', file=sys.stderr) + print(Texts().get("In ") + f'{ctx.command.qualified_name}:', + file=sys.stderr) traceback.print_tb(error.original.__traceback__) - print(f'{error.original.__class__.__name__}: {error.original}', file=sys.stderr) + print(f'{error.original.__class__.__name__}: {error.original}', + file=sys.stderr) elif isinstance(error, commands.ArgumentParsingError): await ctx.send(error.__str__()) @@ -88,7 +100,9 @@ class TuxBot(commands.AutoShardedBot): await self.invoke(ctx) async def on_message(self, message: discord.message): - if message.author.bot or message.author.id in self.blacklist or message.guild.id in self.blacklist: + if message.author.bot \ + or message.author.id in self.blacklist \ + or message.guild.id in self.blacklist: return await self.process_commands(message) @@ -97,7 +111,7 @@ class TuxBot(commands.AutoShardedBot): if not hasattr(self, 'uptime'): self.uptime = datetime.datetime.utcnow() - print(gettext('Ready:') + f' {self.user} (ID: {self.user.id})') + print(Texts().get("Ready:") + f' {self.user} (ID: {self.user.id})') print(self.version) presence: dict = dict(status=discord.Status.dnd) @@ -113,7 +127,11 @@ class TuxBot(commands.AutoShardedBot): @property def logs_webhook(self) -> discord.Webhook: logs_webhook = self.config.logs_webhook - webhook = discord.Webhook.partial(id=logs_webhook.get('id'), token=logs_webhook.get('token'), adapter=discord.AsyncWebhookAdapter(self.session)) + webhook = discord.Webhook.partial(id=logs_webhook.get('id'), + token=logs_webhook.get('token'), + adapter=discord.AsyncWebhookAdapter( + self.session) + ) return webhook diff --git a/cogs/admin.py b/cogs/admin.py index 55052b1..7e0188d 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -1,5 +1,10 @@ +import datetime + +import discord from discord.ext import commands + from bot import TuxBot +from .utils.lang import Texts class Admin(commands.Cog): @@ -9,17 +14,100 @@ class Admin(commands.Cog): async def cog_check(self, ctx: commands.Context): permissions = ctx.channel.permissions_for(ctx.author) - return permissions.administrator + + has_permission = permissions.administrator + is_owner = await self.bot.is_owner(ctx.author) + + return has_permission or is_owner + + @staticmethod + async def kick_ban_message(ctx: commands.Context, **kwargs) -> discord.Embed: + member: discord.Member = kwargs.get('member') + reason = kwargs.get( + 'reason', + Texts('admin').get("Please enter a reason") + ) + + if kwargs.get('type') == 'ban': + title = '**Ban** ' + str(len(await ctx.guild.bans())) + color = discord.Color.dark_red() + else: + title = '**Kick**' + color = discord.Color.red() + e = discord.Embed( + title=title, + description=reason, + timestamp=datetime.datetime.utcnow(), + color=color + ) + e.set_author( + name=f'{member.name}#{member.discriminator} ({member.id})', + icon_url=member.avatar_url_as(format='jpg') + ) + e.set_footer( + text=f'{ctx.author.name}#{ctx.author.discriminator}', + icon_url=ctx.author.avatar_url_as(format='png') + ) + + return e """---------------------------------------------------------------------""" - @commands.command(name='say', pass_context=True) + @commands.command(name='say') async def _say(self, ctx: commands.Context, *, to_say: str): - # try: - await ctx.message.delete() - await ctx.send(to_say) - # except: - # await ctx.send(to_say) + try: + await ctx.message.delete() + await ctx.send(to_say) + except discord.errors.Forbidden: + await ctx.send(to_say) + + """---------------------------------------------------------------------""" + + @commands.command(name="ban") + async def _ban(self, ctx: commands.Context, user: discord.User, *, + reason=""): + member: discord.Member = await ctx.guild.fetch_member(user.id) + + if member: + try: + await member.ban(reason=reason) + e: discord.Embed = await self.kick_ban_message( + ctx, + member=member, + type='ban', + reason=reason + ) + + await ctx.send(embed=e) + except discord.Forbidden: + await ctx.send(Texts('admin').get("Unable to ban this user")) + else: + await ctx.send(Texts('admin').get("Unable to find the user...")) + + """---------------------------------------------------------------------""" + + @commands.command(name="kick") + async def _kick(self, ctx: commands.Context, user: discord.User, *, + reason=""): + member: discord.Member = await ctx.guild.fetch_member(user.id) + + if member: + try: + await member.kick(reason=reason) + e: discord.Embed = await self.kick_ban_message( + ctx, + member=member, + type='kick', + reason=reason + ) + + await ctx.send(embed=e) + except discord.Forbidden: + await ctx.send(Texts('admin').get("Unable to ban this user")) + else: + await ctx.send(Texts('admin').get("Unable to find the user...")) + + """---------------------------------------------------------------------""" def setup(bot: TuxBot): diff --git a/cogs/utils/lang.py b/cogs/utils/lang.py index 9142680..fabb78d 100644 --- a/cogs/utils/lang.py +++ b/cogs/utils/lang.py @@ -1,8 +1,16 @@ import gettext import config -lang = gettext.translation('base', localedir='locales', - languages=[config.lang]) -lang.install() -gettext = lang.gettext +class Texts: + def __init__(self, base: str = 'base'): + self.locale = config.locale + self.texts = gettext.translation(base, localedir='locales', + languages=[self.locale]) + self.texts.install() + + def __str__(self) -> str: + return self.texts + + def get(self, text: str) -> str: + return self.texts.gettext(text) diff --git a/first_run/initializer.py b/first_run/initializer.py index f3870f9..a2c1e95 100644 --- a/first_run/initializer.py +++ b/first_run/initializer.py @@ -10,16 +10,15 @@ class Config: 'log_channel_id': '', 'main_server_id': '', 'authorized_id': '[admin ids here (in int)]', - 'unkickable_id': '[unkickable ids here (in int)]' } with open('requirements.txt', 'r') as f: self.packages = f.read().split('\n') def input(self, key, **kwargs): - lang = self.config.get('lang', 'multiple') + locale = self.config.get('locale', 'multiple') - print('\n\033[4m' + texts.get(lang).get(key) + '\033[0m') + print('\n\033[4m' + texts.get(locale).get(key) + '\033[0m') response = input('> ') if kwargs.get('valid'): @@ -29,7 +28,7 @@ class Config: if not kwargs.get('empty', True): while len(response) == 0: - print('\033[41m' + texts.get(lang).get('not_empty') + print('\033[41m' + texts.get(locale).get('not_empty') + '\033[0m') response = input('> ') else: @@ -39,31 +38,31 @@ class Config: self.config[key] = response def install(self): - self.input('lang', valid=locales) + self.input('locale', valid=locales) print('\n\n\033[4;36m' - + texts.get(self.config.get('lang')).get('install') + + texts.get(self.config.get('locale')).get('install') + '\033[0m\n') for package in self.packages: pip(['install', package]) def ask(self): - print('\n\n\033[4;36m' + texts.get(self.config.get('lang')).get('conf') - + '\033[0m\n') + print('\n\n\033[4;36m' + texts.get(self.config.get('locale')) + .get('conf') + '\033[0m\n') self.input('token', empty=False) self.input('postgresql_username', empty=False) self.input('postgresql_password', empty=False) self.input('postgresql_dbname', empty=False) - print('\n\n\033[4;36m' + texts.get(self.config.get('lang')).get('logs') - + '\033[0m\n') + print('\n\n\033[4;36m' + texts.get(self.config.get('locale')) + .get('logs') + '\033[0m\n') self.input('wh_id', empty=True) self.input('wh_token', empty=True) - print('\n\n\033[4;36m' + texts.get(self.config.get('lang')).get('misc') - + '\033[0m\n') + print('\n\n\033[4;36m' + texts.get(self.config.get('locale')) + .get('misc') + '\033[0m\n') self.input('activity', empty=True) @@ -84,11 +83,11 @@ class Config: and not key.startswith('wh_'): value = f"'{value}'" if type(value) is str else value file.write(f"{key} = {value}\n") - print('\n\n\033[4;36m' + texts.get(self.config.get('lang')).get('end') - + '\033[0m\n') + print('\n\n\033[4;36m' + texts.get(self.config.get('locale')) + .get('end') + '\033[0m\n') def clean(self): print('\n\n\033[4;36m' - + texts.get(self.config.get('lang')).get('clean') + + texts.get(self.config.get('locale')).get('clean') + '\033[0m\n') shutil.rmtree('first_run') diff --git a/first_run/langs.py b/first_run/langs.py index 731084c..1792e71 100644 --- a/first_run/langs.py +++ b/first_run/langs.py @@ -53,7 +53,7 @@ texts = { }, 'multiple': { - 'lang': "Veuillez choisir une langue | Please choose a language " + 'locale': "Veuillez choisir une langue | Please choose a language " "[fr/en]", 'not_empty': "Cette valeur ne doit pas ĂȘtre vide |" " This value must not be empty" diff --git a/launcher.py b/launcher.py index 9a9de54..b425a74 100644 --- a/launcher.py +++ b/launcher.py @@ -3,17 +3,17 @@ import contextlib import logging import socket import sys -import git -import requests import click +import git +import requests from bot import TuxBot from cogs.utils.db import Table try: import config - from cogs.utils.lang import gettext + from cogs.utils.lang import Texts except ModuleNotFoundError: import first_run @@ -48,15 +48,16 @@ def run_bot(unload: list = []): loop = asyncio.get_event_loop() log = logging.getLogger() - print(gettext('Stating...')) + print(Texts().get('Stating...')) try: pool = loop.run_until_complete( Table.create_pool(config.postgresql, command_timeout=60) ) except socket.gaierror as e: - click.echo(gettext('Could not set up PostgreSQL...'), file=sys.stderr) - log.exception(gettext('Could not set up PostgreSQL...')) + click.echo(Texts().get("Could not set up PostgreSQL..."), + file=sys.stderr) + log.exception(Texts().get("Could not set up PostgreSQL...")) return bot = TuxBot(unload) @@ -65,8 +66,10 @@ def run_bot(unload: list = []): @click.command() -@click.option('-d', '--unload', multiple=True, type=str, help=gettext('Launch without loading the module')) -@click.option('-u', '--update', help=gettext('Search for update'), is_flag=True) +@click.option('-d', '--unload', multiple=True, type=str, + help=Texts().get("Launch without loading the module")) +@click.option('-u', '--update', help=Texts().get("Search for update"), + is_flag=True) def main(**kwargs): if kwargs.get('update'): _update() @@ -75,28 +78,31 @@ def main(**kwargs): run_bot(kwargs.get('unload')) -@click.option('-d', '--update', help=gettext('Search for update'), is_flag=True) +@click.option('-d', '--update', help=Texts().get("Search for update"), + is_flag=True) def _update(): - print(gettext('Checking for update...')) + print(Texts().get("Checking for update...")) local = git.Repo(search_parent_directories=True) current = local.head.object.hexsha - origin = requests.get('https://git.gnous.eu/api/v1/repos/gnouseu/tuxbot-bot/branches/rewrite') + gitea = 'https://git.gnous.eu/api/v1/' + origin = requests.get(gitea + 'repos/gnouseu/tuxbot-bot/branches/rewrite') last = origin.json().get('commit').get('id') if current != last: - print(gettext('A new version is available !')) + print(Texts().get("A new version is available !")) check = None while check not in ['', 'y', 'n', 'o']: - check = input(gettext('Update ? [Y/n] ')).lower().strip() + check = input(Texts().get("Update ? [Y/n] ")).lower().strip() print(check) if check in ['y', '', 'o']: - print(gettext('Downloading...')) + print(Texts().get("Downloading...")) - origin = git.Repo(search_parent_directories=True).remotes['origin'] + origin = git.Repo(search_parent_directories=True) \ + .remotes['origin'] origin.pull() with setup_logging(): @@ -105,7 +111,7 @@ def _update(): with setup_logging(): run_bot() else: - print(gettext('Tuxbot is up to date') + '\n') + print(Texts().get("Tuxbot is up to date") + '\n') with setup_logging(): run_bot() diff --git a/locales/en/LC_MESSAGES/admin.mo b/locales/en/LC_MESSAGES/admin.mo new file mode 100644 index 0000000..e56e9c9 Binary files /dev/null and b/locales/en/LC_MESSAGES/admin.mo differ diff --git a/locales/en/LC_MESSAGES/admin.po b/locales/en/LC_MESSAGES/admin.po new file mode 100644 index 0000000..e824822 --- /dev/null +++ b/locales/en/LC_MESSAGES/admin.po @@ -0,0 +1,25 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2019-09-08 19:04+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" + + +msgid "Please enter a reason" +msgstr "" + +msgid "Unable to ban this user" +msgstr "" + +msgid "Unable to find the user..." +msgstr "" \ No newline at end of file diff --git a/locales/fr/LC_MESSAGES/admin.mo b/locales/fr/LC_MESSAGES/admin.mo new file mode 100644 index 0000000..13bb393 Binary files /dev/null and b/locales/fr/LC_MESSAGES/admin.mo differ diff --git a/locales/fr/LC_MESSAGES/admin.po b/locales/fr/LC_MESSAGES/admin.po new file mode 100644 index 0000000..e6eeaca --- /dev/null +++ b/locales/fr/LC_MESSAGES/admin.po @@ -0,0 +1,25 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2019-09-08 19:04+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" + + +msgid "Please enter a reason" +msgstr "Merci d'entrer une raison" + +msgid "Unable to ban this user" +msgstr "Impossible de bannir cet utilisateur" + +msgid "Unable to find the user..." +msgstr "Impossibe de trouver l'utilisateur..." \ No newline at end of file diff --git a/prefixes.json b/prefixes.json index 6bd46e1..e046253 100644 --- a/prefixes.json +++ b/prefixes.json @@ -1,5 +1,5 @@ { "280805240977227776": [ - "$", "b." + "b." ] } \ No newline at end of file