示例#1
0
    async def _unmuting(
        self,
        ctx,
        member: discord.Member,
        *,
        reason='-No reason specified-'
    ):  # TODO: Allow IDs to be unmuted (in the case of not being in the guild)
        if len(reason) > 990:
            return await ctx.send(
                f'{config.redTick} Unmute reason is too long, reduce it by at least {len(reason) - 990} characters'
            )
        db = mclient.bowser.puns
        muteRole = ctx.guild.get_role(config.mute)
        action = db.find_one_and_update(
            {
                'user': member.id,
                'type': 'mute',
                'active': True
            }, {'$set': {
                'active': False
            }})
        if not action:
            return await ctx.send(
                f'{config.redTick} Cannot unmute {member} ({member.id}), they are not currently muted'
            )

        docID = await tools.issue_pun(member.id,
                                      ctx.author.id,
                                      'unmute',
                                      reason,
                                      context=action['_id'],
                                      active=False)
        await member.remove_roles(
            muteRole, reason='Unmute action performed by moderator')
        await tools.send_modlog(self.bot,
                                self.modLogs,
                                'unmute',
                                docID,
                                reason,
                                user=member,
                                moderator=ctx.author,
                                public=True)

        try:
            await member.send(tools.format_pundm('unmute', reason, ctx.author))

        except (discord.Forbidden, AttributeError):
            if not tools.mod_cmd_invoke_delete(ctx.channel):
                await ctx.send(
                    f'{config.greenTick} {member} ({member.id}) has been successfully unmuted. I was not able to DM them about this action'
                )

            return

        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()

        await ctx.send(
            f'{config.greenTick} {member} ({member.id}) has been successfully unmuted'
        )
示例#2
0
    async def _unbanning(self,
                         ctx,
                         user: int,
                         *,
                         reason='-No reason specified-'):
        if len(reason) > 990:
            return await ctx.send(
                f'{config.redTick} Unban reason is too long, reduce it by at least {len(reason) - 990} characters'
            )
        db = mclient.bowser.puns
        userObj = discord.Object(id=user)
        try:
            await ctx.guild.fetch_ban(userObj)

        except discord.NotFound:
            return await ctx.send(
                f'{config.redTick} {user} is not currently banned')

        openAppeal = mclient.modmail.logs.find_one({
            'open': True,
            'ban_appeal': True,
            'recipient.id': str(user)
        })
        if openAppeal:
            return await ctx.send(
                f'{config.redTick} You cannot use the unban command on {user} while a ban appeal is in-progress. You can accept the appeal in <#{int(openAppeal["channel_id"])}> with `!appeal accept [reason]`'
            )

        db.find_one_and_update({
            'user': user,
            'type': 'ban',
            'active': True
        }, {'$set': {
            'active': False
        }})
        docID = await tools.issue_pun(user,
                                      ctx.author.id,
                                      'unban',
                                      reason,
                                      active=False)
        await ctx.guild.unban(userObj,
                              reason='Unban action performed by moderator')
        await tools.send_modlog(
            self.bot,
            self.modLogs,
            'unban',
            docID,
            reason,
            username=str(user),
            userid=user,
            moderator=ctx.author,
            public=True,
        )
        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()

        await ctx.send(f'{config.greenTick} {user} has been unbanned')
示例#3
0
    async def _kicking(self,
                       ctx,
                       member: discord.Member,
                       *,
                       reason='-No reason specified-'):
        if len(reason) > 990:
            return await ctx.send(
                f'{config.redTick} Kick reason is too long, reduce it by at least {len(reason) - 990} characters'
            )
        docID = await tools.issue_pun(member.id,
                                      ctx.author.id,
                                      'kick',
                                      reason,
                                      active=False)
        await tools.send_modlog(self.bot,
                                self.modLogs,
                                'kick',
                                docID,
                                reason,
                                user=member,
                                moderator=ctx.author,
                                public=True)
        try:
            await member.send(tools.format_pundm('kick', reason, ctx.author))

        except (discord.Forbidden, AttributeError):
            if not tools.mod_cmd_invoke_delete(ctx.channel):
                await ctx.send(
                    f'{config.greenTick} {member} ({member.id}) has been successfully kicked. I was not able to DM them about this action'
                )

            await member.kick(reason='Kick action performed by moderator')
            return

        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()

        await ctx.send(
            f'{config.greenTick} {member} ({member.id}) has been successfully kicked'
        )
示例#4
0
    async def _note(self, ctx, user: ResolveUser, *, content):
        userid = user if (type(user) is int) else user.id

        if len(content) > 900:
            return await ctx.send(
                f'{config.redTick} Note is too long, reduce it by at least {len(content) - 990} characters'
            )

        await tools.issue_pun(userid,
                              ctx.author.id,
                              'note',
                              content,
                              active=False,
                              public=False)
        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()

        return await ctx.send(
            f'{config.greenTick} Note successfully added to {user} ({user.id})'
        )
示例#5
0
    async def _strike_set(self, ctx, member: discord.Member,
                          count: StrikeRange, *, reason):
        punDB = mclient.bowser.puns
        activeStrikes = 0
        puns = punDB.find({
            'user': member.id,
            'type': 'strike',
            'active': True
        })
        for pun in puns:
            activeStrikes += pun['active_strike_count']

        if activeStrikes == count:
            return await ctx.send(
                f'{config.redTick} That user already has {activeStrikes} active strikes'
            )

        elif (
                count > activeStrikes
        ):  # This is going to be a positive diff, lets just do the math and defer work to _strike()
            return await self._strike(ctx,
                                      member,
                                      count - activeStrikes,
                                      reason=reason)

        else:  # Negative diff, we will need to reduce our strikes
            diff = activeStrikes - count

            puns = punDB.find({
                'user': member.id,
                'type': 'strike',
                'active': True
            }).sort('timestamp', 1)
            for pun in puns:
                if pun['active_strike_count'] - diff >= 0:
                    userDB = mclient.bowser.users
                    punDB.update_one(
                        {'_id': pun['_id']},
                        {
                            '$set': {
                                'active_strike_count':
                                pun['active_strike_count'] - diff,
                                'active':
                                pun['active_strike_count'] - diff > 0,
                            }
                        },
                    )
                    userDB.update_one({'_id': member.id}, {
                        '$set': {
                            'strike_check': time.time() + (60 * 60 * 24 * 7)
                        }
                    })
                    self.taskHandles.append(
                        self.bot.loop.call_later(
                            60 * 60 * 12, asyncio.create_task,
                            self.expire_actions(pun['_id'], ctx.guild.id))
                    )  # Check in 12 hours, prevents time drifting

                    # Logic to calculate the remaining (diff) strikes will simplify to 0
                    # new_diff = diff - removed_strikes
                    #          = diff - (old_strike_amount - new_strike_amount)
                    #          = diff - (old_strike_amount - (old_strike_amount - diff))
                    #          = diff - old_strike_amount + old_strike_amount - diff
                    #          = 0
                    diff = 0
                    break

                elif pun['active_strike_count'] - diff < 0:
                    punDB.update_one(
                        {'_id': pun['_id']},
                        {'$set': {
                            'active_strike_count': 0,
                            'active': False
                        }})
                    diff -= pun['active_strike_count']

            if diff != 0:  # Something has gone horribly wrong
                raise ValueError('Diff != 0 after full iteration')

            docID = await tools.issue_pun(member.id,
                                          ctx.author.id,
                                          'destrike',
                                          reason=reason,
                                          active=False,
                                          strike_count=activeStrikes - count)
            await tools.send_modlog(
                self.bot,
                self.modLogs,
                'destrike',
                docID,
                reason,
                user=member,
                moderator=ctx.author,
                extra_author=(activeStrikes - count),
                public=True,
            )
            error = ""
            try:
                await member.send(
                    tools.format_pundm('destrike',
                                       reason,
                                       ctx.author,
                                       details=activeStrikes - count))
            except discord.Forbidden:
                error = 'I was not able to DM them about this action'

            if tools.mod_cmd_invoke_delete(ctx.channel):
                return await ctx.message.delete()

            await ctx.send(
                f'{member} ({member.id}) has had {activeStrikes - count} strikes removed, '
                f'they now have {activeStrikes} strike{"s" if activeStrikes > 1 else ""} '
                f'({activeStrikes+count} - {count}) {error}')
示例#6
0
    async def _strike(self,
                      ctx,
                      member: discord.Member,
                      count: typing.Optional[StrikeRange] = 1,
                      *,
                      reason):
        if count == 0:
            return await ctx.send(
                f'{config.redTick} You cannot issue less than one strike. If you need to reset this user\'s strikes to zero instead use `{ctx.prefix}strike set`'
            )

        if len(reason) > 990:
            return await ctx.send(
                f'{config.redTick} Strike reason is too long, reduce it by at least {len(reason) - 990} characters'
            )
        punDB = mclient.bowser.puns
        userDB = mclient.bowser.users

        activeStrikes = 0
        for pun in punDB.find({
                'user': member.id,
                'type': 'strike',
                'active': True
        }):
            activeStrikes += pun['active_strike_count']

        activeStrikes += count
        if activeStrikes > 16:  # Max of 16 active strikes
            return await ctx.send(
                f'{config.redTick} Striking {count} time{"s" if count > 1 else ""} would exceed the maximum of 16 strikes. The amount being issued must be lowered by at least {activeStrikes - 16} or consider banning the user instead'
            )

        docID = await tools.issue_pun(member.id,
                                      ctx.author.id,
                                      'strike',
                                      reason,
                                      strike_count=count,
                                      public=True)
        userDB.update_one(
            {'_id': member.id},
            {'$set': {
                'strike_check': time.time() + (60 * 60 * 24 * 7)
            }})  # 7 days

        self.taskHandles.append(
            self.bot.loop.call_later(60 * 60 * 12, asyncio.create_task,
                                     self.expire_actions(docID, ctx.guild.id))
        )  # Check in 12 hours, prevents time drifting
        await tools.send_modlog(
            self.bot,
            self.modLogs,
            'strike',
            docID,
            reason,
            user=member,
            moderator=ctx.author,
            extra_author=count,
            public=True,
        )
        content = (
            f'{config.greenTick} {member} ({member.id}) has been successfully struck, '
            f'they now have {activeStrikes} strike{"s" if activeStrikes > 1 else ""} ({activeStrikes-count} + {count})'
        )
        try:
            await member.send(
                tools.format_pundm('strike', reason, ctx.author,
                                   details=count))

        except discord.Forbidden:
            if not tools.mod_cmd_invoke_delete(ctx.channel):
                content += '. I was not able to DM them about this action'
                if activeStrikes == 16:
                    content += '.\n:exclamation: You may want to consider a ban'

                await ctx.send(content)

            return

        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()

        if activeStrikes == 16:
            content += '.\n:exclamation: You may want to consider a ban'

        await ctx.send(content)
示例#7
0
    async def _muting(self,
                      ctx,
                      member: discord.Member,
                      duration,
                      *,
                      reason='-No reason specified-'):
        if len(reason) > 990:
            return await ctx.send(
                f'{config.redTick} Mute reason is too long, reduce it by at least {len(reason) - 990} characters'
            )
        db = mclient.bowser.puns
        if db.find_one({'user': member.id, 'type': 'mute', 'active': True}):
            return await ctx.send(
                f'{config.redTick} {member} ({member.id}) is already muted')

        muteRole = ctx.guild.get_role(config.mute)
        try:
            _duration = tools.resolve_duration(duration)
            try:
                if int(duration):
                    raise TypeError

            except ValueError:
                pass

        except (KeyError, TypeError):
            return await ctx.send(f'{config.redTick} Invalid duration passed')

        docID = await tools.issue_pun(member.id, ctx.author.id, 'mute', reason,
                                      int(_duration.timestamp()))
        await member.add_roles(muteRole,
                               reason='Mute action performed by moderator')
        await tools.send_modlog(
            self.bot,
            self.modLogs,
            'mute',
            docID,
            reason,
            user=member,
            moderator=ctx.author,
            expires=
            f'{_duration.strftime("%B %d, %Y %H:%M:%S UTC")} ({tools.humanize_duration(_duration)})',
            public=True,
        )
        error = ""
        try:
            await member.send(
                tools.format_pundm('mute', reason, ctx.author,
                                   tools.humanize_duration(_duration)))

        except (discord.Forbidden, AttributeError):
            error = '. I was not able to DM them about this action'

        if not tools.mod_cmd_invoke_delete(ctx.channel):
            await ctx.send(
                f'{config.greenTick} {member} ({member.id}) has been successfully muted{error}'
            )

        twelveHr = 60 * 60 * 12
        expireTime = time.mktime(_duration.timetuple())
        logging.info(f'using {expireTime}')
        tryTime = twelveHr if expireTime - time.time(
        ) > twelveHr else expireTime - time.time()
        self.taskHandles.append(
            self.bot.loop.call_later(tryTime, asyncio.create_task,
                                     self.expire_actions(docID, ctx.guild.id)))
        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()
示例#8
0
    async def _banning(self,
                       ctx,
                       users: commands.Greedy[ResolveUser],
                       *,
                       reason='-No reason specified-'):
        if len(reason) > 990:
            return await ctx.send(
                f'{config.redTick} Ban reason is too long, reduce it by at least {len(reason) - 990} characters'
            )
        if not users:
            return await ctx.send(
                f'{config.redTick} An invalid user was provided')
        banCount = 0
        failedBans = 0
        for user in users:
            userid = user if (type(user) is int) else user.id

            username = userid if (type(user) is int) else f'{str(user)}'
            user = (discord.Object(id=userid) if (type(user) is int) else user
                    )  # If not a user, manually contruct a user object
            try:
                await ctx.guild.fetch_ban(user)
                if len(users) == 1:
                    return await ctx.send(
                        f'{config.redTick} {username} is already banned')

                else:
                    # If a many-user ban, don't exit if a user is already banned
                    failedBans += 1
                    continue

            except discord.NotFound:
                pass

            try:
                await user.send(tools.format_pundm('ban', reason, ctx.author))

            except (discord.Forbidden, AttributeError):
                pass

            try:
                await ctx.guild.ban(
                    user,
                    reason=f'Ban action performed by moderator',
                    delete_message_days=3)

            except discord.NotFound:
                # User does not exist
                if len(users) == 1:
                    return await ctx.send(
                        f'{config.redTick} User {userid} does not exist')

                failedBans += 1
                continue

            docID = await tools.issue_pun(userid,
                                          ctx.author.id,
                                          'ban',
                                          reason=reason)
            await tools.send_modlog(
                self.bot,
                self.modLogs,
                'ban',
                docID,
                reason,
                username=username,
                userid=userid,
                moderator=ctx.author,
                public=True,
            )
            banCount += 1

        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()

        if len(users) == 1:
            await ctx.send(
                f'{config.greenTick} {users[0]} has been successfully banned')

        else:
            resp = f'{config.greenTick} **{banCount}** users have been successfully banned'
            if failedBans:
                resp += f'. Failed to ban **{failedBans}** from the provided list'
            return await ctx.send(resp)
示例#9
0
    async def _kicking(self,
                       ctx,
                       users: commands.Greedy[ResolveUser],
                       *,
                       reason='-No reason specified-'):
        if len(reason) > 990:
            return await ctx.send(
                f'{config.redTick} Kick reason is too long, reduce it by at least {len(reason) - 990} characters'
            )
        if not users:
            return await ctx.send(
                f'{config.redTick} An invalid user was provided')

        kickCount = 0
        failedKicks = 0
        couldNotDM = False

        for user in users:
            userid = user if (type(user) is int) else user.id
            username = userid if (type(user) is int) else f'{str(user)}'

            user = (discord.Object(id=userid) if (type(user) is int) else user
                    )  # If not a user, manually contruct a user object

            try:
                member = await ctx.guild.fetch_member(userid)
            except discord.HTTPException:  # Member not in guild
                if len(users) == 1:
                    return await ctx.send(
                        f'{config.redTick} {username} is not the server!')

                else:
                    # If a many-user kick, don't exit if a user is already gone
                    failedKicks += 1
                    continue

            usr_role_pos = member.top_role.position

            if (usr_role_pos >= ctx.guild.me.top_role.position) or (
                    usr_role_pos >= ctx.author.top_role.position):
                if len(users) == 1:
                    return await ctx.send(
                        f'{config.redTick} Insufficent permissions to kick {username}'
                    )
                else:
                    failedKicks += 1
                    continue

            try:
                await user.send(tools.format_pundm('kick', reason, ctx.author))
            except (discord.Forbidden, AttributeError):
                couldNotDM = True
                pass

            try:
                await member.kick(reason='Kick action performed by moderator')
            except (discord.Forbidden):
                failedKicks += 1
                continue

            docID = await tools.issue_pun(member.id,
                                          ctx.author.id,
                                          'kick',
                                          reason,
                                          active=False)
            await tools.send_modlog(self.bot,
                                    self.modLogs,
                                    'kick',
                                    docID,
                                    reason,
                                    user=member,
                                    moderator=ctx.author,
                                    public=True)
            kickCount += 1

        if tools.mod_cmd_invoke_delete(ctx.channel):
            return await ctx.message.delete()

        if ctx.author.id != self.bot.user.id:  # Non-command invoke, such as automod
            if len(users) == 1:
                resp = f'{config.greenTick} {users[0]} has been successfully kicked'
                if couldNotDM:
                    resp += '. I was not able to DM them about this action'

            else:
                resp = f'{config.greenTick} **{kickCount}** users have been successfully kicked'
                if failedKicks:
                    resp += f'. Failed to kick **{failedKicks}** from the provided list'

            return await ctx.send(resp)