async def icon_emoji(self, ctx, *, emoji: Union[discord.Emoji, discord.PartialEmoji] = None): """Change icon of personal role using emoji""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) if not emoji: if ctx.channel.permissions_for(ctx.author).add_reactions: m = await ctx.send(_("React to this message with your emoji")) try: reaction = await ctx.bot.wait_for( "reaction_add", check=ReactionPredicate.same_context(message=m, user=ctx.author), timeout=30, ) emoji = reaction[0].emoji except AsyncTimeoutError: return finally: await m.delete(delay=0) else: await ctx.send_help() return try: if isinstance(emoji, (discord.Emoji, discord.PartialEmoji)): await edit_role_icon( self.bot, role, icon=await emoji.url_as(format="png").read(), reason=get_audit_reason(ctx.author, _("Personal Role")), ) else: await edit_role_icon( self.bot, role, unicode_emoji=emoji, reason=get_audit_reason(ctx.author, _("Personal Role")), ) except discord.Forbidden: ctx.command.reset_cooldown(ctx) await ctx.send( chat.error( _("Unable to edit role.\nRole must be lower than my top role" ))) except discord.InvalidArgument: await ctx.send( chat.error( _("This image type is unsupported, or link is incorrect"))) except discord.HTTPException as e: ctx.command.reset_cooldown(ctx) await ctx.send(chat.error(_("Unable to edit role: {}").format(e))) else: await ctx.send( _("Changed icon of {user}'s personal role").format( user=ctx.message.author.name))
async def cleanup_users(self, ctx, days: int = 1): """Cleanup inactive server members""" if days > 30: await ctx.send( chat.info( _("Due to Discord Restrictions, you cannot use more than 30 days for that cmd." ))) days = 30 elif days <= 0: await ctx.send(chat.info(_('"days" arg cannot be less than 1...'))) days = 1 to_kick = await ctx.guild.estimate_pruned_members(days=days) await ctx.send( chat.warning( _("You about to kick **{to_kick}** inactive for **{days}** days members from this server. " 'Are you sure?\nTo agree, type "yes"').format( to_kick=to_kick, days=days))) pred = MessagePredicate.yes_or_no(ctx) try: await self.bot.wait_for("message", check=pred, timeout=30) except AsyncTimeoutError: pass if pred.result: cleanup = await ctx.guild.prune_members(days=days, reason=get_audit_reason( ctx.author)) await ctx.send( chat.info( _("**{removed}**/**{all}** inactive members removed.\n" "(They was inactive for **{days}** days)").format( removed=cleanup, all=to_kick, days=days))) else: await ctx.send(chat.error(_("Inactive members cleanup canceled.")))
async def emoji_add(self, ctx, name: str, url: str, *roles: discord.Role): """Create custom emoji Use double quotes if role name has spaces Examples: `[p]emoji add Example https://example.com/image.png` `[p]emoji add RoleBased https://example.com/image.png EmojiRole "Test image"` """ try: async with self.session.get(url) as r: data = await r.read() except Exception as e: await ctx.send(chat.error(_("Unable to get emoji from provided url: {}").format(e))) return try: await ctx.guild.create_custom_emoji( name=name, image=data, roles=roles, reason=get_audit_reason( ctx.author, _("Restricted to roles: {}").format( ", ".join([f"{role.name}" for role in roles]) ) if roles else None, ), ) except discord.InvalidArgument: await ctx.send(chat.error(_("This image type is unsupported, or link is incorrect"))) except discord.HTTPException as e: await ctx.send(chat.error(_("An error occured on adding an emoji: {}").format(e))) else: await ctx.tick()
async def update_over(self, ctx): """ Marks an update as finished and removes access to operations channels. The operation channels will be archived properly. """ if ctx.guild not in self.operations: return if ctx.author not in ( t["leader"] for t in self.operations[ctx.guild]["teams"] ) and not (await _requires(ctx, COMMAND)): return await ctx.send("Only op leaders and Command can end ops") op = self.operations.pop(ctx.guild) reason = get_audit_reason(ctx.author, "Operation end.") async with ctx.typing(): archives = ctx.guild.get_channel( await self.config.guild(ctx.guild).op_archive() ) for team in op["teams"]: await log(team, archives) if archives: await team["channel"].delete(reason=reason) else: await team["channel"].edit(sync_permissions=True, reason=reason) await op["category"].voice_channels[-1].edit( name="🚫", sync_permissions=True, reason=reason ) await ctx.tick()
async def unmute_guild( self, ctx: commands.Context, user: discord.Member, *, reason: str = None ): """Unmute a user in this server.""" guild = ctx.guild author = ctx.author audit_reason = get_audit_reason(author, reason) unmute_success = [] async with ctx.typing(): for channel in guild.channels: success, message = await self.unmute_user( guild, channel, author, user, audit_reason ) unmute_success.append((success, message)) await modlog.create_case( self.bot, guild, ctx.message.created_at.replace(tzinfo=timezone.utc), "sunmute", user, author, reason, until=None, ) await ctx.send(_("User has been unmuted in this server."))
async def multirole_remove( self, ctx: commands.Context, member: TouchableMember, *roles: StrictRole ): """Remove multiple roles from a member.""" not_allowed = [] not_added = [] to_rm = [] for role in roles: allowed = await is_allowed_by_role_hierarchy(self.bot, ctx.me, ctx.author, role) if not allowed[0]: not_allowed.append(role) elif role not in member.roles: not_added.append(role) else: to_rm.append(role) reason = get_audit_reason(ctx.author) msg = [] if to_rm: await member.remove_roles(*to_rm, reason=reason) msg.append(f"Removed {humanize_roles(to_rm)} from **{member}**.") if not_added: msg.append(f"**{member}** didn't have {humanize_roles(not_added)}.") if not_allowed: msg.append( f"You do not have permission to assign the roles {humanize_roles(not_allowed)}." ) await ctx.send("\n".join(msg))
async def ban_sync(self, user: discord.Member, guild: discord.Guild, reason: str = None) -> Union[str, bool]: global modlog if modlog is None: modlog = self.bot.get_cog("ModLog") author = guild.me if author == user: return "I cannot let you do that. Self-harm is bad \N{PENSIVE FACE}" elif not await is_allowed_by_hierarchy(self.bot, self.config, guild, author, user): return ("I cannot let you do that. You are " "not higher than the user in the role " "hierarchy.") elif author.top_role <= user.top_role or user == guild.owner: return "I cannot do that due to discord hierarchy rules" now = datetime.now(timezone.utc) audit_reason = get_audit_reason(author, reason) queue_entry = (guild.id, user.id) self.ban_queue.append(queue_entry) appeal = await self.config.guild(guild).appealinvite() try: if appeal: await self.send_appeal_info(user, guild, "ban", invite=appeal, is_auto=False, reason=reason) await guild.ban(user, reason=audit_reason, delete_message_days=1) # TODO: Add permission check log.info( f"{author.name}({author.id}) banned {user.name}({user.id}), " f"deleting {str(1)} days worth of messages") except discord.Forbidden: self.ban_queue.remove(queue_entry) return "I'm not allowed to do that." except Exception as err: self.ban_queue.remove(queue_entry) return str(err) try: if modlog: await modlog.create_case(self.bot, guild, now, "ban", user, author, reason, until=None, channel=None) except RuntimeError as err: return ("The user was banned but an error occurred when trying to " f"create the modlog entry: {err}") return True
async def icon_reset(self, ctx): """Remove icon of personal role""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) if not role: await ctx.send( chat.warning( f"Please create your role using `{ctx.prefix}myrole create`!" )) return try: await edit_role_icon( self.bot, role, icon=None, unicode_emoji=None, reason=get_audit_reason(ctx.author, _("Personal Role")), ) await ctx.send( _("Removed icon of {user}'s personal role").format( user=ctx.message.author.name)) except discord.Forbidden: ctx.command.reset_cooldown(ctx) await ctx.send( chat.error( _("Unable to edit role.\nRole must be lower than my top role" ))) except discord.HTTPException as e: ctx.command.reset_cooldown(ctx) await ctx.send(chat.error(_("Unable to edit role: {}").format(e)))
async def channel_mute( self, ctx: commands.Context, user: discord.Member, *, reason: str = None ): """Mute a user in the current text channel.""" author = ctx.message.author channel = ctx.message.channel guild = ctx.guild audit_reason = get_audit_reason(author, reason) success, issue = await self.mute_user(guild, channel, author, user, audit_reason) if success: try: await modlog.create_case( self.bot, guild, ctx.message.created_at, "cmute", user, author, reason, until=None, channel=channel, ) except RuntimeError as e: await ctx.send(e) await channel.send(_("User has been muted in this channel.")) else: await channel.send(issue)
async def channel_create_voice( self, ctx: commands.Context, category: Optional[discord.CategoryChannel] = None, *, name: str, ): """Create a voice channel You can create the channel under a category if passed, else it is created under no category Use double quotes if category has spaces Examples: `[p]channel add voice "The Zoo" Awesome Channel` will create under the "The Zoo" category. `[p]channel add voice Awesome Channel` will create under no category, at the top. """ if category: self.check_channel_permission(ctx, category) try: await ctx.guild.create_voice_channel(name, category=category, reason=get_audit_reason( ctx.author)) except discord.Forbidden: await ctx.send( chat.error(_("I can't create channel in this category"))) except discord.HTTPException as e: await ctx.send( chat.error(_("I am unable to create a channel: {}").format(e))) else: await ctx.tick()
async def name(self, ctx, *, name: str): """Change name of personal role You cant use blacklisted names""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) name = name[:100] if name.casefold() in await self.config.guild(ctx.guild).blacklist(): await ctx.send( chat.error(_("NONONO!!! This rolename is blacklisted."))) return try: await role.edit(name=name, reason=get_audit_reason(ctx.author, _("Personal Role"))) except discord.Forbidden: ctx.command.reset_cooldown(ctx) await ctx.send( chat.error( _("Unable to edit role.\n" 'Role must be lower than my top role and i must have permission "Manage Roles"' ))) except discord.HTTPException as e: ctx.command.reset_cooldown(ctx) await ctx.send(chat.error(_("Unable to edit role: {}").format(e))) else: await ctx.send( _("Changed name of {user}'s personal role to {name}").format( user=ctx.message.author.name, name=name))
async def multirole(self, ctx: commands.Context, member: TouchableMember, *roles: StrictRole): """Add multiple roles to a member.""" not_allowed = [] already_added = [] to_add = [] for role in roles: allowed = await is_allowed_by_role_hierarchy(self.bot, ctx.me, ctx.author, role) if not allowed[0]: not_allowed.append(role) elif role in member.roles: already_added.append(role) else: to_add.append(role) reason = get_audit_reason(ctx.author) msg = [] if to_add: await member.add_roles(*to_add, reason=reason) msg.append(f"Added {humanize_roles(to_add)} to **{member}**.") if already_added: msg.append(f"**{member}** already had {humanize_roles(already_added)}.") if not_allowed: msg.append( f"You do not have permission to assign the roles {humanize_roles(not_allowed)}." ) await ctx.send("\n".join(msg))
async def colour(self, ctx, *, colour: discord.Colour = discord.Colour.default()): """Change color of personal role""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) try: await role.edit(colour=colour, reason=get_audit_reason(ctx.author, _("Personal Role"))) except discord.Forbidden: ctx.command.reset_cooldown(ctx) await ctx.send( chat.error( _("Unable to edit role.\n" 'Role must be lower than my top role and i must have permission "Manage Roles"' ))) except discord.HTTPException as e: ctx.command.reset_cooldown(ctx) await ctx.send(chat.error(_("Unable to edit role: {}").format(e))) else: await ctx.send( _("Changed color of {user}'s personal role to {color}").format( user=ctx.message.author.name, color=colour))
async def emoji_remove(self, ctx, *, emoji: discord.Emoji): """Remove emoji from server""" if emoji.guild != ctx.guild: await ctx.send_help() return await emoji.delete(reason=get_audit_reason(ctx.author)) await ctx.tick()
async def unmute_channel( self, ctx: commands.Context, user: discord.Member, *, reason: str = None ): """Unmute a user in this channel.""" channel = ctx.channel author = ctx.author guild = ctx.guild audit_reason = get_audit_reason(author, reason) success, message = await self.unmute_user(guild, channel, author, user, audit_reason) if success: try: await modlog.create_case( self.bot, guild, ctx.message.created_at, "cunmute", user, author, reason, until=None, channel=channel, ) except RuntimeError as e: await ctx.send(e) await ctx.send(_("User unmuted in this channel.")) else: await ctx.send(_("Unmute failed. Reason: {}").format(message))
async def massmove( self, ctx: commands.Context, from_channel: discord.VoiceChannel, to_channel: discord.VoiceChannel = None, ): """Move all members from one voice channel to another Use double quotes if channel name has spaces""" fails = 0 if not from_channel.members: await ctx.send( chat.error( _("There is no users in channel {}.").format( from_channel.mention))) return if not from_channel.permissions_for(ctx.me).move_members: await ctx.send(chat.error(_("I cant move users from that channel")) ) return if to_channel and not to_channel.permissions_for(ctx.me).connect: await ctx.send(chat.error(_("I cant move users to that channel"))) return async with ctx.typing(): for member in from_channel.members: try: await member.move_to(to_channel, reason=get_audit_reason( ctx.author, _("Massmove"))) except discord.HTTPException: fails += 1 continue await ctx.send( _("Finished moving users. {} members could not be moved.").format( fails))
async def emoji_rename(self, ctx: commands.Context, emoji: discord.Emoji, name: str, *roles: discord.Role): """Rename emoji and restrict to certain roles Only this roles will be able to use this emoji Use double quotes if role name has spaces Examples: `[p]emoji rename emoji NewEmojiName` `[p]emoji rename emoji NewEmojiName Administrator "Allowed role"` """ if emoji.guild != ctx.guild: await ctx.send_help() return try: await emoji.edit( name=name, roles=roles, reason=get_audit_reason( ctx.author, _("Restricted to roles: ").format(", ".join( role.name for role in roles)) if roles else None, ), ) except discord.Forbidden: await ctx.send(chat.error(_("I can't edit this emoji"))) await ctx.tick()
async def multirole_remove(self, ctx: commands.Context, member: discord.Member, *roles: StrictRole): """Remove multiple roles from a member.""" if not await is_allowed_by_hierarchy(ctx.bot, ctx.author, member): await ctx.send( "You cannot do that since you aren't higher than that user in hierarchy." ) return not_allowed = [] not_added = [] to_rm = [] for role in roles: allowed = is_allowed_by_role_hierarchy(self.bot, ctx.me, ctx.author, role) if not allowed[0]: not_allowed.append(role) elif role not in member.roles: not_added.append(role) else: to_rm.append(role) reason = get_audit_reason(ctx.author) msg = "" if to_rm: await member.remove_roles(*to_rm, reason=reason) msg += f"Removed {humanize_roles(to_rm)} from {member}." if not_added: msg += f"\n**{member}** didn't have {humanize_roles(not_added)}." if not_allowed: msg += ( f"\nYou do not have permission to assign the roles {humanize_roles(not_allowed)}." ) if msg: await ctx.send(msg)
async def super_massrole( self, ctx: commands.Context, members: list, role: discord.Role, fail_message: str = "Everyone in the server has this role.", adding: bool = True, ): member_list = self.get_member_list(members, role, adding) if not member_list: await ctx.send(fail_message) return verb = "add" if adding else "remove" word = "to" if adding else "from" await ctx.send( f"Beginning to {verb} `{role.name}` {word} **{len(member_list)}** members. " f"This will take around {humanize_timedelta(timedelta=datetime.timedelta(seconds=len(member_list) * 0.75))}." ) async with ctx.typing(): result = await self.massrole(member_list, [role], get_audit_reason(ctx.author), adding) result_text = f"{verb.title()[:5]}ed `{role.name}` {word} **{len(result['completed'])}** members." if result["skipped"]: result_text += ( f"\nSkipped {verb[:5]}ing roles for **{len(result['skipped'])}** members." ) if result["failed"]: result_text += ( f"\nFailed {verb[:5]}ing roles for **{len(result['failed'])}** members." ) await ctx.send(result_text)
async def gctopic(self, ctx, *, topic: str = None): """Change topic of #general Use `[p]generalchannel topic +<text>` to add text to end of topic""" channel = await self.config.guild(ctx.guild).channel() channel = ctx.guild.get_channel(channel) if topic is not None: if len(topic) > 1024: topic = topic[:1024] if topic.startswith("+"): topic = topic[1:].strip() topic = "{}\n{}".format((channel.topic or ""), topic) if len(topic) > 1024: topic = topic[-1024:] try: await channel.edit(topic=topic, reason=get_audit_reason( ctx.author, "General channel name change")) except discord.Forbidden: await ctx.send( chat.error( "Unable to change channel's topic: Missing permissions")) except discord.HTTPException: await ctx.send( chat.error("Unable to change channel's topic: Failed.")) else: await ctx.tick()
async def channel_delete(self, ctx: commands.Context, *, channel: Union[discord.TextChannel, discord.VoiceChannel]): """Remove a channel from server Example: `[p]channel delete channel` """ self.check_channel_permission(ctx, channel) pred = MessagePredicate.yes_or_no(ctx) if not ctx.assume_yes: await ctx.send( chat.warning( _("You are about to delete channel {channel}. This cannot be undone. Are you sure?\n" 'To agree, type "yes"').format(channel=channel.mention))) try: await self.bot.wait_for("message", check=pred, timeout=30) except AsyncTimeoutError: pass if ctx.assume_yes or pred.result: try: await channel.delete(reason=get_audit_reason(ctx.author)) except discord.Forbidden: await ctx.send(chat.error(_("I can't delete this channel"))) except discord.HTTPException as e: await ctx.send( chat.error( _("I am unable to delete a channel: {}").format(e))) else: await ctx.tick()
async def unmute_guild( self, ctx: commands.Context, user: discord.Member, *, reason: str = None ): """Unmute a user in this server.""" guild = ctx.guild author = ctx.author audit_reason = get_audit_reason(author, reason) unmute_success = [] for channel in guild.channels: success, message = await self.unmute_user(guild, channel, author, user, audit_reason) unmute_success.append((success, message)) await asyncio.sleep(0.1) try: await modlog.create_case( self.bot, guild, ctx.message.created_at, "sunmute", user, author, reason, until=None, ) except RuntimeError as e: await ctx.send(e) await ctx.send(_("User has been unmuted in this server."))
async def channel_rename( self, ctx: commands.Context, channel: Union[discord.TextChannel, discord.VoiceChannel], *, name: str, ): """Rename a channel Use double quotes if channel has spaces Examples: `[p]channel rename channel new-channel-name` """ self.check_channel_permission(ctx, channel) try: await channel.edit(name=name, reason=get_audit_reason(ctx.author)) except discord.Forbidden: await ctx.send(chat.error(_("I can't rename this channel"))) except discord.HTTPException as e: await ctx.send( chat.error( _("I am unable to rename this channel: {}").format(e))) else: await ctx.tick()
async def super_massrole( self, ctx: commands.Context, members: list, role: discord.Role, fail_message: str = "Everyone in the server has this role.", adding: bool = True, ): if guild_roughly_chunked(ctx.guild) is False and self.bot.intents.members: await ctx.guild.chunk() member_list = self.get_member_list(members, role, adding) if not member_list: await ctx.send(fail_message) return verb = "add" if adding else "remove" word = "to" if adding else "from" await ctx.send(f"Beginning to {verb} `{role.name}` {word} **{len(member_list)}** members.") async with ctx.typing(): result = await self.massrole(member_list, [role], get_audit_reason(ctx.author), adding) result_text = f"{verb.title()[:5]}ed `{role.name}` {word} **{len(result['completed'])}** members." if result["skipped"]: result_text += ( f"\nSkipped {verb[:5]}ing roles for **{len(result['skipped'])}** members." ) if result["failed"]: result_text += ( f"\nFailed {verb[:5]}ing roles for **{len(result['failed'])}** members." ) await ctx.send(result_text)
async def lock( self, ctx: commands.Context, channel: Optional[Union[LockableChannel, discord.VoiceChannel]] = None, roles_or_members: commands.Greedy[Union[FuzzyRole, discord.Member]] = None, ): """Lock a channel. Provide a role or member if you would like to lock it for them. You can only lock a maximum of 10 things at once.""" await ctx.trigger_typing() if not channel: channel = ctx.channel if not roles_or_members: roles_or_members = [ctx.guild.default_role] else: roles_or_members = roles_or_members[:10] succeeded = [] cancelled = [] failed = [] reason = get_audit_reason(ctx.author) if isinstance(channel, discord.TextChannel): for role in roles_or_members: current_perms = channel.overwrites_for(role) my_perms = channel.overwrites_for(ctx.me) if my_perms.send_messages != True: my_perms.update(send_messages=True) await channel.set_permissions(ctx.me, overwrite=my_perms) if current_perms.send_messages == False: cancelled.append(inline(role.name)) else: current_perms.update(send_messages=False) try: await channel.set_permissions(role, overwrite=current_perms, reason=reason) succeeded.append(inline(role.name)) except: failed.append(inline(role.name)) elif isinstance(channel, discord.VoiceChannel): for role in roles_or_members: current_perms = channel.overwrites_for(role) if current_perms.connect == False: cancelled.append(inline(role.name)) else: current_perms.update(connect=False) try: await channel.set_permissions(role, overwrite=current_perms, reason=reason) succeeded.append(inline(role.name)) except: failed.append(inline(role.name)) msg = "" if succeeded: msg += f"{channel.mention} has been locked for {humanize_list(succeeded)}.\n" if cancelled: msg += f"{channel.mention} was already locked for {humanize_list(cancelled)}.\n" if failed: msg += f"I failed to lock {channel.mention} for {humanize_list(failed)}.\n" if msg: await ctx.send(msg)
async def emoji_rename(self, ctx, emoji: discord.Emoji, name: str, *roles: discord.Role): """Rename emoji and restrict to certain roles Only this roles will be able to use this emoji""" await emoji.edit(name=name, roles=roles, reason=get_audit_reason(ctx.author, ("Restricted to roles: " + ", ".join([f"{role.name}" for role in roles])) if roles else None)) await ctx.tick()
async def unlock( self, ctx, channel: Optional[Union[LockableChannel, discord.VoiceChannel]] = None, state: Optional[ChannelToggle] = None, roles_or_members: commands.Greedy[Union[FuzzyRole, discord.Member]] = None, ): """Unlock a channel. Provide a role or member if you would like to unlock it for them. If you would like to override-unlock for something, you can do so by pass `true` as the state argument. You can only unlock a maximum of 10 things at once.""" await ctx.trigger_typing() if not channel: channel = ctx.channel if roles_or_members: roles_or_members = roles_or_members[:10] else: roles_or_members = [ctx.guild.default_role] succeeded = [] cancelled = [] failed = [] reason = get_audit_reason(ctx.author) if isinstance(channel, discord.TextChannel): for role in roles_or_members: current_perms = channel.overwrites_for(role) if current_perms.send_messages != False and current_perms.send_messages == state: cancelled.append(inline(role.name)) else: current_perms.update(send_messages=state) try: await channel.set_permissions(role, overwrite=current_perms, reason=reason) succeeded.append(inline(role.name)) except: failed.append(inline(role.name)) elif isinstance(channel, discord.VoiceChannel): for role in roles_or_members: current_perms = channel.overwrites_for(role) if current_perms.connect in [False, state]: current_perms.update(connect=state) try: await channel.set_permissions(role, overwrite=current_perms, reason=reason) succeeded.append(inline(role.name)) except: failed.append(inline(role.name)) else: cancelled.append(inline(role.name)) msg = "" if succeeded: msg += f"{channel.mention} has unlocked for {humanize_list(succeeded)} with state `{'true' if state else 'default'}`.\n" if cancelled: msg += f"{channel.mention} was already unlocked for {humanize_list(cancelled)} with state `{'true' if state else 'default'}`.\n" if failed: msg += f"I failed to unlock {channel.mention} for {humanize_list(failed)}.\n" if msg: await ctx.send(msg)
async def idkick( self, ctx: commands.Context, user_ids: commands.Greedy[RawUserIds], *, reason: str = None, ): """Kick a list of users. If a reason is specified, it will be the reason that shows up in the audit log. """ kicked = [] errors = {} async def show_results(): text = "Kicked {num} users from the server.".format(num=humanize_number(len(kicked))) if errors: text += "\nErrors:\n" text += "\n".join(errors.values()) for p in pagify(text): await ctx.send(p) # def remove_processed(ids): # return [_id for _id in ids if _id not in kicked and _id not in errors] user_ids = list(set(user_ids)) # No dupes author = ctx.author guild = ctx.guild if not user_ids: await ctx.send_help() return if not guild.me.guild_permissions.kick_members: return await ctx.send("I lack the permissions to do this.") for user_id in user_ids: user = discord.Object(id=user_id) audit_reason = get_audit_reason(author, reason) queue_entry = (guild.id, user_id) try: await guild.kick(user, reason=audit_reason) log.info("{}({}) kicked {}".format(author.name, author.id, user_id)) except discord.NotFound: errors[user_id] = "User {user_id} does not exist.".format(user_id=user_id) continue except discord.Forbidden: errors[user_id] = "Could not kick {user_id}: missing permissions.".format( user_id=user_id ) continue else: kicked.append(user_id) await show_results()
async def resetnicks(self, ctx): """Resets nicknames on the server""" server = ctx.guild for user in server.members: try: await user.edit(nickname=None, reason=get_audit_reason(ctx.author, "Reset nicks")) except discord.HTTPException: continue await ctx.send("Finished resetting server nicknames")
async def ban_user( self, user: discord.Member, ctx: commands.Context, days: int = 0, reason: str = None, create_modlog_case=False, ) -> Union[str, bool]: author = ctx.author guild = ctx.guild if author == user: return _("I cannot let you do that. Self-harm is bad {}").format( "\N{PENSIVE FACE}") elif guild.me.top_role <= user.top_role or user == guild.owner: return _("I cannot do that due to discord hierarchy rules") elif not (0 <= days <= 7): return _("Invalid days. Must be between 0 and 7.") audit_reason = get_audit_reason(author, reason) queue_entry = (guild.id, user.id) self.ban_queue.append(queue_entry) try: await guild.ban(user, reason=audit_reason, delete_message_days=days) log.info( "{}({}) banned {}({}), deleting {} days worth of messages". format(author.name, author.id, user.name, user.id, str(days))) except discord.Forbidden: self.ban_queue.remove(queue_entry) return _("I'm not allowed to do that.") except Exception as e: self.ban_queue.remove(queue_entry) return e # TODO: impproper return type? Is this intended to be re-raised? if create_modlog_case: try: await modlog.create_case( self.bot, guild, ctx.message.created_at, "ban", user, author, reason, until=None, channel=None, ) except RuntimeError as e: return _( "The user was banned but an error occurred when trying to " "create the modlog entry: {reason}").format(reason=e) return True