class CustomCommands(commands.Cog, name='CustomCommands'): def __init__(self, bot): self.bot = bot self.db = bot.mdb['custom_commands'] async def cog_check(self, ctx): return ctx.guild is not None async def run_custom_commands(self, ctx): if ctx.guild is None: return cc = await self.db.find_one({'guild_id': ctx.guild_id, 'name': ctx.invoked_with}) if cc is None: return cc = CustomCommand.from_dict(cc) return await ctx.send(cc.content) @commands.group(name='cc', invoke_without_command=True) async def cc_base(self, ctx): """ Base command for CustomCommand commands. Will list any custom commands for this server. Any of these commands require the "DM" or "Dragonspeaker" role. """ aliases = await self.db.find({'guild_id': ctx.guild.id}).to_list(None) source = CommandMenu(data=[CustomCommand.from_dict(a) for a in aliases], ctx=ctx) cc_list = menus.MenuPages(source=source, clear_reactions_after=True) await cc_list.start(ctx) @cc_base.command(name='create') @commands.check_any(commands.has_any_role(BOT_MODS), is_owner()) async def cc_create(self, ctx, name: str, *, content: str): """ Create a new Custom Command. """ try: new_cc = await CustomCommand.new(self.bot, owner_id=ctx.author.id, guild_id=ctx.guild_id, name=name, content=content) except InvalidArgument as e: return await ctx.send(f'Encountered an error while creating the command:\n{str(e)}') return await ctx.send(f'Created new command with name `{new_cc.name}`') @cc_base.command(name='delete') @commands.check_any(commands.has_any_role(BOT_MODS), is_owner()) async def cc_delete(self, ctx, name: str): """ Deletes a Custom Counter. The name must be an existing CC. """ cc_dict = await self.db.find_one({'guild_id': ctx.guild_id, 'name': name}) if cc_dict is None: return await ctx.send(f'No CC with name `{name}` found.') await self.db.delete_one({'guild_id': ctx.guild_id, 'name': name}) return await ctx.send(f'Deleted CC with name `{name}` from the server.')
async def help(self, ctx): """ Displays a useful list of commands. """ desc = "" for key in self.bot.commands.keys(): command = self.bot.get_command(key) if command.hidden and not checks.is_owner(ctx): continue if command.aliases: desc += "`{}{}`".format(self.prefix, command.name)+" - {}\nAliases: `{}`\n".format(command.short_doc, ",".join(command.aliases)) desc += "\n" elif command.short_doc: desc += "`{}{}`".format(self.prefix, command.name)+" - {}\n".format(command.short_doc) desc += "\n" else: desc += "`{}{}`\n".format(self.prefix, command.name) desc += "\n" embed = discord.Embed(description=desc) bot_name="{} commands!".format(self.bot_descr) embed.set_author(icon_url=self.bot.user.avatar_url, name=bot_name)
async def help(self, ctx): """ Displays a useful list of commands. """ desc = "" for key in self.bot.commands.keys(): command = self.bot.get_command(key) if command.hidden and not checks.is_owner(ctx): continue if command.aliases: desc += "`{}{}`".format(self.prefix, command.name)+" - {}\nAliases: `{}`\n".format(command.short_doc, ",".join(command.aliases)) desc += "\n" elif command.short_doc: desc += "`{}{}`".format(self.prefix, command.name)+" - {}\n".format(command.short_doc) desc += "\n" else: desc += "`{}{}`\n".format(self.prefix, command.name) desc += "\n" embed = discord.Embed(description=desc) bot_name="{} commands!".format(self.bot_descr) embed.set_author(icon_url=self.bot.user.avatar_url, name=bot_name) try: await self.bot.send_message(ctx.message.author, embed=embed) if ctx.message.server is not None: await self.bot.say("{}, I PMed you some helpful info! Make sure to double check that it is from me!".format(ctx.message.author.mention)) except discord.HTTPException: await self.bot.say("I need the `Embed links` permission to send this")
def __global_check(self, ctx): msg = ctx.message if checks.is_owner(ctx): return True try: entry = self.disabled_commands[str(msg.guild.id)] except (KeyError, AttributeError): return True else: name = ctx.command.qualified_name.split(' ')[0] return name not in entry
async def help(self, ctx): """ Display a useful list of commands """ channel_name = ctx.message.channel.name allowed_channels = parsing.parse_json( 'config.json')['command_channels'][ctx.command.name] if channel_name not in allowed_channels: return desc = "" for key in self.bot.commands.keys(): command = self.bot.get_command(key) if command.hidden and not checks.is_owner(ctx): continue if command.aliases: desc += "`${}`".format( command.name) + " - {}\nAliases: `{}`\n".format( command.short_doc, ",".join(command.aliases)) desc += "\n" elif command.short_doc: desc += "`${}`".format(command.name) + " - {}\n".format( command.short_doc) desc += "\n" else: desc += "`${}`\n".format(command.name) desc += "\n" embed = discord.Embed(description=desc) embed.set_author(icon_url=self.bot.user.avatar_url, name="SCT-Bot commands!") try: await self.bot.send_message(ctx.message.author, embed=embed) if ctx.message.server is not None: await self.bot.say( "{}, I PMed you some helpful info! Make sure to double check that it is from me! :envelope:" .format(ctx.message.author.mention)) except discord.HTTPException: await self.bot.say( "I need the `Embed links` permission to send this!")
class SheetApproval(commands.Cog): def __init__(self, bot): self.bot = bot async def sheet_from_emoji(self, payload) -> ToBeApproved: # Check the Guild guild_id = payload.guild_id if guild_id != self.bot.personal_server['server_id']: return None # Check the Roles member = payload.member if member is None: member = self.bot.get_guild(guild_id).get_member(payload.user_id) if member is None: return None if len([ role for role in member.roles if role.name.lower() in APPROVAL_ROLES ]) == 0: return None # Check to see if it's an existing sheet result = await self.bot.mdb['to_approve'].find_one( {'message_id': payload.message_id}) if result is None: return None # Get rid of object id result.pop('_id') sheet: ToBeApproved = ToBeApproved.from_dict(result) return sheet @commands.Cog.listener('on_raw_reaction_add') async def check_for_approval(self, payload): sheet: ToBeApproved = await self.sheet_from_emoji(payload) if sheet is None: return if len(sheet.approvals) >= 2: return guild = self.bot.get_guild(payload.guild_id) await sheet.add_approval(guild, payload.member, self.bot) await sheet.commit(self.bot.mdb['to_approve']) @commands.Cog.listener('on_raw_reaction_remove') async def check_for_deny(self, payload): sheet: ToBeApproved = await self.sheet_from_emoji(payload) if sheet is None: return guild = self.bot.get_guild(payload.guild_id) await sheet.remove_approval(guild, payload.user_id, self.bot) await sheet.commit(self.bot.mdb['to_approve']) @commands.command(name='sheet', aliases=['submit']) @is_personal_server() async def new_sheet(self, ctx, *, content: str): """ Adds a sheet to be approved """ embed = create_default_embed(ctx) embed.title = f'Sheet Approval - {ctx.author.display_name}' embed.description = content if '(url)' in content: return await ctx.author.send( 'You must include your *actual* sheet URL in the command, not `(url)`' ) # If not character-submission or FrogBot dev if (ctx.channel.id != self.bot.personal_server['sheet_channel'] ) and not (ctx.guild.id == 755202524859859004): return await ctx.send( 'This channel is not valid for submitting sheets.') msg = await ctx.send(embed=embed) new_sheet = ToBeApproved(message_id=msg.id, approvals=[], channel_id=ctx.channel.id, owner_id=ctx.author.id) await self.bot.mdb['to_approve'].insert_one(new_sheet.to_dict()) @commands.command('cleanup_sheets') @is_personal_server() @commands.check_any(is_owner(), commands.has_any_role(*BOT_MODS)) async def remove_sheets(self, ctx): """ Removes deleted sheets from database. Run every once and a while. """ db = self.bot.mdb['to_approve'] embed = create_default_embed(ctx) embed.title = f'Pruning Old Sheets from Database.' all_sheets = await db.find().to_list(None) count = 0 for sheet in all_sheets: sheet.pop('_id') sheet = ToBeApproved.from_dict(sheet) channel = ctx.guild.get_channel(sheet.channel_id) if channel is None: continue try: await channel.fetch_message(sheet.message_id) except discord.NotFound: count += 1 await db.delete_one({'message_id': sheet.message_id}) embed.description = f'Pruned {count} Sheet{"s" if count != 1 else ""} from the DB.' await ctx.send(embed=embed)
async def on_command_error(ctx, err): if isinstance(err, errors.MissingRequiredArgument) or isinstance( err, errors.BadArgument): cmd = ctx.command help = " ".join([f"<{x}>" for x in cmd.clean_params]) help = help desc = ('\n\n`' + cmd.help + '`' if cmd.help else '') helpem = discord.Embed( title="Invalid args.", description=f"`{ctx.prefix}{cmd} {help}`{desc}".replace( f"<@{bot.user.id}>", f"@{bot.user.name}").replace(f"<@!{bot.user.id}>", f"@{bot.user.name}"), color=bot.color) await ctx.send(embed=helpem) elif isinstance(err, discord.errors.Forbidden): pass elif isinstance(err, errors.CommandInvokeError): err = err.original if str(type(err).__name__) == "Forbidden" and "403" in str(err): return _traceback = traceback.format_tb(err.__traceback__) _traceback = ''.join(_traceback) fullerror = ('```py\n{2}{0}: {3}\n```').format( type(err).__name__, ctx.message.content, _traceback, err) shorterror = ('`{}` - `{}`').format(type(err).__name__, err) shorterrorem = discord.Embed( title= f"It appears an error has occured trying to run {ctx.command}.", color=bot.color) if not checks.is_owner(ctx): # shorterrorem.description = shorterror shorterrorem.set_footer( text="This error has been reported to my owner.") await bot.doge.send(embed=discord.Embed( description=f"Command: {ctx.command}\n{fullerror}", color=0x36393f ).set_author( name="Command Error.", icon_url= "https://cdn.discordapp.com/emojis/588404204369084456.png") ) else: shorterrorem.description = fullerror await ctx.send(embed=shorterrorem) elif isinstance(err, errors.CheckFailure): em = discord.Embed(color=bot.color).set_author(name="Spotify", icon_url=bot.img) if ctx.command.checks[0].__qualname__ == "has_voted": em.description = f"To use this command you must [vote](https://discordbots.org/bot/{ctx.bot.user.id}/vote)." else: em.description = "You're not allowed to use this command." await ctx.send(embed=em) elif isinstance(err, errors.CommandNotFound): pass elif isinstance(err, errors.NoPrivateMessage): await ctx.send(embed=discord.Embed( color=bot.color, description="This command can't be used in dms." ).set_author( name="Sorry :(", icon_url= "https://cdn.discordapp.com/emojis/585861960613101573.gif?v=1") )
class Admin(commands.Cog): def __init__(self, bot): self.bot = bot # ---- Bot Owner Commands ---- @commands.group(name='admin', invoke_without_command=True) @is_owner() async def admin(self, ctx): """ Owner only commands for the bot. """ await ctx.send('give a subcommand nerd') @admin.command(name="restart") @is_owner() async def restart(self, ctx): """ Stops the bot, restarting it. """ confirm = await ctx.prompt('Are you sure you want to shutdown the bot?') if confirm: try: await self.bot.logout() except RuntimeError: pass @admin.command(name='change_status', description='Owner Only - Changes the bot\'s status.') @is_owner() async def change_status(self, ctx, *, value: str): """ Changes the bot's status. Will reset if `reset` is passed. """ if value != 'reset': await ctx.bot.mdb['bot_settings'].update_one({'setting': 'status'}, {'$set': {'status': value}}, upsert=True) else: await ctx.bot.mdb['bot_settings'].delete_one({'setting': 'status'}) await ctx.bot.change_presence(activity=await ctx.bot.update_status_from_db()) return await ctx.send(f'Status changed to {value}' if value != 'reset' else 'Status Reset.') @admin.group(name='personal_server', aliases=['ps'], invoke_without_command=True) @is_owner() async def personal_server(self, ctx): """ Base command for personal server commands. Displays information about currently set personal server. """ if self.bot.personal_server['server_id'] is None: return await ctx.send('Personal Server not set, no information available.') personal_server = self.bot.get_guild(self.bot.personal_server['server_id']) sheet_channel = channel_id_to_link(personal_server.get_channel(self.bot.personal_server['sheet_channel'])) \ if self.bot.personal_server['sheet_channel'] is not None else 'Not set.' general_channel = channel_id_to_link(personal_server.get_channel(self.bot.personal_server['general_channel'])) \ if self.bot.personal_server['general_channel'] is not None else 'Not set.' embed = create_default_embed(ctx) embed.title = 'FrogBot Personal Server Information' embed.add_field(name='Server Info', value=f'Server ID: {personal_server.id}\n' f'Server Name: {personal_server.name}') embed.add_field(name='Channel Info', value=f'Sheet Channel: {sheet_channel}\n' f'General Channel: {general_channel}') await ctx.send(embed=embed) @personal_server.command(name='set_server', aliases=['ss']) @is_owner() async def set_personal_server(self, ctx, guild_id: int): """ Sets the bot's personal server. This is the server where SheetApproval works. """ await ctx.bot.mdb['bot_settings'].update_one({'setting': 'personal_server'}, {'$set': {'server_id': guild_id}}, upsert=True ) self.bot.personal_server['server_id'] = guild_id return await ctx.send(f'Set {guild_id} to personal server.') @personal_server.command(name='set_sheet_channel', aliases=['ssc']) @is_owner() async def set_personal_sheet_channel(self, ctx, channel: discord.TextChannel): """ Sets the sheet channel for the bot's personal server. """ await ctx.bot.mdb['bot_settings'].update_one({'setting': 'personal_server'}, {'$set': {'sheet_channel': channel.id}}, upsert=True ) self.bot.personal_server['sheet_channel'] = channel.id return await ctx.send(f'Set <#{channel.id}> to sheet channel.') @personal_server.command(name='set_general_channel', aliases=['sgc']) @is_owner() async def set_personal_general_channel(self, ctx, channel: discord.TextChannel): """ Sets the general channel for the bot's personal server. """ await ctx.bot.mdb['bot_settings'].update_one({'setting': 'personal_server'}, {'$set': {'general_channel': channel.id}}, upsert=True ) self.bot.personal_server['general_channel'] = channel.id return await ctx.send(f'Set <#{channel.id}> to sheet channel.') @admin.command(name='leave') @is_owner() async def leave_guild(self, ctx, guild_id: int): """ Leaves the specified guild """ to_leave: discord.Guild = self.bot.get_guild(guild_id) if to_leave is not None: await ctx.send(f'Leaving Guild: `{to_leave.name}`') try: await to_leave.leave() except discord.HTTPException: pass else: return await ctx.send('Guild not found.') @admin.command(name='mute', description='Mutes a user. Prevents them from using the bot.') @is_owner() async def mute(self, ctx, to_mute: discord.Member): """ Mutes a user from the bot. """ record = {'_id': to_mute.id} db = self.bot.mdb['muted_clients'] muted = await db.find_one(record) if muted is None: await db.insert_one(record) await self.bot.update_muted_from_db() return await ctx.send(f'User {to_mute.name}#{to_mute.discriminator} has been muted.') else: return await ctx.send(f'User {to_mute.name}#{to_mute.discriminator} has already been muted.') @admin.command(name='unmute', description='Un-mutes a user.') @is_owner() async def unmute(self, ctx, to_mute: discord.Member): """ Unmutes a user from the bot. """ record = {'_id': to_mute.id} db = self.bot.mdb['muted_clients'] muted = await db.find_one(record) if muted: await db.delete_one(record) await self.bot.update_muted_from_db() return await ctx.send(f'User {to_mute.name}#{to_mute.discriminator} has been un-muted.') else: return await ctx.send(f'User {to_mute.name}#{to_mute.discriminator} is not muted.') # ---- Server Owner Commands ---- @commands.command(name='prefix', description='Changes the Bot\'s Prefix. Must have Manage Server.') @commands.check_any(commands.has_guild_permissions(manage_guild=True), is_owner()) @commands.guild_only() async def change_prefix(self, ctx, to_change: str = None): """ Changes the prefix for the current guild Can only be ran in a guild. If no prefix is specified, will show the current prefix. """ embed = create_default_embed(ctx) guild_id = str(ctx.guild.id) if to_change is None: if guild_id in self.bot.prefixes: prefix = self.bot.prefixes.get(guild_id, self.bot.prefix) else: dbsearch = await self.bot.mdb['prefixes'].find_one({'guild_id': guild_id}) if dbsearch is not None: prefix = dbsearch.get('prefix', self.bot.prefix) else: prefix = self.bot.prefix self.bot.prefixes[guild_id] = prefix embed.title = f'Prefix for {ctx.guild.name}' embed.description = f'Current Prefix: `{prefix}`' return await ctx.send(embed=embed) else: await ctx.bot.mdb['prefixes'].update_one({'guild_id': guild_id}, {'$set': {'prefix': to_change}}, upsert=True) ctx.bot.prefixes[guild_id] = to_change embed.title = f'Prefix updated for {ctx.guild.name}!' embed.description = f'Server prefix updated to `{to_change}`' return await ctx.send(embed=embed)