Example #1
0
    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
Example #2
0
    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()
Example #3
0
    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
Example #4
0
    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
Example #5
0
    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
Example #6
0
    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)
Example #7
0
    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)
Example #8
0
    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)