Exemplo n.º 1
0
    async def timeout_member(self, member: disnake.Member, original_message,
                             until: datetime.timedelta) -> None:
        guild = original_message.guild
        perms = guild.me.guild_permissions
        if not perms.moderate_members:
            raise MissingGuildPermissions(
                "moderate_members is required to timeout members.\n"
                f"Tried timing out Member(id={member.id}) in Guild(id={member.guild.id})"
            )

        await member.timeout(duration=until,
                             reason="Automated timeout from Discord-Anti-Spam")
Exemplo n.º 2
0
    async def timeout_member(
        self,
        member: guilds.Member,
        original_message: messages.Message,
        until: datetime.timedelta,
    ) -> None:
        guild: guilds.Guild = self.handler.bot.cache.get_guild(member.guild_id)
        perms = await self._get_perms(guild.get_my_member())  # type: ignore
        if not perms.MODERATE_MEMBERS:
            raise MissingGuildPermissions(
                "MODERATE_MEMBERS is required to timeout members.\n"
                f"Tried timing out Member(id={member.id}) in Guild(id={member.guild_id})"
            )

        internal_guild: Guild = await self.handler.cache.get_guild(
            member.guild_id)

        time_now = datetime.datetime.utcnow() + until
        await member.edit(
            communication_disabled_until=time_now,
            reason="Automated timeout from Discord-Anti-Spam"  # type: ignore
        )
Exemplo n.º 3
0
    async def punish_member(
        self,
        original_message: discord.Message,
        member: Member,
        internal_guild: Guild,
        user_message,
        guild_message,
        is_kick: bool,
        user_delete_after: int = None,
        channel_delete_after: int = None,
    ):  # pragma: no cover
        guild = original_message.guild
        author = original_message.author

        # Check we have perms to punish
        perms = guild.me.guild_permissions
        if not perms.kick_members and is_kick:
            member._in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need kick perms to punish someone in {guild.name}")

        elif not perms.ban_members and not is_kick:
            member._in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need ban perms to punish someone in {guild.name}")

        # We also check they don't own the guild, since ya know...
        elif guild.owner_id == member.id:
            member._in_guild = True
            member.kick_count -= 1

            # TODO Make this consistent across libs
            await self.send_guild_log(
                guild=internal_guild,
                message=
                f"I am failing to punish {original_message.author.display_name} because they own this guild.",
                delete_after_time=channel_delete_after,
                original_channel=original_message.channel,
            )
            raise MissingGuildPermissions(
                f"I cannot punish {author.display_name}({author.id}) "
                f"because they own this guild. ({guild.name})")

        # Ensure we can actually punish the user, for this
        # we just check our top role is higher then them
        elif guild.me.top_role.position < author.top_role.position:
            log.warning(
                "I might not be able to punish %s(%s) in Guild: %s(%s) "
                "because they are higher then me, which means I could lack the ability to kick/ban them.",
                author.display_name,
                member.id,
                guild.name,
                guild.id,
            )

        sent_message: Optional[discord.Message] = None
        try:
            if isinstance(user_message, discord.Embed):
                sent_message = await author.send(
                    embed=user_message, delete_after=user_delete_after)
            else:
                sent_message = await author.send(
                    user_message, delete_after=user_delete_after)

        except discord.HTTPException:
            await self.send_guild_log(
                guild=internal_guild,
                message=
                f"Sending a message to {author.mention} about their {'kick' if is_kick else 'ban'} failed.",
                delete_after_time=channel_delete_after,
                original_channel=original_message.channel,
            )
            log.warning(
                f"Failed to message Member(id=%s) about {'kick' if is_kick else 'ban'}",
                author.id,
            )

        # Even if we can't tell them they are being punished
        # We still need to punish them, so try that
        try:
            if is_kick:
                await guild.kick(
                    member, reason="Automated punishment from DPY Anti-Spam.")
                log.info("Kicked Member(id=%s)", member.id)
            else:
                await guild.ban(
                    member, reason="Automated punishment from DPY Anti-Spam.")
                log.info("Banned Member(id=%s)", member.id)

        except discord.Forbidden as e:
            # In theory we send the failed punishment method
            # here, although we check first so I think its fine
            # to remove it from this part
            raise e from None

        except discord.HTTPException:
            member._in_guild = True
            member.kick_count -= 1
            await self.send_guild_log(
                guild=internal_guild,
                message=
                f"An error occurred trying to {'kick' if is_kick else 'ban'}: <@{member.id}>",
                delete_after_time=channel_delete_after,
                original_channel=original_message.channel,
            )
            log.warning(
                "An error occurred trying to %s: Member(id=%s)",
                {"kick" if is_kick else "ban"},
                member.id,
            )
            if sent_message is not None:
                if is_kick:
                    user_failed_message = self.transform_message(
                        self.handler.options.member_failed_kick_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )
                else:
                    user_failed_message = self.transform_message(
                        self.handler.options.member_failed_ban_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )

                await self.send_guild_log(
                    internal_guild,
                    user_failed_message,
                    channel_delete_after,
                    original_message.channel,
                )
                await sent_message.delete()

        else:
            await self.send_guild_log(
                guild=internal_guild,
                message=guild_message,
                delete_after_time=channel_delete_after,
                original_channel=original_message.channel,
            )

        member._in_guild = True
        await self.handler.cache.set_member(member)
Exemplo n.º 4
0
 def test_missing_guild_perms(self):
     assert (
         str(MissingGuildPermissions()) ==
         "I need both permissions to kick & ban people from this guild in order to work!"
     )
Exemplo n.º 5
0
    async def punish_member(
        self,
        original_message: messages.Message,
        member: Member,
        internal_guild: Guild,
        user_message,
        guild_message,
        is_kick: bool,
        user_delete_after: int = None,
        channel_delete_after: int = None,
    ):  # pragma: no cover
        guild = self.handler.bot.cache.get_guild(original_message.guild_id)
        author = original_message.author
        channel = await self.handler.bot.rest.fetch_channel(
            original_message.channel_id)

        # Check we have perms to punish
        perms = await self._get_perms(guild.get_my_member())
        if not perms.KICK_MEMBERS and is_kick:
            member.internal_is_in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need kick perms to punish someone in {guild.name}")

        elif not perms.BAN_MEMBERS and not is_kick:
            member.internal_is_in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need ban perms to punish someone in {guild.name}")

        # We also check they don't own the guild, since ya know...
        elif guild.owner_id == member.id:
            member.internal_is_in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I cannot punish {author.username}({author.id}) "
                f"because they own this guild. ({guild.name})")

        sent_message: Optional[messages.Message] = None
        try:
            if isinstance(user_message, embeds.Embed):
                sent_message = await author.send(embed=user_message)
            else:
                sent_message = await author.send(user_message)

            if user_delete_after:
                await asyncio.sleep(user_delete_after)
                await sent_message.delete()

        except InternalServerError:
            await self.send_guild_log(
                guild=internal_guild,
                message=
                f"Sending a message to {author.mention} about their {'kick' if is_kick else 'ban'} failed.",
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )
            log.warning(
                f"Failed to message Member(id=%s) about {'kick' if is_kick else 'ban'}",
                author.id,
            )

        # Even if we can't tell them they are being punished
        # We still need to punish them, so try that
        _success = True
        try:
            if is_kick:
                await guild.kick(
                    author, reason="Automated punishment from DPY Anti-Spam.")
                log.info("Kicked Member(id=%s)", member.id)
            else:
                await guild.ban(
                    author, reason="Automated punishment from DPY Anti-Spam.")
                log.info("Banned Member(id=%s)", member.id)

        except InternalServerError:
            _success = False
            member.internal_is_in_guild = True
            member.kick_count -= 1
            await self.send_guild_log(
                guild=internal_guild,
                message=
                f"An error occurred trying to {'kick' if is_kick else 'ban'}: <@{member.id}>",
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )
            log.warning(
                "An error occurred trying to %s: Member(id=%s)",
                {"kick" if is_kick else "ban"},
                member.id,
            )
            if sent_message is not None:
                if is_kick:
                    user_failed_message = await self.transform_message(
                        self.handler.options.member_failed_kick_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )
                else:
                    user_failed_message = await self.transform_message(
                        self.handler.options.member_failed_ban_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )

                await self.send_guild_log(internal_guild, user_failed_message,
                                          channel_delete_after, channel)
                await sent_message.delete()

        else:
            await self.send_guild_log(
                guild=internal_guild,
                message=guild_message,
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )

        member.internal_is_in_guild = True
        await self.handler.cache.set_member(member)
        return _success
Exemplo n.º 6
0
    async def punish_member(
        self,
        original_message,
        member: Member,
        internal_guild: Guild,
        user_message,
        guild_message,
        is_kick: bool,
        user_delete_after: int = None,
        channel_delete_after: int = None,
    ):
        guild: objects.Guild = await self._fetch_guild(member.guild_id)
        author: objects.User = original_message.author
        channel: objects.Channel = await self._fetch_text_channel(
            original_message.channel_id)
        _member: objects.GuildMember = await self._fetch_member(
            original_message.author.id, original_message.guild_id)

        # Check we have perms to punish
        perms: int = int(_member.permissions)
        kick_members = bool(perms << 1)
        ban_members = bool(perms << 2)
        if not kick_members and is_kick:
            member.internal_is_in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need kick perms to punish someone in {guild.name}")

        elif not ban_members and not is_kick:
            member.internal_is_in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need ban perms to punish someone in {guild.name}")

        # We also check they don't own the guild, since ya know...
        elif guild.owner_id == member.id:
            member.internal_is_in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I cannot punish Member(id={_member.id}, username={_member.username}) "
                f"because they own this guild. Guild(name={guild.name})")
        # TODO Add error handling when #421 is merged
        sent_message: objects.UserMessage = await author.send(user_message)

        if user_delete_after:
            await asyncio.sleep(user_delete_after)
            await sent_message.delete()

        # Even if we can't tell them they are being punished
        # We still need to punish them, so try that
        _success = True
        try:
            if is_kick:
                await guild.kick(
                    _member.id,
                    reason="Automated punishment from DPY Anti-Spam.")
                log.info("Kicked Member(id=%s)", member.id)
            else:
                await guild.ban(
                    _member.id,
                    reason="Automated punishment from DPY Anti-Spam.")
                log.info("Banned Member(id=%s)", member.id)
        except:
            _success = False
            # TODO Pincer doesnt throw errors
            member.internal_is_in_guild = True
            member.kick_count -= 1
            await self.send_guild_log(
                guild=internal_guild,
                message=
                f"An error occurred trying to {'kick' if is_kick else 'ban'}: <@{member.id}>",
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )
            log.warning(
                "An error occurred trying to %s: Member(id=%s)",
                {"kick" if is_kick else "ban"},
                member.id,
            )
            if sent_message is not None:
                if is_kick:
                    user_failed_message = await self.transform_message(
                        self.handler.options.member_failed_kick_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )
                else:
                    user_failed_message = await self.transform_message(
                        self.handler.options.member_failed_ban_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )

                await self.send_guild_log(internal_guild, user_failed_message,
                                          channel_delete_after, channel)
                await sent_message.delete()

        else:
            await self.send_guild_log(
                guild=internal_guild,
                message=guild_message,
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )

        member.internal_is_in_guild = True
        await self.handler.cache.set_member(member)
        return _success
Exemplo n.º 7
0
    async def punish_member(
        self,
        original_message: objects.UserMessage,
        member: Member,
        internal_guild: Guild,
        user_message,
        guild_message,
        is_kick: bool,
        user_delete_after: int = None,
        channel_delete_after: int = None,
    ):
        guild: objects.Guild = await objects.Guild.from_id(
            self.bot, original_message.guild_id
        )
        author = original_message.author
        guild_me: objects.GuildMember = await objects.GuildMember.from_id(
            self.bot, original_message.guild_id, self.bot.bot.id
        )
        guild_member: objects.GuildMember = await objects.GuildMember.from_id(
            self.bot, original_message.guild_id, original_message.author.id
        )

        async def get_hoisted(member: objects.GuildMember) -> int:
            if not member.roles:
                # TODO return guild's default role
                pass

            roles = list(map(int, member.roles))
            return max(roles)

        my_top_role: objects.Role = await objects.Role.from_id(
            self.bot, original_message.guild_id, await get_hoisted(guild_me)
        )
        author_top_role: objects.Role = await objects.Role.from_id(
            self.bot, original_message.guild_id, await get_hoisted(guild_member)
        )
        my_top_role_pos: int = my_top_role.position
        author_top_role_pos: int = author_top_role.position

        # Check we have perms to punish
        perms: int = await self.get_guild_member_perms(
            original_message.guild_id, self.bot.bot.id
        )
        kick_members = bool(perms << 1)
        ban_members = bool(perms << 2)
        if not kick_members and is_kick:
            member._in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need kick perms to punish someone in {guild.name}"
            )

        elif not ban_members and not is_kick:
            member._in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I need ban perms to punish someone in {guild.name}"
            )

        # We also check they don't own the guild, since ya know...
        elif guild.owner_id == member.id:
            member._in_guild = True
            member.kick_count -= 1
            raise MissingGuildPermissions(
                f"I cannot punish {author.username}({author.id}) "
                f"because they own this guild. ({guild.name})"
            )

        elif my_top_role_pos < author_top_role_pos:
            log.warning(
                "I might not be able to punish %s(%s) in Guild: %s(%s) "
                "because they are higher then me, which means I could lack the ability to kick/ban them.",
                author.username,
                member.id,
                guild.name,
                guild.id,
            )

        sent_message: Optional[objects.UserMessage] = None
        try:
            await self.send_message_to_(
                target=author,
                message=user_message,
                delete_after_time=user_delete_after,
                mention=original_message.author.mention,
            )

        except pincer.exceptions.PincerError:
            channel: objects.Channel = await objects.Channel.from_id(
                self.bot, original_message.channel_id
            )
            await self.send_guild_log(
                guild=internal_guild,
                message=f"Sending a message to {author.mention} about their {'kick' if is_kick else 'ban'} failed.",
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )
            log.warning(
                f"Failed to message Member(id=%s) about {'kick' if is_kick else 'ban'}",
                author.id,
            )

        # Even if we can't tell them they are being punished
        # We still need to punish them, so try that
        try:
            if is_kick:
                await guild.kick(
                    member.id, reason="Automated punishment from DPY Anti-Spam."
                )

                log.info("Kicked Member(id=%s)", member.id)
            else:
                await guild.ban(
                    member.id, reason="Automated punishment from DPY Anti-Spam."
                )
                log.info("Banned Member(id=%s)", member.id)

        except pincer.exceptions.ForbiddenError as e:
            # In theory we send the failed punishment method
            # here, although we check first so I think its fine
            # to remove it from this part
            raise e from None

        except pincer.exceptions.PincerError:
            channel: objects.Channel = await self.bot.get_channel(
                original_message.channel_id
            )
            member._in_guild = True
            member.kick_count -= 1
            await self.send_guild_log(
                guild=internal_guild,
                message=f"An error occurred trying to {'kick' if is_kick else 'ban'}: <@{member.id}>",
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )
            log.warning(
                "An error occurred trying to %s: Member(id=%s)",
                {"kick" if is_kick else "ban"},
                member.id,
            )
            if sent_message is not None:
                if is_kick:
                    user_failed_message = await self.transform_message(
                        self.handler.options.member_failed_kick_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )
                else:
                    user_failed_message = await self.transform_message(
                        self.handler.options.member_failed_ban_message,
                        original_message,
                        member.warn_count,
                        member.kick_count,
                    )

                await self.send_guild_log(
                    internal_guild,
                    user_failed_message,
                    channel_delete_after,
                    channel,
                )
                await sent_message.delete()

        else:
            channel: objects.Channel = await self.bot.get_channel(
                original_message.channel_id
            )
            await self.send_guild_log(
                guild=internal_guild,
                message=guild_message,
                delete_after_time=channel_delete_after,
                original_channel=channel,
            )

        member._in_guild = True
        await self.handler.cache.set_member(member)