async def _do_kick(self, guild, user, mod, reason, note, audit_reason): """Applies a kick to a user and dispatches the event to the modlog.""" config = await db.get_config(guild) member = await self.bot.get_or_fetch_member(guild, user.id) # some checks to make sure we can actually do this if not member: raise UserNotInGuild(user) if not guild.me.guild_permissions.kick_members: raise BotMissingPermission('Kick Members') if not guild.me.top_role > member.top_role: raise BotRoleHierarchyError if await is_server_mod(member): raise ModActionOnMod # notify the user if the setting is enabled # this one has to be done before kicking (for obvious reasons) if not config or config.dm_on_infraction: message = format_alert_dm(guild, user, 'kick', reason=reason) delivered = await try_send(user, message) else: delivered = None # kick the user await member.kick(reason=audit_reason) # dispatch the modlog event and return to the command await LogEvent('kick', guild, user, mod, reason, note, None).dispatch() return delivered
async def _do_unban(self, guild, user, mod, reason, note, audit_reason): """Removes a ban from a user and dispatches the event to the modlog.""" # check to make sure we can actually do this if not guild.me.guild_permissions.ban_members: raise BotMissingPermission('Ban Members') # unban the user await guild.unban(user, reason=audit_reason) # mark any bans for this user as inactive await self.bot.run_in_background( modlog.deactivate_infractions(guild.id, user.id, 'ban')) # dispatch the modlog event and return to the command await LogEvent('unban', guild, user, mod, reason, note, None).dispatch()
async def _from_bans(self, ctx, argument): if not ctx.guild.me.guild_permissions.ban_members: raise BotMissingPermission("Ban Members") if argument.isdigit(): member_id = int(argument, base=10) try: return await ctx.guild.fetch_ban(discord.Object(id=member_id) ), True except discord.NotFound: raise BadArgument('This user is not banned.') from None ban_list = await ctx.guild.bans() entity = discord.utils.find(lambda u: str(u.user) == argument, ban_list) if entity is None: raise BadArgument('This user is not banned.') return entity, True
async def _do_mute(self, guild, user, mod, reason, note, audit_reason, duration=None): """Applies a mute to a user and dispatches the event to the modlog.""" config = await db.get_config(guild) member = await self.bot.get_or_fetch_member(guild, user.id) role = guild.get_role(config.mute_role_id if config else 0) # some checks to make sure we can actually do this if not member: raise UserNotInGuild(user) if not role: raise NotConfigured('mute_role') if role in member.roles: raise ModerationError('User is already muted.') if not guild.me.guild_permissions.manage_roles: raise BotMissingPermission('Manage Roles') if not guild.me.top_role > role: raise BotRoleHierarchyError if await is_server_mod(member): raise ModActionOnMod # add the role await member.add_roles(role, reason=audit_reason) # notify the user if the setting is enabled if not config or config.dm_on_infraction: message = format_alert_dm(guild, user, 'mute', reason=reason, duration=duration) delivered = await try_send(user, message) else: delivered = None # dispatch the modlog event and return to the command await LogEvent('mute', guild, user, mod, reason, note, duration).dispatch() return delivered
async def _do_unmute(self, guild, user, mod, reason, note, audit_reason): """Lifts a user's mute and dispatches the event to the modlog.""" config = await db.get_config(guild) member = await self.bot.get_or_fetch_member(guild, user.id) role = guild.get_role(config.mute_role_id if config else 0) # some checks to make sure we can actually do this if not member: raise UserNotInGuild(user) if not role: raise NotConfigured('mute_role') if not guild.me.guild_permissions.manage_roles: raise BotMissingPermission('Manage Roles') if not guild.me.top_role > role: raise BotRoleHierarchyError if await is_server_mod(member): raise ModActionOnMod # remove the role await member.remove_roles(role, reason=audit_reason) # notify the user if the setting is enabled if not config or config.dm_on_infraction: message = format_alert_dm(guild, user, 'unmute', reason=reason) delivered = await try_send(user, message) else: delivered = None # mark any mutes for this user as inactive await self.bot.run_in_background( modlog.deactivate_infractions(guild.id, user.id, 'mute')) # dispatch the modlog event and return to the command await LogEvent('unmute', guild, user, mod, reason, note, None).dispatch() return delivered
async def _do_mass_ban(self, ctx, users, mod, reason, note, audit_reason, duration=None): """Bans a set of users and dispatches the event to the modlog.""" guild = ctx.guild users = set(users) total = len(users) if total <= 1: raise ModerationError("Not enough users to ban.") await ctx.confirm_action( f"{TICK_YELLOW} Are you sure you would like to ban {total} users? (y/n)" ) # filter out already-banned users ban_list = set(b.user.id for b in await guild.bans()) bannable_users = [u for u in users if u.id not in ban_list] already_banned = total - len(bannable_users) # check to make sure we can actually do this for user in users: member = await self.bot.get_or_fetch_member(guild, user.id) if not guild.me.guild_permissions.ban_members: raise BotMissingPermission('Ban Members') if member: if not guild.me.top_role > member.top_role: raise BotRoleHierarchyError if await is_server_mod(member): raise ModActionOnMod m = await ctx.send("Banning...") # do the actual bans now success = [] not_found = 0 for user in bannable_users: try: await guild.ban(user, reason=audit_reason, delete_message_days=0) success.append(user) except discord.NotFound: not_found += 1 # dispatch the modlog event if success: await MassActionLogEvent('ban', guild, success, mod, reason, note, duration).dispatch() # format response message def _s(i): return "s" if i != 1 else "" content = f"{ZAP} Banned {len(success)}/{total} users" if success: dt = exact_timedelta(duration) if duration else 'permanent' content += f' ({dt}).' else: content += '.' extra_lines = [ f"{already_banned} user{_s(already_banned)} already banned" if already_banned else "", f"{not_found} user{_s(not_found)} not found" if not_found else "" ] extra = ", ".join(e for e in extra_lines if e) if extra: content += " *" + extra + ".*" await m.edit(content=content)
async def _do_ban(self, guild, user, mod, reason, note, audit_reason, duration=None): """Bans a user and dispatches the event to the modlog.""" config = await db.get_config(guild) member = await self.bot.get_or_fetch_member(guild, user.id) # some checks to make sure we can actually do this if not guild.me.guild_permissions.ban_members: raise BotMissingPermission('Ban Members') if member: if not guild.me.top_role > member.top_role: raise BotRoleHierarchyError if await is_server_mod(member): raise ModActionOnMod # notify the user if the setting is enabled # this one has to be done before banning (for obvious reasons) if not config or config.dm_on_infraction: if member: message = format_alert_dm(guild, user, 'ban', reason=reason, duration=duration) delivered = await try_send(user, message) else: delivered = None else: delivered = None # set up a task that waits a few moments for discord to dispatch the event. # this makes printing the user look pretty without having to fetch. async def _wait(): try: def check(_, _u): return _u.id == user.id _, _u = await self.bot.wait_for('member_ban', check=check, timeout=1) return _u except asyncio.TimeoutError: pass # ban the user coro = guild.ban(user, reason=audit_reason, delete_message_days=0) if member: # regular ban await coro else: # forceban case user = (await asyncio.gather(_wait(), coro))[0] or user # dispatch the modlog event and return to the command type = ('force' if not member else '') + 'ban' await LogEvent(type, guild, user, mod, reason, note, duration).dispatch() return user, delivered, not bool(member)
async def _do_mass_mute(self, ctx, users, mod, reason, note, audit_reason, duration=None): """Mutes a set of users and dispatches the event to the modlog.""" guild = ctx.guild users = set(users) total = len(users) config = await db.get_config(guild) role = guild.get_role(config.mute_role_id if config else 0) if total <= 1: raise ModerationError("Not enough users to mute.") await ctx.confirm_action( f"{TICK_YELLOW} Are you sure you would like to mute {total} users? (y/n)" ) # check to make sure we can actually do this not_in_guild = 0 already_muted = 0 mutable_members = [] for user in users: member = await self.bot.get_or_fetch_member(guild, user.id) if not member: not_in_guild += 1 continue elif role in member.roles: already_muted += 1 continue else: mutable_members.append(member) if not role: raise NotConfigured('mute_role') if not guild.me.guild_permissions.manage_roles: raise BotMissingPermission('Manage Roles') if not guild.me.top_role > role: raise BotRoleHierarchyError if await is_server_mod(member): raise ModActionOnMod m = await ctx.send("Muting...") # do the actual mutes now success = [] for member in mutable_members: await member.add_roles(role, reason=audit_reason) success.append(member) # dispatch the modlog event if success: await MassActionLogEvent('mute', guild, success, mod, reason, note, duration).dispatch() # format response message def _s(i): return "s" if i != 1 else "" content = f"{OK_HAND} Muted {len(success)}/{total} users" if success: dt = exact_timedelta(duration) if duration else 'permanent' content += f' ({dt}).' else: content += '.' extra_lines = [ f"{already_muted} user{_s(already_muted)} already muted" if already_muted else "", f"{not_in_guild} user{_s(not_in_guild)} not found" if not_in_guild else "" ] extra = ", ".join(e for e in extra_lines if e) if extra: content += " *" + extra + ".*" await m.edit(content=content)