async def learn_markov_from_history(self, channel: discord.TextChannel): if channel.permissions_for(channel.guild.me).read_message_history: await channel.history(limit=5000).map(self.learn_markov).flatten() self.log_info('Markov: Initialized channel %s', channel) return True self.log_error('Markov: missing ReadMessageHistory permission for %s', channel) return False
async def modlog(self, ctx: commands.Context, channel: discord.TextChannel = None): """Set a channel as the modlog. Omit `<channel>` to disable the modlog. """ guild = ctx.guild if channel: if channel.permissions_for(guild.me).send_messages: await modlog.set_modlog_channel(guild, channel) await ctx.send( _("Mod events will be sent to {channel}").format(channel=channel.mention) ) else: await ctx.send( _("I do not have permissions to send messages in {channel}!").format( channel=channel.mention ) ) else: try: await modlog.get_modlog_channel(guild) except RuntimeError: await ctx.send_help() else: await modlog.set_modlog_channel(guild, None) await ctx.send(_("Mod log deactivated."))
async def logset_channel(self, ctx: commands.Context, module: str, channel: discord.TextChannel = None): """Set the log channel for a module Passing no log channel effectively acts as disabling the module """ module = await retrieve_module(ctx, module) if channel and not channel.permissions_for(ctx.guild.me).send_messages: await ctx.send( warning(i18n("I'm not able to send messages in that channel"))) return await module.module_config.set_raw("_log_channel", value=getattr(channel, "id", None)) if channel: await ctx.send( tick( i18n("Module **{module}** will now log to {channel}"). format(module=module.friendly_name, channel=channel.mention))) else: await ctx.send( tick( i18n( "The log channel for module **{module}** has been cleared" ).format(module=module.friendly_name)))
async def _embed_requested(self, ctx: commands.Context, channel: discord.TextChannel) -> bool: if not await self.config.embeds(): return False if isinstance(channel, discord.DMChannel): return True return channel.permissions_for(ctx.me).embed_links
async def set_news_channel(self, ctx, channel: discord.TextChannel): """ Adds channel to publish list To remove, please use `[p]publishset removenews channel-name` """ if not channel.is_news(): return await ctx.send("{} is not a News Channel.".format( channel.mention)) if channel.permissions_for(ctx.guild.me).manage_messages is False: return await ctx.send( "I do not have `manage_messages` in {} to publish. Please adjust my permissions." .format(channel.mention)) if await self.is_in_list(guild=ctx.guild, channel=channel): return await ctx.send( "{} is already in the publish list. Nothing for me to add.". format(channel.mention)) async with self.config.guild(ctx.guild).news_channels() as news: news.append(channel.id) await ctx.send("Added {} to publish watchlist.".format(channel.mention) )
async def oof( self, ctx: commands.Context, msg_id: int = None, channel: discord.TextChannel = None ) -> None: """ react 🅾🇴🇫 to a message `msg_id` must be the message ID for desited message within the channel `channel` must be the channel where the desired message is defaults to current channel if the bot has manage messages permission it will attempt to delete the command """ emojis = ["🅾", "🇴", "🇫"] if channel is None: channel = ctx.message.channel if msg_id is None: async for messages in channel.history(limit=2): message = messages else: try: message = await channel.fetch_message(msg_id) except AttributeError: message = await channel.get_message(msg_id) # type: ignore # discord.py backwards compatibility support except Exception: await ctx.send( "Message ID {} not found in {}".format(msg_id, channel.mention), delete_after=5 ) return if ctx.channel.permissions_for(ctx.me).manage_messages: await ctx.message.delete() if channel.permissions_for(ctx.me).add_reactions: for emoji in emojis: try: await message.add_reaction(emoji) except discord.errors.Forbidden: return
async def diagnoseissues( self, ctx: commands.Context, channel: discord.TextChannel, member: Union[discord.Member, discord.User], *, command_name: str, ) -> None: """Diagnose issues with command checks with ease!""" command = self.bot.get_command(command_name) if command is None: await ctx.send("Command not found!") return # This is done to allow the bot owner to diagnose a command # while not being a part of the server. if isinstance(member, discord.User): maybe_member = channel.guild.get_member(member.id) if maybe_member is None: await ctx.send( _("The given user is not a member of the diagnosed server." )) return member = maybe_member if not channel.permissions_for(member).send_messages: # Let's make Flame happy here await ctx.send( _("Don't try to fool me, the given member can't access the {channel} channel!" ).format(channel=channel.mention)) return issue_diagnoser = IssueDiagnoser(self.bot, ctx, channel, member, command) await ctx.send(await issue_diagnoser.diagnose())
async def new(self, ctx: commands.Context, channel: discord.TextChannel): perms = channel.permissions_for(ctx.guild.me) if not perms.send_messages: return await ctx.send( embed=discord.Embed(description=( f"I'm missing the **send messages** permission " f"in {channel.mention}.\n" f"Correct my permissions and try again!"), color=ctx.bot.colorsg['failure'])) if not perms.embed_links: return await ctx.send( embed=discord.Embed(description=( f"I'm missing the **embed links** permission " f"in {channel.mention}.\n" f"Correct my permissions and try again!"), color=ctx.bot.colorsg['failure'])) gstorage = ctx.bot.get_storage(ctx.guild) # type: Storage id = await gstorage.increment('statusembeds') storage = gstorage / 'statusembed' / str(id) await storage.set('channel', channel.id) message = await channel.send(embed=discord.Embed( description=f'{EMOJIS[STATE_OPERATIONAL]} All systems operational', color=ctx.bot.colorsg['success'])) await storage.set('message', message.id) prefix = (await ctx.bot.get_command_prefix(ctx.bot, ctx.message))[0] await ctx.send(embed=discord.Embed( title=f'Statusembed {id} created!', description=( f'The statusembed id is **{id}**.\n\n' f'You can now use commands to manage the statusembed.\n' f'- `{prefix}statusembed add {id} "Bot Status"`\n'), color=ctx.bot.colorsg['success']))
async def disable(self, ctx: commands.Context, channel: discord.TextChannel = None): plugin_config = self._config.get('reactToPin', {}) # type: dict if channel is None: channel = ctx.channel if not channel.permissions_for(ctx.author).manage_channels: # Prevent editing channels out of scope. raise commands.MissingPermissions( discord.Permissions.manage_channels) channel_config = plugin_config.setdefault(str(channel.id), {'enabled': False}) if not channel_config.get('enabled', False): await ctx.send(embed=discord.Embed( title=Emojis.PIN + " ReactToPin Already Disabled!", description= f"ReactToPin has already been disabled for {channel.mention}. No changes were made.", color=Colors.WARNING)) return channel_config['enabled'] = False self._config.set('reactToPin', plugin_config) await ctx.send(embed=discord.Embed( title=Emojis.PIN + " ReactToPin Disabled!", description= f"ReactToPin has been disabled for {channel.mention} with default settings. Settings are " "preserved.", color=Colors.SUCCESS))
async def move_message_attempt(self, message: discord.Message, channel: discord.TextChannel, move_request_user: discord.Member): """ Called when ther user attempts to move a message. Can be called with an emoji or with a command. """ member_can_move_messages = channel.permissions_for( move_request_user).manage_messages should_get_moved = (member_can_move_messages or move_request_user == message.author or move_request_user.id == self.bot.makusu.id) if should_get_moved: attachment_files = [ await attachment.to_file() for attachment in message.attachments ] move_description = (f"{move_request_user.mention} has moved " f"this here from {message.channel.mention}. " f"OP was {message.author.mention}.\n" f"{message.content}") await channel.send(move_description, files=attachment_files) await message.delete() else: await message.channel.send("Looks like you don\"t have the manage " "messages role and you\"re not OP :(")
async def modlogs(self, ctx, *, new: discord.TextChannel = None): """Views (or sets) the guild's new modlog! To set a channel, you must have `manage server` and `manage channels` permissions.""" data = read("./data/core.json") def a(): return ctx.author.guild_permissions.manage_channels and ctx.author.guild_permissions.manage_guild if not a() or new is None: channel = self.bot.get_channel(data[str( ctx.guild.id)]["log channel"]) if channel is None: data[str(ctx.guild.id)]["log channel"] = None write("./data/core.json", data) return await ctx.send(embed=discord.Embed( description="You don't have a modlog channel set.")) else: e = discord.Embed( description= f"**Modlog Channel:** {channel.mention} ({channel.name})") return await ctx.send(embed=e) else: perms = new.permissions_for(ctx.me) if not perms.read_message_history or not perms.read_messages or not perms.embed_links or not perms.send_messages: return await ctx.send(embed=discord.Embed( title="That channel can't be used for modlog:", description="Not enough permissions", color=discord.Color.red())) data[str(ctx.guild.id)]["log channel"] = new.id write("./data/core.json", data) return await ctx.send(embed=discord.Embed( description=f"Set your modlog to {new.mention}.", color=discord.Color.dark_green()))
async def webhook_list(self, ctx: cmd.Context, channel: discord.TextChannel = None): """Lists webhooks for the server or a given channel""" if channel: channel_perms = channel.permissions_for(ctx.me) if not channel_perms.view_channel or not channel_perms.manage_webhooks: raise commands.BotMissingPermissions(["manage_webhooks"]) embed = discord.Embed( title="Webhooks", description=f"Use {get_command_signature(ctx, self.webhook_get)}" " to get more info on a webhook.", ) embed.set_footer( text="Page {current_page}/{total_pages}, " "showing webhook {first_field}..{last_field}/{total_fields}." ) paginator = menus.FieldPaginator(self.bot, base_embed=embed) for webhook in await ctx.guild.webhooks(): if webhook.type != discord.WebhookType.incoming: continue if channel and webhook.channel_id != channel.id: continue paginator.add_field( name=webhook.name, value=f"Channel: {webhook.channel.mention}\nID: {webhook.id}", ) await paginator.send(ctx)
def _permissions_checker(permissions: list, channel: discord.TextChannel): """Function to checks if the permissions are available. Parameters: permissions: list - List of permissions needed. channel: discord.TextChannel - Channel where permissions will be checked. Returns: bool or str: If all permissions are given to bot, it will return True, else it return a text which include missing permissions. """ missing_perm = [] for permission in permissions: if not getattr(channel.permissions_for(channel.guild.me), permission): missing_perm.append(permission.replace("_", " ").title()) if missing_perm: return ( "I am missing the following permission{plural} in {channel} " "before I start:\n{permissions}").format( plural="s" if len(missing_perm) > 1 else "", channel=channel.name, permissions="\n- ".join(("", *map(inline, missing_perm))), ) return True
async def webhook_new( self, ctx: cmd.Context, channel: discord.TextChannel, *, name: str ): """Creates a new webhook for a given channel""" channel_perms = channel.permissions_for(ctx.me) if not channel_perms.view_channel or not channel_perms.manage_webhooks: raise commands.BotMissingPermissions(["manage_webhooks"]) if len(name) > 80: await ctx.prompt( embed=discord.Embed( title="Webhook name too long", description="Webhook names can only be up to 80 characters long", ) ) return avatar_file = ( await ctx.message.attachments[0].read() if len(ctx.message.attachments) > 0 else None ) webhook = await channel.create_webhook(name=name, avatar=avatar_file) await ctx.prompt( embed=self.get_webhook_embed(ctx, webhook, message="New webhook created") )
async def oof(self, ctx, msg_id: int = None, channel: discord.TextChannel = None): """ react 🅾🇴🇫 to a message `msg_id` must be the message ID for desited message within the channel `channel` must be the channel where the desired message is defaults to current channel if the bot has manage messages permission it will attempt to delete the command """ emojis = ["🅾", "🇴", "🇫"] if channel is None: channel = ctx.message.channel if msg_id is None: async for message in channel.history(limit=2): msg_id = message else: try: msg_id = await channel.get_message(msg_id) except: await ctx.send("Message ID {} not found in {}".format( msg_id, channel.mention), delete_after=5) return if ctx.channel.permissions_for(ctx.me).manage_messages: await ctx.message.delete() if channel.permissions_for(ctx.me).add_reactions: for emoji in emojis: try: await msg_id.add_reaction(emoji) except: pass
async def add(self, ctx, discord_channel: discord.TextChannel, twitch_user: str, *, msg: str = None): """Sets up notifications for a Twitch user in the specified channel.""" if not ctx.message.author.permissions_in(ctx.message.channel).manage_guild: return await ctx.send("You need the **Manage Server** permission to do this.") username = twitch_user.split('/')[-1] if self.regex.match(username) is None: return await ctx.send("That doesn't look like a valid Twitch user. You can only include underscores, letters, and numbers.") if not discord_channel.permissions_for(ctx.guild.me).send_messages: return await ctx.send("I don't have permission to send messages in the requested channel.") try: await ctx.trigger_typing() s = TWAPI_REQUEST("https://api.twitch.tv/helix/users?login="******"That user does not exist.") else: if self.bot.notifs.get(s.json()['data'][0]['id']) is None: self.bot.notifs[s.json()['data'][0]['id']] = {str(discord_channel.id): {"name": username, "last_stream_id": None, "message": msg or "<https://twitch.tv/{}> is now live on Twitch!".format(username)}} else: self.bot.notifs[s.json()['data'][0]['id']][str(discord_channel.id)] = {"name": username, "last_stream_id": None, "message": msg or "<https://twitch.tv/{}> is now live on Twitch!".format(username)} f = open(os.path.join(os.getcwd(), 'data', 'notifs.json'), 'w') f.write(json.dumps(self.bot.notifs)) f.close() return await ctx.send("You should now receive a message in {} when `{}` goes live.".format(discord_channel.mention, username)) except KeyError as e: return await ctx.send("That Twitch user doesn't exist. Make sure that you're not putting <> around the name, and that you're not @mentioning a Discord user.") except IndexError as e: return await ctx.send("That Twitch user doesn't exist. Make sure that you're not putting <> around the name, and that you're not @mentioning a Discord user.") except: return await ctx.send(traceback.format_exc())
async def addchannel(self, ctx: commands.Context, channel: discord.TextChannel, *, time: str): """Add a channel cooldown. Time format can be the following: - `1 hour` - `1h` - `1 hour 5 minutes` - `2h30m10s` """ if not channel.permissions_for(ctx.me).manage_messages: await ctx.send( "I require the 'Manage messages' permission to let you use this command." ) return if str(channel.id) in await self.config.guild(ctx.guild ).cooldown_channels(): await ctx.send( "This channel is already added to the cooldown. If you want to edit" " the cooldown time, use `{prefix}slow channel edit`.".format( prefix=ctx.clean_prefix)) return time = self._return_time(time) if not time: await ctx.send("Your time is not correct to me.") return await self._update_channel_data(ctx, channel, time) await ctx.send( "{channel} is now set at 1 message every {time} seconds.".format( channel=channel.mention, time=time))
async def defmessagesgroupuserchannel(self, ctx: commands.Context, channel: discord.TextChannel): """Shows recent messages of a channel""" author = ctx.author if not channel.permissions_for(author).read_messages: self.send_to_monitor( ctx.guild, f"{author} ({author.id}) attempted to access the message " f"history of channel #{channel.name}") return await ctx.send( "You do not have read permissions in that channel. Request denied." ) pages = await self.make_message_log(channel, guild=author.guild, requester=author, pagify_log=True, replace_backtick=True) if not pages: return await ctx.send("No messages recorded in that channel.") self.send_to_monitor( ctx.guild, f"{author} ({author.id}) accessed the message history " f"of channel #{channel.name}") if len(pages) == 1: await ctx.send(box(pages[0], lang="rust")) else: pages = [box(p, lang="rust") for p in pages] await menu(ctx, pages, DEFAULT_CONTROLS)
async def modlog(self, ctx: commands.Context, channel: discord.TextChannel = None): """Set a channel as the modlog. Omit `<channel>` to disable the modlog. """ guild = ctx.guild if channel: if channel.permissions_for(guild.me).send_messages: await modlog.set_modlog_channel(guild, channel) await ctx.send( _("Mod events will be sent to {channel}.").format( channel=channel.mention)) else: await ctx.send( _("I do not have permissions to send messages in {channel}!" ).format(channel=channel.mention)) else: try: await modlog.get_modlog_channel(guild) except RuntimeError: await ctx.send_help() else: await modlog.set_modlog_channel(guild, None) await ctx.send(_("Mod log deactivated."))
async def send_embed(self, ctx: Context, channel: TextChannel, color: Optional[Union[Color, str]] = None): """ send an embed """ if isinstance(color, str): if not re.match(r"^[0-9a-fA-F]{6}$", color): raise CommandError(translations.invalid_color) color = int(color, 16) permissions: Permissions = channel.permissions_for(channel.guild.me) if not permissions.send_messages: raise CommandError(translations.could_not_send_message) if not permissions.embed_links: raise CommandError(translations.could_not_send_embed) embed = await read_embed(self.bot, ctx.channel, ctx.author) if color is not None: embed.colour = color try: await channel.send(embed=embed) except (HTTPException, Forbidden): raise CommandError(translations.msg_could_not_be_sent) else: await ctx.send(translations.msg_sent)
async def _get_mention_str( self, guild: discord.Guild, channel: discord.TextChannel) -> Tuple[str, List[discord.Role]]: """Returns a 2-tuple with the string containing the mentions, and a list of all roles which need to have their `mentionable` property set back to False. """ settings = self.config.guild(guild) mentions = [] edited_roles = [] if await settings.mention_everyone(): mentions.append("@everyone") if await settings.mention_here(): mentions.append("@here") can_manage_roles = guild.me.guild_permissions.manage_roles can_mention_everyone = channel.permissions_for( guild.me).mention_everyone for role in guild.roles: if await self.config.role(role).mention(): if not can_mention_everyone and can_manage_roles and not role.mentionable: try: await role.edit(mentionable=True) except discord.Forbidden: # Might still be unable to edit role based on hierarchy pass else: edited_roles.append(role) mentions.append(role.mention) return " ".join(mentions), edited_roles
async def modlog(self, ctx, channel: discord.TextChannel = None): """If no parameters are passed gets the current modlog If channel is provided modlog will be set to that channel. channel can be a channel mention, channel id or channel name (case sensitive) **Bot needs embed links permissions in modlog**""" if channel is None: modlog = self.bot.guild_cache.modlog(ctx.guild.id) modlog = self.bot.get_channel(modlog) if modlog: await ctx.send( f'Current modlog channel is {modlog.mention}\n' f'Use `{ctx.prefix}settings {ctx.invoked_with} channel_name` to change it' ) else: await ctx.send( 'No modlog channel set\n' f'Use `{ctx.prefix}settings {ctx.invoked_with} channel_name` to set one' ) ctx.command.reset_cooldown(ctx) return if not channel.permissions_for(ctx.guild.me).embed_links: return await ctx.send( f"Bot doesn't have embed links permissions in {channel.mention}" ) await self.bot.guild_cache.set_modlog(channel.guild.id, channel.id) await channel.send('Modlog set to this channel')
async def oof(self, ctx: commands.Context, msg_id: int = None, channel: discord.TextChannel = None) -> None: """ React 🅾🇴🇫 to a message. `msg_id` must be the message ID for desited message within the channel. `channel` must be the channel where the desired message is defaults to current channel if the bot has manage messages permission it will attempt to delete the command. """ if channel is None: channel = ctx.message.channel if msg_id is None: async for messages in channel.history(limit=2): message = messages else: try: message = await channel.fetch_message(msg_id) except discord.NotFound: return await ctx.send("Message ID {} not found in {}".format( msg_id, channel.mention), delete_after=5) if channel.permissions_for(ctx.me).add_reactions: with contextlib.suppress(discord.HTTPException): for emoji in ("🅾", "🇴", "🇫"): await message.add_reaction(emoji) if ctx.channel.permissions_for(ctx.me).manage_messages: await ctx.message.delete()
async def permissions(self, ctx: NabCtx, member: discord.Member = None, channel: discord.TextChannel = None): """Shows a member's permissions in the current channel. If no member is provided, it will show your permissions. Optionally, a channel can be provided as the second parameter, to check permissions in said channel.""" member = member or ctx.author channel = channel or ctx.channel guild_permissions = channel.permissions_for(member) embed = discord.Embed(title=f"Permissions in #{channel.name}", colour=member.colour) embed.set_author(name=member.display_name, icon_url=get_user_avatar(member)) allowed = [] denied = [] for name, value in guild_permissions: name = name.replace('_', ' ').replace('guild', 'server').title() if value: allowed.append(name) else: denied.append(name) if allowed: embed.add_field(name=f"{ctx.tick()}Allowed", value="\n".join(allowed)) if denied: embed.add_field(name=f"{ctx.tick(False)}Denied", value="\n".join(denied)) await ctx.send(embed=embed)
async def edit_goal(self, bot: Red, channel: discord.TextChannel, message_id: int, em: discord.Embed) -> None: try: if not channel.permissions_for(channel.guild.me).embed_links: return try: if version_info >= VersionInfo.from_str("3.4.6"): message = channel.get_partial_message(message_id) else: message = await channel.fetch_message(message_id) except (discord.errors.NotFound, discord.errors.Forbidden): return guild = channel.guild game_day_channels = await bot.get_cog("Hockey").config.guild( guild).gdc() role = discord.utils.get(guild.roles, name=self.team_name + " GOAL") if game_day_channels is not None: # We don't want to ping people in the game day channels twice if channel.id in game_day_channels: role = None if role is None or "missed" in self.event.lower(): await message.edit(embed=em) else: await message.edit(content=role.mention, embed=em) except (discord.errors.NotFound, discord.errors.Forbidden): return except Exception: log.exception(f"Could not edit goal in {channel=}")
async def news_auth_add(self, ctx: Context, user: Member, channel: TextChannel, notification_role: Optional[Role]): """ authorize a new user to send news to a specific channel """ if await db_thread(db.first, NewsAuthorization, user_id=user.id, channel_id=channel.id) is not None: raise CommandError(translations.news_already_authorized) if not channel.permissions_for(channel.guild.me).send_messages: raise CommandError(translations.news_not_added_no_permissions) role_id = notification_role.id if notification_role is not None else None await db_thread(NewsAuthorization.create, user.id, channel.id, role_id) embed = Embed(title=translations.news, colour=Colours.News, description=translations.news_authorized) await ctx.send(embed=embed) await send_to_changelog( ctx.guild, translations.f_log_news_authorized(user.mention, channel.mention))
async def post_period_recap( self, channel: discord.TextChannel, embed: discord.Embed, publish: bool ): """ Posts the period recap in designated channels """ if not channel.permissions_for(channel.guild.me).send_messages: log.debug( _("No permission to send messages in {channel} ({id})").format( channel=channel, id=channel.id ) ) return try: msg = await channel.send(embed=embed) if publish and channel.is_news(): pass # await msg.publish() except Exception: log.error( _("Could not post goal in {channel} ({id})").format( channel=channel, id=channel.id ), exc_info=True, )
async def currencylogs(self, ctx, channel: discord.TextChannel = None): """ This enables all currency logs in the specified channel """ if channel and not channel.can_send or channel and not channel.permissions_for( ctx.guild.me).embed_links: return await ctx.send( _("{0} I'm missing permissions in that channel. Make sure you have given me the correct permissions!" ).format(config.crossmark)) cl = await self.bot.database.fetchval( "SELECT channel_id FROM moneylogs WHERE guild_id = $1", ctx.guild.id) if cl and not channel: await self.bot.database.execute( "DELETE FROM moneylogs WHERE guild_id = $1", ctx.guild.id) return await ctx.send("Disabled currency logging.") elif cl and channel: await self.bot.database.execute( "UPDATE moneylogs SET channel_id = $1 WHERE guild_id = $2", channel.id, ctx.guild.id) return await ctx.send( f"Your currency logging channel was set to {channel.mention}.") elif not cl and not channel: return await ctx.send("You do not have a logging channel") elif not cl and channel: await self.bot.database.execute( "INSERT INTO moneylogs VALUES($1, $2)", ctx.guild.id, channel.id) return await ctx.send( f"Currency will now be logged in {channel.mention}")
async def set_daily_channel(self, interaction: discord.Interaction, new_channel: discord.TextChannel): """A command for authorized users to set or update the channel that receives the daily stock message""" if await self.bot.db.is_authorized( interaction.user) or await self.bot.is_owner(interaction.user): perms = new_channel.permissions_for(interaction.guild.me) if not (perms.use_external_emojis and perms.send_messages and perms.embed_links): await interaction.response.send_message( f"⚠️ Missing permissions for {new_channel.mention}. I'll need " f"`send messages`, `use external emojis`, and `embed links`." ) return new = await self.bot.db.set_channel(new_channel) await interaction.response.send_message( f"Daily message channel {'set' if new else 'updated'} to {new_channel.mention}" ) else: print(f"{interaction.user} tried to call set daily channel!") await self.bot.procUser.send( f"{interaction.user} tried to call set daily channel!") owner = await interaction.guild.fetch_member( interaction.guild.owner_id) await interaction.response.send_message( f"You aren't authorized to do that. Owner {owner.mention} is " f"authorized by default, and can authorize others. If there's " f"been a mistake send @ragnarak54#9413 a PM!", ephemeral=True)
async def defmessagesgroupuserexportchannel(self, ctx: commands.Context, channel: discord.TextChannel): """Exports recent messages of a channel to a file""" author = ctx.author if not channel.permissions_for(author).read_messages: return await ctx.send( "You do not have read permissions in that channel. Request denied." ) _log = await self.make_message_log(channel, guild=author.guild, requester=author) if not _log: return await ctx.send("No messages recorded in that channel.") self.send_to_monitor( ctx.guild, f"{author} ({author.id}) exported message history " f"of channel #{channel.name}") ts = utcnow().strftime("%Y-%m-%d") _log = "\n".join(_log) f = discord.File(BytesIO(_log.encode("utf-8")), f"{ts}-#{channel.name}.txt") await ctx.send(file=f)
async def __check_channel_permissions( channel: discord.TextChannel) -> Tuple[bool, str]: """ Utility method to determine if the bot has the necessary permissions to use the functions of the Cog on the specified channel. Checks if the specified channel is in a guild (vs in a DM) Checks if the bot can manage the channel guild's roles. Checks if the bot can add reactions to messages in the channel. :param channel: Channel on which to check permissions :return: Tuple[bool, str]. bool is whether the bot has all the necessary permissions, str is the response error message explaining the failing permission. """ guild = channel.guild bot_member = guild.me if channel.guild is None: response = (False, ErrorStrings.channel_not_part_of_server) elif bot_member.guild_permissions.manage_roles is False: response = (False, ErrorStrings.perm_not_manage_roles) elif channel.permissions_for(bot_member).add_reactions is False: response = (False, ErrorStrings.perm_not_add_react) else: response = (True, MiscStrings.perm_passed) return response
async def _roles_add( self, ctx: Context, message_id: int, channel: discord.TextChannel, emoji, *, role: discord.Role ): """Add a role on a message `message_id` must be found in `channel` To get a message's id: Settings > Appearance > Developer mode then Right click a message > Copy ID `emoji` can either be a Unicode emoji or a server emote `role` must be found in the channel's server""" guild = channel.guild message = await self.safe_get_message(channel, message_id) if message is None: response = self.MESSAGE_NOT_FOUND elif guild is None: response = self.NOT_IN_SERVER elif role.guild != channel.guild: response = self.ROLE_NOT_FOUND elif channel.guild.me.guild_permissions.manage_roles is False: response = self.CANT_MANAGE_ROLES elif channel.permissions_for(channel.guild.me).add_reactions is False: response = self.CANT_ADD_REACTIONS else: msg_conf = self.get_message_config(channel.id, message.id) emoji_match = self.EMOTE_REGEX.fullmatch(emoji) emoji_id = emoji if emoji_match is None else emoji_match.group(1) if emoji_id in await msg_conf({}): response = self.ALREADY_BOUND else: emoji = None if emoji_id.isdigit(): for emoji_server in self.bot.guilds: if emoji is None: emoji = discord.utils.get(emoji_server.emojis, id=int(emoji_id)) try: await message.add_reaction(emoji or emoji_id) except discord.HTTPException: # Failed to find the emoji response = self.EMOJI_NOT_FOUND else: try: await ctx.message.author.add_roles(role) await ctx.message.author.remove_roles(role) except (discord.Forbidden, discord.HTTPException): response = self.CANT_GIVE_ROLE await message.remove_reaction(emoji or emoji_id, self.bot.user) else: self.add_to_message_cache(channel.id, message_id, message) self.add_to_cache(guild.id, channel.id, message_id, emoji_id, role) await msg_conf.get_attr(emoji_id).set(role.id) response = self.ROLE_SUCCESSFULLY_BOUND.format( emoji or emoji_id, channel.mention ) await ctx.send(response)
async def chatchart(self, ctx, channel: discord.TextChannel = None, messages=5000): """ Generates a pie chart, representing the last 5000 messages in the specified channel. """ e = discord.Embed(description="Loading...", colour=0x00CCFF) e.set_thumbnail(url="https://i.imgur.com/vSp4xRk.gif") em = await ctx.send(embed=e) if channel is None: channel = ctx.message.channel history = [] if not channel.permissions_for(ctx.message.author).read_messages == True: await em.delete() return await ctx.send("You're not allowed to access that channel.") try: async for msg in channel.history(limit=messages): history.append(msg) except discord.errors.Forbidden: await em.delete() return await ctx.send("No permissions to read that channel.") msg_data = {"total count": 0, "users": {}} for msg in history: if len(msg.author.name) >= 20: short_name = "{}...".format(msg.author.name[:20]) else: short_name = msg.author.name whole_name = "{}#{}".format(short_name, msg.author.discriminator) if msg.author.bot: pass elif whole_name in msg_data["users"]: msg_data["users"][whole_name]["msgcount"] += 1 msg_data["total count"] += 1 else: msg_data["users"][whole_name] = {} msg_data["users"][whole_name]["msgcount"] = 1 msg_data["total count"] += 1 for usr in msg_data["users"]: pd = float(msg_data["users"][usr]["msgcount"]) / float(msg_data["total count"]) msg_data["users"][usr]["percent"] = round(pd * 100, 1) top_ten = heapq.nlargest( 20, [ (x, msg_data["users"][x][y]) for x in msg_data["users"] for y in msg_data["users"][x] if y == "percent" ], key=lambda x: x[1], ) others = 100 - sum(x[1] for x in top_ten) img = self.create_chart(top_ten, others, channel) await em.delete() await ctx.message.channel.send(file=discord.File(img, "chart.png"))
async def channelinfo(self, ctx: NabCtx, channel: discord.TextChannel = None): """Shows information about a channel. If no channel is specified, the information for the current channel is shown.""" if channel is None: channel = ctx.channel if not channel.permissions_for(ctx.author).read_messages: return await ctx.error("You are not supposed to see that channel, so I can't show you anything.") embed = discord.Embed(title=f"#{channel}", description=f"**ID** {channel.id}", colour=discord.Colour.blurple(), timestamp=channel.created_at) if channel.topic: embed.description += f"\n{channel.topic}" embed.add_field(name="Visible by", value=f"{len(channel.members):,} members") embed.add_field(name="Mention", value=f"`{channel.mention}`") embed.add_field(name="NSFW", value=ctx.tick(channel.nsfw)) embed.set_footer(text="Created on") await ctx.send(embed=embed)
async def checkchannel(self, ctx: NabCtx, *, channel: discord.TextChannel = None): """Checks the channel's permissions. Makes sure that the bot has all the required permissions to work properly. If no channel is specified, the current one is checked.""" if channel is None: channel = ctx.channel permissions = channel.permissions_for(ctx.me) content = f"**Checking {channel.mention}:**" if permissions.administrator: content += f"\n{ctx.tick(True)} I have `Administrator` permission." await ctx.send(content) return perm_dict = dict(permissions) check_permissions = { "read_messages": ["error", "I won't be able to see commands in here."], "send_messages": ["error", "I won't be able to respond in here."], "add_reactions": ["error", "Pagination or commands that require emoji confirmation won't work."], "external_emojis": ["warn", "I won't be able to show my emojis in some commands."], "read_message_history": ["error", "I won't be able to see your reactions in commands."], "manage_messages": ["warn", "Command pagination won't work well and I won't be able to delete messages " "in the ask channel."], "embed_links": ["error", "I won't be able to show many of my commands."], "attach_files": ["warn", "I won't be able to show images in some of my commands."], "manage_roles": ["warn", "I only need this to manage auto roles and joinable roles."], "manage_channels": ["warn", "I only need this to create watchlists."] } ok = True for k, v in check_permissions.items(): level, explain = v if not perm_dict[k]: ok = False perm_name = k.replace("_", " ").title() icon = ctx.tick(False) if level == "error" else config.warn_emoji content += f"\nMissing `{perm_name}` permission\n\t{icon} {explain}" if ok: content += f"\n{ctx.tick(True)} All permissions are correct!" await ctx.send(content)
def __can_speak_in(channel: discord.TextChannel) -> bool: """Indicates whether the bot has permission to speak in channel.""" return channel.permissions_for(channel.guild.me).send_messages