async def tagremote_update(bot, context): """Renames the webhook with an updated tag list file.""" # Check for an existing session session_data = data.get(bot, __name__, 'data', guild_id=context.guild.id) if not session_data: raise CBException("No session available.") channel = data.get_channel(bot, session_data['channel']) if not channel: await _delete_session(bot, context.guild) raise CBException("Failed to get the channel.") voice_channel = data.get_channel(bot, session_data['voice_channel']) if not voice_channel: await _delete_session(bot, context.guild) raise CBException("Failed to get the voice channel.") webhooks = await channel.webhooks() if not webhooks: await _delete_session(bot, context.guild) raise CBException("No webhooks available.") for webhook in webhooks: if webhook.id == session_data['webhook']: break else: await _delete_session(bot, context.guild) raise CBException("Webhook not found.") tag_dictionary = _get_tag_dictionary(bot, context.guild) session_code = await _upload_session_data(bot, channel, voice_channel, webhook, tag_dictionary) updated_code = session_code.split(':')[1] await webhook.edit(name='Tag Remote [{}]'.format(updated_code)) return Response( content="Tag data refreshed. Update the remote on your phone via the options menu.")
async def setup_globals(bot): """Sets up the DATA_CHANNEL global""" global DATA_CHANNEL DATA_CHANNEL = data.get_channel(bot, configurations.get(bot, __name__, key='data_channel')) if not DATA_CHANNEL: logger.warn("Failed to find the data channel. Defaulting to the upload channel.") DATA_CHANNEL = data.get_channel(bot, configurations.get(bot, 'core', key='upload_channel')) # Clear any webhooks (debug) webhooks = await DATA_CHANNEL.webhooks() for webhook in webhooks: logger.debug("Deleting webhook %s", webhook) await webhook.delete()
async def commission_configure(bot, context): """Configures the channel and cooldown for the commission channel rules.""" rules = data.get(bot, __name__, 'rules', guild_id=context.guild.id, default={}) default_cooldown = configurations.get(bot, __name__, 'default_cooldown') replace_channel = context.options.get('channel', rules.get('channel')) replace_cooldown = context.options.get( 'cooldown', rules.get('cooldown', default_cooldown)) if not replace_channel: raise CBException("No commission channel configured.") # Reset advertisement data rules = {'channel': replace_channel, 'cooldown': replace_cooldown} data.add(bot, __name__, 'rules', rules, guild_id=context.guild.id) data.remove(bot, __name__, 'advertisements', guild_id=context.guild.id, volatile=True, safe=True) await _get_advertisement_data(bot, context.guild) description = 'Channel: {0.mention}\nCooldown: {1}'.format( data.get_channel(bot, replace_channel), utilities.get_time_string(replace_cooldown, text=True, full=True)) embed = discord.Embed(title='Commission channel configuration:', description=description) return Response(embed=embed)
async def autolog_dump(bot, context): """Dumps logs into the set channel.""" log_channel = _check_log_channel(bot, context.guild) logged_channel_ids = data.get(bot, __name__, 'channels', guild_id=context.guild.id, default=[]) logged_channels = [] if context.arguments[0]: for channel in context.arguments: if channel.id not in logged_channel_ids: raise CBException("{} is not being logged.".format(channel.mention)) else: logged_channels.append(channel) else: for channel_id in logged_channel_ids: channel = data.get_channel(bot, channel_id, safe=True) if channel: logged_channels.append(channel) else: channel = discord.Object(id=channel_id) channel.mention = 'Deleted channel ({})'.format(channel_id) logged_channels.append(channel) # Build dump data logs = data.get(bot, __name__, 'logs', guild_id=context.guild.id, volatile=True) details = 'Manual dump by {0} (<@{0.id}>): {1}'.format( context.author, context.options['details']) dump_data = _build_dump_data(bot, logs, log_channel, details=details) # Upload dump data logged_messages = await _dump( bot, dump_data, log_channel, details=details, query=context.options['query'], moderator_id=context.author.id, logged_channels=logged_channels) if not logged_messages: raise CBException("No messages to log.") return Response("Messages dumped in {}".format(log_channel.mention))
async def tagremote(bot, context): """Gets the current session data as a link.""" session_data = data.get(bot, __name__, 'data', guild_id=context.guild.id) if not session_data: raise CBException( "No session available.\nStart one with `{}tagremote start`".format( utilities.get_invoker(bot, guild=context.guild))) channel_id, session_code = session_data['channel'], session_data['session'] voice_channel_id = session_data['voice_channel'] channel_mention = data.get_channel(bot, channel_id, guild=context.guild).mention voice_channel_mention = data.get_channel(bot, voice_channel_id, guild=context.guild).mention description = 'The session code is:\n`{}`\nThe session is attached to {} and {}'.format( session_code, channel_mention, voice_channel_mention) return Response(embed=discord.Embed( title='Tap here on your phone to use the tag remote', url='https://jkchen2.github.io/tag-remote/#{}'.format(session_code), description=description))
def __call__(self, bot, message, value, *a): if self.live_check: guild = self.live_check(bot, message, value, *a) else: guild = message.guild if self.server_only else None try: return data.get_channel( bot, value, guild=guild, strict=self.server_only, constraint=self.constraint, attribute=self.attribute) except BotException as e: self.set_error_reason(e, 'channel')
async def _get_advertisement_data(bot, guild, ignore_user_id=None): """Gets a dictionary of advertisements in the guild, or builds one if necessary. If ignore_user_id is provided, this will ignore the first message by that user. """ rules = data.get(bot, __name__, 'rules', guild_id=guild.id) if not rules: raise CBException( "Commission channel rules are not configured on this server.") advertisement_data = data.get(bot, __name__, 'advertisements', guild_id=guild.id, volatile=True) if advertisement_data: return advertisement_data # No data found. Fetch it manually channel = data.get_channel(bot, rules['channel'], safe=True) if not channel: raise CBException("The commission channel was not found.") # TODO: Add permission checks for channel access and deleting messages advertisement_data = {} whitelist = data.get(bot, __name__, 'whitelist', guild_id=guild.id, default=[]) async for message in channel.history(limit=100): author_id = message.author.id if (not message.author.bot and message.type is discord.MessageType.default and not message.pinned and author_id not in whitelist): if author_id in advertisement_data: logger.warn('Deleting previously undetected message %s', message.id) await message.delete() else: if ignore_user_id == author_id: ignore_user_id = None else: advertisement_data[author_id] = message data.add(bot, __name__, 'advertisements', advertisement_data, guild_id=guild.id, volatile=True) return advertisement_data
async def autolog_channels(bot, context): """Sets the channels that will be logged.""" log_channel = _check_log_channel(bot, context.guild) # Toggle channels for logging if context.arguments[0]: changes = [] for channel in context.arguments: appended = data.list_data_toggle( bot, __name__, 'channels', channel.id, guild_id=context.guild.id) if appended: changes.append('Now logging {}'.format(channel.mention)) _set_logger(bot, channel) else: changes.append('No longer logging {}'.format(channel.mention)) _delete_logger(bot, channel) embed = discord.Embed(title='Logging changes', description='\n'.join(changes)) # Show channels that are currently logged else: default_message_limit = configurations.get(bot, __name__, key='message_limit') message_limit = data.get( bot, __name__, 'message_limit', guild_id=context.guild.id, default=default_message_limit) logged_channel_ids = data.get(bot, __name__, 'channels', guild_id=context.guild.id) if not logged_channel_ids: raise CBException("No channels are currently logged.") # Check logged channels # Removes channels that were deleted and have no logged messages logged_channels = [] logs = data.get(bot, __name__, 'logs', guild_id=context.guild.id, volatile=True) for channel_id in logged_channel_ids: channel = data.get_channel(bot, channel_id, safe=True) if channel: logged_channels.append(channel) else: if len(logs[channel_id]): channel = discord.Object(id=channel_id) channel.mention = 'Deleted channel ({})'.format(channel_id) logged_channels.append(channel) else: # No logged messages for removed channel. Delete log. del logs[channel_id] embed = discord.Embed(title='Logging info') embed.add_field( inline=False, name='Logged channels', value=', '.join(it.mention for it in logged_channels)) embed.add_field(name='Dump channel', value=log_channel.mention) embed.add_field(name='Logged messages', value=message_limit) return Response(embed=embed)
def __call__(self, bot, message, value, *a): if self.live_check: guild = live_check(bot, message, value, *a) else: guild = message.guild if self.server_only else None try: return data.get_channel(bot, value, guild=guild, strict=self.server_only, constraint=self.constraint) except BotException as e: self.set_error_reason(e, 'channel')
async def autolog_dump(bot, context): """Dumps logs into the set channel.""" log_channel = _check_log_channel(bot, context.guild) logged_channel_ids = data.get(bot, __name__, 'channels', guild_id=context.guild.id, default=[]) logged_channels = [] if context.arguments[0]: for channel in context.arguments: if channel.id not in logged_channel_ids: raise CBException("{} is not being logged.".format( channel.mention)) else: logged_channels.append(channel) else: for channel_id in logged_channel_ids: channel = data.get_channel(bot, channel_id, safe=True) if channel: logged_channels.append(channel) else: channel = discord.Object(id=channel_id) channel.mention = 'Deleted channel ({})'.format(channel_id) logged_channels.append(channel) # Build dump data logs = data.get(bot, __name__, 'logs', guild_id=context.guild.id, volatile=True) details = 'Manual dump by {0} (<@{0.id}>): {1}'.format( context.author, context.options['details']) dump_data = _build_dump_data(bot, logs, log_channel, details=details) # Upload dump data logged_messages = await _dump(bot, dump_data, log_channel, details=details, query=context.options['query'], moderator_id=context.author.id, logged_channels=logged_channels) if not logged_messages: raise CBException("No messages to log.") return Response("Messages dumped in {}".format(log_channel.mention))
async def upload_to_discord(bot, fp, filename=None, rewind=True, close=False): """Uploads the given file-like object to the upload channel. If the upload channel is specified in the configuration files, files will be uploaded there. Otherwise, a new guild will be created, and used as the upload channel.""" channel_id = configurations.get(bot, 'core', 'upload_channel') if not channel_id: # Check to see if a guild was already created channel_id = data.get(bot, 'core', 'upload_channel') channel = data.get_channel(bot, channel_id, safe=True) if channel is None: # Create guild logger.debug("Creating guild for upload channel...") try: guild = await bot.create_guild('uploads') except Exception as e: raise CBException( "Failed to create upload guild. This bot is not whitelisted " "to create guilds.", e=e) data.add(bot, 'core', 'upload_channel', guild.id) channel = bot.get_channel(guild.id) if channel is None: # Shouldn't happen raise CBException("Failed to get upload channel.") try: discord_file = discord.File(fp, filename=filename) message = await channel.send(file=discord_file) upload_url = message.attachments[0].url except Exception as e: raise CBException("Failed to upload file.", e=e) try: if close: fp.close() elif rewind: fp.seek(0) except: pass return upload_url
async def upload_to_discord(bot, fp, filename=None, rewind=True, close=False): """Uploads the given file-like object to the upload channel. If the upload channel is specified in the configuration files, files will be uploaded there. Otherwise, a new guild will be created, and used as the upload channel.""" channel_id = configurations.get(bot, 'core', 'upload_channel') if not channel_id: # Check to see if a guild was already created channel_id = data.get(bot, 'core', 'upload_channel') channel = data.get_channel(bot, channel_id, safe=True) # TODO: Remove. Guild creation via bots is a whitelisted process if channel is None: # Create guild logger.debug("Creating guild for upload channel...") try: guild = await bot.create_guild('uploads') except Exception as e: raise CBException( "Failed to create upload guild. This bot is not whitelisted " "to create guilds.", e=e) data.add(bot, 'core', 'upload_channel', guild.id) channel = bot.get_channel(guild.id) if channel is None: # Shouldn't happen raise CBException("Failed to get upload channel.") try: discord_file = discord.File(fp, filename=filename) message = await channel.send(file=discord_file) upload_url = message.attachments[0].url except Exception as e: raise CBException("Failed to upload file.", e=e) try: if close: fp.close() elif rewind: fp.seek(0) except: pass return upload_url
async def check_webhook_messages(bot, message): """Reads webhook messages and calls tags if necessary.""" if message.author.id in WEBHOOK_SET: session_data = data.get(bot, __name__, 'data', guild_id=message.guild.id) voice_channel = data.get_channel(bot, session_data['voice_channel'], guild=message.guild) # Ignore if nobody is in the channel if not [it for it in voice_channel.members if not it.bot]: pass # Retrieve tag elif message.content.startswith('[Retrieve]'): tag_name = message.content[10:].strip() try: tag = TAG_CONVERTER(bot, message, tag_name, channel_bypass=voice_channel) except BotException as e: logger.warn("Failed to retrieve tag: %s", e) else: tags_plugin = bot.plugins['tags.py'] url = random.choice(tag.value) try: await tags_plugin._play_sound_tag(bot, tag, url, voice_channel, delay=-1) except BotException as e: logger.warn("Failed to play tag: %s", e) else: tags_plugin._update_hits(bot, tag.key, message.author.id, message.guild.id) # Stop audio elif message.content == '[Stop audio]': voice_client = message.guild.voice_client if (voice_client and voice_client.channel == voice_channel and voice_client.is_playing()): voice_client.stop() # Always remove messages await asyncio.sleep(3) try: await message.delete() except: pass
async def _delete_session(bot, guild): """Deletes the session for the given guild.""" session_data = data.remove(bot, __name__, 'data', guild_id=guild.id, safe=True) if not session_data: raise CBException("Session does not exist.") channel_id, webhook_id = session_data['channel'], session_data['webhook'] channel = data.get_channel(bot, channel_id, safe=True) webhooks = await channel.webhooks() for webhook in webhooks: if webhook.id == webhook_id: await webhook.delete() break else: logger.warn('Webhook to delete (%s) not found!', webhook_id) try: WEBHOOK_SET.remove(webhook_id) except KeyError: logger.warn("Webhook not found in WEBHOOK_SET") data.list_data_remove(bot, __name__, 'webhooks', value=webhook_id, safe=True) if guild.voice_client and guild.voice_client.channel.id == session_data['voice_channel']: await utilities.stop_audio(bot, guild)
async def _menu(bot, context, response, result, timed_out): if not result and not timed_out: return # Timed out or skipped waiting period if timed_out or (result[0].emoji == '⏭'): response.embed.remove_field(2) response.embed.set_field_at(1, name='\u200b', value='Logging started.') await response.message.edit(embed=response.embed) asyncio.ensure_future( _dump(bot, dump_data, log_channel, details=details, query=query, moderator_id=moderator_id)) # Cancelled elif result[0].emoji == '❌': response.embed.remove_field(2) response.embed.add_field(name='\u200b', value='Logging cancelled.') await response.message.edit(embed=response.embed) # Specify channels else: response.embed.set_field_at( 2, name='\u200b', inline=False, value= '**Type the channels you want to log, separated by spaces.**') await response.message.edit(embed=response.embed) try: await response.message.clear_reactions() except: pass # Read response kwargs = { 'timeout': 300, 'check': lambda m: m.author == result[1] and m.channel == context. channel } channels = [] response.embed.remove_field(2) try: result = await bot.wait_for('message', **kwargs) for it in result.content.split(): channel = data.get_channel(bot, it, constraint=discord.TextChannel) if channel.id not in channel_ids: raise CBException("Channel {} not logged.".format( channel.mention)) channels.append(channel) try: await result.delete() except: pass except BotException as e: logger.debug("Error!") response.embed.set_field_at( 1, name='\u200b', value='{}\nDefault channels will be logged.'.format( e.error_details)) except Exception as e: logger.debug("Timeout!") response.embed.set_field_at( 1, name='\u200b', value= 'Channel selection timed out. Default channels will be logged.' ) # Upload dump data await response.message.edit(embed=response.embed) await _dump(bot, dump_data, log_channel, details=details, query=query, moderator_id=moderator_id, logged_channels=channels) return False
async def _menu(bot, context, response, result, timed_out): if not result and not timed_out: return # Timed out or skipped waiting period if timed_out or (result[0].emoji == '⏭'): response.embed.remove_field(2) response.embed.set_field_at(1, name='\u200b', value='Logging started.') await response.message.edit(embed=response.embed) asyncio.ensure_future(_dump( bot, dump_data, log_channel, details=details, query=query, moderator_id=moderator_id)) # Cancelled elif result[0].emoji == '❌': response.embed.remove_field(2) response.embed.add_field( name='\u200b', value='Logging cancelled.') await response.message.edit(embed=response.embed) # Specify channels else: response.embed.set_field_at( 2, name='\u200b', inline=False, value='**Type the channels you want to log, separated by spaces.**') await response.message.edit(embed=response.embed) try: await response.message.clear_reactions() except: pass # Read response kwargs = { 'timeout': 300, 'check': lambda m: m.author == result[1] and m.channel == context.channel } channels = [] response.embed.remove_field(2) try: result = await bot.wait_for('message', **kwargs) for it in result.content.split(): channel = data.get_channel(bot, it, constraint=discord.TextChannel) if channel.id not in channel_ids: raise CBException("Channel {} not logged.".format(channel.mention)) channels.append(channel) try: await result.delete() except: pass except BotException as e: logger.debug("Error!") response.embed.set_field_at( 1, name='\u200b', value='{}\nDefault channels will be logged.'.format(e.error_details)) except Exception as e: logger.debug("Timeout!") response.embed.set_field_at( 1, name='\u200b', value='Channel selection timed out. Default channels will be logged.') # Upload dump data await response.message.edit(embed=response.embed) await _dump( bot, dump_data, log_channel, details=details, query=query, moderator_id=moderator_id, logged_channels=channels) return False
async def mod_wrapper(bot, message, base, blueprint_index, options, arguments, keywords, cleaned_content): response, tts, message_type, extra = ('', False, 0, None) mod_action = '' if blueprint_index == 0: # info server_data = data.get(bot, 'base', None, server_id=message.server.id, default={}) disabled_commands = server_data.get('disabled', []) display_list = [] for disabled_command in disabled_commands: display_list.append('{0} ({1})'.format( disabled_command[0], 'all' if disabled_command[1] == -1 else disabled_command[1] + 1)) response = ('```\n' 'Information for server {0}\n' 'ID: {0.id}\n' 'Owner: {0.owner.id}\n' 'Moderators: {1}\n' 'Blocked users: {2}\n' 'Muted: {3}\n' 'Muted channels: {4}\n' 'Command invoker: {5}\n' 'Mention mode: {6}\n' 'Disabled commands: {7}```').format( message.server, server_data.get('moderators', []), server_data.get('blocked', []), server_data.get('muted', []), server_data.get('muted_channels', []), server_data.get('command_invoker', None), server_data.get('mention_mode', False), display_list) elif blueprint_index == 1: # Toggle command try: # Explicit index split_arguments = arguments[0].split() command = bot.commands[split_arguments[0]] guess = [command.base, int(split_arguments[1]) - 1] assert -1 < guess[1] < len(command.blueprints) except IndexError: # No index guess = [command.base, -1] except: # Guess the help index guess = list(parser.guess_index(bot, arguments[0])) if guess[0] is None: raise BotException(EXCEPTION, "Invalid base.") command = bot.commands[guess[0]] if command.plugin is bot.commands['base'].plugin: raise BotException(EXCEPTION, "The base commands cannot be disabled.") pass_in = (bot, 'base', 'disabled', guess) pass_in_keywords = {'server_id': message.server.id} disabled_commands = data.get(*pass_in[:-1], **pass_in_keywords, default=[]) if guess in disabled_commands: data.list_data_remove(*pass_in, **pass_in_keywords) response = "Enabled" else: data.list_data_append(*pass_in, **pass_in_keywords) response = "Disabled" response += " the `{0}` command {1}.".format( guess[0], "and all associated subcommands" if guess[1] == -1 else "(subcommand {})".format(guess[1] + 1)) mod_action = response elif blueprint_index in (2, 3): # Block or unblock user = data.get_member(bot, arguments[0], message.server) block = blueprint_index == 2 mod_action = 'Blocked {}' if block else 'Unblocked {}' mod_action = mod_action.format('{0} ({0.id})'.format(user)) blocked = data.is_blocked(bot, message.server, user.id, strict=True) mod = data.is_mod(bot, message.server, user.id) if mod: raise BotException(EXCEPTION, "Cannot block or unblock a moderator.") elif block: if blocked: raise BotException(EXCEPTION, "User is already blocked.") else: data.list_data_append(bot, 'base', 'blocked', user.id, server_id=message.server.id) response = "User is now blocked." else: if not blocked: raise BotException(EXCEPTION, "User is already unblocked.") else: data.list_data_remove(bot, 'base', 'blocked', user.id, server_id=message.server.id) response = "User is now unblocked." elif blueprint_index == 4: # Clear response = ('' + '\n' * 80 + "The chat was pushed up by a bot moderator.") elif blueprint_index in (5, 6): # Mute or unmute server_id = message.server.id mute = blueprint_index == 5 mod_action = 'Muted {}' if mute else 'Unmuted {}' if arguments[0]: channel = data.get_channel(bot, arguments[0], message.server) muted = channel.id in data.get(bot, 'base', 'muted_channels', server_id=server_id, default=[]) mod_action = mod_action.format(channel.name) if mute: if muted: raise BotException(EXCEPTION, "Channel is already muted.") else: data.list_data_append(bot, 'base', 'muted_channels', channel.id, server_id=server_id) if str(channel.type) == 'voice': # disconnect await utilities.leave_and_stop(bot, message.server) response = "Channel muted." else: # unmute if not muted: raise BotException(EXCEPTION, "Channel is already unmuted.") else: data.list_data_remove(bot, 'base', 'muted_channels', channel.id, server_id=server_id) response = "Channel unmuted." else: # server mod_action = mod_action.format('the server') muted = data.get(bot, 'base', 'muted', server_id=server_id, default=False) if not (muted ^ mute): response = "Server is already {}muted.".format( '' if muted else 'un') raise BotException(EXCEPTION, response) else: data.add(bot, 'base', 'muted', mute, server_id=server_id) response = "Server {}muted.".format('' if mute else 'un') elif blueprint_index == 7: # Invoker if len(arguments[0]) > 10: raise BotException( EXCEPTION, "The invoker can be a maximum of 10 characters long.") data.add(bot, 'base', 'command_invoker', arguments[0] if arguments[0] else None, server_id=message.server.id) response = "Custom command invoker {}.".format( 'set' if arguments[0] else 'cleared') if arguments[0]: response = "Custom command invoker set." mod_action = "Set the server command invoker to '{}'.".format( arguments[0]) else: response = "Custom command invoker cleared." mod_action = "Removed the custom command invoker." elif blueprint_index == 8: # Mention current_mode = data.get(bot, 'base', 'mention_mode', server_id=message.server.id, default=False) data.add(bot, 'base', 'mention_mode', not current_mode, server_id=message.server.id) response = "Mention mode {}activated.".format( 'de' if current_mode else '') mod_action = "{}activated mention mode.".format( 'de' if current_mode else '').capitalize() # Send notification if configured send_notifications = data.get(bot, 'base', 'notifications', server_id=message.server.id, default=True) if mod_action and send_notifications: if message.edited_timestamp: timestamp = message.edited_timestamp else: timestamp = message.timestamp notification = ('Moderator {0} ({0.id}) from {0.server} on {1}:\n\t' '{2}').format(message.author, timestamp, mod_action) logs = await utilities.get_log_text(bot, message.channel, limit=20, before=message) logs += '\n{}'.format(utilities.get_formatted_message(message)) await bot.send_message(message.server.owner, notification) await utilities.send_text_as_file(bot, message.server.owner, logs, 'context') return (response, tts, message_type, extra)
async def autolog_channels(bot, context): """Sets the channels that will be logged.""" log_channel = _check_log_channel(bot, context.guild) # Toggle channels for logging if context.arguments[0]: changes = [] for channel in context.arguments: appended = data.list_data_toggle(bot, __name__, 'channels', channel.id, guild_id=context.guild.id) if appended: changes.append('Now logging {}'.format(channel.mention)) _set_logger(bot, channel) else: changes.append('No longer logging {}'.format(channel.mention)) _delete_logger(bot, channel) embed = discord.Embed(title='Logging changes', description='\n'.join(changes)) # Show channels that are currently logged else: default_message_limit = configurations.get(bot, __name__, key='message_limit') message_limit = data.get(bot, __name__, 'message_limit', guild_id=context.guild.id, default=default_message_limit) logged_channel_ids = data.get(bot, __name__, 'channels', guild_id=context.guild.id) if not logged_channel_ids: raise CBException("No channels are currently logged.") # Check logged channels # Removes channels that were deleted and have no logged messages logged_channels = [] logs = data.get(bot, __name__, 'logs', guild_id=context.guild.id, volatile=True) for channel_id in logged_channel_ids: channel = data.get_channel(bot, channel_id, safe=True) if channel: logged_channels.append(channel) else: if len(logs[channel_id]): channel = discord.Object(id=channel_id) channel.mention = 'Deleted channel ({})'.format(channel_id) logged_channels.append(channel) else: # No logged messages for removed channel. Delete log. del logs[channel_id] embed = discord.Embed(title='Logging info') embed.add_field(inline=False, name='Logged channels', value=', '.join(it.mention for it in logged_channels)) embed.add_field(name='Dump channel', value=log_channel.mention) embed.add_field(name='Logged messages', value=message_limit) return Response(embed=embed)