from data import constants import discord from discord.commands import SlashCommand from discord.ext import commands from enums.help_categories import categories, getCategory, Category import json class HelpCommand(commands.MinimalHelpCommand): def __init__(self, **options): super().__init__(**options) self.ctx = None self.target = None self.is_mod = False # Slightly modifying the original callback in order to # allow sending help to DM's & checking for Enums # while removing cog help & checking for mentions async def command_callback(self, ctx, *, command=None): self.ctx = ctx self.is_mod = str(ctx.author.id) == constants.myId bot = ctx.bot if ctx.bot.locked: return # If mention prefix was used, don't count it as a target if ctx.message.content.startswith("<@"): ctx.message.mentions = ctx.message.mentions[1:] if len(ctx.message.mentions) > 5: return await ctx.send("Je kan Help maar naar maximaal 5 mensen doorsturen.") # Send help categories if command is None: return await self.send_bot_help(self.get_bot_mapping()) # Check if command is a category if command.lower() == "mod" and not self.is_mod: return await self.send_error_message("Je hebt geen toegang tot deze commando's.") category = getCategory(command, self.is_mod) if category: return await self.send_category_help(category) # Cut the mentions out & split based on subcommand spl = command.split(" ") spl = spl[:len(spl) - len(self.ctx.message.mentions)] # A person was mentioned without passing an argument if not spl: return await self.send_bot_help(self.get_bot_mapping()) # Turn dic to lowercase to allow proper name searching all_commands = {} for k, v in bot.all_commands.items(): if k is None or v is None: continue if isinstance(v, SlashCommand): continue all_commands[k.lower()] = v if spl[0].lower() not in all_commands: return await self.send_error_message(await self.command_not_found(spl[0])) cmd = all_commands[spl[0].lower()] # Check if the entered command path exists for key in spl[1:]: try: all_commands = dict((k.lower(), v) for k, v in cmd.all_commands.items()) if key.lower() not in all_commands: raise AttributeError found = all_commands[key.lower()] except AttributeError: return await self.send_error_message(await self.subcommand_not_found(cmd, key)) cmd = found # Subcommands should have the parent command's category temp = cmd while temp.parent is not None: temp = temp.parent # Don't allow non-mods to see mod commands try: if temp.callback.category == Category.Mod and not self.is_mod: return await self.send_error_message("Je hebt geen toegang tot dit commando.") except AttributeError: return await self.send_error_message("Dit is geen (openbaar) commando.") if isinstance(cmd, commands.Group): return await self.send_group_help(cmd) else: return await self.send_command_help(cmd) def get_bot_mapping(self): return categories(self.is_mod) # Sends list of commands in a category async def send_category_help(self, category): # Get a list of all commands in this category category_commands = [command.name if not command.callback.unpack else command for command in self.ctx.bot.commands if hasattr(command.callback, "category") and command.callback.category == category] # Unpack any groups that have to be unpacked for command in list(category_commands): if not isinstance(command, str): category_commands.remove(command) category_commands.extend([self.get_name(c) for c in self.unpack_group(command)]) embed = self.create_help_embed(category.value) embed.add_field(name="Commands", value="\n".join(sorted(category_commands))) for person in await self.get_destination(): await person.send(embed=embed) async def send_bot_help(self, mapping): embed = self.create_help_embed("Help") embed.add_field(name="Categorieën", value="\n".join(sorted(mapping))) await self.ctx.send(embed=embed) async def send_command_help(self, command): with open("files/help.json", "r") as fp: helpFile = json.load(fp) try: helpDescription = helpFile[self.get_name(command).lower()] except KeyError: helpDescription = "Indien je dit leest is DJ STIJN vergeten om dit commando in de help page te zetten. Stuur hem een DM om hem eraan te herinneren." embed = self.create_help_embed("Help") embed.add_field(name=await self.get_command_signature(command), value=await self.add_aliases_formatting(sorted(command.aliases)) + helpDescription) for person in await self.get_destination(): # Can't send to bots if person.bot: continue await person.send(embed=embed) async def send_group_help(self, group): with open("files/help.json", "r") as fp: helpFile = json.load(fp) embed = self.create_help_embed(group.name + " Commando's") try: helpDescription = helpFile[self.get_name(group).lower()] except KeyError: helpDescription = "Indien je dit leest is DJ STIJN vergeten om dit commando in de help page te zetten. Stuur hem een DM om hem eraan te herinneren." embed.add_field(name=await self.get_command_signature(group), value=await self.add_aliases_formatting(sorted(group.aliases)) + helpDescription, inline=False) # Signature: Aliases - Usage for subcommand in self.unpack_group(group): embed.add_field(name=await self.get_command_signature(subcommand), value=await self.add_aliases_formatting(sorted(subcommand.aliases)) + helpFile[self.get_name(subcommand).lower()], inline=False) for person in await self.get_destination(): # Can't send to bots if person.bot: continue await person.send(embed=embed) # Allow mentioning people to send it to them instead async def get_destination(self): if self.ctx.message.mentions: return set(mention for mention in self.ctx.message.mentions if not mention.bot) return [self.ctx.author] async def command_not_found(self, string): return "Er bestaat geen commando met de naam **{}**".format(string) async def subcommand_not_found(self, command, string): return "**{}** heeft geen subcommando met de naam **{}**.".format(command.name, string) async def get_command_signature(self, command): return "{} {}".format(self.get_name(command), command.usage if command.usage is not None else "") async def add_aliases_formatting(self, aliases): return "*Alias: {}*\n".format(", ".join(aliases)) if aliases else "" async def send_error_message(self, error): embed = discord.Embed(colour=discord.Colour.red()) embed.set_author(name="Help") embed.add_field(name="Error", value=error) await self.ctx.author.send(embed=embed) def unpack_group(self, group): # Create a list of all command objects in this group, in case they aren't hidden, sorted by name subcommands = [group.all_commands.get(command) for command in group.all_commands] subcommands.sort(key=lambda x: x.name) subcommands = filter(lambda x: not x.hidden, subcommands) return list(set(subcommands)) def get_name(self, command): return command.qualified_name if command.parents else command.name def create_help_embed(self, title): embed = discord.Embed(colour=discord.Colour.blue()) embed.set_author(name=title) embed.set_footer(text="Syntax: Didier Help [Categorie] of Didier Help [Commando]") return embed class Help(commands.Cog): def __init__(self, client): self.client = client self._original_help_command = client.help_command client.help_command = HelpCommand(command_attrs={"aliases": ["rtfm"]}) client.help_command.cog = self def cog_unload(self): self.client.help_command = self._original_help_command def setup(client): client.add_cog(Help(client))