diff --git a/README b/README new file mode 100644 index 0000000..23ef5a9 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +TuxBot, un bot discord écrit en Python. +Ici ce trouve le code source du bot provenant du serveur Discord [Aide GNU/Linux-Fr"](https://discord.gg/79943dJ "Rejoindre le serveur"), il à été créé spécialement pour ce discord, si vous souhaitez l'utiliser il vous faudra modifier ``params.json`` et ``cogs/utils/checks.py`` ;) + +### Pré-requis + +Il vous faut : + +- Un ordinateur sous **GNU/Linux** avec une connexion à internet; +- Python3.5 ou + ; +- Installer ``requirements.txt`` (avec ``pip install -r requirements.txt`` par ex) + +### Installation + +Une fois les pré-requis installés et ``params.json`` édité, placez vous dans le repertoire de tuxbot et lancez ``bot.py`` avec python3 (ex: ``python3 bot.py``) + +## Démarrage + +Placez vous dans le repertoire de tuxbot et exécutez ``bot.py`` avec python3 (ex: ``python3 bot.py``) + +## Fabriqué avec +* [PyCharm](https://www.jetbrains.com/pycharm/) - Editeur de texte payant :3 +* [discord.py](https://github.com/Rapptz/discord.py) - API Python pour discord + +## Versions +Liste des versions : [Cliquer pour afficher](https://github.com/outout14/tuxbot-bot/tags) + +## Auteurs +* **Maël** _alias_ [@outout14](https://github.com/outout14) +* **Romain** _alias_ [Romain le malchanceux](https://github.com/Rom194) + +## License + +Ce projet est sous licence ``Creative Commons BY-NC-SA 4.0`` - voir le fichier [LICENSE.md](LICENSE.md) pour plus d'informations + + + +## Support on Beerpay +Hey dude! Help me out for a couple of :beers:! + diff --git a/bot.py b/bot.py index 7121d2c..5458874 100755 --- a/bot.py +++ b/bot.py @@ -1,149 +1,120 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -__author__ = "Maël / Outout" +__author__ = ["Romain", "Maël / Outout"] __licence__ = "WTFPL Licence 2.0" from discord.ext import commands import discord from cogs.utils import checks -import datetime, re -import json, asyncio + +import datetime +import json import copy -import logging -from logging.handlers import RotatingFileHandler import traceback import sys -from collections import Counter +import os +import aiohttp -description = """ -Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) -""" +import config +import cogs.utils.cli_colors as colors l_extensions = [ - 'cogs.basics', - #'cogs.test', - 'cogs.admin', - 'cogs.funs', - 'cogs.utility', - 'cogs.search', - 'cogs.ci' + 'cogs.admin', + # 'cogs.afk', + 'cogs.basics', + 'cogs.ci', + 'cogs.cog_manager', + 'cogs.filter_messages', + 'cogs.funs', + 'cogs.passport', + 'cogs.role', + 'cogs.search', + 'cogs.send_logs', + 'cogs.sondage', + 'cogs.utility' ] -# DISCORD LOGGER # -discord_logger = logging.getLogger('discord') -discord_logger.setLevel(logging.CRITICAL) -log = logging.getLogger() -log.setLevel(logging.INFO) -handler = logging.FileHandler(filename='logs/discord.log', encoding='utf-8', mode='w') -log.addHandler(handler) - help_attrs = dict(hidden=True, in_help=True, name="DONOTUSE") -# CREDENTIALS # -try: - def load_credentials(): - with open('params.json') as f: - return json.load(f) -except: - print("Le fichier de paramètre est introuvable, veuillez le créer et le configurer.") +class TuxBot(commands.Bot): + def __init__ (self): + self.config = config + super().__init__(command_prefix=self.config.prefix[0], + description=self.config.description, + pm_help=None, + help_attrs=help_attrs) -credentials = load_credentials() -prefix = credentials.get("prefix", ["."]) -bot = commands.Bot(command_prefix=prefix, description=description, pm_help=None, help_attrs=help_attrs) + self.client_id = self.config.client_id + self.session = aiohttp.ClientSession(loop=self.loop) + self._events = [] -@bot.event -async def on_command_error(error, ctx): - if isinstance(error, commands.NoPrivateMessage): - await bot.send_message(ctx.message.author, 'Cette commande ne peut pas être utilisée en message privée.') - elif isinstance(error, commands.DisabledCommand): - await bot.send_message(ctx.message.author, 'Désoler mais cette commande est désactivé, elle ne peut donc pas être utilisée.') - elif isinstance(error, commands.CommandInvokeError): - print('In {0.command.qualified_name}:'.format(ctx), file=sys.stderr) - traceback.print_tb(error.original.__traceback__) - print('{0.__class__.__name__}: {0}'.format(error.original), file=sys.stderr) -@bot.event -async def on_ready(): - print('---------------------') - print('CONNECTÉ :') - print(""" Nom d\'utilisateur : {0.name}#{0.discriminator} - ID : {0.id}""".format(bot.user)) - print('Merci d\'utiliser TuxBot') - print('---------------------') - await bot.change_presence(game=discord.Game(name=credentials.get("game", "Manger des pommes | .help")), status=discord.Status("dnd"), afk=False) - if bot.client_id == None: - bot.client_id = bot.user.id - if not hasattr(bot, 'uptime'): - bot.uptime = datetime.datetime.utcnow() + self.add_command(self.do) -@bot.event -async def on_resumed(): - print('resumed...') + for extension in l_extensions: + try: + self.load_extension(extension) + print(f"{colors.text_colors.GREEN}\"{extension}\" chargé !{colors.ENDC}") + except Exception as e: + print(f"{colors.text_colors.RED}Impossible de charger l'extension {extension}\n{type(e).__name__}: {e}{colors.ENDC}", file=sys.stderr) -@bot.event -async def on_message(message): - if message.author.bot: - return + async def on_command_error(self, ctx, error): + if isinstance(error, commands.NoPrivateMessage): + await ctx.author.send('Cette commande ne peut pas être utilisee en message privee.') + elif isinstance(error, commands.DisabledCommand): + await ctx.author.send('Desoler mais cette commande est desactive, elle ne peut donc pas être utilisée.') + elif isinstance(error, commands.CommandInvokeError): + print(f'In {ctx.command.qualified_name}:', file=sys.stderr) + traceback.print_tb(error.original.__traceback__) + print(f'{error.original.__class__.__name__}: {error.original}', file=sys.stderr) - try: - await bot.process_commands(message) - except Exception as e: - print('Erreur rencontré : \n {}: {} \n \n'.format(type(e).__name__, e)) + async def on_ready(self): + if not hasattr(self, 'uptime'): + self.uptime = datetime.datetime.utcnow() -@bot.command(pass_context=True, hidden=True) -@checks.is_owner() -async def do(ctx, times : int, *, command): - """Repeats a command a specified number of times.""" - msg = copy.copy(ctx.message) - msg.content = command - for i in range(times): - await bot.process_commands(msg) + log_channel_id = self.get_channel(int(self.config.log_channel_id)) -@bot.command(pass_context=True) -async def github(ctx): - """Pour voir mon code""" - text = "How tu veux voir mon repos Github pour me disséquer ? Pas de soucis ! Je suis un Bot, je ne ressens pas la douleur !\n https://github.com/outout14/tuxbot-bot" - em = discord.Embed(title='Repos TuxBot-Bot', description=text, colour=0xE9D460) - em.set_author(name='Outout', icon_url="https://avatars0.githubusercontent.com/u/14958554?v=3&s=400") - await ctx.send(embed=em) + print('\n\n---------------------') + print('CONNECTÉ :') + print(f'Nom d\'utilisateur: {self.user} {colors.text_style.DIM}(ID: {self.user.id}){colors.ENDC}') + print(f'Channel de log: {log_channel_id} {colors.text_style.DIM}(ID: {log_channel_id.id}){colors.ENDC}') + print(f'Prefix: {self.config.prefix[0]}') + print('Merci d\'utiliser TuxBot') + print('---------------------\n\n') -async def on_command_error(self, ctx, error): - if isinstance(error, commands.NoPrivateMessage): - await ctx.author.send('Cette commande ne peut pas être utilisée en message privée.') - elif isinstance(error, commands.DisabledCommand): - await ctx.author.send('Désoler mais cette commande est désactivé, elle ne peut donc pas être utilisée.') - elif isinstance(error, commands.CommandInvokeError): - print(f'In {ctx.command.qualified_name}:', file=sys.stderr) - traceback.print_tb(error.original.__traceback__) - print(f'{error.original.__class__.__name__}: {error.original}', file=sys.stderr) + await self.change_presence(status=discord.Status.dnd, activity=discord.Game(name=self.config.game)) + + async def on_resumed(): + print('resumed...') + + async def on_message(self, message): + if message.author.bot: + return + + try: + await self.process_commands(message) + except Exception as e: + print(f'{colors.text_colors.RED}Erreur rencontré : \n {type(e).__name__}: {e}{colors.ENDC} \n \n') + + def run(self): + super().run(self.config.token, reconnect=True) + + @checks.has_permissions(administrator=True) + @commands.command(pass_context=True, hidden=True) + async def do(ctx, times: int, *, command): + """Repeats a command a specified number of times.""" + msg = copy.copy(ctx.message) + msg.content = command + for i in range(times): + await bot.process_commands(msg) ## LOAD ## if __name__ == '__main__': - try: - credentials = load_credentials() - token = credentials.get('token') - if token is None: - print("/!\ Le token est manquant dans le fichier params.json...") - bot.client_id = credentials.get('client_id', None) - except: - print("Impossible de démarer TuxBot dû à une erreur inconnue.") - - - for extension in l_extensions: - try: - bot.load_extension(extension) - except Exception as e: - print('Impossible de charger l\'extension {}\n{}: {}'.format(extension, type(e).__name__, e)) - - try: - bot.run(token) - except: - print("Une erreur est survenue avec votre Token, merci de le vérifier.") - - handlers = log.handlers[:] - for hdlr in handlers: - hdlr.close() - log.removeHandler(hdlr) + if os.path.exists('config.py') is not True: + print(f"{colors.text_colors.RED}Veuillez créer le fichier config.py{colors.ENDC}"); exit() + + tuxbot = TuxBot() + tuxbot.run() diff --git a/cogs/__pycache__/admin.cpython-35.pyc b/cogs/__pycache__/admin.cpython-35.pyc new file mode 100644 index 0000000..a59a8e0 Binary files /dev/null and b/cogs/__pycache__/admin.cpython-35.pyc differ diff --git a/cogs/__pycache__/admin.cpython-36.pyc b/cogs/__pycache__/admin.cpython-36.pyc new file mode 100644 index 0000000..1d7be72 Binary files /dev/null and b/cogs/__pycache__/admin.cpython-36.pyc differ diff --git a/cogs/__pycache__/admin.cpython-37.pyc b/cogs/__pycache__/admin.cpython-37.pyc new file mode 100644 index 0000000..91662d1 Binary files /dev/null and b/cogs/__pycache__/admin.cpython-37.pyc differ diff --git a/cogs/__pycache__/basics.cpython-35.pyc b/cogs/__pycache__/basics.cpython-35.pyc new file mode 100644 index 0000000..af1b71e Binary files /dev/null and b/cogs/__pycache__/basics.cpython-35.pyc differ diff --git a/cogs/__pycache__/basics.cpython-36.pyc b/cogs/__pycache__/basics.cpython-36.pyc new file mode 100644 index 0000000..3442f97 Binary files /dev/null and b/cogs/__pycache__/basics.cpython-36.pyc differ diff --git a/cogs/__pycache__/basics.cpython-37.pyc b/cogs/__pycache__/basics.cpython-37.pyc new file mode 100644 index 0000000..6acd4cb Binary files /dev/null and b/cogs/__pycache__/basics.cpython-37.pyc differ diff --git a/cogs/__pycache__/ci.cpython-36.pyc b/cogs/__pycache__/ci.cpython-36.pyc new file mode 100644 index 0000000..053c626 Binary files /dev/null and b/cogs/__pycache__/ci.cpython-36.pyc differ diff --git a/cogs/__pycache__/ci.cpython-37.pyc b/cogs/__pycache__/ci.cpython-37.pyc new file mode 100644 index 0000000..d27cc4c Binary files /dev/null and b/cogs/__pycache__/ci.cpython-37.pyc differ diff --git a/cogs/__pycache__/cog_manager.cpython-36.pyc b/cogs/__pycache__/cog_manager.cpython-36.pyc new file mode 100644 index 0000000..92abd70 Binary files /dev/null and b/cogs/__pycache__/cog_manager.cpython-36.pyc differ diff --git a/cogs/__pycache__/cog_manager.cpython-37.pyc b/cogs/__pycache__/cog_manager.cpython-37.pyc new file mode 100644 index 0000000..32b94ed Binary files /dev/null and b/cogs/__pycache__/cog_manager.cpython-37.pyc differ diff --git a/cogs/__pycache__/filter_messages.cpython-35.pyc b/cogs/__pycache__/filter_messages.cpython-35.pyc new file mode 100644 index 0000000..f4411ad Binary files /dev/null and b/cogs/__pycache__/filter_messages.cpython-35.pyc differ diff --git a/cogs/__pycache__/filter_messages.cpython-36.pyc b/cogs/__pycache__/filter_messages.cpython-36.pyc new file mode 100644 index 0000000..fe466b5 Binary files /dev/null and b/cogs/__pycache__/filter_messages.cpython-36.pyc differ diff --git a/cogs/__pycache__/filter_messages.cpython-37.pyc b/cogs/__pycache__/filter_messages.cpython-37.pyc new file mode 100644 index 0000000..af56896 Binary files /dev/null and b/cogs/__pycache__/filter_messages.cpython-37.pyc differ diff --git a/cogs/__pycache__/funs.cpython-36.pyc b/cogs/__pycache__/funs.cpython-36.pyc new file mode 100644 index 0000000..75013bf Binary files /dev/null and b/cogs/__pycache__/funs.cpython-36.pyc differ diff --git a/cogs/__pycache__/funs.cpython-37.pyc b/cogs/__pycache__/funs.cpython-37.pyc new file mode 100644 index 0000000..7346fb6 Binary files /dev/null and b/cogs/__pycache__/funs.cpython-37.pyc differ diff --git a/cogs/__pycache__/passport.cpython-36.pyc b/cogs/__pycache__/passport.cpython-36.pyc new file mode 100644 index 0000000..4ce245f Binary files /dev/null and b/cogs/__pycache__/passport.cpython-36.pyc differ diff --git a/cogs/__pycache__/passport.cpython-37.pyc b/cogs/__pycache__/passport.cpython-37.pyc new file mode 100644 index 0000000..1b7bf84 Binary files /dev/null and b/cogs/__pycache__/passport.cpython-37.pyc differ diff --git a/cogs/__pycache__/role.cpython-35.pyc b/cogs/__pycache__/role.cpython-35.pyc new file mode 100644 index 0000000..ca98279 Binary files /dev/null and b/cogs/__pycache__/role.cpython-35.pyc differ diff --git a/cogs/__pycache__/role.cpython-36.pyc b/cogs/__pycache__/role.cpython-36.pyc new file mode 100644 index 0000000..14584a2 Binary files /dev/null and b/cogs/__pycache__/role.cpython-36.pyc differ diff --git a/cogs/__pycache__/role.cpython-37.pyc b/cogs/__pycache__/role.cpython-37.pyc new file mode 100644 index 0000000..0fad80d Binary files /dev/null and b/cogs/__pycache__/role.cpython-37.pyc differ diff --git a/cogs/__pycache__/search.cpython-35.pyc b/cogs/__pycache__/search.cpython-35.pyc new file mode 100644 index 0000000..e87d2f0 Binary files /dev/null and b/cogs/__pycache__/search.cpython-35.pyc differ diff --git a/cogs/__pycache__/search.cpython-36.pyc b/cogs/__pycache__/search.cpython-36.pyc new file mode 100644 index 0000000..4d282e9 Binary files /dev/null and b/cogs/__pycache__/search.cpython-36.pyc differ diff --git a/cogs/__pycache__/search.cpython-37.pyc b/cogs/__pycache__/search.cpython-37.pyc new file mode 100644 index 0000000..b018e33 Binary files /dev/null and b/cogs/__pycache__/search.cpython-37.pyc differ diff --git a/cogs/__pycache__/send_logs.cpython-36.pyc b/cogs/__pycache__/send_logs.cpython-36.pyc new file mode 100644 index 0000000..3a5b371 Binary files /dev/null and b/cogs/__pycache__/send_logs.cpython-36.pyc differ diff --git a/cogs/__pycache__/send_logs.cpython-37.pyc b/cogs/__pycache__/send_logs.cpython-37.pyc new file mode 100644 index 0000000..d8f1bfc Binary files /dev/null and b/cogs/__pycache__/send_logs.cpython-37.pyc differ diff --git a/cogs/__pycache__/sondage.cpython-35.pyc b/cogs/__pycache__/sondage.cpython-35.pyc new file mode 100644 index 0000000..10130da Binary files /dev/null and b/cogs/__pycache__/sondage.cpython-35.pyc differ diff --git a/cogs/__pycache__/sondage.cpython-36.pyc b/cogs/__pycache__/sondage.cpython-36.pyc new file mode 100644 index 0000000..64531ab Binary files /dev/null and b/cogs/__pycache__/sondage.cpython-36.pyc differ diff --git a/cogs/__pycache__/sondage.cpython-37.pyc b/cogs/__pycache__/sondage.cpython-37.pyc new file mode 100644 index 0000000..6fa0781 Binary files /dev/null and b/cogs/__pycache__/sondage.cpython-37.pyc differ diff --git a/cogs/__pycache__/utility.cpython-36.pyc b/cogs/__pycache__/utility.cpython-36.pyc new file mode 100644 index 0000000..0512a89 Binary files /dev/null and b/cogs/__pycache__/utility.cpython-36.pyc differ diff --git a/cogs/__pycache__/utility.cpython-37.pyc b/cogs/__pycache__/utility.cpython-37.pyc new file mode 100644 index 0000000..eb55289 Binary files /dev/null and b/cogs/__pycache__/utility.cpython-37.pyc differ diff --git a/cogs/admin.py b/cogs/admin.py index 790bbf1..91b6e7c 100755 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -1,105 +1,336 @@ from discord.ext import commands +import discord import aiohttp import asyncio import time -import discord from .utils import checks +from .utils.checks import get_user + +import json +import random + +import datetime + import requests + class Admin: - """Commandes secrètes d'administration.""" + """Commandes secrètes d'administration.""" - def __init__(self, bot): - self.bot = bot - @checks.is_owner() - @commands.command(name='unload_cog', hidden=True) - async def _unload(self, ctx, module: str): - """Unloads a module.""" - try: - self.bot.unload_extension("cogs."+module) - except Exception as e: - await ctx.send('\N{PISTOL}') - await ctx.send('{}: {}'.format(type(e).__name__, e)) - else: - await ctx.send('\N{OK HAND SIGN}') - print("cog : " + str(module) + " activé") + def __init__(self, bot): + self.bot = bot - """--------------------------------------------------------------------------------------------------------------------------""" + """--------------------------------------------------------------------------------------------------------------------------""" - @checks.is_owner() - @commands.command(name='load_cog', hidden=True) - async def _load(self, ctx, module: str): - """Unloads a module.""" - try: - self.bot.load_extension("cogs."+module) - except Exception as e: - await ctx.send('\N{PISTOL}') - await ctx.send('{}: {}'.format(type(e).__name__, e)) - else: - await ctx.send('\N{OK HAND SIGN}') - print("cog : " + str(module) + " desactivé") + @checks.has_permissions(administrator=True) + @commands.command(pass_context=True) + async def ban(self, ctx, user, *, reason=""): + """Ban user""" + user = get_user(ctx.message, user) + if user: + try: + await user.ban(reason=reason) + return_msg = "`{}` a été banni\n".format(user.mention) + if reason: + return_msg += "raison : `{}`".format(reason) + return_msg += "." + await ctx.send(return_msg) + except discord.Forbidden: + await ctx.send('Impossible de bannir cet user, probleme de permission.') + else: + return await ctx.send('Impossible de trouver l\'user.') - """--------------------------------------------------------------------------------------------------------------------------""" + """--------------------------------------------------------------------------------------------------------------------------""" - @checks.is_owner() - @commands.command(name='reload_cog', hidden=True) - async def _reload(self, ctx, *, module: str): - """Reloads a module.""" - try: - self.bot.unload_extension("cogs."+module) - self.bot.load_extension("cogs."+module) - await ctx.send("Je te reload ca") - except Exception as e: #TODO : A virer dans l'event on_error - await ctx.send(':( Erreur :') - await ctx.send('{}: {}'.format(type(e).__name__, e)) - else: - await ctx.send('\N{OK HAND SIGN}') - print("cog : " + str(module) + " relancé") + @checks.has_permissions(administrator=True) + @commands.command(pass_context=True) + async def kick(self, ctx, user, *, reason=""): + """Kick a user""" + user = get_user(ctx.message, user) + if user: + try: + await user.kick(reason=reason) + return_msg = "`{}` a été kické\n".format(user.mention) + if reason: + return_msg += "raison : `{}`".format(reason) + return_msg += "." + await ctx.send(return_msg) + except discord.Forbidden: + await ctx.send('Impossible de kicker cet user, probleme de permission.') + else: + return await ctx.send('Impossible de trouver l\'user.') - """--------------------------------------------------------------------------------------------------------------------------""" + """--------------------------------------------------------------------------------------------------------------------------""" - @checks.is_owner() - @commands.command(name='clear', pass_context=True, hidden=True) - async def _clear(self, ctx, number: int): + @checks.has_permissions(administrator=True) + @commands.command(name='clear', pass_context=True) + async def _clear(self, ctx, number: int, silent: str = True): + """Clear of message(s)""" + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + if number < 1000: + async for message in ctx.message.channel.history(limit=number): + try: + await message.delete() + except Exception as e: #TODO : A virer dans l'event on_error + if silent is not True: + await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) + if silent is not True: + await ctx.send("Hop voila j'ai viré des messages! Hello World") + print(str(number)+" messages ont été supprimés") + else: + await ctx.send('Trop de messages, entre un nombre < 1000') - await ctx.message.delete() - if number < 1000: - async for message in ctx.message.channel.history(limit=number): - try: - await message.delete() - except Exception as e: #TODO : A virer dans l'event on_error - await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) - await ctx.send("Hop voila j'ai viré des messages! Hello World") - print(str(number)+" messages ont été supprimés") - else: - await ctx.send('Trop de messages, entre un nombre < 1000') + """--------------------------------------------------------------------------------------------------------------------------""" - """--------------------------------------------------------------------------------------------------------------------------""" + @checks.has_permissions(administrator=True) + @commands.command(name='say', pass_context=True) + async def _say(self, ctx, *, tosay:str): + """Say a message in the current channel""" + try: + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + await ctx.send(tosay) + except Exception as e: #TODO : A virer dans l'event on_error + await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) - @checks.is_owner() - @commands.command(name='say', pass_context=True, hidden=True) - async def _say(self, ctx, *direuh:str): - try: - dire = ctx.message.content.split("say ") - await ctx.message.delete() - await ctx.send(dire[1]) - except Exception as e: #TODO : A virer dans l'event on_error - await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) + """--------------------------------------------------------------------------------------------------------------------------""" - """--------------------------------------------------------------------------------------------------------------------------""" + @checks.has_permissions(administrator=True) + @commands.command(name='sayto', pass_context=True) + async def _sayto(self, ctx, id:int, *, tosay:str): + """Say a message in the channel""" + try: + chan = self.bot.get_channel(id) + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + try: + await chan.send(tosay) + except Exception as e: + print("Impossible d'envoyer le message dans " + str(id)) + except Exception as e: #TODO : A virer dans l'event on_error + await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) - @checks.is_owner() - @commands.command(pass_context=True, hidden=True) - async def _clearterm(self, ctx): - clear = "\n" * 100 - print(clear) - await ctx.send(":ok_hand: It's good") + """--------------------------------------------------------------------------------------------------------------------------""" - """--------------------------------------------------------------------------------------------------------------------------""" + @checks.has_permissions(administrator=True) + @commands.command(name='sayto_dm', pass_context=True) + async def _sayto_dm(self, ctx, id:int, *, tosay:str): + """Say a message to the user""" + try: + user = self.bot.get_user(id) + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + try: + await user.send(tosay) + except Exception as e: + print("Impossible d'envoyer le message dans " + str(id)) + except Exception as e: #TODO : A virer dans l'event on_error + await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) + """--------------------------------------------------------------------------------------------------------------------------""" + + @checks.has_permissions(administrator=True) + @commands.command(name='editsay', pass_context=True) + async def _editsay(self, ctx, id:int, *, new_content:str): + """Edit a bot's message""" + try: + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + toedit = await ctx.channel.get_message(id) + except discord.errors.NotFound: + await ctx.send("Impossible de trouver le message avec l'id `{}` sur ce salon".format(id)) + return + try: + await toedit.edit(content=str(new_content)) + except discord.errors.Forbidden: + await ctx.send("J'ai po les perms pour editer mes messages :(") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @checks.has_permissions(administrator=True) + @commands.command(name='addreaction', pass_context=True) + async def _addreaction(self, ctx, id:int, reaction:str): + """Add reactions to a message""" + try: + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + toadd = await ctx.channel.get_message(id) + except discord.errors.NotFound: + await ctx.send("Impossible de trouver le message avec l'id `{}` sur ce salon".format(id)) + return + try: + await toadd.add_reaction(reaction) + except discord.errors.Forbidden: + await ctx.send("J'ai po les perms pour ajouter des réactions :(") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @checks.has_permissions(administrator=True) + @commands.command(name='delete', pass_context=True) + async def _delete(self, ctx, id:int): + """Delete message in current channel""" + try: + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + todelete = await ctx.channel.get_message(id) + except discord.errors.NotFound: + await ctx.send("Impossible de trouver le message avec l'id `{}` sur ce salon".format(id)) + return + try: + await todelete.delete() + except discord.errors.Forbidden: + await ctx.send("J'ai po les perms pour supprimer des messages :(") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @checks.has_permissions(administrator=True) + @commands.command(name='deletefrom', pass_context=True) + async def _deletefrom(self, ctx, chan_id:int, *, message_id:str): + """Delete message in channel""" + try: + chan = self.bot.get_channel(chan_id) + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + todelete = await chan.get_message(message_id) + except discord.errors.NotFound: + await ctx.send("Impossible de trouver le message avec l'id `{}` sur le salon".format(id)) + return + try: + await todelete.delete() + except discord.errors.Forbidden: + await ctx.send("J'ai po les perms pour supprimer le message :(") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @checks.has_permissions(administrator=True) + @commands.command(name='embed', pass_context=True) + async def _embed(self, ctx, *, msg: str = "help"): + """Send an embed""" + if msg != "help": + ptext = title = description = image = thumbnail = color = footer = author = None + timestamp = discord.Embed.Empty + embed_values = msg.split('|') + for i in embed_values: + if i.strip().lower().startswith('ptext='): + ptext = i.strip()[6:].strip() + elif i.strip().lower().startswith('title='): + title = i.strip()[6:].strip() + elif i.strip().lower().startswith('description='): + description = i.strip()[12:].strip() + elif i.strip().lower().startswith('desc='): + description = i.strip()[5:].strip() + elif i.strip().lower().startswith('image='): + image = i.strip()[6:].strip() + elif i.strip().lower().startswith('thumbnail='): + thumbnail = i.strip()[10:].strip() + elif i.strip().lower().startswith('colour='): + color = i.strip()[7:].strip() + elif i.strip().lower().startswith('color='): + color = i.strip()[6:].strip() + elif i.strip().lower().startswith('footer='): + footer = i.strip()[7:].strip() + elif i.strip().lower().startswith('author='): + author = i.strip()[7:].strip() + elif i.strip().lower().startswith('timestamp'): + timestamp = ctx.message.created_at + else: + if description is None and not i.strip().lower().startswith('field='): + description = i.strip() + + if color: + if color.startswith('#'): + color = color[1:] + if not color.startswith('0x'): + color = '0x' + color + + if ptext is title is description is image is thumbnail is color is footer is author is None and 'field=' not in msg: + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + return await ctx.send(content=None, + embed=discord.Embed(description=msg)) + + if color: + em = discord.Embed(timestamp=timestamp, title=title, description=description, color=int(color, 16)) + else: + em = discord.Embed(timestamp=timestamp, title=title, description=description) + for i in embed_values: + if i.strip().lower().startswith('field='): + field_inline = True + field = i.strip().lstrip('field=') + field_name, field_value = field.split('value=') + if 'inline=' in field_value: + field_value, field_inline = field_value.split('inline=') + if 'false' in field_inline.lower() or 'no' in field_inline.lower(): + field_inline = False + field_name = field_name.strip().lstrip('name=') + em.add_field(name=field_name, value=field_value.strip(), inline=field_inline) + if author: + if 'icon=' in author: + text, icon = author.split('icon=') + if 'url=' in icon: + em.set_author(name=text.strip()[5:], icon_url=icon.split('url=')[0].strip(), url=icon.split('url=')[1].strip()) + else: + em.set_author(name=text.strip()[5:], icon_url=icon) + else: + if 'url=' in author: + em.set_author(name=author.split('url=')[0].strip()[5:], url=author.split('url=')[1].strip()) + else: + em.set_author(name=author) + + if image: + em.set_image(url=image) + if thumbnail: + em.set_thumbnail(url=thumbnail) + if footer: + if 'icon=' in footer: + text, icon = footer.split('icon=') + em.set_footer(text=text.strip()[5:], icon_url=icon) + else: + em.set_footer(text=footer) + + try: + await ctx.message.delete() + except: + print("Impossible de supprimer le message \"" + str(ctx.message.content) + "\"") + await ctx.send(content=ptext, embed=em) + + else: + embed=discord.Embed(title="Aide sur l'utilisation de la commande .embed:") + embed.add_field(name="Titre:", value="title=", inline=True) + embed.add_field(name="Description:", value="description=", inline=True) + embed.add_field(name="Couleur:", value="color=", inline=True) + embed.add_field(name="Image:", value="image=", inline=True) + embed.add_field(name="Thumbnail:", value="thumbnail=", inline=True) + embed.add_field(name="Auteur:", value="author=", inline=True) + embed.add_field(name="Icon", value="icon=", inline=True) + embed.add_field(name="Footer", value="footer=", inline=True) + embed.set_footer(text="Exemple: .embed title=Un titre | description=Une description | color=3AB35E | field=name=test value=test") + + await ctx.send(embed=embed) + + """--------------------------------------------------------------------------------------------------------------------------""" def setup(bot): - bot.add_cog(Admin(bot)) + bot.add_cog(Admin(bot)) diff --git a/cogs/afk.py b/cogs/afk.py new file mode 100755 index 0000000..cb1151b --- /dev/null +++ b/cogs/afk.py @@ -0,0 +1,78 @@ +from discord.ext import commands +import random + + +class AFK: + """Commandes utilitaires.""" + + def __init__(self, bot): + self.bot = bot + + """---------------------------------------------------------------------""" + + @commands.command(pass_context=True) + async def afk(self, ctx): + + user = ctx.message.author + + try: + await user.edit(nick="[AFK] "+str(user.name)) + author = ctx.message.author + channel = await author.create_dm() + await channel.send("Ton pseudo a prit le prefix `[AFK]` pour " + "monter que tu es absent,") + await channel.send("tu auras juste a mettre un message pour que " + "je signale ton retour parmis nous et que je " + "retire le prefix `[AFK]` de ton pseudo 😉") + + except KeyError: + print('') + author = ctx.message.author + channel = await author.create_dm() + await channel.send("Tu auras juste a mettre un message pour que " + "je signale ton retour parmis nous 😉") + + msgs = ["s'absente de discord quelques instants", + "se casse de son pc", + "va sortir son chien", + "reviens bientôt", + "va nourrir son cochon", + "va manger des cookies", + "va manger de la poutine", + "va faire caca", + "va faire pipi"] + msg = random.choice(msgs) + + await ctx.send("**{}** {}...".format(ctx.message.author.mention, msg)) + + """---------------------------------------------------------------------""" + + +async def on_message(message): + + ni = str(message.author.nick) + + if ni: + ni2 = ni.split(" ") + if "[AFK]" in ni2: + user = message.author + await user.edit(nick=None) + + msgs = ["a réssuscité", + "est de nouveau parmi nous", + "a fini de faire caca", + "a fini d'uriner", + "n'est plus mort", + "est de nouveau sur son PC", + "a fini de manger sa poutine", + "a fini de danser", + "s'est réveillé", + "est de retour dans ce monde cruel"] + msg = random.choice(msgs) + + await message.channel.send("**{}** {} !".format( + message.author.mention, msg)) + + +def setup(bot): + bot.add_cog(AFK(bot)) diff --git a/cogs/basics.py b/cogs/basics.py index 60831ff..066b6aa 100755 --- a/cogs/basics.py +++ b/cogs/basics.py @@ -1,56 +1,67 @@ from discord.ext import commands -from random import choice, shuffle -import aiohttp -import asyncio -import time import discord -import platform, socket -import os +import platform +import socket -import wikipedia, bs4 - -class General: - """Commandes générales.""" - - def __init__(self, bot): - self.bot = bot - - @commands.command() - async def ping(self, ctx): - t1 = time.perf_counter() - await ctx.trigger_typing() - t2 = time.perf_counter() - - result = round((t2-t1)*1000) - - if int(result) >=200: - em = discord.Embed(title="Ping : " + str(result) + "ms", description="... c'est quoi ce ping !", colour=0xFF1111) - await ctx.send(embed=em) - elif int(result) > 100 and int(result) < 200: - em = discord.Embed(title="Ping : " + str(result) + "ms", description="Ca va, ça peut aller, mais j'ai l'impression d'avoir 40 ans !", colour=0xFFA500) - await ctx.send(embed=em) - elif int(result) <= 100: - em = discord.Embed(title="Ping : " + str(result) + "ms", description="Wow c'te vitesse de réaction, je m'épate moi-même !",colour=0x11FF11) - await ctx.send(embed=em) - - ##INFO## - @commands.command() - async def info(self, ctx): - """Affiches des informations sur le bot""" - text = open('texts/info.md').read() - os_info = str(platform.system()) + " / " + str(platform.release()) - em = discord.Embed(title='Informations sur TuxBot', description=text.format(os_info, platform.python_version(), socket.gethostname(), discord.__version__), colour=0x89C4F9) - em.set_footer(text=os.getcwd() + "/bot.py") - await ctx.send(embed=em) +import subprocess - ## HELP PLZ ## - @commands.command() - async def help(self, ctx): - """Affiches l'aide du bot""" - text = open('texts/help.md').read() - em = discord.Embed(title='Commandes de TuxBot', description=text, colour=0x89C4F9) - await ctx.send(embed=em) +class Basics: + """Commandes générales.""" + + def __init__(self, bot): + self.bot = bot + + @commands.command() + async def ping(self, ctx): + ping_res = str(subprocess.Popen(["/bin/ping", "-c1", "discordapp.com"], stdout=subprocess.PIPE).stdout.read()) + formated_res = [item for item in ping_res.split() if 'time=' in item] + result = str(formated_res[0])[5:] + + if float(result) >= 200: + em = discord.Embed(title="Ping : " + str(result) + "ms", + description="... c'est quoi ce ping !", + colour=0xFF1111) + await ctx.send(embed=em) + elif float(result) > 100 < 200: + em = discord.Embed(title="Ping : " + str(result) + "ms", + description="Ca va, ça peut aller, mais j'ai " + "l'impression d'avoir 40 ans !", + colour=0xFFA500) + await ctx.send(embed=em) + else: + em = discord.Embed(title="Ping : " + str(result) + "ms", + description="Wow c'te vitesse de réaction, " + "je m'épate moi-même !", + colour=0x11FF11) + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command() + async def info(self, ctx): + """Affiches des informations sur le bot""" + text = open('texts/info.md').read() + os_info = str(platform.system()) + " / " + str(platform.release()) + em = discord.Embed(title='Informations sur TuxBot', + description=text.format(os_info, + platform.python_version(), + socket.gethostname(), + discord.__version__), + colour=0x89C4F9) + em.set_footer(text="/home/****/bot.py") + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command() + async def help(self, ctx): + """Affiches l'aide du bot""" + text = open('texts/help.md').read() + em = discord.Embed(title='Commandes de TuxBot', description=text, + colour=0x89C4F9) + await ctx.send(embed=em) + def setup(bot): - bot.add_cog(General(bot)) + bot.add_cog(Basics(bot)) diff --git a/cogs/ci.py b/cogs/ci.py index 3f668ce..e8ce594 100755 --- a/cogs/ci.py +++ b/cogs/ci.py @@ -1,188 +1,249 @@ from discord.ext import commands -from random import choice, shuffle -import aiohttp -import asyncio import discord -import platform, socket -import os -import sqlite3 -import time -import datetime, pytz +from .utils import checks +from .utils import db +from .utils.checks import get_user, check_date -from datetime import date -import calendar +import datetime -#### SQL ##### -conn = sqlite3.connect('tuxbot.db') #Connexion SQL +import pymysql +import requests -cursor = conn.cursor() -cursor.execute(""" -CREATE TABLE IF NOT EXISTS users( - id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, - userid TEXT, - username TEXT, - os TEXT, - config TEXT, - useravatar TEXT, - userbirth TEXT, - pays TEXT, - cidate TEXT, - cibureau TEXT -) -""")# Creation table Utilisateur si premiere fois -conn.commit() class Identity: - """Commandes des cartes d'identité .""" + """Commandes des cartes d'identité .""" - def __init__(self, bot): - self.bot = bot + def __init__(self, bot): + self.bot = bot - @commands.group(name="ci", no_pm=True, pass_context=True) - async def _ci(self, ctx): - """Cartes d'identité""" - if ctx.invoked_subcommand is None: - text = open('texts/ci-info.md').read() - em = discord.Embed(title='Commandes de carte d\'identité de TuxBot', description=text, colour=0x89C4F9) - await ctx.send(embed=em) + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() - @_ci.command(pass_context=True, name="show") - async def ci_test(self, ctx, args : discord.Member): + self.cursor.execute("""SHOW TABLES LIKE 'users'""") + result = self.cursor.fetchone() - def isexist(var): - if not var: - return "Non renseigné." - else: - return var + if not result: + # Creation table Utilisateur si premiere fois + sql = "CREATE TABLE users ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, userid TEXT null, username TEXT null, os TEXT null, config TEXT null, useravatar TEXT null, userbirth TEXT null, pays TEXT null, cidate TEXT null, cibureau TEXT null);" + self.cursor.execute(sql) - cursor.execute("""SELECT userid, username, useravatar, userbirth, cidate, cibureau, os, config, pays, id FROM users WHERE userid=?""",(args.id,)) - result = cursor.fetchone() + @commands.group(name="ci", no_pm=True, pass_context=True) + async def _ci(self, ctx): + """Cartes d'identité""" + + if ctx.invoked_subcommand is None: + text = open('texts/ci-info.md').read() + em = discord.Embed(title='Commandes de carte d\'identité de TuxBot', description=text, colour=0x89C4F9) + await ctx.send(embed=em) - if not result: - await ctx.send(ctx.message.author.mention + "> :x: Désolé mais {} est sans papier !".format(args.mention)) + @_ci.command(pass_context=True, name="show") + async def ci_show(self, ctx, args: str = None): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() - else: - try: - userbirth = result[3].split(" ") - cidate = result[4].split(" ") - embed=discord.Embed(title="Carte d'identité | Communisme Linuxien") - embed.set_author(name=result[1], icon_url=result[2]) - embed.set_thumbnail(url = result[2]) - embed.add_field(name="Nom :", value=result[1], inline=True) - embed.add_field(name="Système d'exploitation :", value=isexist(result[6]), inline=True) - embed.add_field(name="Configuration Système : ", value=isexist(result[7]), inline=True) - embed.add_field(name="Date de naissance : ", value=userbirth[0], inline=True) - embed.add_field(name="Pays : ", value=isexist(result[8]), inline=True) - embed.add_field(name="Profil sur le web : ", value="https://tuxbot.outout.tech/user-{}".format(result[9]), inline=True) - embed.set_footer(text="Enregistré dans le bureau {} le {}.".format(result[5], cidate[0])) - await ctx.send(embed=embed) - except: - await ctx.send(ctx.message.author.mention + "> :x: Désolé mais la carte d'identité de {0} est trop longue de ce fait je ne peux te l'envoyer, essaye de l'aléger, {0} :wink: !".format(args.mention)) + if args == None: + user = get_user(ctx.message, ctx.message.author.name) + else: + user = get_user(ctx.message, args) - @_ci.command(pass_context=True, name="register") - async def ci_register(self, ctx): - cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) - existansw = cursor.fetchone() - if existansw != None: - await ctx.send("Mais tu as déja une carte d'identité ! u_u") - else: - date = datetime.datetime.now() + if user: + self.cursor.execute("""SELECT userid, username, useravatar, userbirth, cidate, cibureau, os, config, pays, id FROM users WHERE userid=%s""",(str(user.id))) + result = self.cursor.fetchone() - nd = str(date.day) - nd += "-" - nd += str(date.month) - nd += "-" - nd += str(date.year) + def isexist(var): + if not var: + return "Non renseigné." + else: + return var - cursor.execute("""INSERT INTO users(userid, username, useravatar, userbirth, cidate, cibureau) VALUES(?, ?, ?, ?, ?, ?)""", (ctx.message.author.id, ctx.message.author.name, ctx.message.author.avatar_url, ctx.message.author.created_at, nd, str(ctx.message.guild.name))) - conn.commit() - await ctx.send(":clap: Bievenue à toi {} dans le communisme {} ! Fait ``.ci`` pour plus d'informations !".format(ctx.message.author.name, str(ctx.message.guild.name))) + if not result: + await ctx.send(f"{ctx.message.author.mention}> :x: Désolé mais {user.mention} est sans papier !") + else: + try: + user_birth = datetime.datetime.fromisoformat(result[3]) + user_birth_day = check_date(str(user_birth.day)) + user_birth_month = check_date(str(user_birth.month)) - @_ci.command(pass_context=True, name="delete") - async def ci_delete(self, ctx): - cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) - existansw = cursor.fetchone() - if existansw != None: - cursor.execute("""DELETE FROM users WHERE userid =?""", (ctx.message.author.id,)) - await ctx.send("Tu es maintenant sans papiers !") - else: - await ctx.send("Déja enregistre ta carte d'identité avant de la supprimer u_u (après c'est pas logique...)") + formated_user_birth = str(user_birth_day) + "/" + str(user_birth_month) + "/" + str(user_birth.year) - @_ci.command(pass_context=True, name="update") - async def ci_image(self, ctx): - try: - cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) - existansw = cursor.fetchone() + try: ## a virer une fois le patch appliqué pour tout le monde + cidate = datetime.datetime.fromisoformat(result[4]) + cidate_day = check_date(str(cidate.day)) ## a garder + cidate_month = check_date(str(cidate.month)) ## a garder - if existansw != None: - cursor.execute("""UPDATE users SET useravatar = ?, username = ?, cibureau = ? WHERE userid = ?""", (ctx.message.author.avatar_url, ctx.message.author.name, str(ctx.message.guild), ctx.message.author.id)) - conn.commit() - await ctx.send(ctx.message.author.mention + "> Tu viens, en quelques sortes, de renaitre !") - else: - await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + formated_cidate = str(cidate_day) + "/" + str(cidate_month) + "/" + str(cidate.year) ## a garder + except ValueError: ## a virer une fois le patch appliqué pour tout le monde + formated_cidate = str(result[4]).replace('-', '/') ## a virer une fois le patch appliqué pour tout le monde + await ctx.send(f"{user.mention} vous êtes prié(e) de faire la commande `.ci update` afin de regler un probleme de date coté bdd") ## a virer une fois le patch appliqué pour tout le monde - except Exception as e: #TODO : A virer dans l'event on_error - await ctx.send(':( Erreur veuillez contacter votre administrateur :') - await ctx.send('{}: {}'.format(type(e).__name__, e)) + embed=discord.Embed(title="Carte d'identité | Communisme Linuxien") + embed.set_author(name=result[1], icon_url=result[2]) + embed.set_thumbnail(url = result[2]) + embed.add_field(name="Nom :", value=result[1], inline=True) + embed.add_field(name="Système d'exploitation :", value=isexist(result[6]), inline=True) + embed.add_field(name="Configuration Système : ", value=isexist(result[7]), inline=True) + embed.add_field(name="Date de naissance sur discord : ", value=formated_user_birth, inline=True) + embed.add_field(name="Pays : ", value=isexist(result[8]), inline=True) + embed.add_field(name="Profil sur le web : ", value=f"https://tuxbot.outout.xyz/user-{result[9]}", inline=True) + embed.set_footer(text=f"Enregistré dans le bureau {result[5]} le {formated_cidate}.") + await ctx.send(embed=embed) + except Exception as e: + await ctx.send(f"{ctx.message.author.mention}> :x: Désolé mais la carte d'identité de {user.mention} est trop longue de ce fait je ne peux te l'envoyer, essaye de l'aléger, {user.mention} :wink: !") + await ctx.send(f':sob: Une erreur est survenue : \n {type(e).__name__}: {e}') + else: + return await ctx.send('Impossible de trouver l\'user.') - @_ci.command(pass_context=True, name="setconfig") - async def ci_setconfig(self, ctx, args_): - try: - args = ctx.message.content.split("setconfig ") - args = args[1] - cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) - existansw = cursor.fetchone() + @_ci.command(pass_context=True, name="register") + async def ci_register(self, ctx): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() - if existansw != None: - cursor.execute("""UPDATE users SET config = ? WHERE userid = ?""", (args, ctx.message.author.id)) - conn.commit() - await ctx.send(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") - else: - await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") - except: - await ctx.send(ctx.message.author.mention + "> :x: Il manque un paramètre !") + self.cursor.execute("""SELECT id, userid FROM users WHERE userid=%s""", (str(ctx.message.author.id))) + result = self.cursor.fetchone() - @_ci.command(pass_context=True, name="setos") - async def ci_setos(self, ctx, args_): - try: - args = ctx.message.content.split("setos ") - args = args[1] - cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) - existansw = cursor.fetchone() + if result: + await ctx.send("Mais tu as déja une carte d'identité ! u_u") + else: + now = datetime.datetime.now() - if existansw != None: - cursor.execute("""UPDATE users SET os = ? WHERE userid = ?""", (args, ctx.message.author.id)) - conn.commit() - await ctx.send(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") - else: - await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") - except: - await ctx.send(ctx.message.author.mention + "> :x: Il manque un paramètre !") + self.cursor.execute("""INSERT INTO users(userid, username, useravatar, userbirth, cidate, cibureau) VALUES(%s, %s, %s, %s, %s, %s)""", (str(ctx.message.author.id), str(ctx.message.author), str(ctx.message.author.avatar_url_as(format="jpg", size=512)), str(ctx.message.author.created_at), now, str(ctx.message.guild.name))) + self.conn.commit() + await ctx.send(f":clap: Bievenue à toi {ctx.message.author.name} dans le communisme {ctx.message.guild.name} ! Fait ``.ci`` pour plus d'informations !") - @_ci.command(pass_context=True, name="setcountry") - async def ci_setcountry(self, ctx, args): - cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) - existansw = cursor.fetchone() + @_ci.command(pass_context=True, name="delete") + async def ci_delete(self, ctx): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() - if existansw != None: - cursor.execute("""UPDATE users SET pays = ? WHERE userid = ?""", (args, ctx.message.author.id)) - conn.commit() - await ctx.send(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") - else: - await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + self.cursor.execute("""SELECT id, userid FROM users WHERE userid=%s""", (str(ctx.message.author.id))) + result = self.cursor.fetchone() - @_ci.command(pass_context=True, name="list") - async def ci_list(self, ctx): - cursor.execute("""SELECT id, username FROM users""") - rows = cursor.fetchall() - msg = "" - try: - for row in rows: - msg = msg + '{0} : {1} \n'.format(row[0], row[1]) - await ctx.send(msg) - except: - await ctx.send(":x: Pas d'entrés") + if result: + self.cursor.execute("""DELETE FROM users WHERE userid =%s""", (str(ctx.message.author.id))) + self.conn.commit() + await ctx.send("Tu es maintenant sans papiers !") + else: + await ctx.send("Déja enregistre ta carte d'identité avant de la supprimer u_u (après c'est pas logique...)") + + @_ci.command(pass_context=True, name="update") + async def ci_update(self, ctx): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + try: + self.cursor.execute("""SELECT id, userid FROM users WHERE userid=%s""", (str(ctx.message.author.id))) + result = self.cursor.fetchone() + + if result: + self.cursor.execute("""SELECT cidate FROM users WHERE userid=%s""",(str(ctx.message.author.id))) + old_ci_date = self.cursor.fetchone() + + try: + new_ci_date = datetime.datetime.fromisoformat(old_ci_date[0]) + except ValueError: + old_ci_date = datetime.datetime.strptime(old_ci_date[0].replace('/', '-'), '%d-%m-%Y') + + old_ci_date_day = check_date(str(old_ci_date.day)) + old_ci_date_month = check_date(str(old_ci_date.month)) + + new_ci_date = f"{str(old_ci_date.year)}-{str(old_ci_date_month)}-{str(old_ci_date_day)} 00:00:00.000000" + + await ctx.send("succes update") + + self.cursor.execute("""UPDATE users SET cidate = %s WHERE userid = %s""", (str(new_ci_date), str(ctx.message.author.id))) + self.conn.commit() + + self.cursor.execute("""UPDATE users SET useravatar = %s, username = %s, cibureau = %s WHERE userid = %s""", (str(ctx.message.author.avatar_url_as(format="jpg", size=512)), str(ctx.message.author), str(ctx.message.guild), str(ctx.message.author.id))) + self.conn.commit() + await ctx.send(f"{ctx.message.author.mention}> Tu viens, en quelques sortes, de renaitre !") + else: + await ctx.send(f"{ctx.message.author.mention}> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + + except Exception as e: #TODO : A virer dans l'event on_error + await ctx.send(':( Erreur veuillez contacter votre administrateur :') + await ctx.send(f'{type(e).__name__}: {e}') + + @_ci.command(pass_context=True, name="setconfig") + async def ci_setconfig(self, ctx, *, conf: str = None): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + if conf: + self.cursor.execute("""SELECT id, userid FROM users WHERE userid=%s""", (str(ctx.message.author.id))) + result = self.cursor.fetchone() + + if result: + self.cursor.execute("""UPDATE users SET config = %s WHERE userid = %s""", (str(conf), str(ctx.message.author.id))) + self.conn.commit() + await ctx.send(f"{ctx.message.author.mention}> :ok_hand: Carte d'identité mise à jour !") + else: + await ctx.send(f"{ctx.message.author.mention}> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + else: + await ctx.send(f"{ctx.message.author.mention}> :x: Il manque un paramètre !") + + @_ci.command(pass_context=True, name="setos") + async def ci_setos(self, ctx, *, conf: str = None): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + if conf: + self.cursor.execute("""SELECT id, userid FROM users WHERE userid=%s""", (str(ctx.message.author.id))) + result = self.cursor.fetchone() + + if result: + self.cursor.execute("""UPDATE users SET os = %s WHERE userid = %s""", (str(conf), str(ctx.message.author.id))) + self.conn.commit() + await ctx.send(f"{ctx.message.author.mention}> :ok_hand: Carte d'identité mise à jour !") + else: + await ctx.send(f"{ctx.message.author.mention}> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + else: + await ctx.send(f"{ctx.message.author.mention}> :x: Il manque un paramètre !") + + @_ci.command(pass_context=True, name="setcountry") + async def ci_setcountry(self, ctx, *, country: str = None): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + if country: + self.cursor.execute("""SELECT id, userid FROM users WHERE userid=%s""", (str(ctx.message.author.id))) + result = self.cursor.fetchone() + + if result: + self.cursor.execute("""UPDATE users SET pays = %s WHERE userid = %s""", (str(country), str(ctx.message.author.id))) + self.conn.commit() + await ctx.send(f"{ctx.message.author.mention}> :ok_hand: Carte d'identité mise à jour !") + else: + await ctx.send(f"{ctx.message.author.mention}> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + else: + await ctx.send(f"{ctx.message.author.mention}> :x: Il manque un paramètre !") + + @checks.has_permissions(administrator=True) + @_ci.command(pass_context=True, name="list") + async def ci_list(self, ctx): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + self.cursor.execute("""SELECT id, username FROM users""") + rows = self.cursor.fetchall() + msg = "" + try: + for row in rows: + row_id = row[0] + row_name = row[1].encode('utf-8') + msg += f"{str(row_id)} : {str(row_name)} \n" + post = requests.post("https://hastebin.com/documents", data=msg) + await ctx.send(f"{ctx.message.author.mention} liste posté avec succès sur :\nhttps://hastebin.com/{post.json()['key']}.txt") + + with open('ci_list.txt', 'w', encoding='utf-8') as fp: + for row in rows: + row_id = row[0] + row_name = row[1] + + fp.write(f"{str(row_id)} : {str(row_name)} \n") + + except Exception as e: + await ctx.send(f':sob: Une erreur est survenue : \n {type(e).__name__}: {e}') def setup(bot): - bot.add_cog(Identity(bot)) + bot.add_cog(Identity(bot)) diff --git a/cogs/cog_manager.py b/cogs/cog_manager.py new file mode 100755 index 0000000..1093882 --- /dev/null +++ b/cogs/cog_manager.py @@ -0,0 +1,110 @@ +from discord.ext import commands +import discord +from .utils import checks +from .utils.paginator import HelpPaginator + + +class CogManager: + """Gestionnaire des cogs""" + + def __init__(self, bot): + self.bot = bot + + """--------------------------------------------------------------------------------------------------------------------------""" + + @checks.has_permissions(administrator=True) + @commands.group(name="cogs", no_pm=True, pass_context=True, case_insensitive=True) + async def _cogs(self, ctx): + """show help about 'cogs' command""" + + if ctx.invoked_subcommand is None: + text = "Tuxbot - Commandes cogs\n-> .cogs *{cog}* : *{cog}*\n-> .cogs : affiche cette aide" + em = discord.Embed(title='Tuxbot - Commandes cogs', description=text, colour=0x89C4F9) + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_cogs.command(name="load", pass_context=True) + async def cogs_load(self, ctx, cog: str = ""): + """load a cog""" + if cog != "": + try: + self.bot.load_extension(cog) + + await ctx.send('\N{OK HAND SIGN}') + print("cog : " + str(cog) + " chargé") + except Exception as e: + await ctx.send('\N{PISTOL}') + await ctx.send(f'{type(e).__name__}: {e}') + else: + text = "Tuxbot - Commandes cogs\n-> .cogs *{cog}* : *{cog}*\n-> .cogs : affiche cette aide" + em = discord.Embed(title='Tuxbot - Commandes cogs', description=text, colour=0x89C4F9) + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_cogs.command(name="unload", pass_context=True) + async def cogs_unload(self, ctx, cog: str = ""): + """unload a cog""" + if cog != "": + try: + self.bot.unload_extension(cog) + + await ctx.send('\N{OK HAND SIGN}') + print("cog : " + str(cog) + " déchargé") + except Exception as e: + await ctx.send('\N{PISTOL}') + await ctx.send(f'{type(e).__name__}: {e}') + else: + text = "Tuxbot - Commandes cogs\n-> .cogs *{cog}* : *{cog}*\n-> .cogs : affiche cette aide" + em = discord.Embed(title='Tuxbot - Commandes cogs', description=text, colour=0x89C4F9) + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_cogs.command(name="reload", pass_context=True) + async def cogs_reload(self, ctx, cog: str = ""): + """reload a cog""" + if cog != "": + try: + self.bot.unload_extension(cog) + self.bot.load_extension(cog) + + await ctx.send('\N{OK HAND SIGN}') + print("cog : " + str(cog) + " rechargé") + except Exception as e: + await ctx.send('\N{PISTOL}') + await ctx.send(f'{type(e).__name__}: {e}') + else: + text = "Tuxbot - Commandes cogs\n-> .cogs *{cog}* : *{cog}*\n-> .cogs : affiche cette aide" + em = discord.Embed(title='Tuxbot - Commandes cogs', description=text, colour=0x89C4F9) + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_cogs.command(name="info", pass_context=True) + async def cogs_info(self, ctx, cog: str = ""): + """show info about a cog""" + if cog != "": + try: + entity = self.bot.get_cog(cog) + + if entity is None: + clean = cog.replace('@', '@\u200b') + await ctx.send(f'Command or category "{clean}" not found.') + else: + p = await HelpPaginator.from_cog(ctx, entity) + await p.paginate() + + + except Exception as e: + await ctx.send('\N{PISTOL}') + await ctx.send(f'{type(e).__name__}: {e}') + else: + text = "Tuxbot - Commandes cogs\n-> .cogs *{cog}* : *{cog}*\n-> .cogs : affiche cette aide" + em = discord.Embed(title='Tuxbot - Commandes cogs', description=text, colour=0x89C4F9) + await ctx.send(embed=em) + + +def setup(bot): + bot.add_cog(CogManager(bot)) diff --git a/cogs/dev.py b/cogs/dev.py new file mode 100644 index 0000000..28fac78 --- /dev/null +++ b/cogs/dev.py @@ -0,0 +1,24 @@ +from discord.ext import commands +import discord + + +class Dev: + """Gestionnaire des cogs""" + + def __init__(self, bot): + self.bot = bot + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command(name="test", no_pm=True, pass_context=True, case_insensitive=True) + async def _test(self, ctx): + """show help about 'cogs' command""" + + if ctx.invoked_subcommand is None: + text = "<:python:334346615366221825>" + em = discord.Embed(title='Some test', description=text, colour=0x89C4F9) + await ctx.send(embed=em) + + +def setup(bot): + bot.add_cog(Dev(bot)) diff --git a/cogs/filter_messages.py b/cogs/filter_messages.py new file mode 100755 index 0000000..b7752d0 --- /dev/null +++ b/cogs/filter_messages.py @@ -0,0 +1,52 @@ +from discord.ext import commands +import discord +import asyncio +import discord + +import re + + +class FilterMessages: + """Flitre des messages""" + + def __init__(self, bot): + self.bot = bot + + async def on_message(self, message): + no_pub_guild = [280805240977227776, 303633056944881686, 274247231534792704] + lien_channel = [280805783795662848, 508794201509593088] + sondage_channel = [394146769107419146, 477147964393914388] + + if message.author.bot \ + or str(message.author.id) in self.bot.config.authorized_id \ + or message.channel.permissions_for(message.author).administrator is True: + return + + discord_invite_regex = re.compile(r"(discord\.(gg|io|me|li)|discordapp\.com\/invite)\/[0-9A-Za-z]*", re.IGNORECASE) + invalid_link_regex = re.compile(r"^(\[[^\]]+\]|<\:[a-z0-9]+\:[0-9]+>) .+ https?:\/\/\S*$", re.IGNORECASE) + + try: + if message.guild.id in no_pub_guild: ## discord invitation send by a non-admin and a non-authorized_id + if isinstance(discord_invite_regex.search(message.content), re.Match): + author = self.bot.get_user(message.author.id) + await message.delete() + await author.send("La pub pour les serveurs discord n'est pas autorisée ici") + + if message.channel.id in lien_channel \ + and not isinstance(invalid_link_regex.search(message.content), re.Match): ## link send without pattern + author = self.bot.get_user(message.author.id) + await message.delete() + await author.send("Votre message `" + content + "` a été supprimé du channel `liens` car il ne respecte pas la structure définie. Pour partager un lien veuillez suivre la structure suivante : ` [Sujet] Descirption http(s)://....`") + await author.send("Si vous voulez commenter ou discuter à propos d'un lien, veuillez le faire dans le channel `#discussion-des-liens`.") + + if message.channel.id in sondage_channel: ## a non-sondage send by a non-admin + prefix_lenght = len(await self.bot.get_prefix(message)) + command = (message.content.split()[0])[prefix_lenght:] + if command != "sondage": + await message.delete() + except AttributeError: + pass + + +def setup(bot): + bot.add_cog(FilterMessages(bot)) diff --git a/cogs/funs.py b/cogs/funs.py index f93d465..64375ea 100755 --- a/cogs/funs.py +++ b/cogs/funs.py @@ -1,133 +1,188 @@ from discord.ext import commands -from random import choice, shuffle -import aiohttp import asyncio import discord -import urllib.request, json +import urllib.request +import json import random import requests + class Funs: - """Commandes funs.""" + """Commandes funs.""" - def __init__(self, bot): - self.bot = bot + def __init__(self, bot): + self.bot = bot + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command() + async def avatar(self, ctx, user: discord.Member = None): + """Récuperer l'avatar de ...""" + + if user == None: + user = ctx.message.author + + embed = discord.Embed(title="Avatar de : " + user.name, + url=user.avatar_url_as(format="png"), + description=f"[Voir en plus grand]({user.avatar_url_as(format='png')})") + embed.set_thumbnail(url=user.user.avatar_url_as(format="png")) + await ctx.send(embed=embed) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command(pass_context=True) + async def poke(self, ctx, user: discord.Member): + """Poke quelqu'un""" + await ctx.send(":clap: Hey {0} tu t'es fait poker par {1} !".format( + user.mention, ctx.message.author.name)) + await ctx.message.delete() + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command() + async def btcprice(self, ctx): + """Le prix du BTC""" + loading = await ctx.send("_réfléchis..._") + try: + url = urllib.request.urlopen("https://blockchain.info/fr/ticker") + btc = json.loads(url.read().decode()) + except KeyError: + btc = 1 + + if btc == 1: + await loading.edit(content="Impossible d'accèder à l'API blockchain.info, " + "veuillez réessayer ultérieurment ! :c") + else: + frbtc = str(btc["EUR"]["last"]).replace(".", ",") + usbtc = str(btc["USD"]["last"]).replace(".", ",") + await loading.edit(content="Un bitcoin est égal à : {0}$US soit {1}€.".format(usbtc, frbtc)) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command() + async def joke(self, ctx, number:str = 0): + """Print a random joke in a json file""" + with open('texts/jokes.json') as js: + jk = json.load(js) + + try: + if int(number) <= 15 and int(number) > 0: + clef = str(number) + else: + clef = str(random.randint(1,15)) + except: + clef = str(random.randint(1,15)) + joke = jk["{}".format(clef)] - @commands.command() - async def avatar(self, ctx, user : discord.Member): - """Récuperer l'avatar de ...""" - embed = discord.Embed(title="Avatar de : " + user.name, url=user.avatar_url, description="[Voir en plus grand]({})".format(user.avatar_url)) - embed.set_thumbnail(url=user.avatar_url) - await ctx.send(embed=embed) + embed = discord.Embed(title="Blague _{}_ : ".format(clef), description=joke['content'], colour=0x03C9A9) + embed.set_footer(text="Par " + joke['author']) + embed.set_thumbnail(url='https://outout.tech/tuxbot/blobjoy.png') + await ctx.send(embed=embed) - @commands.command(pass_context=True) - async def poke(self, ctx, user : discord.Member): - """Poke quelqu'un""" - await ctx.send(":clap: Hey {0} tu t'es fait poker par {1} !".format(user.mention, ctx.message.author.name)) - await ctx.message.delete() + """--------------------------------------------------------------------------------------------------------------------------""" - @commands.command() - async def btcprice(self, ctx): - """Le prix du BTC""" - loading = await ctx.send("_réfléchis..._") - try: - with urllib.request.urlopen("http://api.coindesk.com/v1/bpi/currentprice/EUR.json") as url: - data = json.loads(url.read().decode()) - btc = data['bpi']['EUR']['rate'] - btc = btc.split(".") - except: - btc = 1 + @commands.command() + async def ethylotest(self, ctx): + """Ethylotest simulator 2018""" + results_poulet = ["Désolé mais mon ethylotest est sous Windows Vista, " + "merci de patienter...", + "_(ethylotest)_ : Une erreur est survenue. Windows " + "cherche une solution à se problème.", + "Mais j'l'ai foutu où ce p\\*\\*\\* d'ethylotest de m\\*\\*\\* " + "bordel fait ch\\*\\*\\*", + "C'est pas possible z'avez cassé l'ethylotest !"] + results_client = ["D'accord, il n'y a pas de problème à cela je suis " + "complètement clean", + "Bien sur si c'est votre devoir !", "Suce bi\\*e !", + "J'ai l'air d'être bourré ?", + "_laissez moi prendre un bonbon à la menthe..._"] - if btc == 1: - await ctx.send("Impossible d'accèder à l'API coindesk.com, veuillez réessayer ultérieurment !") - else: - await loading.edit(content="Un bitcoin est égal à : " + btc[0] + " €") + result_p = random.choice(results_poulet) + result_c = random.choice(results_client) - @commands.command() - async def joke(self, ctx): - """Print a random joke in a json file""" - with open('texts/jokes.json') as js: - jk = json.load(js) + await ctx.send(":oncoming_police_car: Bonjour bonjour, contrôle " + "d'alcoolémie !") + await asyncio.sleep(0.5) + await ctx.send(":man: " + result_c) + await asyncio.sleep(1) + await ctx.send(":police_car: " + result_p) - clef = str(random.randint(1,13)) - joke = jk["{}".format(clef)] + """--------------------------------------------------------------------------------------------------------------------------""" - embed = discord.Embed(title="Blague _{}_ : ".format(clef), description=joke['content'], colour=0x03C9A9) - embed.set_footer(text="Par " + joke['author']) - embed.set_thumbnail(url='https://outout.tech/tuxbot/blobjoy.png') - await ctx.send(embed=embed) + @commands.command() + async def coin(self, ctx): + """Coin flip simulator 2025""" + starts_msg = ["Je lance la pièce !", "C'est parti !", "C'est une pièce" + " d'un cent faut" + " pas la perdre", + "C'est une pièce d'un euro faut pas la perdre", + "Je lance !"] + results_coin = ["{0} pile", "{0} face", "{1} Heu c'est quoi pile c'est" + " quoi face enfaite ?", + "{1} Oh shit, je crois que je l'ai perdue", + "{1} Et bim je te vol ta pièce !", + "{0} Oh une erreur d'impression il n'y a ni pile ni" + " face !"] - @commands.command() - async def ethylotest(self, ctx): - """Ethylotest simulator 2018""" - results_poulet = ["Désolé mais mon ethylotest est sous Windows Vista, merci de patienter...", "_(ethylotest)_ ``Une erreur est survenue. Windows cherche une solution à se problème...``", "Mais j'l'ai foutu où ce p*** d'ethylotest de m*** bordel fait ch*** tab***", "C'est pas possible z'avez cassé l'ethylotest !"] - results_client = ["D'accord, il n'y a pas de problème à cela je suis complètement clean", "Bien sur si c'est votre devoir !", "Suce bi** !", "J'ai l'air d'être bourré ?", "_laissez moi prendre un bonbon à la menthe..._"] + start = random.choice(starts_msg) + result = random.choice(results_coin) - result_p = random.choice(results_poulet) - result_c = random.choice(results_client) + await ctx.send(start) + await asyncio.sleep(0.6) + await ctx.send(result.format(":moneybag: Et la pièce retombe sur ...", + ":robot:")) - await ctx.send(":oncoming_police_car: Bonjour bonjour, controle d'alcoolémie !") - await asyncio.sleep(0.5) - await ctx.send(":man: " + result_c) - await asyncio.sleep(1) - await ctx.send(":police_car: " + result_p) + """--------------------------------------------------------------------------------------------------------------------------""" - @commands.command() - async def coin(self, ctx): - """Coin flip simulator 2025""" - starts_msg = ["Je lance la pièce !", "C'est parti !", "C'est une pièce d'un cent faut pas la perdre", "C'est une pièce d'un euro faut pas la perdre", "Je lance !"] - results_coin = ["{0} pile", "{0} face", "{1} Heu c'est quoi pile c'est quoi face enfaite ?", "{1} Oh shit, je crois que je l'ai perdue", "{1} Et bim je te vol ta pièce !", "{0} Oh une erreur d'impression il n'y a ni pile ni face !"] + @commands.command() + async def pokemon(self, ctx): + """Random pokemon fight""" + with open('texts/pokemons.json') as js: + jk = json.load(js) - start = random.choice(starts_msg) - result = random.choice(results_coin) + poke1 = jk[random.randint(1, 150)] + poke2 = jk[random.randint(1, 150)] - await ctx.send(start) - await asyncio.sleep(0.6) - await ctx.send(result.format(":moneybag: Et la pièce retombe sur ...", ":robot:")) + try: + if poke1['MaxHP'] > poke2['MaxHP']: + winer = poke1 + else: + winer = poke2 + except KeyError: + winer = poke1 - @commands.command() - async def pokemon(self, ctx): - """Random pokemon fight""" - with open('texts/pokemons.json') as js: - jk = json.load(js) + await ctx.send(":flag_white: **Le combat commence !**") + await asyncio.sleep(1) + await ctx.send(":loudspeaker: Les concurants sont {} contre {} ! Bonne" + " chance à eux !".format(poke1["Name"], poke2["Name"])) + await asyncio.sleep(0.5) + await ctx.send(":boom: {} commence et utilise {}".format( + poke1["Name"], poke1["Fast Attack(s)"][0]["Name"])) + await asyncio.sleep(1) + await ctx.send(":dash: {} réplique avec {}".format( + poke2["Name"], poke2["Fast Attack(s)"][0]["Name"])) + await asyncio.sleep(1.2) + await ctx.send("_le combat continue de se dérouler..._") + await asyncio.sleep(1.5) + await ctx.send(":trophy: Le gagnant est **{}** !".format( + winer["Name"])) - poke1 = jk[random.randint(1, 150)] - poke2 = jk[random.randint(1, 150)] - - try: - if poke1['MaxHP'] > poke2['MaxHP']: - winer = poke1 - else: - winer = poke2 - except: - winer = poke1 - - await ctx.send(":flag_white: **Le combat commence !**") - await asyncio.sleep(1) - await ctx.send(":loudspeaker: Les concurants sont {} contre {} ! Bonne chance à eux !".format(poke1["Name"], poke2["Name"])) - await asyncio.sleep(0.5) - await ctx.send(":boom: {} commence et utilise {}".format(poke1["Name"], poke1["Fast Attack(s)"][0]["Name"])) - await asyncio.sleep(1) - await ctx.send(":dash: {} réplique avec {}".format(poke2["Name"], poke2["Fast Attack(s)"][0]["Name"])) - await asyncio.sleep(1.2) - await ctx.send("_le combat continue de se dérouler..._") - await asyncio.sleep(1.5) - await ctx.send(":trophy: Le gagnant est **{}** !".format(winer["Name"])) - - @commands.command() - async def randomcat(self, ctx): - """Display a random cat""" - - r = requests.get('http://random.cat/meow.php') - cat = str(r.json()['file']) - embed = discord.Embed(title="Meow", description="[Voir le chat plus grand]({})".format(cat), colour=0x03C9A9) - embed.set_thumbnail(url=cat) - embed.set_author(name="Random.cat", url='https://random.cat/', icon_url='http://outout.tech/tuxbot/nyancat2.gif') - await ctx.send(embed=embed) + """--------------------------------------------------------------------------------------------------------------------------""" + @commands.command() + async def randomcat(self, ctx): + """Display a random cat""" + r = requests.get('http://aws.random.cat/meow') + cat = str(r.json()['file']) + embed = discord.Embed(title="Meow", + description="[Voir le chat plus grand]({})". + format(cat), colour=0x03C9A9) + embed.set_thumbnail(url=cat) + embed.set_author(name="Random.cat", url='https://random.cat/') + await ctx.send(embed=embed) def setup(bot): - bot.add_cog(Funs(bot)) + bot.add_cog(Funs(bot)) diff --git a/cogs/passport.py b/cogs/passport.py new file mode 100755 index 0000000..95c8301 --- /dev/null +++ b/cogs/passport.py @@ -0,0 +1,222 @@ +from discord.ext import commands +import discord + +from PIL import Image +from PIL import ImageOps + +from .utils import checks +from .utils import db +from .utils.passport_generator import generate_passport +from .utils.checks import get_user, check_date + +import asyncio, aiohttp, io, time, imghdr, os, shutil, json, textwrap, re, math, datetime + +class Passport: + """Commandes des passeports .""" + + def __init__(self, bot): + self.bot = bot + + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + self.cursor.execute("""SHOW TABLES LIKE 'passport'""") + result = self.cursor.fetchone() + + if not result: + # Creation table Passport si premiere fois + sql = "CREATE TABLE passport ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, userid TEXT null, os TEXT null, config TEXT null, languages TEXT null, pays TEXT null, passportdate TEXT null, theme CHAR(5) DEFAULT 'dark');" + self.cursor.execute(sql) + + @commands.group(pass_context=True) + async def passeport(self, ctx): + """Passeport""" + + if ctx.invoked_subcommand is None: + text = open('texts/passport-info.md').read() + em = discord.Embed(title='Commandes de carte de passeport de TuxBot', description=text, colour=0x89C4F9) + await ctx.send(embed=em) + + @passeport.command(pass_context=True) + async def show(self, ctx, user: str = None): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + if user == None: + user = get_user(ctx.message, ctx.message.author.name) + else: + user = get_user(ctx.message, user) + + wait_message = await ctx.send(f"Je vais chercher le passeport de {user.name} dans les archives, je vous prie de bien vouloir patienter...") + + card = await generate_passport(self, user) + s = 'data/users/cards/{0}.png'.format(user.id) + + card.save(s, 'png') + + with open('data/users/cards/{0}.png'.format(user.id), 'rb') as g: + await ctx.message.channel.send(file=discord.File(g)) + await wait_message.delete() + + @passeport.command(name="config", pass_context=True) + async def passeport_config(self, ctx): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + await ctx.send('Un message privé vous a été envoyé pour configurer votre passeport.') + + questions = ["Système(s) d'exploitation :", "Configuration Système :", "Langages de programmation préférés :", "Pays :"] + answers = {} + + user_dm = await ctx.author.create_dm() + + try: + await user_dm.send("Salut ! Je vais vous posez quelques questions afin de configurer votre passeport, si vous ne voulez pas répondre à une question, envoyez `skip` pour passer à la question suivante.") + except discord.HTTPException: + await ctx.send(f"{str(ctx.message.author.mention)}> il m'est impossible de vous envoyer les messages nécessaire a la configuration de votre passeport :sob:") + return + + for x, question in enumerate(questions): + await user_dm.send(question) + + def check(m): + return m.channel.id == user_dm.id and m.author.id == user_dm.recipient.id + + answer = await self.bot.wait_for('message', check=check) + if answer.content.lower() == 'skip': + answers[x] = 'n/a' + else: + answers[x] = answer.content + try: + self.cursor.execute("""SELECT id, userid FROM passport WHERE userid = %s""", str(user_dm.recipient.id)) + result = self.cursor.fetchone() + + if result: + self.cursor.execute("""UPDATE passport SET os = %s, config = %s, languages = %s, pays = %s WHERE userid = %s""", (str(answers[0]), str(answers[1]), str(answers[2]), str(answers[3]), str(ctx.message.author.id))) + self.conn.commit() + else: + now = datetime.datetime.now() + + self.cursor.execute("""INSERT INTO passport(userid, os, config, languages, pays, passportdate, theme) VALUES(%s, %s, %s, %s, %s, %s, %s)""", (str(ctx.message.author.id), str(answers[0]), str(answers[1]), str(answers[2]), str(answers[3]), now, "dark")) + self.conn.commit() + await user_dm.send('Configuration de votre passeport terminée avec succès, vous pouvez désormais la voir en faisant `.passeport show`.') + except Exception as e: + await user_dm.send(f':sob: Une erreur est survenue : \n {type(e).__name__}: {e}') + + @passeport.command(name="background", pass_context=True) + async def passeport_background(self, ctx, *, url=""): + try: + background = ctx.message.attachments[0].url + except: + if url != "": + background = url + else: + em = discord.Embed(title='Une erreur est survenue', description="Image ou URL introuvable.", colour=0xDC3546) + await ctx.send(embed=em) + return + + user = ctx.message.author + try: + async with aiohttp.ClientSession() as session: + async with session.get(background) as r: + image = await r.content.read() + except: + em = discord.Embed(title='Une erreur est survenue', description="Image ou URL introuvable.", colour=0xDC3546) + await ctx.send(embed=em) + return + + with open(f"data/users/backgrounds/{str(user.id)}.png",'wb') as f: + f.write(image) + + isImage = imghdr.what(f"data/users/backgrounds/{str(user.id)}.png") + + if isImage == 'png' or isImage == 'jpeg' or isImage == 'jpg' or isImage == 'gif': + f.close() + em = discord.Embed(title='Configuration terminée', description="Fond d'écran enregistré et configuré avec succes", colour=0x28a745) + await ctx.send(embed=em) + else: + f.close() + os.remove(f"data/users/backgrounds/{str(user.id)}.png") + em = discord.Embed(title='Une erreur est survenue', description="Est-ce bien une image que vous avez envoyé ? :thinking:", colour=0xDC3546) + await ctx.send(embed=em) + + @passeport.command(name="theme", aliases=["thème"], pass_context=True) + async def passeport_theme(self, ctx, theme: str = ""): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + possible_theme = ["dark", "light", "preview"] + + if theme.lower() in possible_theme: + if theme.lower() == "dark": + self.cursor.execute("""UPDATE passport SET theme = %s WHERE userid = %s""", ("dark", str(ctx.message.author.id))) + self.conn.commit() + + em = discord.Embed(title='Configuration terminée', description="Thème enregistré avec succes", colour=0x28a745) + await ctx.send(embed=em) + elif theme.lower() == "light": + self.cursor.execute("""UPDATE passport SET theme = %s WHERE userid = %s""", ("light", str(ctx.message.author.id))) + self.conn.commit() + + em = discord.Embed(title='Configuration terminée', description="Thème enregistré avec succes", colour=0x28a745) + await ctx.send(embed=em) + else: + wait_message = await ctx.send(f"Laissez moi juste le temps de superposer les 2 passeports, je vous prie de bien vouloir patienter...") + cardbg = Image.new('RGBA', (1600, 500), (0, 0, 0, 255)) + + card_dark = await generate_passport(self, ctx.author, "dark") + card_dark.save(f'data/tmp/{ctx.author.id}_dark.png', 'png') + + card_light = await generate_passport(self, ctx.author, "light") + card_light.save(f'data/tmp/{ctx.author.id}_light.png', 'png') + + saved_card_dark = Image.open(f'data/tmp/{ctx.author.id}_dark.png') + saved_card_light = Image.open(f'data/tmp/{ctx.author.id}_light.png') + + saved_card_dark = ImageOps.fit(saved_card_dark, (800, 500)) + saved_card_light = ImageOps.fit(saved_card_light, (800, 500)) + + cardbg.paste(saved_card_dark, (0, 0)) + cardbg.paste(saved_card_light, (800, 0)) + + cardbg.save(f'data/tmp/{ctx.author.id}.png', 'png') + + with open(f'data/tmp/{ctx.author.id}.png', 'rb') as g: + await ctx.send(file=discord.File(g)) + await wait_message.delete() + await ctx.send(f"Et voila {ctx.author.mention} ! à gauche votre passeport avec le thème \"dark\" et à droite avec le thème \"light\" :wink:") + + shutil.rmtree("data/tmp") + os.mkdir("data/tmp") + + else: + em = discord.Embed(title='Une erreur est survenue', description="Les choix possible pour cette commande sont : `dark`, `light`, `preview`", colour=0xDC3546) + await ctx.send(embed=em) + + @passeport.command(name="delete", pass_context=True) + async def passeport_delete(self, ctx): + self.conn = db.connect_to_db(self) + self.cursor = self.conn.cursor() + + self.cursor.execute("""SELECT id, userid FROM passport WHERE userid = %s""", str(ctx.author.id)) + result = self.cursor.fetchone() + + if result: + def check(m): + return m.author.id == ctx.author.id and \ + m.channel.id == ctx.channel.id + + await ctx.send(f"{str(ctx.message.author.mention)}> envoyez `CONFIRMER` afin de supprimer vos données conformément à l'article 17 du `règlement général sur la protection des données` sur le `Droit à l'effacement`") + response = await self.bot.wait_for('message', check=check, timeout=10.0 * 60.0) + if response.content == "CONFIRMER": + os.remove(f"data/users/backgrounds/{str(ctx.author.id)}.png") + self.cursor.execute("""DELETE FROM passport WHERE userid =%s""", (str(ctx.message.author.id))) + self.conn.commit() + + em = discord.Embed(title='Suppression confirmée', description="Vos données ont été supprimées avec succès", colour=0x28a745) + await ctx.send(embed=em) + else: + await ctx.send("Déja configure ton passeport avant de la supprimer u_u (après c'est pas logique...)") + +def setup(bot): + bot.add_cog(Passport(bot)) diff --git a/cogs/role.py b/cogs/role.py new file mode 100755 index 0000000..47e3282 --- /dev/null +++ b/cogs/role.py @@ -0,0 +1,127 @@ +from discord.ext import commands +import discord + +class Role: + """Commandes role.""" + + def __init__(self, bot): + self.bot = bot + + self.ARCH_ROLE = 393077257826205706 + self.DEBIAN_ROLE = 393077933209550859 + self.RHEL_ROLE = 393078333245751296 + self.ANDROID_ROLE = 393087862972612627 + self.BSD_ROLE = 401791543708745738 + + @commands.group(name="role", no_pm=True, pass_context=True, case_insensitive=True) + async def _role(self, ctx): + """Affiche l'aide sur la commande role""" + if ctx.message.guild.id != 280805240977227776: + return + + if ctx.invoked_subcommand is None: + text = open('texts/roles.md').read() + em = discord.Embed(title='Gestionnaires de rôles', description=text,colour=0x89C4F9) + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_role.command(name="arch", aliases=["archlinux", "arch_linux"], pass_context=True) + async def role_arch(self, ctx): + """Ajoute/retire le role 'Arch user'""" + roles = ctx.message.author.roles + role_id = [] + for role in roles: + role_id.append(role.id) + + user = ctx.message.author + if self.ARCH_ROLE in role_id: + await user.remove_roles(discord.Object(id=self.ARCH_ROLE)) + await ctx.send(ctx.message.author.mention + " > Pourquoi tu viens de supprimer Arch Linux, c'était trop compliqué pour toi ? <:sad:343723037331292170>") + else: + await user.add_roles(discord.Object(id=self.ARCH_ROLE)) + await ctx.send(ctx.message.author.mention + " > How un ArchLinuxien, c'est bon les ``yaourt`` ? <:hap:354275645574086656>") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_role.command(name="debian", pass_context=True) + async def role_debian(self, ctx): + """Ajoute/retire le role 'debian user'""" + roles = ctx.message.author.roles + role_id = [] + for role in roles: + role_id.append(role.id) + + user = ctx.message.author + if self.DEBIAN_ROLE in role_id: + await user.remove_roles(discord.Object(id=self.DEBIAN_ROLE)) + await ctx.send(ctx.message.author.mention + " > Adieu ! Tu verras, APT te manquera ! ") + else: + await user.add_roles(discord.Object(id=self.DEBIAN_ROLE)) + await ctx.send(ctx.message.author.mention + " > Un utilisateur de Debian, encore et encore ! <:stuck_out_tongue:343723077412323339>") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_role.command(name="rhel", pass_context=True) + async def role_rhel(self, ctx): + """Ajoute/retire le role 'rhel user'""" + roles = ctx.message.author.roles + role_id = [] + for role in roles: + role_id.append(role.id) + + user = ctx.message.author + if self.RHEL_ROLE in role_id: + await user.remove_roles(discord.Object(id=self.RHEL_ROLE)) + await ctx.send(ctx.message.author.mention + " > Pourquoi tu t'en vas, il sont déjà assez seul là-bas <:sad:343723037331292170>") + else: + await user.add_roles(discord.Object(id=self.RHEL_ROLE)) + await ctx.send(ctx.message.author.mention + " > Mais, voila quelqu'un qui porte des chapeaux ! <:hap:354275645574086656>") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_role.command(name="android", pass_context=True) + async def role_android(self, ctx): + """Ajoute/retire le role 'android user'""" + roles = ctx.message.author.roles + role_id = [] + for role in roles: + role_id.append(role.id) + + user = ctx.message.author + if self.ANDROID_ROLE in role_id: + await user.remove_roles(discord.Object(id=self.ANDROID_ROLE)) + await ctx.send(ctx.message.author.mention + " > How, me dit pas que tu as compris que les Android's allaient exterminer le monde ? <:trollface:375327667160875008>") + else: + await user.add_roles(discord.Object(id=self.ANDROID_ROLE)) + await ctx.send(ctx.message.author.mention + " > Hey, un utilisateur d'Android, prêt à continuer l'extermination de WP et iOS ? <:stuck_out_tongue:343723077412323339>") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_role.command(name="bsd", pass_context=True) + async def role_bsd(self, ctx): + """Ajoute/retire le role 'BSD user'""" + roles = ctx.message.author.roles + role_id = [] + for role in roles: + role_id.append(role.id) + + user = ctx.message.author + if self.BSD_ROLE in role_id: + await user.remove_roles(discord.Object(id=self.BSD_ROLE)) + await ctx.send(ctx.message.author.mention + " > Ohhhh fait gaffe ou le démon va te piquer") + else: + await user.add_roles(discord.Object(id=self.BSD_ROLE)) + await ctx.send(ctx.message.author.mention + " > Quelqu'un sous BSD ! Au moins il a pas besoin de mettre GNU devant son OS à chaque fois :d") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @_role.command(name="staff", pass_context=True, hidden=True) + async def role_staff(self, ctx): + """Easter egg""" + user = ctx.message.author + await ctx.send(ctx.message.author.mention + " > Vous n'avez pas le rôle staff, tu crois quoi :joy:") + + +def setup(bot): + bot.add_cog(Role(bot)) diff --git a/cogs/search.py b/cogs/search.py index 8952358..73c7799 100755 --- a/cogs/search.py +++ b/cogs/search.py @@ -1,128 +1,157 @@ from discord.ext import commands -import aiohttp -import asyncio import discord -import urllib.request, json -import wikipedia, bs4 +import asyncio +import urllib.request +import wikipedia wikipedia.set_lang("fr") + class Search: - """Commandes de WWW.""" + """Commandes de WWW.""" - def __init__(self, bot): - self.bot = bot + def __init__(self, bot): + self.bot = bot - @commands.group(name="search", no_pm=True, pass_context=True) - async def _search(self, ctx): - """Rechercher sur le world wide web""" - if ctx.invoked_subcommand is None: - text = open('texts/search.md').read() - em = discord.Embed(title='Commandes de search TuxBot', description=text, colour=0x89C4F9) - await ctx.send(embed=em) + @commands.group(name="search", no_pm=True, pass_context=True) + async def _search(self, ctx): + """Rechercher sur le world wide web""" + if ctx.invoked_subcommand is None: + text = open('texts/search.md').read() + em = discord.Embed(title='Commandes de search TuxBot', + description=text, + colour=0x89C4F9) + await ctx.send(embed=em) + @_search.command(pass_context=True, name="docubuntu") + async def search_docubuntu(self, ctx, args): + attends = await ctx.send("_Je te cherche ça {} !_".format( + ctx.message.author.mention)) + html = urllib.request.urlopen("https://doc.ubuntu-fr.org/" + + args).read() + if "avez suivi un lien" in str(html): + await attends.edit(content=":sob: Nooooon ! Cette page n'existe " + "pas, mais tu peux toujours la créer : " + "https://doc.ubuntu-fr.org/" + args) + else: + await attends.delete() + embed = discord.Embed(description="Voila j'ai trouvé ! Voici la " + "page ramenant à votre recherche," + " toujours aussi bien rédigée " + ":wink: : https://doc.ubuntu-fr." + "org/" + args, + url='http://doc.ubuntu-fr.org/') + embed.set_author(name="DocUbuntu-Fr", + url='http://doc.ubuntu-fr.org/', + icon_url='https://tuxbot.outout.xyz/data/ubuntu.png') + embed.set_thumbnail(url='https://tuxbot.outout.xyz/data/ubuntu.png') + embed.set_footer(text="Merci à ceux qui ont pris le temps d'écrire " + "cette documentation") + await ctx.send(embed=embed) + @_search.command(pass_context=True, name="docarch") + async def search_docarch(self, ctx, args): + attends = await ctx.send("_Je te cherche ça {} !_".format( + ctx.message.author.mention)) + html = urllib.request.urlopen("https://wiki.archlinux.org/index.php/" + + args).read() + if "There is currently no text in this page" in str(html): + await attends.edit(content=":sob: Nooooon ! Cette page n'existe " + "pas.") + else: + await attends.delete() + embed = discord.Embed(description="Voila j'ai trouvé ! Voici la " + "page ramenant à votre recherche," + " toujours aussi bien rédigée " + ":wink: : https://wiki.archlinux." + "org/index.php/" + args, + url='https://wiki.archlinux.org/index.php/') + embed.set_author(name="Doc ArchLinux", + url='https://wiki.archlinux.org/index.php/', + icon_url='https://tuxbot.outout.xyz/data/arch.png') + embed.set_thumbnail(url='https://tuxbot.outout.xyz/data/arch.png') + embed.set_footer(text="Merci à ceux qui ont pris le temps d'écrire " + "cette documentation") + await ctx.send(embed=embed) + @_search.command(pass_context=True, name="wikipedia") + async def search_wikipedia(self, ctx: commands.Context, args): + """Fait une recherche sur wikipd""" - @_search.command(pass_context=True, name="docubuntu") - async def search_docubuntu(self, ctx, args): - attends = await ctx.send("_Je te cherche ça {} !_".format(ctx.message.author.mention)) - html = urllib.request.urlopen("https://doc.ubuntu-fr.org/" + args).read() - if "avez suivi un lien" in str(html): - await attends.edit(content=":sob: Nooooon ! Cette page n'existe pas, mais tu peux toujours la créer : https://doc.ubuntu-fr.org/"+ args) - else: - await attends.delete() - embed = discord.Embed(description="Voila j'ai trouvé ! Voici la page ramenant à votre recherche, toujours aussi bien rédigée :wink: : https://doc.ubuntu-fr.org/" + args, url='http://doc.ubuntu-fr.org/') - embed.set_author(name="DocUbuntu-Fr", url='http://doc.ubuntu-fr.org/', icon_url='http://outout.tech/tuxbot/ubuntu.png') - embed.set_thumbnail(url='http://outout.tech/tuxbot/ubuntu.png') - embed.set_footer(text="Merci à ceux qui ont pris le temps d'écrire cette documentation") - await ctx.send(embed=embed) + wait = await ctx.send("_Je cherche..._") + results = wikipedia.search(args) + nbmr = 0 + mmssgg = "" - @_search.command(pass_context=True, name="aur") - async def search_aur(self, ctx, args): - attends = await ctx.send("_Je te cherche ça {} !_".format(ctx.message.author.mention)) - erreur = 0 - try: - html = urllib.request.urlopen("https://aur.archlinux.org/packages/" + args).read() - except: - erreur = 1 + for value in results: + nbmr = nbmr + 1 + mmssgg = mmssgg + "**{}**: {} \n".format(str(nbmr), value) - if erreur == 1: - await attends.delete() - embed = discord.Embed(description=":sob: Je n'ai pas trouvé le packet mais j'ai lancé une petite recherche, tu y trouveras peut être ton bonheur ? https://aur.archlinux.org/packages/?K=" + args,url='https://aur.archlinux.org/') - embed.set_author(name="Aur.archlinux", url='https://aur.archlinux.org/', icon_url='http://outout.tech/tuxbot/arch.png') - embed.set_thumbnail(url='http://outout.tech/tuxbot/arch.png') - embed.set_footer(text="Pff même pas trouvé !") - await ctx.send(embed=embed) + em = discord.Embed(title='Résultats de : ' + args, + description = mmssgg, + colour=0x4ECDC4) + em.set_thumbnail(url="https://upload.wikimedia.org/wikipedia/commons/" + "2/26/Paullusmagnus-logo_%28large%29.png") + await wait.delete() - else: - await attends.delete() - embed = discord.Embed(description="Et voila, j'ai trouvé la page sur le packet : https://aur.archlinux.org/packages/{0} ! \n Ca te dit un petit ``pacaur -S {0}`` ?".format(args), url='https://aur.archlinux.org/') - embed.set_author(name="Aur.archlinux", url='https://aur.archlinux.org/', icon_url='http://outout.tech/tuxbot/arch.png') - embed.set_thumbnail(url='http://outout.tech/tuxbot/arch.png') - embed.set_footer(text="C'est vrai que pacman et pacaur sont mieux qu'APT ^^") - await ctx.send(embed=embed) + sending = ["1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟"] + def check(reaction, user): + return user == ctx.author and reaction.emoji in sending and \ + reaction.message.id == msg.id - @_search.command(pass_context=True, name="wikipedia") - async def search_wikipedia(self, ctx: commands.Context, args): - """Fait une recherche sur wikipd""" + async def waiter(future: asyncio.Future): + reaction, user = await self.bot.wait_for('reaction_add', + check=check) + future.set_result(reaction.emoji) - wait = await ctx.send("_Je cherche..._") - results = wikipedia.search(args) - nbmr = 0 - mmssgg = "" + emoji = asyncio.Future() + self.bot.loop.create_task(waiter(emoji)) - for value in results: - nbmr = nbmr + 1 - mmssgg = mmssgg + "**{}**: {} \n".format(str(nbmr), value) + msg = await ctx.send(embed=em) + for e in sending: + await msg.add_reaction(e) + if emoji.done(): + break - em = discord.Embed(title='Résultats de : ' + args, description = mmssgg, colour=0x4ECDC4) - em.set_thumbnail(url = "https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png") - await wait.delete() + while not emoji.done(): + await asyncio.sleep(0.1) - sending = ["1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟"] + sPage = int(sending.index(emoji.result())) - def check(reaction, user): - return user == ctx.author and reaction.emoji in sending and reaction.message.id == msg.id + args_ = results[sPage] - async def waiter(future: asyncio.Future): - reaction, user = await self.bot.wait_for('reaction_add', check=check) - future.set_result(reaction.emoji) - - emoji = asyncio.Future() - self.bot.loop.create_task(waiter(emoji)) - - msg = await ctx.send(embed=em) - for e in sending: - await msg.add_reaction(e) - if emoji.done(): - break - - while not emoji.done(): - await asyncio.sleep(0.1) - - sPage = int(sending.index(emoji.result())) - - args_ = results[sPage] - - try: - await msg.delete() - await ctx.trigger_typing() - wait = await ctx.send(ctx.message.author.mention + " ah ok sympa cette recherche, je l'effectue de suite !") - wp = wikipedia.page(args_) - wp_contenu = wp.summary[:200] + "..." - em = discord.Embed(title='Wikipedia : ' + wp.title, description = "{} \n_Lien_ : {} ".format(wp_contenu, wp.url), colour=0x9B59B6) - em.set_author(name="Wikipedia", url='http://wikipedia.org', icon_url='https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png') - em.set_thumbnail(url = "https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png") - em.set_footer(text="Merci à eux de nous fournir une encyclopédie libre !") - await wait.delete() - await ctx.send(embed=em) - - except wikipedia.exceptions.PageError: #TODO : A virer dans l'event on_error - await ctx.send(":open_mouth: Une **erreur interne** est survenue, si cela ce reproduit contactez votre administrateur ou faites une Issue sur ``github`` !") + try: + await msg.delete() + await ctx.trigger_typing() + wait = await ctx.send(ctx.message.author.mention + + " ah ok sympa cette recherche, je l'effectue de suite !") + wp = wikipedia.page(args_) + wp_contenu = wp.summary[:200] + "..." + em = discord.Embed(title='Wikipedia : ' + wp.title, + description = "{} \n_Lien_ : {} ".format( + wp_contenu, wp.url), + colour=0x9B59B6) + em.set_author(name="Wikipedia", + url='http://wikipedia.org', + icon_url='https://upload.wikimedia.org/wikipedia/' + 'commons/2/26/Paullusmagnus-logo_%28large' + '%29.png') + em.set_thumbnail(url = "https://upload.wikimedia.org/wikipedia/" + "commons/2/26/Paullusmagnus-logo_%28large" + "%29.png") + em.set_footer(text="Merci à eux de nous fournir une encyclopédie " + "libre !") + await wait.delete() + await ctx.send(embed=em) + except wikipedia.exceptions.PageError: + # TODO : A virer dans l'event on_error + await ctx.send(":open_mouth: Une **erreur interne** est survenue," + " si cela ce reproduit contactez votre" + " administrateur ou faites une Issue sur" + " ``github`` !") def setup(bot): - bot.add_cog(Search(bot)) + bot.add_cog(Search(bot)) diff --git a/cogs/send_logs.py b/cogs/send_logs.py new file mode 100755 index 0000000..e821e9e --- /dev/null +++ b/cogs/send_logs.py @@ -0,0 +1,80 @@ +from discord.ext import commands +import discord + +import datetime, socket + +class SendLogs: + """Send logs to a specific channel""" + + def __init__(self, bot): + + self.bot = bot + self.log_channel = None + self.main_server_id = int(self.bot.config.main_server_id) + + async def on_resumed(self): + em = discord.Embed(title="Et hop je me reconnecte à l'api 😃", colour=0x5cb85c) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + + async def on_ready(self): + self.log_channel = self.bot.get_channel(int(self.bot.config.log_channel_id)) + em = discord.Embed(title="Je suis opérationnel 😃", description=f"*Instance lancée sur {socket.gethostname()}*", colour=0x5cb85c) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + async def on_guild_join(self, guild: discord.Guild): + em = discord.Embed(title=f"On m'a ajouté à : {str(guild.name)} 😃", colour=0x51A351) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + + async def on_guild_remove(self, guild: discord.Guild): + em = discord.Embed(title=f"On m'a viré de : {str(guild.name)} 😦", colour=0xBD362F) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + async def on_member_join(self, member): + if member.guild.id == self.main_server_id: + em = discord.Embed(title=f"{str(member)} *`({str(member.id)})`* nous a rejoint 😃", colour=0x51A351) + em.set_footer(text="Compte crée le " + str(member.created_at), ) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + + async def on_member_remove(self, member): + if member.guild.id == self.main_server_id: + em = discord.Embed(title=f"{str(member)} *`({str(member.id)})`* nous a quitter 😦", colour=0xBD362F) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + async def on_message_delete(self, message): + if message.guild.id == self.main_server_id and not message.author.bot: + async def is_a_command(message): + prefix_lenght = len(await self.bot.get_prefix(message)) + command = (message.content.split()[0])[prefix_lenght:] + if command == '': + command = "not_a_command" + + return self.bot.get_command(str(command)) + + if await is_a_command(message) is None: + em = discord.Embed(title=f"Message supprimé dans : {str(message.channel.name)}", colour=0xBD362F) + em.add_field(name=f"{str(message.author)} *`({str(message.author.id)})`* a supprimé :", value=str(message.content)) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + + async def on_message_edit(self, before, after): + if before.guild.id == self.main_server_id and not before.author.bot: + em = discord.Embed(title="Message edité dans : " + str(before.channel.name), colour=0x0088CC) + em.add_field(name=f"{str(before.author)} *`({str(before.author.id)})`* a edité :", value=str(before.content)) + em.add_field(name="Pour remplacer par :", value=str(after.content)) + em.timestamp = datetime.datetime.utcnow() + await self.log_channel.send(embed=em) + +def setup(bot): + bot.add_cog(SendLogs(bot)) diff --git a/cogs/sondage.py b/cogs/sondage.py new file mode 100755 index 0000000..8162c0e --- /dev/null +++ b/cogs/sondage.py @@ -0,0 +1,109 @@ +from discord.ext import commands +import discord +import random +import asyncio +import datetime + + +class Sondage: + """Commandes sondage.""" + + def __init__(self, bot): + self.bot = bot + + @commands.command(pass_context=True) + async def sondage(self, ctx, *, msg="help"): + if msg != "help": + await ctx.message.delete() + options = msg.split(" | ") + time = [x for x in options if x.startswith("time=")] + if time: + time = time[0] + if time: + options.remove(time) + if len(options) <= 1: + raise commands.errors.MissingRequiredArgument + if len(options) >= 21: + return await ctx.send(ctx.message.author.mention + "> :octagonal_sign: Vous ne pouvez pas mettre plus de 20 réponses !") + if time: + time = int(time.strip("time=")) + else: + time = 0 + emoji = ['1⃣', + '2⃣', + '3⃣', + '4⃣', + '5⃣', + '6⃣', + '7⃣', + '8⃣', + '9⃣', + '🔟', + '0⃣', + '🇦', + '🇧', + '🇨', + '🇩', + '🇪', + '🇫', + '🇬', + '🇭', + '🇮' + ] + to_react = [] + confirmation_msg = "**{}?**:\n\n".format(options[0].rstrip("?")) + for idx, option in enumerate(options[1:]): + confirmation_msg += "{} - {}\n".format(emoji[idx], option) + to_react.append(emoji[idx]) + confirmation_msg += "*Sondage proposé par* " + \ + str(ctx.message.author.mention) + if time == 0: + confirmation_msg += "" + else: + confirmation_msg += "\n\nVous avez {} secondes pour voter!".\ + format(time) + poll_msg = await ctx.send(confirmation_msg) + for emote in to_react: + await poll_msg.add_reaction(emote) + + if time != 0: + await asyncio.sleep(time) + + if time != 0: + async for message in ctx.message.channel.history(): + if message.id == poll_msg.id: + poll_msg = message + results = {} + for reaction in poll_msg.reactions: + if reaction.emoji in to_react: + results[reaction.emoji] = reaction.count - 1 + end_msg = "Le sondage est términé. Les résultats sont:\n\n" + for result in results: + end_msg += "{} {} - {} votes\n".\ + format(result, + options[emoji.index(result)+1], + results[result]) + top_result = max(results, key=lambda key: results[key]) + if len([x for x in results + if results[x] == results[top_result]]) > 1: + top_results = [] + for key, value in results.items(): + if value == results[top_result]: + top_results.append(options[emoji.index(key)+1]) + end_msg += "\nLes gagnants sont : {}".\ + format(", ".join(top_results)) + else: + top_result = options[emoji.index(top_result)+1] + end_msg += "\n\"{}\" est le gagnant!".format(top_result) + await ctx.send(end_msg) + else: + await ctx.message.delete() + + text = open('texts/rpoll.md').read() + em = discord.Embed(title='Aide sur le sondage', + description=text, + colour=0xEEEEEE) + await ctx.send(embed=em) + +def setup(bot): + bot.add_cog(Sondage(bot)) diff --git a/cogs/utility.py b/cogs/utility.py index b7bb422..c886116 100755 --- a/cogs/utility.py +++ b/cogs/utility.py @@ -1,242 +1,284 @@ from discord.ext import commands -from random import choice, shuffle -import random -import aiohttp -import asyncio -import time import discord -import urllib.request, json +import random +import json import datetime, pytz - -from datetime import date import calendar + import requests +import urllib class Utility: - """Commandes utilitaires.""" + """Commandes utilitaires.""" - def __init__(self, bot): - self.bot = bot + def __init__(self, bot): + self.bot = bot - @commands.command() - async def clock(self, ctx, args): - """Display hour in a country""" - args = args.upper() - then = datetime.datetime.now(pytz.utc) - form = '%H heures %M' - try: - argument = args[1] - if args == "MONTREAL": - utc = then.astimezone(pytz.timezone('America/Montreal')) - site = "http://ville.montreal.qc.ca/" - img = "https://upload.wikimedia.org/wikipedia/commons/e/e0/Rentier_fws_1.jpg" - country = "au Canada, Québec" - description = "Montréal est la deuxième ville la plus peuplée du Canada. Elle se situe dans la région du Québec" - elif args == "VANCOUVER": - utc = then.astimezone(pytz.timezone('America/Vancouver')) - site = "http://vancouver.ca/" - img = "https://upload.wikimedia.org/wikipedia/commons/f/fe/Dock_Vancouver.JPG" - country = "au Canada" - description = "Vancouver, officiellement City of Vancouver, est une cité portuaire au Canada" - elif args == "NEW-YORK" or args == "N-Y": - utc = then.astimezone(pytz.timezone('America/New_York')) - site = "http://www1.nyc.gov/" - img = "https://upload.wikimedia.org/wikipedia/commons/e/e3/NewYork_LibertyStatue.jpg" - country = "aux U.S.A." - description = "New York, est la plus grande ville des États-Unis en termes d'habitants et l'une des plus importantes du continent américain. " - elif args == "LOSANGELES" or args == "L-A" or args == "LA" or args == "LACITY": - utc = then.astimezone(pytz.timezone('America/Los_Angeles')) - site = "https://www.lacity.org/" - img = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/LA_Skyline_Mountains2.jpg/800px-LA_Skyline_Mountains2.jpg" - country = "aux U.S.A." - description = "Los Angeles est la deuxième ville la plus peuplée des États-Unis après New York. Elle est située dans le sud de l'État de Californie, sur la côte pacifique." - elif args == "PARIS": - utc = then.astimezone(pytz.timezone('Europe/Paris')) - site = "http://www.paris.fr/" - img = "https://upload.wikimedia.org/wikipedia/commons/a/af/Tour_eiffel_at_sunrise_from_the_trocadero.jpg" - country = "en France" - description = "Paris est la capitale de la France. Elle se situe au cœur d'un vaste bassin sédimentaire aux sols fertiles et au climat tempéré, le bassin parisien." - elif args == "BERLIN": - utc = then.astimezone(pytz.timezone('Europe/Berlin')) - site = "http://www.berlin.de/" - img = "https://upload.wikimedia.org/wikipedia/commons/9/91/Eduard_Gaertner_Schlossfreiheit.jpg" - country = "en Allemagne" - description = "Berlin est la capitale et la plus grande ville d'Allemagne. Située dans le nord-est du pays, elle compte environ 3,5 millions d'habitants. " - elif args == "BERN" or args == "ZURICH" or args == "BERNE": - utc = then.astimezone(pytz.timezone('Europe/Zurich')) - site = "http://www.berne.ch/" - img = "https://upload.wikimedia.org/wikipedia/commons/d/db/Justitia_Statue_02.jpg" - country = "en Suisse" - description = "Berne est la cinquième plus grande ville de Suisse et la capitale du canton homonyme. Depuis 1848, Berne est la « ville fédérale »." - elif args == "TOKYO": - utc = then.astimezone(pytz.timezone('Asia/Tokyo')) - site = "http://www.gotokyo.org/" - img = "https://upload.wikimedia.org/wikipedia/commons/3/37/TaroTokyo20110213-TokyoTower-01.jpg" - country = "au Japon" - description = "Tokyo, anciennement Edo, officiellement la préfecture métropolitaine de Tokyo, est la capitale du Japon." - elif args == "MOSCOU": - utc = then.astimezone(pytz.timezone('Europe/Moscow')) - site = "https://www.mos.ru/" - img = "https://upload.wikimedia.org/wikipedia/commons/f/f7/Andreyevsky_Zal.jpg" - country = "en Russie" - description = "Moscou est la capitale de la Fédération de Russie et la plus grande ville d'Europe. Moscou est situé sur la rivière Moskova. " - try: - if args == "LIST": - text = open('texts/clocks.md').read() - em = discord.Embed(title='Liste des Horloges', description=text, colour=0xEEEEEE) - await ctx.send(embed=em) - else: - tt = utc.strftime(form) - em = discord.Embed(title='Heure à ' + args.title(), description="A [{}]({}) {}, Il est **{}** ! \n {} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_".format(str(args), site, str(country), str(tt), str(description)), colour=0xEEEEEE) - em.set_thumbnail(url = img) - await ctx.send(embed=em) - except UnboundLocalError: - await ctx.send("[**Erreur**] Ville inconnue, faites ``.clock list`` pour obtenir la liste des villes") - except IndexError: - await ctx.send("[**Erreur**] Ville inconnue, faites ``.clock list`` pour obtenir la liste des villes") + @commands.group(name="clock", pass_context=True, case_insensitive=True) + async def clock(self, ctx): + """Display hour in a country""" - """--------------------------------------------------------------------------------------------------------------------------""" + if ctx.invoked_subcommand is None: + text = open('texts/clocks.md').read() + em = discord.Embed(title='Liste des Horloges', description=text, colour=0xEEEEEE) + await ctx.send(embed=em) - @commands.command() - async def ytdiscover(self, ctx): - """Random youtube channel""" - with open('texts/ytb.json') as js: - ytb = json.load(js) + @clock.command(name="montréal", aliases=["mtl", "montreal"], pass_context=True) + async def clock_montreal(self, ctx): + then = datetime.datetime.now(pytz.utc) - clef = str(random.randint(0,12)) - chaine = ytb["{}".format(clef)] + utc = then.astimezone(pytz.timezone('America/Montreal')) + site = "http://ville.montreal.qc.ca/" + img = "https://upload.wikimedia.org/wikipedia/commons/e/e0/Rentier_fws_1.jpg" + country = "au Canada, Québec" + description = "Montréal est la deuxième ville la plus peuplée du Canada. Elle se situe dans la région du Québec" - embed = discord.Embed(title=chaine['name'], url=chaine['url'], - description="**{}**, {} \n[Je veux voir ça]({})".format(chaine['name'], chaine['desc'], chaine['url'])) - embed.set_thumbnail(url='https://outout.tech/tuxbot/yt.png') - await ctx.send(embed=embed) + form = '%H heures %M' + tt = utc.strftime(form) - """--------------------------------------------------------------------------------------------------------------------------""" + em = discord.Embed(title='Heure à Montréal', description=f"A [Montréal]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) - @commands.command(pass_context=True) - async def afk(self, ctx): - """Away from keyboard""" - msgs = ["s'absente de discord quelques instants", "se casse de son pc", "va sortir son chien", "reviens bientôt", "va nourrir son cochon", "va manger des cookies", "va manger de la poutine", "va faire caca", "va faire pipi"] - msg = random.choice(msgs) + @clock.command(name="vancouver", pass_context=True) + async def clock_vancouver(self, ctx): + then = datetime.datetime.now(pytz.utc) - await ctx.send("**{}** {}...".format(ctx.message.author.mention, msg)) + utc = then.astimezone(pytz.timezone('America/Vancouver')) + site = "http://vancouver.ca/" + img = "https://upload.wikimedia.org/wikipedia/commons/f/fe/Dock_Vancouver.JPG" + country = "au Canada" + description = "Vancouver, officiellement City of Vancouver, est une cité portuaire au Canada" - """--------------------------------------------------------------------------------------------------------------------------""" + form = '%H heures %M' + tt = utc.strftime(form) - @commands.command(pass_context=True) - async def back(self, ctx): - """I'm back !""" - msgs = ["a réssuscité", "est de nouveau parmi nous", "a fini de faire caca", "a fini d'urine", "n'est plus mort", "est de nouveau sur son PC", "a fini de manger sa poutine", "a fini de danser", "s'est réveillé", "est de retour dans ce monde cruel"] - msg = random.choice(msgs) + em = discord.Embed(title='Heure à Vancouver', description=f"A [Vancouver]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) - await ctx.send("**{}** {} !".format(ctx.message.author.mention, msg)) + @clock.command(name="new-york",aliases=["ny", "n-y", "new york"], pass_context=True) + async def clock_new_york(self, ctx): + then = datetime.datetime.now(pytz.utc) - """--------------------------------------------------------------------------------------------------------------------------""" + utc = then.astimezone(pytz.timezone('America/New_York')) + site = "http://www1.nyc.gov/" + img = "https://upload.wikimedia.org/wikipedia/commons/e/e3/NewYork_LibertyStatue.jpg" + country = "aux U.S.A." + description = "New York, est la plus grande ville des États-Unis en termes d'habitants et l'une des plus importantes du continent américain. " - @commands.command(pass_context=True) - async def sondage(self, ctx, *, msg): - """Create a poll using reactions. >help rpoll for more information. - >rpoll | | - Create a poll. You may use as many answers as you want, placing a pipe | symbol in between them. - Example: - >rpoll What is your favorite anime? | Steins;Gate | Naruto | Attack on Titan | Shrek - You can also use the "time" flag to set the amount of time in seconds the poll will last for. - Example: - >rpoll What time is it? | HAMMER TIME! | SHOWTIME! | time=10 - """ - await ctx.message.delete() - options = msg.split(" | ") - time = [x for x in options if x.startswith("time=")] - if time: - time = time[0] - if time: - options.remove(time) - if len(options) <= 1: - raise commands.errors.MissingRequiredArgument - if len(options) >= 11: - return await ctx.send("Vous ne pouvez mettre que 9 options de réponse ou moins.") - if time: - time = int(time.strip("time=")) - else: - time = 0 - emoji = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣'] - to_react = [] - confirmation_msg = "**{}?**:\n\n".format(options[0].rstrip("?")) - for idx, option in enumerate(options[1:]): - confirmation_msg += "{} - {}\n".format(emoji[idx], option) - to_react.append(emoji[idx]) - confirmation_msg += "*Sondage proposé par* "+str(ctx.message.author.mention) - if time == 0: - confirmation_msg += "" - else: - confirmation_msg += "\n\nVous avez {} secondes pour voter!".format(time) - poll_msg = await ctx.send(confirmation_msg) - for emote in to_react: - await poll_msg.add_reaction(emote) + form = '%H heures %M' + tt = utc.strftime(form) - if time != 0: - await asyncio.sleep(time) + em = discord.Embed(title='Heure à New York', description=f"A [str(New York]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) + + @clock.command(name="la", aliases=["los-angeles", "losangeles", "l-a", "los angeles"], pass_context=True) + async def clock_la(self, ctx): + then = datetime.datetime.now(pytz.utc) - if time != 0: - async for message in ctx.message.channel.history(): - if message.id == poll_msg.id: - poll_msg = message - results = {} - for reaction in poll_msg.reactions: - if reaction.emoji in to_react: - results[reaction.emoji] = reaction.count - 1 - end_msg = "Le sondage est términé. Les résultats sont:\n\n" - for result in results: - end_msg += "{} {} - {} votes\n".format(result, options[emoji.index(result)+1], results[result]) - top_result = max(results, key=lambda key: results[key]) - if len([x for x in results if results[x] == results[top_result]]) > 1: - top_results = [] - for key, value in results.items(): - if value == results[top_result]: - top_results.append(options[emoji.index(key)+1]) - end_msg += "\nLes gagnants sont : {}".format(", ".join(top_results)) - else: - top_result = options[emoji.index(top_result)+1] - end_msg += "\n\"{}\" est le gagnant!".format(top_result) - await ctx.send(end_msg) + utc = then.astimezone(pytz.timezone('America/Los_Angeles')) + site = "https://www.lacity.org/" + img = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/LA_Skyline_Mountains2.jpg/800px-LA_Skyline_Mountains2.jpg" + country = "aux U.S.A." + description = "Los Angeles est la deuxième ville la plus peuplée des États-Unis après New York. Elle est située dans le sud de l'État de Californie, sur la côte pacifique." - - """--------------------------------------------------------------------------------------------------------------------------""" + form = '%H heures %M' + tt = utc.strftime(form) - @commands.command(pass_context=True) - async def sondage_aide(self, ctx): - await ctx.message.delete() + em = discord.Embed(title='Heure à Los Angeles', description=f"A [Los Angeles]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) + + @clock.command(name="paris", aliases=["baguette"],pass_context=True) + async def clock_paris(self, ctx): + then = datetime.datetime.now(pytz.utc) - text = open('texts/rpoll.md').read() - em = discord.Embed(title='Aide sur le sondage', description=text, colour=0xEEEEEE) - await ctx.send(embed=em) + utc = then.astimezone(pytz.timezone('Europe/Paris')) + site = "http://www.paris.fr/" + img = "https://upload.wikimedia.org/wikipedia/commons/a/af/Tour_eiffel_at_sunrise_from_the_trocadero.jpg" + country = "en France" + description = "Paris est la capitale de la France. Elle se situe au cœur d'un vaste bassin sédimentaire aux sols fertiles et au climat tempéré, le bassin parisien." - """--------------------------------------------------------------------------------------------------------------------------""" + form = '%H heures %M' + tt = utc.strftime(form) - @commands.command(name='hastebin', pass_context=True) - async def _hastebin(self, ctx, *, data): - """Poster sur Hastebin.""" - await ctx.message.delete() + em = discord.Embed(title='Heure à Paris', description=f"A [Paris]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) + + @clock.command(name="berlin", pass_context=True) + async def clock_berlin(self, ctx): + then = datetime.datetime.now(pytz.utc) - post = requests.post("https://hastebin.com/documents", data=data) + utc = then.astimezone(pytz.timezone('Europe/Berlin')) + site = "http://www.berlin.de/" + img = "https://upload.wikimedia.org/wikipedia/commons/9/91/Eduard_Gaertner_Schlossfreiheit.jpg" + country = "en Allemagne" + description = "Berlin est la capitale et la plus grande ville d'Allemagne. Située dans le nord-est du pays, elle compte environ 3,5 millions d'habitants. " - try: - await ctx.send(str(ctx.message.author.mention)+" message posté avec succes sur :\nhttps://hastebin.com/{}.txt".format(post.json()["key"])) - except json.JSONDecodeError: - await ctx.send("Impossible de poster ce message. L'API doit etre HS.") + form = '%H heures %M' + tt = utc.strftime(form) - @commands.command(name='test', pass_context=True) - async def test(self, ctx): + em = discord.Embed(title='Heure à Berlin', description=f"A [Berlin]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) + + @clock.command(name="berne", aliases=["zurich", "bern"], pass_context=True) + async def clock_berne(self, ctx): + then = datetime.datetime.now(pytz.utc) - date = datetime.datetime.now() + utc = then.astimezone(pytz.timezone('Europe/Zurich')) + site = "http://www.berne.ch/" + img = "https://upload.wikimedia.org/wikipedia/commons/d/db/Justitia_Statue_02.jpg" + country = "en Suisse" + description = "Berne est la cinquième plus grande ville de Suisse et la capitale du canton homonyme. Depuis 1848, Berne est la « ville fédérale »." - nd = str(date.day) - nd += "-" - nd += str(date.month) - nd += "-" - nd += str(date.year) + form = '%H heures %M' + tt = utc.strftime(form) - await ctx.send(nd) + em = discord.Embed(title='Heure à Berne', description=f"A [Berne]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) + + @clock.command(name="tokyo", pass_context=True) + async def clock_tokyo(self, ctx): + then = datetime.datetime.now(pytz.utc) + + utc = then.astimezone(pytz.timezone('Asia/Tokyo')) + site = "http://www.gotokyo.org/" + img = "https://upload.wikimedia.org/wikipedia/commons/3/37/TaroTokyo20110213-TokyoTower-01.jpg" + country = "au Japon" + description = "Tokyo, anciennement Edo, officiellement la préfecture métropolitaine de Tokyo, est la capitale du Japon." + + form = '%H heures %M' + tt = utc.strftime(form) + + em = discord.Embed(title='Heure à Tokyo', description=f"A [Tokyo]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) + + @clock.command(name="moscou", aliases=["moscow", "moskova"], pass_context=True) + async def clock_moscou(self, ctx): + then = datetime.datetime.now(pytz.utc) + + utc = then.astimezone(pytz.timezone('Europe/Moscow')) + site = "https://www.mos.ru/" + img = "https://upload.wikimedia.org/wikipedia/commons/f/f7/Andreyevsky_Zal.jpg" + country = "en Russie" + description = "Moscou est la capitale de la Fédération de Russie et la plus grande ville d'Europe. Moscou est situé sur la rivière Moskova. " + + form = '%H heures %M' + tt = utc.strftime(form) + + em = discord.Embed(title='Heure à Moscou', description=f"A [Moscou]({site}) {country}, Il est **{str(tt)}** ! \n {description} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_", colour=0xEEEEEE) + em.set_thumbnail(url = img) + await ctx.send(embed=em) + + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command() + async def ytdiscover(self, ctx): + """Random youtube channel""" + with open('texts/ytb.json') as js: + ytb = json.load(js) + + clef = str(random.randint(0,12)) + chaine = ytb["{}".format(clef)] + + embed = discord.Embed(title=chaine['name'], + url=chaine['url'], + description=f"**{chaine['name']}**, {chaine['desc']} \n[Je veux voir ça]({chaine['url']})") + embed.set_thumbnail(url='https://outout.tech/tuxbot/yt.png') + await ctx.send(embed=embed) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command(name='hastebin', pass_context=True) + async def _hastebin(self, ctx, *, data): + """Poster sur Hastebin.""" + await ctx.message.delete() + + post = requests.post("https://hastebin.com/documents", data=data) + + try: + await ctx.send(f"{ctx.message.author.mention} message posté avec succès sur :\nhttps://hastebin.com/{post.json()['key']}.txt") + except json.JSONDecodeError: + await ctx.send("Impossible de poster ce message. L'API doit être HS.") + + """---------------------------------------------------------------------""" + + @commands.command(name='iplocalise', pass_context=True) + async def _iplocalise(self, ctx, ipaddress): + """Recup headers.""" + if ipaddress.startswith("http://"): + ipaddress = ipaddress.split("http://")[1] + if ipaddress.startswith("https://"): + ipaddress = ipaddress.split("https://")[1] + iploading = await ctx.send("_réfléchis..._") + ipapi = urllib.request.urlopen("http://ip-api.com/json/" + ipaddress) + ipinfo = json.loads(ipapi.read().decode()) + + if ipinfo["status"] != "fail": + await iploading.edit(content="L'adresse IP ``{query}`` appartient à ``{org}`` et se situe à ``{city}``, dans ``{regionName}``, ``{country}``.".format(**ipinfo)) + else: + await iploading.edit(content=f"Erreur, impossible d'avoir des informations sur l'adresse IP {ipinfo['query']}") + + """--------------------------------------------------------------------------------------------------------------------------""" + @commands.command(name='getheaders', pass_context=True) + async def _getheaders(self, ctx, *, adresse): + """Recuperer les HEADERS :d""" + print("Loaded") + if adresse.startswith("http://") != True and adresse.startswith("https://") != True: + adresse = "http://" + adresse + if len(adresse) > 200: + await ctx.send("{0} Essaye d'entrer une adresse de moins de 200 caractères plutôt.".format(ctx.author.mention)) + elif adresse.startswith("http://") or adresse.startswith("https://") or adresse.startswith("ftp://"): + try: + get = urllib.request.urlopen(adresse, timeout = 1) + embed = discord.Embed(title="Entêtes de {0}".format(adresse), color=0xd75858) + embed.add_field(name="Code Réponse", value=get.getcode(), inline = True) + embed.set_thumbnail(url="https://http.cat/{}".format(str(get.getcode()))) + if get.getheader('location'): + embed.add_field(name="Redirection vers", value=get.getheader('location'), inline=True) + if get.getheader('server'): + embed.add_field(name="Serveur", value=get.getheader('server'), inline=True) + if get.getheader('content-type'): + embed.add_field(name="Type de contenu", value = get.getheader('content-type'), inline = True) + if get.getheader('x-content-type-options'): + embed.add_field(name="x-content-type", value= get.getheader('x-content-type-options'), inline=True) + if get.getheader('x-frame-options'): + embed.add_field(name="x-frame-options", value= get.getheader('x-frame-options'), inline=True) + if get.getheader('cache-control'): + embed.add_field(name="Controle du cache", value = get.getheader('cache-control'), inline = True) + await ctx.send(embed=embed) + except urllib.error.HTTPError as e: + embed = discord.Embed(title="Entêtes de {0}".format(adresse), color=0xd75858) + embed.add_field(name="Code Réponse", value=e.getcode(), inline = True) + embed.set_thumbnail(url="https://http.cat/{}".format(str(e.getcode()))) + await ctx.send(embed=embed) + print('''An error occurred: {} The response code was {}'''.format(e, e.getcode())) + except urllib.error.URLError as e: + print("ERROR @ getheaders @ urlerror : {} - adress {}".format(e, adresse)) + await ctx.send('[CONTACTER ADMIN] URLError: {}'.format(e.reason)) + except Exception as e: + print("ERROR @ getheaders @ Exception : {} - adress {}".format(e, adresse)) + await ctx.send("{0} Impossible d'accèder à {1}, es-tu sur que l'adresse {1} est correcte et que le serveur est allumé ?".format(ctx.author.mention, adresse)) + else: + await ctx.send("{0} Merci de faire commencer {1} par ``https://``, ``http://`` ou ``ftp://``.".format(ctx.message.author.mention, adresse)) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command(name='github', pass_context=True) + async def _github(ctx): + """Pour voir mon code""" + text = "How tu veux voir mon repos Github pour me disséquer ? Pas de soucis ! Je suis un Bot, je ne ressens pas la douleur !\n https://github.com/outout14/tuxbot-bot" + em = discord.Embed(title='Repos TuxBot-Bot', description=text, colour=0xE9D460) + em.set_author(name='Outout', icon_url="https://avatars0.githubusercontent.com/u/14958554?v=3&s=400") + await ctx.send(embed=em) def setup(bot): - bot.add_cog(Utility(bot)) + bot.add_cog(Utility(bot)) diff --git a/cogs/utils/__pycache__/__init__.cpython-35.pyc b/cogs/utils/__pycache__/__init__.cpython-35.pyc new file mode 100644 index 0000000..728222e Binary files /dev/null and b/cogs/utils/__pycache__/__init__.cpython-35.pyc differ diff --git a/cogs/utils/__pycache__/__init__.cpython-36.pyc b/cogs/utils/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..731a5d3 Binary files /dev/null and b/cogs/utils/__pycache__/__init__.cpython-36.pyc differ diff --git a/cogs/utils/__pycache__/__init__.cpython-37.pyc b/cogs/utils/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000..d1286a1 Binary files /dev/null and b/cogs/utils/__pycache__/__init__.cpython-37.pyc differ diff --git a/cogs/utils/__pycache__/checks.cpython-35.pyc b/cogs/utils/__pycache__/checks.cpython-35.pyc new file mode 100644 index 0000000..d194d57 Binary files /dev/null and b/cogs/utils/__pycache__/checks.cpython-35.pyc differ diff --git a/cogs/utils/__pycache__/checks.cpython-36.pyc b/cogs/utils/__pycache__/checks.cpython-36.pyc new file mode 100644 index 0000000..257116e Binary files /dev/null and b/cogs/utils/__pycache__/checks.cpython-36.pyc differ diff --git a/cogs/utils/__pycache__/checks.cpython-37.pyc b/cogs/utils/__pycache__/checks.cpython-37.pyc new file mode 100644 index 0000000..50c0fa1 Binary files /dev/null and b/cogs/utils/__pycache__/checks.cpython-37.pyc differ diff --git a/cogs/utils/__pycache__/cli_colors.cpython-36.pyc b/cogs/utils/__pycache__/cli_colors.cpython-36.pyc new file mode 100644 index 0000000..a22d821 Binary files /dev/null and b/cogs/utils/__pycache__/cli_colors.cpython-36.pyc differ diff --git a/cogs/utils/__pycache__/cli_colors.cpython-37.pyc b/cogs/utils/__pycache__/cli_colors.cpython-37.pyc new file mode 100644 index 0000000..3c44c72 Binary files /dev/null and b/cogs/utils/__pycache__/cli_colors.cpython-37.pyc differ diff --git a/cogs/utils/__pycache__/db.cpython-36.pyc b/cogs/utils/__pycache__/db.cpython-36.pyc new file mode 100644 index 0000000..5f43e71 Binary files /dev/null and b/cogs/utils/__pycache__/db.cpython-36.pyc differ diff --git a/cogs/utils/__pycache__/db.cpython-37.pyc b/cogs/utils/__pycache__/db.cpython-37.pyc new file mode 100644 index 0000000..250e0b4 Binary files /dev/null and b/cogs/utils/__pycache__/db.cpython-37.pyc differ diff --git a/cogs/utils/__pycache__/paginator.cpython-36.pyc b/cogs/utils/__pycache__/paginator.cpython-36.pyc new file mode 100644 index 0000000..043c87f Binary files /dev/null and b/cogs/utils/__pycache__/paginator.cpython-36.pyc differ diff --git a/cogs/utils/__pycache__/paginator.cpython-37.pyc b/cogs/utils/__pycache__/paginator.cpython-37.pyc new file mode 100644 index 0000000..1a93cbd Binary files /dev/null and b/cogs/utils/__pycache__/paginator.cpython-37.pyc differ diff --git a/cogs/utils/__pycache__/passport_generator.cpython-36.pyc b/cogs/utils/__pycache__/passport_generator.cpython-36.pyc new file mode 100644 index 0000000..2ab7013 Binary files /dev/null and b/cogs/utils/__pycache__/passport_generator.cpython-36.pyc differ diff --git a/cogs/utils/__pycache__/passport_generator.cpython-37.pyc b/cogs/utils/__pycache__/passport_generator.cpython-37.pyc new file mode 100644 index 0000000..f17e332 Binary files /dev/null and b/cogs/utils/__pycache__/passport_generator.cpython-37.pyc differ diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 5f8fd47..91e291d 100755 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -1,75 +1,101 @@ -# -*- coding: utf-8 -*- -import discord.utils from discord.ext import commands -def is_owner_check(message): # OUTOUT id RICK id L4P1N id GIGA id FLAYOR id ROMAIN id - owner = str(message.author.id) in ['171685542553976832', '163697401935298560', '88644904112128000', '92619860521005056', '273757386127441920', '269156684155453451'] ###ID's modo & admin - rights = str(message.author.top_role.name).upper() in ['ADMIN', 'ADMINISTRATEURS', 'ADMINISTRATEUR', 'MODO', 'MODÉRATEUR', 'MODÉRATEURS', 'MODERATEUR', 'MODERATEURS'] - if rights == True or owner == True: - return True # Owner of the bot - else: - return False +def is_owner_check(message): + return str(message.author.id) in ['171685542553976832', '269156684155453451'] def is_owner(warn=True): - def check(ctx, warn): - owner = is_owner_check(ctx.message) - if not owner and warn: - print(ctx.message.author.name + " à essayer d'executer " + ctx.message.content) - return owner + def check(ctx, warn): + owner = is_owner_check(ctx.message) + if not owner and warn: + print(ctx.message.author.name + " à essayer d'executer " + ctx.message.content + " sur le serveur " + ctx.message.guild.name) + return owner - owner = commands.check(lambda ctx: check(ctx, warn)) - return owner + owner = commands.check(lambda ctx: check(ctx, warn)) + return owner -def check_permissions(ctx, perms): - msg = ctx.message - if is_owner_check(msg): - return True +"""--------------------------------------------------------------------------------------------------------------------------""" - ch = msg.channel - author = msg.author - resolved = ch.permissions_for(author) - return all(getattr(resolved, name, None) == value for name, value in perms.items()) +async def check_permissions(ctx, perms, *, check=all): + is_owner = await ctx.bot.is_owner(ctx.author) + if is_owner or is_owner_check(ctx.message) == True: + return True + resolved = ctx.channel.permissions_for(ctx.author) + return check(getattr(resolved, name, None) == value for name, value in perms.items()) -def role_or_permissions(ctx, check, **perms): - if check_permissions(ctx, perms): - return True +def has_permissions(*, check=all, **perms): + async def pred(ctx): + return await check_permissions(ctx, perms, check=check) + return commands.check(pred) - ch = ctx.message.channel - author = ctx.message.author - if ch.is_private: - return False # can't have roles in PMs +async def check_guild_permissions(ctx, perms, *, check=all): + is_owner = await ctx.bot.is_owner(ctx.author) + if is_owner: + return True - role = discord.utils.find(check, author.roles) - return role is not None + if ctx.guild is None: + return False + resolved = ctx.author.guild_permissions + return check(getattr(resolved, name, None) == value for name, value in perms.items()) -def admin_or_permissions(**perms): - def predicate(ctx): - return role_or_permissions(ctx, lambda r: r.name == 'Bot Admin', **perms) +def has_guild_permissions(*, check=all, **perms): + async def pred(ctx): + return await check_guild_permissions(ctx, perms, check=check) + return commands.check(pred) - return commands.check(predicate) - - -def is_in_servers(*server_ids): - def predicate(ctx): - server = ctx.message.server - if server is None: - return False - return server.id in server_ids - - return commands.check(predicate) - -def embed_perms(message): - try: - check = message.author.permissions_in(message.channel).embed_links - except: - check = True - - return check +# These do not take channel overrides into account def is_mod(): - async def pred(ctx): - return await check_guild_permissions(ctx, {'manage_guild': True}) - return commands.check(pred) \ No newline at end of file + async def pred(ctx): + return await check_guild_permissions(ctx, {'manage_guild': True}) + return commands.check(pred) + +def is_admin(): + async def pred(ctx): + return await check_guild_permissions(ctx, {'administrator': True}) + return commands.check(pred) + +def mod_or_permissions(**perms): + perms['manage_guild'] = True + async def predicate(ctx): + return await check_guild_permissions(ctx, perms, check=any) + return commands.check(predicate) + +def admin_or_permissions(**perms): + perms['administrator'] = True + async def predicate(ctx): + return await check_guild_permissions(ctx, perms, check=any) + return commands.check(predicate) + +def is_in_guilds(*guild_ids): + def predicate(ctx): + guild = ctx.guild + if guild is None: + return False + return guild.id in guild_ids + return commands.check(predicate) + +def is_lounge_cpp(): + return is_in_guilds(145079846832308224) + +def get_user(message, user): + try: + member = message.mentions[0] + except: + member = message.guild.get_member_named(user) + if not member: + try: + member = message.guild.get_member(int(user)) + except ValueError: + pass + if not member: + return None + return member + +def check_date(date: str): + if len(date) == 1: + return f"0{date}" + else: + return date \ No newline at end of file diff --git a/cogs/utils/cli_colors.py b/cogs/utils/cli_colors.py new file mode 100644 index 0000000..5e5ee26 --- /dev/null +++ b/cogs/utils/cli_colors.py @@ -0,0 +1,43 @@ +class text_colors: + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + LIGHT_GRAY = '\033[37m' + DARK_GRAY = '\033[90m' + LIGHT_RED = '\033[91m' + LIGHT_GREEN = '\033[92m' + LIGHT_YELLOW = '\033[93m' + LIGHT_BLUE = '\033[94m' + LIGHT_MAGENTA = '\033[95m' + LIGHT_CYAN = '\033[96m' + WHITE = '\033[97m' + +class bg_colors: + BLACK = '\033[40m' + RED = '\033[41m' + GREEN = '\033[42m' + YELLOW = '\033[43m' + BLUE = '\033[44m' + MAGENTA = '\033[45m' + CYAN = '\033[46m' + LIGHT_GRAY = '\033[47m' + DARK_GRAY = '\033[100m' + LIGHT_RED = '\033[101m' + LIGHT_GREEN = '\033[102m' + LIGHT_YELLOW = '\033[103m' + LIGHT_BLUE = '\033[104m' + LIGHT_MAGENTA = '\033[105m' + LIGHT_CYAN = '\033[106m' + WHITE = '\033[107m' + +class text_style: + BOLD = '\033[1m' + DIM = '\033[2m' + UNDERLINE = '\033[4m' + BLINK = '\033[5m' + +ENDC = '\033[0m' \ No newline at end of file diff --git a/cogs/utils/db.py b/cogs/utils/db.py new file mode 100755 index 0000000..a5431f4 --- /dev/null +++ b/cogs/utils/db.py @@ -0,0 +1,24 @@ +import pymysql + +def connect_to_db(self): + mysqlHost = self.bot.config.mysql["host"] + mysqlUser = self.bot.config.mysql["username"] + mysqlPass = self.bot.config.mysql["password"] + mysqlDB = self.bot.config.mysql["dbname"] + + try: + return pymysql.connect(host=mysqlHost, user=mysqlUser, passwd=mysqlPass, db=mysqlDB, charset='utf8') + except KeyError: + print("Rest in peperoni, Impossible de se connecter a la base de données.") + print(str(KeyError)) + return + +def reconnect_to_db(self): + if not self.conn: + mysqlHost = self.bot.config.mysql["host"] + mysqlUser = self.bot.config.mysql["username"] + mysqlPass = self.bot.config.mysql["password"] + mysqlDB = self.bot.config.mysql["dbname"] + + return pymysql.connect(host=mysqlHost, user=mysqlUser, passwd=mysqlPass, db=mysqlDB, charset='utf8') + return self.conn \ No newline at end of file diff --git a/cogs/utils/passport_generator.py b/cogs/utils/passport_generator.py new file mode 100644 index 0000000..3ea6332 --- /dev/null +++ b/cogs/utils/passport_generator.py @@ -0,0 +1,245 @@ +from PIL import Image +from PIL import ImageOps +from PIL import ImageDraw +from PIL import ImageFont + +from .checks import check_date +import aiohttp, imghdr, textwrap, math, datetime + +async def generate_passport(self, user, theme: str = None): + name = user.name + userid = user.id + avatar = user.avatar_url + def_avatar = user.default_avatar_url + created = datetime.datetime.fromisoformat(str(user.created_at)) + nick = user.display_name + discr = user.discriminator + roles = user.roles + + top_role_color = str(user.top_role.color)[1:] + user_color = tuple(int(top_role_color[i:i+2], 16) for i in (0, 2 ,4)) + user_color += (255,) + + color = { + "dark": { + "background": 39, + "question": 220, + "answer": 150 + }, + "light": { + "background": 216, + "question": 35, + "answer": 61 + } + } + + user_birth_day = check_date(str(created.day)) + user_birth_month = check_date(str(created.month)) + + formated_user_birth = str(user_birth_day) + "/" + str(user_birth_month) + "/" + str(created.year) + formated_passportdate = "n/a" + + roleImages = {} + + def draw_underlined_text(draw, pos, text, font, **options): + twidth, theight = draw.textsize(text, font=font) + lx, ly = pos[0], pos[1] + theight + draw.text(pos, text, font=font, **options) + draw.line((lx, ly, lx + twidth, ly), **options) + + def break_line(draw, pos, text, font, **options): + lines = text.split("\n") + current_y = pos[1] + for line in lines: + twidth, theight = draw.textsize(line, font=font) + lx, ly = pos[0], current_y + if textwrap.fill(line, 60) == line: + draw.text((lx, ly), textwrap.fill(line, 60), font=font, **options) + current_y += math.floor(theight) + else: + draw.text((lx, ly), textwrap.fill(line, 60), font=font, **options) + current_y += math.floor(theight*2) + + for x, role in enumerate(roles): + try: + roleImages[role.name] = Image.open(f"data/images/roles/small/{role.name.lower().replace(' user', '')}.png") + except Exception as e: + next + + if avatar == '': + async with aiohttp.ClientSession() as session: + async with session.get(def_avatar) as r: + image = await r.content.read() + else: + async with aiohttp.ClientSession() as session: + async with session.get(avatar) as r: + image = await r.content.read() + with open('data/users/avatars/{}.png'.format(user.id), 'wb') as f: + f.write(image) + + checked = False + + while checked == False: + checks = 0 + isImage = imghdr.what('data/users/avatars/{}.png'.format(user.id)) + + if checks > 4: + checked = True + + if isImage != 'None': + checked = True + else: + checks += 1 + + av = Image.open('data/users/avatars/{}.png'.format(user.id)) + userAvatar = av.resize((128, 128), resample=Image.BILINEAR).convert('RGBA') + maxsize = ( 800, 500) + try: + bg = Image.open('data/users/backgrounds/{0}.png'.format(user.id)) + bg_width, bg_height = bg.size + + bg = ImageOps.fit(bg,maxsize) + + except: + bg = Image.open('data/images/background_default.png') + + fontFace = 'data/fonts/{}'.format(self.bot.config.fonts['normal']) + fontFace_bold = 'data/fonts/{}'.format(self.bot.config.fonts['bold']) + + fontSize = 18 + fontSizeVeryTiny = 16 + + descSizeQuestion = 10 + descSizeAnswer = 10 + + headerSize = 32 + headerSizeTiny = 24 + headerSizeVeryTiny = 16 + + header_font = ImageFont.truetype(fontFace_bold, headerSize) + header_font_tiny = ImageFont.truetype(fontFace_bold, headerSizeTiny) + header_font_very_tiny = ImageFont.truetype(fontFace_bold, headerSizeVeryTiny) + + font = ImageFont.truetype(fontFace, fontSize) + font_very_tiny = ImageFont.truetype(fontFace, fontSizeVeryTiny) + + desc_font_question = ImageFont.truetype(fontFace_bold, descSizeQuestion) + desc_font_answer = ImageFont.truetype(fontFace, descSizeAnswer) + font_bold = font = ImageFont.truetype(fontFace_bold, fontSize) + + answers = None + + self.cursor.execute("SELECT os, config, languages, pays, passportdate, theme FROM passport WHERE userid=%s", str(user.id)) + answers = self.cursor.fetchone() + + if not theme: + if answers: + theme = str(answers[5]) + else: + theme = "dark" + + cardbg = Image.new('RGBA', (800, 500), (0, 0, 0, 255)) + d = ImageDraw.Draw(cardbg) + + d.rectangle([(0, 0), 800, 500], fill=(255, 255, 255, 255)) + cardbg.paste(bg, (0, 0)) + + cardfg = Image.new('RGBA', (800, 500), (255, 255, 255, 0)) + dd = ImageDraw.Draw(cardfg) + + # Info Box Top + dd.rectangle([(60, 60), (600, 191)], fill=(color[theme]["background"], color[theme]["background"], color[theme]["background"], 200)) + dd.rectangle([(60, 60), (600, 134)], fill=(color[theme]["background"], color[theme]["background"], color[theme]["background"], 255)) + + # Avatar box + if user_color == (0, 0, 0, 255): + user_color = (color[theme]["background"], color[theme]["background"], color[theme]["background"], 255) + dd.rectangle([(609, 60), (740, 191)], fill=user_color) + cardfg.paste(userAvatar, (611, 62)) + + # Profile Information + if textwrap.fill(nick, 25) != nick: + dd.text((70, 70), nick, fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 220), font=header_font_very_tiny) + dd.text((70, 106), '@' + name + '#' + discr, fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 225), font=font_very_tiny) + elif textwrap.fill(nick, 15) != nick: + dd.text((70, 70), nick, fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 220), font=header_font_tiny) + dd.text((70, 106), '@' + name + '#' + discr, fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 225), font=font) + else: + dd.text((70, 64), nick, fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 220), font=header_font) + dd.text((70, 106), '@' + name + '#' + discr, fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 225), font=font) + + draw_underlined_text(dd, (380, 75), "Date de parution sur discord :", fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 220), font=desc_font_question) + dd.text((542, 75), formated_user_birth, fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 225), font=desc_font_answer) + + # Roles + for idy, ii in enumerate(roleImages): + + startx = int((270 - (30 * len(roleImages))) / 2) + + cardfg.paste(roleImages[ii], (197 + startx + (30 * idy),152), roleImages[ii]) + + + #Info Box Bottom + dd.rectangle([(60, 200), (740, 450)], fill=(color[theme]["background"], color[theme]["background"], color[theme]["background"], 200)) + + if answers: + passportdate = datetime.datetime.fromisoformat(answers[4]) + passportdate_day = check_date(str(passportdate.day)) + passportdate_month = check_date(str(passportdate.month)) + + formated_passportdate = str(passportdate_day) + "/" + str(passportdate_month) + "/" + str(passportdate.year) + + draw_underlined_text(dd, (80, 220), "Système(s) d'exploitation :", desc_font_question, fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 255)) + break_line( + dd, + (80, 240), + answers[0], + fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 255), + font=desc_font_answer + ) + + draw_underlined_text(dd, (80, 300), "Langages de programmation préférés :", desc_font_question, fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 255)) + break_line( + dd, + (80, 320), + answers[2], + fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 255), + font=desc_font_answer + ) + + draw_underlined_text(dd, (80, 380), "Pays :", desc_font_question, fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 255)) + break_line( + dd, + (80, 400), + answers[3], + fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 255), + font=desc_font_answer + ) + + dd.line((400, 220, 400, 430), fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 255)) + + draw_underlined_text(dd, (410, 220), "Configuration Système :", desc_font_question, fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 255)) + break_line( + dd, + (410, 240), + answers[1], + fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 255), + font=desc_font_answer + ) + + else: + dd.text( + (370, 300), + "Non renseigné.", + fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 255), + font=desc_font_question + ) + + draw_underlined_text(dd, (380, 100), "Date de création du passeport :", fill=(color[theme]["question"], color[theme]["question"], color[theme]["question"], 220), font=desc_font_question) + dd.text((542, 100), formated_passportdate, fill=(color[theme]["answer"], color[theme]["answer"], color[theme]["answer"], 225), font=desc_font_answer) + + card = Image.new('RGBA', (800, 500), (255, 255, 255, 255)) + card = Image.alpha_composite(card, cardbg) + card = Image.alpha_composite(card, cardfg) + + return card \ No newline at end of file diff --git a/config.py b/config.py new file mode 100755 index 0000000..5f6e314 --- /dev/null +++ b/config.py @@ -0,0 +1,26 @@ +token = "INSERT_TOKEN_HERE" +client_id = "INSERT_CLIENT_ID_HERE" +log_channel_id = "INSERT_LOG_CHANNEL_HERE" +main_server_id = "INSERT_MAIN_CHANNEL_ID_HERE" + +game = "PLAYING_GAME_HERE" +prefix = ["."] +description = """ +Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) +""" + +mysql = { + "host": "localhost", + "username": "msqlusername", + "password": "msqlpasswd", + "dbname": "mysqldb" +} + +authorized_id = ['admin ids here'] + +## Passport settings + +fonts = { + "normal": "NotoSansCJK-Regular.ttc", + "bold": "NotoSansCJK-Bold.ttc" +} diff --git a/data/fonts/NotoSansCJK-Bold.ttc b/data/fonts/NotoSansCJK-Bold.ttc new file mode 100755 index 0000000..09707f9 Binary files /dev/null and b/data/fonts/NotoSansCJK-Bold.ttc differ diff --git a/data/fonts/NotoSansCJK-Regular.ttc b/data/fonts/NotoSansCJK-Regular.ttc new file mode 100755 index 0000000..271526f Binary files /dev/null and b/data/fonts/NotoSansCJK-Regular.ttc differ diff --git a/data/images/background_default.light.png b/data/images/background_default.light.png new file mode 100755 index 0000000..c8089ee Binary files /dev/null and b/data/images/background_default.light.png differ diff --git a/data/images/background_default.png b/data/images/background_default.png new file mode 100755 index 0000000..1b76156 Binary files /dev/null and b/data/images/background_default.png differ diff --git a/data/images/roles/android.png b/data/images/roles/android.png new file mode 100644 index 0000000..467e13a Binary files /dev/null and b/data/images/roles/android.png differ diff --git a/data/images/roles/antergos.png b/data/images/roles/antergos.png new file mode 100755 index 0000000..4e890b9 Binary files /dev/null and b/data/images/roles/antergos.png differ diff --git a/data/images/roles/arch.png b/data/images/roles/arch.png new file mode 100755 index 0000000..c5cc227 Binary files /dev/null and b/data/images/roles/arch.png differ diff --git a/data/images/roles/bsd.png b/data/images/roles/bsd.png new file mode 100755 index 0000000..8eb3adc Binary files /dev/null and b/data/images/roles/bsd.png differ diff --git a/data/images/roles/debian.png b/data/images/roles/debian.png new file mode 100755 index 0000000..02bdd0e Binary files /dev/null and b/data/images/roles/debian.png differ diff --git a/data/images/roles/elementary.png b/data/images/roles/elementary.png new file mode 100755 index 0000000..a16f944 Binary files /dev/null and b/data/images/roles/elementary.png differ diff --git a/data/images/roles/fedora.png b/data/images/roles/fedora.png new file mode 100755 index 0000000..74c2569 Binary files /dev/null and b/data/images/roles/fedora.png differ diff --git a/data/images/roles/gentoo.png b/data/images/roles/gentoo.png new file mode 100755 index 0000000..9416575 Binary files /dev/null and b/data/images/roles/gentoo.png differ diff --git a/data/images/roles/linuxmint.png b/data/images/roles/linuxmint.png new file mode 100755 index 0000000..55a883f Binary files /dev/null and b/data/images/roles/linuxmint.png differ diff --git a/data/images/roles/manjaro.png b/data/images/roles/manjaro.png new file mode 100755 index 0000000..30e320b Binary files /dev/null and b/data/images/roles/manjaro.png differ diff --git a/data/images/roles/opensuse.png b/data/images/roles/opensuse.png new file mode 100755 index 0000000..de5a9fb Binary files /dev/null and b/data/images/roles/opensuse.png differ diff --git a/data/images/roles/rhel.png b/data/images/roles/rhel.png new file mode 100755 index 0000000..c4ce3af Binary files /dev/null and b/data/images/roles/rhel.png differ diff --git a/data/images/roles/small/android.png b/data/images/roles/small/android.png new file mode 100644 index 0000000..a573bcd Binary files /dev/null and b/data/images/roles/small/android.png differ diff --git a/data/images/roles/small/antergos.png b/data/images/roles/small/antergos.png new file mode 100755 index 0000000..41e32ec Binary files /dev/null and b/data/images/roles/small/antergos.png differ diff --git a/data/images/roles/small/arch.png b/data/images/roles/small/arch.png new file mode 100755 index 0000000..15a9cb6 Binary files /dev/null and b/data/images/roles/small/arch.png differ diff --git a/data/images/roles/small/bsd.png b/data/images/roles/small/bsd.png new file mode 100755 index 0000000..2c153a8 Binary files /dev/null and b/data/images/roles/small/bsd.png differ diff --git a/data/images/roles/small/debian.png b/data/images/roles/small/debian.png new file mode 100755 index 0000000..3c34aad Binary files /dev/null and b/data/images/roles/small/debian.png differ diff --git a/data/images/roles/small/elementaryOS.png b/data/images/roles/small/elementaryOS.png new file mode 100755 index 0000000..93dfbd0 Binary files /dev/null and b/data/images/roles/small/elementaryOS.png differ diff --git a/data/images/roles/small/fedora.png b/data/images/roles/small/fedora.png new file mode 100755 index 0000000..97df660 Binary files /dev/null and b/data/images/roles/small/fedora.png differ diff --git a/data/images/roles/small/gentoo.png b/data/images/roles/small/gentoo.png new file mode 100755 index 0000000..33029e3 Binary files /dev/null and b/data/images/roles/small/gentoo.png differ diff --git a/data/images/roles/small/macos.png b/data/images/roles/small/macos.png new file mode 100755 index 0000000..0cbcd39 Binary files /dev/null and b/data/images/roles/small/macos.png differ diff --git a/data/images/roles/small/manjaro.png b/data/images/roles/small/manjaro.png new file mode 100755 index 0000000..560c979 Binary files /dev/null and b/data/images/roles/small/manjaro.png differ diff --git a/data/images/roles/small/mint.png b/data/images/roles/small/mint.png new file mode 100755 index 0000000..beeb0d9 Binary files /dev/null and b/data/images/roles/small/mint.png differ diff --git a/data/images/roles/small/opensuse.png b/data/images/roles/small/opensuse.png new file mode 100755 index 0000000..b5f3f4f Binary files /dev/null and b/data/images/roles/small/opensuse.png differ diff --git a/data/images/roles/small/other.png b/data/images/roles/small/other.png new file mode 100755 index 0000000..edc09b0 Binary files /dev/null and b/data/images/roles/small/other.png differ diff --git a/data/images/roles/small/rhel.png b/data/images/roles/small/rhel.png new file mode 100755 index 0000000..8f72c8a Binary files /dev/null and b/data/images/roles/small/rhel.png differ diff --git a/data/images/roles/small/ubuntu.png b/data/images/roles/small/ubuntu.png new file mode 100755 index 0000000..e0ed3de Binary files /dev/null and b/data/images/roles/small/ubuntu.png differ diff --git a/data/images/roles/small/void.png b/data/images/roles/small/void.png new file mode 100755 index 0000000..26b4735 Binary files /dev/null and b/data/images/roles/small/void.png differ diff --git a/data/images/roles/small/windows.png b/data/images/roles/small/windows.png new file mode 100755 index 0000000..594d8d4 Binary files /dev/null and b/data/images/roles/small/windows.png differ diff --git a/data/images/roles/ubuntu.png b/data/images/roles/ubuntu.png new file mode 100755 index 0000000..c1b95c6 Binary files /dev/null and b/data/images/roles/ubuntu.png differ diff --git a/data/images/roles/void.png b/data/images/roles/void.png new file mode 100755 index 0000000..5d2b9fa Binary files /dev/null and b/data/images/roles/void.png differ diff --git a/data/users/avatars/124930356167049218.png b/data/users/avatars/124930356167049218.png new file mode 100755 index 0000000..e6765f6 Binary files /dev/null and b/data/users/avatars/124930356167049218.png differ diff --git a/data/users/avatars/163750228619427840.png b/data/users/avatars/163750228619427840.png new file mode 100644 index 0000000..18a4060 Binary files /dev/null and b/data/users/avatars/163750228619427840.png differ diff --git a/data/users/avatars/171685542553976832.png b/data/users/avatars/171685542553976832.png new file mode 100755 index 0000000..2933507 Binary files /dev/null and b/data/users/avatars/171685542553976832.png differ diff --git a/data/users/avatars/177093008271998976.png b/data/users/avatars/177093008271998976.png new file mode 100755 index 0000000..d66cf01 Binary files /dev/null and b/data/users/avatars/177093008271998976.png differ diff --git a/data/users/avatars/193869956214030336.png b/data/users/avatars/193869956214030336.png new file mode 100755 index 0000000..f25c56c Binary files /dev/null and b/data/users/avatars/193869956214030336.png differ diff --git a/data/users/avatars/196668513601978369.png b/data/users/avatars/196668513601978369.png new file mode 100755 index 0000000..142751f Binary files /dev/null and b/data/users/avatars/196668513601978369.png differ diff --git a/data/users/avatars/199807621794889729.png b/data/users/avatars/199807621794889729.png new file mode 100755 index 0000000..5ea6217 Binary files /dev/null and b/data/users/avatars/199807621794889729.png differ diff --git a/data/users/avatars/203874311696547851.png b/data/users/avatars/203874311696547851.png new file mode 100644 index 0000000..ffbe910 Binary files /dev/null and b/data/users/avatars/203874311696547851.png differ diff --git a/data/users/avatars/215819175640170496.png b/data/users/avatars/215819175640170496.png new file mode 100755 index 0000000..d7c7ddf Binary files /dev/null and b/data/users/avatars/215819175640170496.png differ diff --git a/data/users/avatars/218001834055303168.png b/data/users/avatars/218001834055303168.png new file mode 100644 index 0000000..e30ff5d Binary files /dev/null and b/data/users/avatars/218001834055303168.png differ diff --git a/data/users/avatars/260112844425658370.png b/data/users/avatars/260112844425658370.png new file mode 100644 index 0000000..cef8ac8 Binary files /dev/null and b/data/users/avatars/260112844425658370.png differ diff --git a/data/users/avatars/260433835353702400.png b/data/users/avatars/260433835353702400.png new file mode 100755 index 0000000..f67f02e Binary files /dev/null and b/data/users/avatars/260433835353702400.png differ diff --git a/data/users/avatars/269156684155453451.png b/data/users/avatars/269156684155453451.png new file mode 100755 index 0000000..923bca7 Binary files /dev/null and b/data/users/avatars/269156684155453451.png differ diff --git a/data/users/avatars/279395573503623169.png b/data/users/avatars/279395573503623169.png new file mode 100755 index 0000000..fc7f519 Binary files /dev/null and b/data/users/avatars/279395573503623169.png differ diff --git a/data/users/avatars/286881789392191488.png b/data/users/avatars/286881789392191488.png new file mode 100755 index 0000000..d534084 Binary files /dev/null and b/data/users/avatars/286881789392191488.png differ diff --git a/data/users/avatars/297447589438160897.png b/data/users/avatars/297447589438160897.png new file mode 100755 index 0000000..d2e5082 Binary files /dev/null and b/data/users/avatars/297447589438160897.png differ diff --git a/data/users/avatars/301062143942590465.png b/data/users/avatars/301062143942590465.png new file mode 100755 index 0000000..7342038 Binary files /dev/null and b/data/users/avatars/301062143942590465.png differ diff --git a/data/users/avatars/326770983274938370.png b/data/users/avatars/326770983274938370.png new file mode 100644 index 0000000..1eb5b62 Binary files /dev/null and b/data/users/avatars/326770983274938370.png differ diff --git a/data/users/avatars/329149664865550336.png b/data/users/avatars/329149664865550336.png new file mode 100755 index 0000000..5f07b14 Binary files /dev/null and b/data/users/avatars/329149664865550336.png differ diff --git a/data/users/avatars/331516411883159554.png b/data/users/avatars/331516411883159554.png new file mode 100755 index 0000000..678711e Binary files /dev/null and b/data/users/avatars/331516411883159554.png differ diff --git a/data/users/avatars/338003221110980608.png b/data/users/avatars/338003221110980608.png new file mode 100644 index 0000000..daf617e Binary files /dev/null and b/data/users/avatars/338003221110980608.png differ diff --git a/data/users/avatars/350647804307177474.png b/data/users/avatars/350647804307177474.png new file mode 100755 index 0000000..420d282 Binary files /dev/null and b/data/users/avatars/350647804307177474.png differ diff --git a/data/users/avatars/351115710992351234.png b/data/users/avatars/351115710992351234.png new file mode 100755 index 0000000..05c92c2 Binary files /dev/null and b/data/users/avatars/351115710992351234.png differ diff --git a/data/users/avatars/356829119499206656.png b/data/users/avatars/356829119499206656.png new file mode 100755 index 0000000..ee478a8 Binary files /dev/null and b/data/users/avatars/356829119499206656.png differ diff --git a/data/users/avatars/366544765644439563.png b/data/users/avatars/366544765644439563.png new file mode 100755 index 0000000..9f52b04 Binary files /dev/null and b/data/users/avatars/366544765644439563.png differ diff --git a/data/users/avatars/372093907158171649.png b/data/users/avatars/372093907158171649.png new file mode 100644 index 0000000..9d85811 Binary files /dev/null and b/data/users/avatars/372093907158171649.png differ diff --git a/data/users/avatars/380425790686494720.png b/data/users/avatars/380425790686494720.png new file mode 100644 index 0000000..4531157 Binary files /dev/null and b/data/users/avatars/380425790686494720.png differ diff --git a/data/users/avatars/404421267236716544.png b/data/users/avatars/404421267236716544.png new file mode 100644 index 0000000..6c5bc4c Binary files /dev/null and b/data/users/avatars/404421267236716544.png differ diff --git a/data/users/avatars/429216329610821632.png b/data/users/avatars/429216329610821632.png new file mode 100755 index 0000000..e606b50 Binary files /dev/null and b/data/users/avatars/429216329610821632.png differ diff --git a/data/users/avatars/467753460289241089.png b/data/users/avatars/467753460289241089.png new file mode 100644 index 0000000..5aa64ec Binary files /dev/null and b/data/users/avatars/467753460289241089.png differ diff --git a/data/users/avatars/477577534708645930.png b/data/users/avatars/477577534708645930.png new file mode 100644 index 0000000..a99205d Binary files /dev/null and b/data/users/avatars/477577534708645930.png differ diff --git a/data/users/avatars/478946967532339201.png b/data/users/avatars/478946967532339201.png new file mode 100755 index 0000000..34bce34 Binary files /dev/null and b/data/users/avatars/478946967532339201.png differ diff --git a/data/users/avatars/488087525286477825.png b/data/users/avatars/488087525286477825.png new file mode 100755 index 0000000..1461f83 Binary files /dev/null and b/data/users/avatars/488087525286477825.png differ diff --git a/data/users/avatars/499227115414355988.png b/data/users/avatars/499227115414355988.png new file mode 100755 index 0000000..27f1881 Binary files /dev/null and b/data/users/avatars/499227115414355988.png differ diff --git a/data/users/avatars/504208368853057537.png b/data/users/avatars/504208368853057537.png new file mode 100755 index 0000000..7820be6 Binary files /dev/null and b/data/users/avatars/504208368853057537.png differ diff --git a/data/users/avatars/506573994657579018.png b/data/users/avatars/506573994657579018.png new file mode 100644 index 0000000..2e740ee Binary files /dev/null and b/data/users/avatars/506573994657579018.png differ diff --git a/data/users/avatars/88644904112128000.png b/data/users/avatars/88644904112128000.png new file mode 100755 index 0000000..9bcd533 Binary files /dev/null and b/data/users/avatars/88644904112128000.png differ diff --git a/data/users/avatars/92619860521005056.png b/data/users/avatars/92619860521005056.png new file mode 100755 index 0000000..7929b6d Binary files /dev/null and b/data/users/avatars/92619860521005056.png differ diff --git a/data/users/avatars/93801185122713600.png b/data/users/avatars/93801185122713600.png new file mode 100755 index 0000000..e7b7983 Binary files /dev/null and b/data/users/avatars/93801185122713600.png differ diff --git a/data/users/avatars/94877519622184960.png b/data/users/avatars/94877519622184960.png new file mode 100644 index 0000000..e1ba50e Binary files /dev/null and b/data/users/avatars/94877519622184960.png differ diff --git a/data/users/backgrounds/124930356167049218.png b/data/users/backgrounds/124930356167049218.png new file mode 100644 index 0000000..8c08e91 Binary files /dev/null and b/data/users/backgrounds/124930356167049218.png differ diff --git a/data/users/backgrounds/171685542553976832.png b/data/users/backgrounds/171685542553976832.png new file mode 100644 index 0000000..8d16ad4 Binary files /dev/null and b/data/users/backgrounds/171685542553976832.png differ diff --git a/data/users/backgrounds/269156684155453451.png b/data/users/backgrounds/269156684155453451.png new file mode 100755 index 0000000..ea199ff Binary files /dev/null and b/data/users/backgrounds/269156684155453451.png differ diff --git a/data/users/backgrounds/279395573503623169.png b/data/users/backgrounds/279395573503623169.png new file mode 100755 index 0000000..dc6d28a Binary files /dev/null and b/data/users/backgrounds/279395573503623169.png differ diff --git a/data/users/backgrounds/301062143942590465.png b/data/users/backgrounds/301062143942590465.png new file mode 100755 index 0000000..1facb6d Binary files /dev/null and b/data/users/backgrounds/301062143942590465.png differ diff --git a/data/users/backgrounds/351115710992351234.png b/data/users/backgrounds/351115710992351234.png new file mode 100644 index 0000000..4b591b0 Binary files /dev/null and b/data/users/backgrounds/351115710992351234.png differ diff --git a/data/users/backgrounds/356829119499206656.png b/data/users/backgrounds/356829119499206656.png new file mode 100644 index 0000000..247c2aa Binary files /dev/null and b/data/users/backgrounds/356829119499206656.png differ diff --git a/data/users/backgrounds/380425790686494720.png b/data/users/backgrounds/380425790686494720.png new file mode 100644 index 0000000..9a2811c Binary files /dev/null and b/data/users/backgrounds/380425790686494720.png differ diff --git a/data/users/backgrounds/93801185122713600.png b/data/users/backgrounds/93801185122713600.png new file mode 100755 index 0000000..864299f Binary files /dev/null and b/data/users/backgrounds/93801185122713600.png differ diff --git a/data/users/backgrounds/94877519622184960.png b/data/users/backgrounds/94877519622184960.png new file mode 100644 index 0000000..15a9d77 Binary files /dev/null and b/data/users/backgrounds/94877519622184960.png differ diff --git a/data/users/cards/124930356167049218.png b/data/users/cards/124930356167049218.png new file mode 100755 index 0000000..5e7af15 Binary files /dev/null and b/data/users/cards/124930356167049218.png differ diff --git a/data/users/cards/163750228619427840.png b/data/users/cards/163750228619427840.png new file mode 100644 index 0000000..84239cc Binary files /dev/null and b/data/users/cards/163750228619427840.png differ diff --git a/data/users/cards/171685542553976832.png b/data/users/cards/171685542553976832.png new file mode 100755 index 0000000..f03769d Binary files /dev/null and b/data/users/cards/171685542553976832.png differ diff --git a/data/users/cards/177093008271998976.png b/data/users/cards/177093008271998976.png new file mode 100755 index 0000000..b55d643 Binary files /dev/null and b/data/users/cards/177093008271998976.png differ diff --git a/data/users/cards/193869956214030336.png b/data/users/cards/193869956214030336.png new file mode 100755 index 0000000..932c04d Binary files /dev/null and b/data/users/cards/193869956214030336.png differ diff --git a/data/users/cards/196668513601978369.png b/data/users/cards/196668513601978369.png new file mode 100755 index 0000000..788f438 Binary files /dev/null and b/data/users/cards/196668513601978369.png differ diff --git a/data/users/cards/199807621794889729.png b/data/users/cards/199807621794889729.png new file mode 100755 index 0000000..96e9f7c Binary files /dev/null and b/data/users/cards/199807621794889729.png differ diff --git a/data/users/cards/203874311696547851.png b/data/users/cards/203874311696547851.png new file mode 100644 index 0000000..f39d866 Binary files /dev/null and b/data/users/cards/203874311696547851.png differ diff --git a/data/users/cards/215819175640170496.png b/data/users/cards/215819175640170496.png new file mode 100755 index 0000000..9ea2a1f Binary files /dev/null and b/data/users/cards/215819175640170496.png differ diff --git a/data/users/cards/218001834055303168.png b/data/users/cards/218001834055303168.png new file mode 100644 index 0000000..706e2a7 Binary files /dev/null and b/data/users/cards/218001834055303168.png differ diff --git a/data/users/cards/260112844425658370.png b/data/users/cards/260112844425658370.png new file mode 100644 index 0000000..b05ed94 Binary files /dev/null and b/data/users/cards/260112844425658370.png differ diff --git a/data/users/cards/260433835353702400.png b/data/users/cards/260433835353702400.png new file mode 100755 index 0000000..6925085 Binary files /dev/null and b/data/users/cards/260433835353702400.png differ diff --git a/data/users/cards/269156684155453451.png b/data/users/cards/269156684155453451.png new file mode 100755 index 0000000..1f9fa8d Binary files /dev/null and b/data/users/cards/269156684155453451.png differ diff --git a/data/users/cards/279395573503623169.png b/data/users/cards/279395573503623169.png new file mode 100755 index 0000000..8cf1190 Binary files /dev/null and b/data/users/cards/279395573503623169.png differ diff --git a/data/users/cards/286881789392191488.png b/data/users/cards/286881789392191488.png new file mode 100755 index 0000000..cdcebef Binary files /dev/null and b/data/users/cards/286881789392191488.png differ diff --git a/data/users/cards/297447589438160897.png b/data/users/cards/297447589438160897.png new file mode 100755 index 0000000..91c9412 Binary files /dev/null and b/data/users/cards/297447589438160897.png differ diff --git a/data/users/cards/301062143942590465.png b/data/users/cards/301062143942590465.png new file mode 100755 index 0000000..634780e Binary files /dev/null and b/data/users/cards/301062143942590465.png differ diff --git a/data/users/cards/326770983274938370.png b/data/users/cards/326770983274938370.png new file mode 100644 index 0000000..864931c Binary files /dev/null and b/data/users/cards/326770983274938370.png differ diff --git a/data/users/cards/329149664865550336.png b/data/users/cards/329149664865550336.png new file mode 100755 index 0000000..5fe4919 Binary files /dev/null and b/data/users/cards/329149664865550336.png differ diff --git a/data/users/cards/331516411883159554.png b/data/users/cards/331516411883159554.png new file mode 100755 index 0000000..15db50a Binary files /dev/null and b/data/users/cards/331516411883159554.png differ diff --git a/data/users/cards/338003221110980608.png b/data/users/cards/338003221110980608.png new file mode 100644 index 0000000..cc570b0 Binary files /dev/null and b/data/users/cards/338003221110980608.png differ diff --git a/data/users/cards/350647804307177474.png b/data/users/cards/350647804307177474.png new file mode 100755 index 0000000..f66967c Binary files /dev/null and b/data/users/cards/350647804307177474.png differ diff --git a/data/users/cards/351115710992351234.png b/data/users/cards/351115710992351234.png new file mode 100755 index 0000000..e63d8d1 Binary files /dev/null and b/data/users/cards/351115710992351234.png differ diff --git a/data/users/cards/356829119499206656.png b/data/users/cards/356829119499206656.png new file mode 100755 index 0000000..537310e Binary files /dev/null and b/data/users/cards/356829119499206656.png differ diff --git a/data/users/cards/366544765644439563.png b/data/users/cards/366544765644439563.png new file mode 100755 index 0000000..68e988b Binary files /dev/null and b/data/users/cards/366544765644439563.png differ diff --git a/data/users/cards/372093907158171649.png b/data/users/cards/372093907158171649.png new file mode 100644 index 0000000..aef4bf5 Binary files /dev/null and b/data/users/cards/372093907158171649.png differ diff --git a/data/users/cards/380425790686494720.png b/data/users/cards/380425790686494720.png new file mode 100644 index 0000000..0ad6334 Binary files /dev/null and b/data/users/cards/380425790686494720.png differ diff --git a/data/users/cards/404421267236716544.png b/data/users/cards/404421267236716544.png new file mode 100644 index 0000000..205f628 Binary files /dev/null and b/data/users/cards/404421267236716544.png differ diff --git a/data/users/cards/467753460289241089.png b/data/users/cards/467753460289241089.png new file mode 100644 index 0000000..a06e654 Binary files /dev/null and b/data/users/cards/467753460289241089.png differ diff --git a/data/users/cards/477577534708645930.png b/data/users/cards/477577534708645930.png new file mode 100644 index 0000000..a1f2bd4 Binary files /dev/null and b/data/users/cards/477577534708645930.png differ diff --git a/data/users/cards/478946967532339201.png b/data/users/cards/478946967532339201.png new file mode 100755 index 0000000..8f57882 Binary files /dev/null and b/data/users/cards/478946967532339201.png differ diff --git a/data/users/cards/488087525286477825.png b/data/users/cards/488087525286477825.png new file mode 100755 index 0000000..935fab4 Binary files /dev/null and b/data/users/cards/488087525286477825.png differ diff --git a/data/users/cards/499227115414355988.png b/data/users/cards/499227115414355988.png new file mode 100755 index 0000000..ea2634e Binary files /dev/null and b/data/users/cards/499227115414355988.png differ diff --git a/data/users/cards/504208368853057537.png b/data/users/cards/504208368853057537.png new file mode 100755 index 0000000..08b4624 Binary files /dev/null and b/data/users/cards/504208368853057537.png differ diff --git a/data/users/cards/506573994657579018.png b/data/users/cards/506573994657579018.png new file mode 100644 index 0000000..2074297 Binary files /dev/null and b/data/users/cards/506573994657579018.png differ diff --git a/data/users/cards/88644904112128000.png b/data/users/cards/88644904112128000.png new file mode 100755 index 0000000..a4a1771 Binary files /dev/null and b/data/users/cards/88644904112128000.png differ diff --git a/data/users/cards/92619860521005056.png b/data/users/cards/92619860521005056.png new file mode 100755 index 0000000..2b8d22f Binary files /dev/null and b/data/users/cards/92619860521005056.png differ diff --git a/data/users/cards/93801185122713600.png b/data/users/cards/93801185122713600.png new file mode 100755 index 0000000..83ff13f Binary files /dev/null and b/data/users/cards/93801185122713600.png differ diff --git a/data/users/cards/94877519622184960.png b/data/users/cards/94877519622184960.png new file mode 100644 index 0000000..518c03e Binary files /dev/null and b/data/users/cards/94877519622184960.png differ diff --git a/launch.py b/launch.py new file mode 100644 index 0000000..1d94f5a --- /dev/null +++ b/launch.py @@ -0,0 +1,43 @@ +#! /usr/bin/env python3 + +import locale +from dialog import Dialog +from subprocess import call +import os + +locale.setlocale(locale.LC_ALL, '') +d = Dialog(dialog="dialog") +d.set_background_title("Tuxbot Manager v0.5a") + +while True: + + mmenu, rmenu = d.menu("Que souhaitez vous faire ?", choices = [("(1)", "Lancer Tuxbot"), ("(2)", "Eteindre Tuxbot"), ("(3)", "Mettre à jour Tuxbot"), ("(4)", "Quitter")]) + + if rmenu == "(1)": + d.gauge_start("Lancement") + d.gauge_update(10) +# try: +# call(["screen", "-S", "tuxbot", "-X","quit"]) +# except: +# d.gauge_update(35) + d.gauge_update(40) + call(["screen","-S","tuxbot", "-d", "-m", "python3", "bot.py"]) + d.gauge_update(100) + d.gauge_stop() + d.msgbox("Tuxbot est correctement lancé ! Merci de faire .ping sur discord pour vérifier.") + + if rmenu == "(2)": + d.gauge_start("Arrêt") + d.gauge_update(10) + call(["screen", "-S", "tuxbot", "-X","quit"]) + d.gauge_update(100) + d.gauge_stop() + d.msgbox("Tuxbot s'est correctement arrêté. Faites vite ;-) !") + + if rmenu == "(4)": + d.pause("A bientôt !\n(C) 2018 Gnous.EU Dev Team.", seconds=2) + call(["clear"]) + exit() + + if rmenu == "(3)": + d.msgbox("Fonctionnalité indisponible pour le moment du fait que le serveur GIT de tuxbot est hors service.") diff --git a/readme.md b/readme.md index 975ebee..fd6cbcc 100755 --- a/readme.md +++ b/readme.md @@ -1,8 +1,4 @@ # Tuxbot - -[![forthebadge](http://forthebadge.com/images/badges/contains-cat-gifs.svg)](http://forthebadge.com) -[![forthebadge](https://forthebadge.com/images/badges/made-with-python.svg)](http://forthebadge.com) - TuxBot, un bot discord écrit en Python. Ici ce trouve le code source du bot provenant du serveur Discord [Aide GNU/Linux-Fr"](https://discord.gg/79943dJ "Rejoindre le serveur"), il à été créé spécialement pour ce discord, si vous souhaitez l'utiliser il vous faudra modifier ``params.json`` et ``cogs/utils/checks.py`` ;) @@ -12,11 +8,11 @@ Il vous faut : - Un ordinateur sous **GNU/Linux** avec une connexion à internet; - Python3.5 ou + ; -- Installer ``requirements.txt`` (avec ``pip install -r requirements.txt`` par ex) +- Installer ``requirements.txt`` (avec ``pip3 install -r requirements.txt`` par ex) ### Installation -Une fois les pré-requis installés et ``params.json`` édité, placez vous dans le repertoire de tuxbot et lancez ``bot.py`` avec python3 (ex: ``python3 bot.py``) +Une fois les pré-requis installés et ``config.py`` édité, placez vous dans le repertoire de tuxbot et lancez ``bot.py`` avec python3 (ex: ``python3 bot.py``) ## Démarrage diff --git a/requirements.txt b/requirements.txt index 4bf95d8..fb72858 100755 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,5 @@ bs4 pytz requests wikipedia +pymysql +pillow \ No newline at end of file diff --git a/texts/ci-info.md b/texts/ci-info.md index fff5609..af595b3 100755 --- a/texts/ci-info.md +++ b/texts/ci-info.md @@ -7,5 +7,5 @@ La carte d'identité est un petit système dans tuxbot permetant de vous démarq -> .ci setos _nom de l'os_ : Défini votre système d'exploitation -> .ci setconfig _votre configuration pc_ : Défini la configuration de votre ordinateur -> .ci setcountry : Défini votre pays --> .ci update : Met à jour votre image si vous l'avez changé :wink: --> .ci delete : Supprime votre carte d'identité :sob: +-> .ci update : Met à jour votre image si vous l'avez changé +-> .ci delete : Supprime votre carte d'identité diff --git a/texts/help.md b/texts/help.md index cdd1bb9..c991137 100755 --- a/texts/help.md +++ b/texts/help.md @@ -1,6 +1,6 @@ **Commandes utilitaires** --> .afk : Signaler son absence --> .back : Signaler son retour +-> .afk : Signaler son absence *(commande désactivée)* +-> .back : Signaler son retour *(commande désactivée)* -> .clock _ville_: Affiche l'heure et quelques infos sur la ville en question -> .ytdiscover : Découvrir des chaines youtube -> .search _site_ _contenu_ : Fait une recherche sur un site (.search pour plus d'infos) @@ -8,7 +8,11 @@ -> .poke _@pseudo_ : Poke _@pseudo_ -> .hastebin _code_ : Poste du code sur hastebin -> .sondage _question_ | _reponse_ | _reponse_ | _option_ : Créer un sondage avec des réactions --> .sondage_aide : Affiche l'aide pour la commande sondage +-> .sondage : Affiche l'aide pour la commande sondage +-> .role _nomdurole_ : Ajoute/Retire le rôle en question +-> .iplocalise _IP ou NDD_ : affiche la localisation et le propriétaire de l'ip (ou de l'IP lié a un nom de domaine) +-> .getheaders _IP ou NDD_ : affiche les en-têtes (headers) d'une IP/Nom de domaine via HTTP/HTTPS/FTP +-> .btcprice : Affiche le prix du bitcoin **Commandes Funs** -> .joke : Affiche une blague aléatoire @@ -30,6 +34,6 @@ **Commandes diverses** : -> .info : Affiche des informations sur le bot -> .help : Affiche ce message --> .clock list: Affiche la liste des horloges des villes +-> .clock : Affiche la liste des horloges des villes -> .ping : Ping le bot -> .github : Affiche le repos Github du Bot :heart: diff --git a/texts/info.md b/texts/info.md index 9dbdf15..aad0f4d 100755 --- a/texts/info.md +++ b/texts/info.md @@ -1,7 +1,7 @@ <:stafftools:314348604095594498> **Développement** : - └> Outout : [outout.tech](https://outout.tech/) - └> Romain : [son github](https://github.com/Rom194) + └> Outout : [outout.xyz](https://outout.xyz/) + └> Romain : [son github](http://git.dyjix.eu/Romain) └> Langage : [Python3](http://www.python.org/) └> Api : [discord.py {3}](https://github.com/Rapptz/discord.py) └> En se basant sur : [RobotDanny](https://github.com/Rapptz/RoboDanny) @@ -14,6 +14,7 @@ └> <:discord:314003252830011395> : Outout#8406 └> <:twitter:314349922877046786> : [@outout14_](https://twitter.com/outout14_) └> <:mail:334345653419245571> : [outout@linuxmail.org](mailto:outout@linuxmail.org) + └> <:discord:314003252830011395> : Romain#5117 <:discord:314003252830011395> **Serveurs** : diff --git a/texts/passport-info.md b/texts/passport-info.md new file mode 100755 index 0000000..c3b128c --- /dev/null +++ b/texts/passport-info.md @@ -0,0 +1,9 @@ +Le passeport est un petit système dans tuxbot permetant de vous démarquer de vos amis en ayant la possibilité d'y renseigner plusieurs informations ! + +**Liste des commandes : ** +-> .passeport : Affiche l'aide sur les cartes d'identité +-> .passeport show _pseudo_ : Affiche le passeport de _pseudo_ +-> .passeport config : Vous envois un message privé afin de configurer votre passeport +-> .passeport background _url_ : Défini _url_ comme étant le fond d'écran de votre passeport +-> .passeport thème : Definie le theme de votre passeport (`.passeport preview` envoi une image avec les 2 thèmes pour comparer) +-> .passeport delete : Supprime les informations de votre carte passeport diff --git a/texts/roles.md b/texts/roles.md new file mode 100755 index 0000000..27f1196 --- /dev/null +++ b/texts/roles.md @@ -0,0 +1,13 @@ + +Pour améliorer l'expérience utilisateur de tout le monde, vous pouvez spécifier la·les distribution·s que vous utilisez via les rôles Discord. + +**Liste des rôles** + └> Arch : pour <:archlinux:282214818486812673> + └> Debian : pour Debian <:debian:375326392482791424> et ses dérivés (Ubuntu, Kali, etc.) + └> Rhel : pour Red Hat Entreprise Linux et ses dérivés (Fedora, CentOS, etc.) + └> Android : pour Android <:android:282214818486812673> + └> BSD : pour BSD <:bsd:401797313657569280> + +**Commandes** + └> Pour ajouter un rôle : ``.role Nomdurole`` + └> Pour retirer un rôle : ``.role Nomdurole`` \ No newline at end of file diff --git a/texts/search.md b/texts/search.md index 42078b6..52523d0 100755 --- a/texts/search.md +++ b/texts/search.md @@ -3,4 +3,4 @@ _Attention ! entrez vos termes de recherche sans espaces !_ Pour effectuer une recherche utilisez la commande ``.search {site_de_recherche} {termes_recherche}`` -> [**docubuntu**](https://doc.ubuntu-fr.org) : Effectuer une recherche sur un paquet dans la Documentation du site ubuntu-fr.org. -> [**wikipedia**](https://fr.wikipedia.org) : Effectuer une recherche sur l'encyclopédie libre Wikipedia en Français ! --> [**aur**](https://aur.archlinux.org) : Effectuer une recherche sur Archlinux Aur ! +-> [**docaur**](https://doc.archlinux.org) : Effectuer une recherche sur la doc ArchLinux !