import os # OS Locations import yaml # YAML parser for Bot config files import asyncio # Discord Py Dependency import discord # Main Lib from discord.ext import commands # Commands module from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library from discord_slash.utils.manage_commands import create_choice, create_option, create_permission # Slash Command features from discord_slash.model import SlashCommandPermissionType from discord_slash.client import SlashCommand from discord_slash.utils.manage_components import create_select, create_select_option, create_actionrow, wait_for_component # from discord_components import * from bot import configFile, yaml_load, yaml_dump, reloadCog, cogsDir, unloadCog, dataFile #### Separate cog to remove and modify timeslots that is reloaded if timeslots are added or removed class ManipulateTimeslots(commands.Cog, name='Manipulate Timeslots'): def __init__(self, client): self.client = client #### Only emable for guilds with timeslots #### N.B.: if there are no guilds with any timeslots, then this will throw an exception. #### The solution I have implemented is that this will be classed as a 'secondary' cog: it will not be loaded by default, and will only be loaded if at least one guild has a timeslot configured. #### If the deletion of timeslots removes timeslots from all guilds, it will unload the cog and delete the commands until a new timeslot is defined. guild_ids=[int(guildKey) for guildKey in yaml_load(configFile) if len(yaml_load(configFile)[guildKey]['timeslots']) > 0] conf = yaml_load(configFile) permissions = {} for guildID in guild_ids: permissions[guildID] = [] permissions[guildID].append(create_permission(id=conf[str(guildID)]['owner'],id_type=SlashCommandPermissionType.USER,permission=True)) for admin in conf[str(guildID)]['roles']['admin']: permissions[guildID].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True)) @cog_ext.cog_subcommand( base='config', subcommand_group='timeslots', name='remove', description='Remove a configured game timeslot.', # base_description='Commands for configuring the various parameters of the Guild', # base_default_permission=False, # base_permissions=permissions, # subcommand_group_description='Adds a time slot available to the channel for games.', guild_ids=guild_ids, # options=[ # create_option( # name='timeslot', # description='The timeslot you wish to delete.', # option_type=3, # required=True # ) # ] ) async def _config_timeslots_remove(self, ctx:SlashContext,):# timeslot:str): conf = yaml_load(configFile) data = yaml_load(dataFile) guildStr = str(ctx.guild.id) if 'timeslots' not in conf[guildStr]: conf[guildStr]['timeslots'] = {} tsDict = conf[guildStr]['timeslots'].copy() optionsList = [create_select_option(label=tsDict[x], value=x, description=x) for x in tsDict] try: m = await ctx.send( content='```Select which time slot you would like to delete.```', components=[ create_actionrow( create_select( placeholder='Time Slot', options= optionsList, min_values=1, max_values=1 ) ) ], delete_after=5, # hidden=True Can't have hidden responses for menus apparently. ) while True: select_ctx = await wait_for_component(self.client,messages=m, timeout=5) if select_ctx.author != ctx.author: await select_ctx.send(f'```Invalid response: you are not the person who issued the command.```', hidden=True) else: break await m.delete() [timeslot] = select_ctx.selected_options except asyncio.TimeoutError: await ctx.send(f'```Error: Command timed out.```', hidden=True) return if timeslot not in data[guildStr] or not data[guildStr][timeslot]: await ctx.send(f'```Timeslot {conf[guildStr]["timeslots"][timeslot]} with the key `{timeslot}` has been deleted for the guild `{ctx.guild.name}`.```',hidden=True) conf[guildStr]['timeslots'].pop(timeslot, None) yaml_dump(conf, configFile) if not all([x['timeslots'] for x in yaml_load(configFile).values()]): unloadCog(f'./{cogsDir}/slashcommands/secondary/manipulate_timeslots.py') if self.client.get_cog('Game Management') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py') if self.client.get_cog('Game Setup') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/game_setup.py') await self.client.slash.sync_all_commands() else: await ctx.send('```Error: You cannot delete a timeslot that has existing game entries. Please delete all games first.```',hidden=True) @cog_ext.cog_subcommand( base='config', subcommand_group='timeslots', name='modify', description='Modify the value of a configured gametime slot.', # base_description='Commands for configuring the various parameters of the Guild', # base_default_permission=False, # base_permissions=permissions, # subcommand_group_description='Adds a time slot available to the channel for games.', guild_ids=guild_ids, options=[ create_option( name='key', description='Key of timeslot being modified', option_type=3, required=True, ), create_option( name='name', description='New value for timeslot name', option_type=3, required=True ) ] ) async def _config_timeslots_modify(self, ctx:SlashContext, key:str, name:str): conf = yaml_load(configFile) guildStr = str(ctx.guild.id) if 'timeslots' not in conf[guildStr]: conf[guildStr]['timeslots'] = {} if key in conf[guildStr]['timeslots']: await ctx.send(f'```Timeslot {conf[guildStr]["timeslots"][key]} with the key `{key}` has been renamed to {name} for the guild `{ctx.guild.name}`.```',hidden=True) conf[guildStr]['timeslots'][key] = name yaml_dump(conf, configFile) elif len(conf[guildStr]['timeslots']) > 0: output = f'```Timeslot `{key}` was not found in the guild `{ctx.guild.name}`. Please enter a valid key.\n\n Available timeslots are:\n(key): (timeslot name)' for c in conf[guildStr]['timeslots']: output = ''.join([output, f'\n {c}: {conf[guildStr]["timeslots"][c]}']) await ctx.send(''.join([output,'```']),hidden=True) else: await ctx.send(f'```No timeslots have been defined for the guild `{ctx.guild.name}`.```',hidden=True) @cog_ext.cog_subcommand( base='config', subcommand_group='timeslots', name='list', description='List the existing game timeslots on the server.', # base_description='Commands for configuring the various parameters of the Guild', # base_default_permission=False, # base_permissions=permissions, # subcommand_group_description='Adds a time slot available to the channel for games.', guild_ids=guild_ids, ) async def _config_timeslots_list(self, ctx:SlashContext): conf = yaml_load(configFile) guildStr = str(ctx.guild.id) if 'timeslots' not in conf[guildStr]: conf[guildStr]['timeslots'] = {} if len(conf[guildStr]['timeslots']) > 0: output = f'```The following timeslots have been configured for the guild {ctx.guild.name}:\n(key): (timeslot name)' for c in conf[guildStr]['timeslots']: output = ''.join([output, f'\n {c}: {conf[guildStr]["timeslots"][c]}']) await ctx.send(''.join([output,'```'])) else: await ctx.send(f'```No timeslots have been defined for the guild `{ctx.guild.name}`.```',hidden=True) def setup(client): client.add_cog(ManipulateTimeslots(client))