import itertools import random import datetime from operator import attrgetter from pprint import pprint from time import time import discord from discord import Guild from discord.ext import commands from discord.ext.commands import ( Cog, command, Context, Bot, Command, CommandError, Group, ) from src.constants import * from src.utils import has_role class MiscCog(Cog, name="Divers"): def __init__(self, bot: Bot): self.bot = bot self.show_hidden = False self.verify_checks = True @command( name="choose", usage='choix1 choix2 "choix 3"...', aliases=["choice", "choix", "ch"], ) async def choose(self, ctx: Context, *args): """ Choisit une option parmi tous les arguments. Pour les options qui contiennent une espace, il suffit de mettre des guillemets (`"`) autour. """ choice = random.choice(args) await ctx.send(f"J'ai choisi... **{choice}**") @command(name="joke", aliases=["blague"], hidden=True) async def joke_cmd(self, ctx): await ctx.message.delete() with open(JOKES_FILE) as f: jokes = f.read().split("\n\n\n") msg = random.choice(jokes) await ctx.send(msg) @command(name="status") @commands.has_role(Role.CNO) async def status_cmd(self, ctx: Context): """(cno) Affiche des informations à propos du serveur.""" guild: Guild = ctx.guild embed = discord.Embed(title="État du serveur", color=EMBED_COLOR) benevoles = [g for g in guild.members if has_role(g, Role.BENEVOLE)] participants = [g for g in guild.members if has_role(g, Role.PARTICIPANT)] no_role = [g for g in guild.members if g.top_role == guild.default_role] uptime = datetime.timedelta(seconds=round(time() - START_TIME)) infos = { "Bénévoles": len(benevoles), "Participants": len(participants), "Sans rôle": len(no_role), "Total": len(guild.members), "Bot uptime": uptime, } width = max(map(len, infos)) txt = "\n".join( f"`{key.rjust(width)}`: {value}" for key, value in infos.items() ) embed.add_field(name="Stats", value=txt) await ctx.send(embed=embed) # ----------------- Help ---------------- # @command(name="help", aliases=["h"]) async def help_cmd(self, ctx: Context, *args): """Affiche des détails à propos d'une commande.""" if not args: await self.send_bot_help(ctx) else: await self.send_command_help(ctx, args) async def send_bot_help(self, ctx: Context): embed = discord.Embed( title="Aide pour le bot du TFJM²", description="Ici est une liste des commandes utiles (ou pas) " "durant le tournoi. Pour avoir plus de détails il " "suffit d'écrire `!help COMMANDE` en remplacant `COMMANDE` " "par le nom de la commande, par exemple `!help team channel`.", color=0xFFA500, ) commands = itertools.groupby(self.bot.walk_commands(), attrgetter("cog_name")) for cat_name, cat in commands: cat = {c.qualified_name: c for c in cat if not isinstance(c, Group)} cat = await self.filter_commands( ctx, list(cat.values()), sort=True, key=attrgetter("qualified_name") ) if not cat: continue names = ["!" + c.qualified_name for c in cat] width = max(map(len, names)) names = [name.rjust(width) for name in names] short_help = [c.short_doc for c in cat] lines = [f"`{n}` - {h}" for n, h in zip(names, short_help)] if cat_name is None: cat_name = "Autres" c: Command text = "\n".join(lines) embed.add_field(name=cat_name, value=text, inline=False) embed.set_footer(text="Suggestion ? Problème ? Envoie un message à @Diego") await ctx.send(embed=embed) async def send_command_help(self, ctx, args): name = " ".join(args) comm: Command = self.bot.get_command(name) if comm is None: return await ctx.send( f"La commande `!{name}` n'existe pas. " f"Utilise `!help` pour une liste des commandes." ) elif isinstance(comm, Group): return await self.send_group_help(ctx, comm) embed = discord.Embed( title=f"Aide pour la commande `!{comm.qualified_name}`", description=comm.help, color=0xFFA500, ) if comm.aliases: aliases = ", ".join(f"`{a}`" for a in comm.aliases) embed.add_field(name="Alias", value=aliases, inline=True) if comm.signature: embed.add_field( name="Usage", value=f"`!{comm.qualified_name} {comm.signature}`" ) embed.set_footer(text="Suggestion ? Problème ? Envoie un message à @Diego") await ctx.send(embed=embed) async def send_group_help(self, ctx, group: Group): embed = discord.Embed( title=f"Aide pour le groupe de commandes `!{group.qualified_name}`", description=group.help, color=0xFFA500, ) comms = await self.filter_commands(ctx, group.commands, sort=True) if not comms: embed.add_field( name="Désolé", value="Il n'y a aucune commande pour toi ici." ) else: names = ["!" + c.qualified_name for c in comms] width = max(map(len, names)) just_names = [name.rjust(width) for name in names] short_help = [c.short_doc for c in comms] lines = [f"`{n}` - {h}" for n, h in zip(just_names, short_help)] c: Command text = "\n".join(lines) embed.add_field(name="Sous-commandes", value=text, inline=False) if group.aliases: aliases = ", ".join(f"`{a}`" for a in group.aliases) embed.add_field(name="Alias", value=aliases, inline=True) if group.signature: embed.add_field( name="Usage", value=f"`!{group.qualified_name} {group.signature}`" ) embed.add_field( name="Plus d'aide", value=f"Pour plus de détails sur une commande, " f"il faut écrire `!help COMMANDE` en remplaçant " f"COMMANDE par le nom de la commande qui t'intéresse.\n" f"Exemple: `!help {random.choice(names)[1:]}`", ) embed.set_footer(text="Suggestion ? Problème ? Envoie un message à @Diego") await ctx.send(embed=embed) def _name(self, command: Command): return f"`!{command.qualified_name}`" async def filter_commands(self, ctx, commands, *, sort=False, key=None): """|coro| Returns a filtered list of commands and optionally sorts them. This takes into account the :attr:`verify_checks` and :attr:`show_hidden` attributes. Parameters ------------ commands: Iterable[:class:`Command`] An iterable of commands that are getting filtered. sort: :class:`bool` Whether to sort the result. key: Optional[Callable[:class:`Command`, Any]] An optional key function to pass to :func:`py:sorted` that takes a :class:`Command` as its sole parameter. If ``sort`` is passed as ``True`` then this will default as the command name. Returns --------- List[:class:`Command`] A list of commands that passed the filter. """ if sort and key is None: key = lambda c: c.qualified_name iterator = ( commands if self.show_hidden else filter(lambda c: not c.hidden, commands) ) if not self.verify_checks: # if we do not need to verify the checks then we can just # run it straight through normally without using await. return sorted(iterator, key=key) if sort else list(iterator) # if we're here then we need to check every command if it can run async def predicate(cmd): try: return await cmd.can_run(ctx) except CommandError: return False ret = [] for cmd in iterator: valid = await predicate(cmd) if valid: ret.append(cmd) if sort: ret.sort(key=key) return ret def setup(bot: Bot): bot.add_cog(MiscCog(bot))