Esempio n. 1
0
    def test_calculate_ratios_does_nothing(self, create_core):
        """Tests the loop does nothing on different messages"""
        member = Member(1,
                        1,
                        messages=[Message(1, 2, 3, 4, "Hello I am the world")])

        create_core._calculate_ratios(Message(2, 2, 3, 4, "My name is Ethan!"),
                                      member, Guild(1))
Esempio n. 2
0
    def test_calculate_ratios_raises(self, create_core):
        member = Member(
            1,
            1,
            messages=[Message(1, 2, 3, 4, "One"),
                      Message(2, 2, 3, 4, "Two")])

        m = Message(1, 2, 3, 4, "One")
        m.creation_time = member.messages[0].creation_time
        with pytest.raises(DuplicateObject):
            create_core._calculate_ratios(m, member, Guild(1))
Esempio n. 3
0
    async def test_delete_member_messages(self, create_dpy_lib_handler):
        member = Member(1, 2)
        member.messages = [
            Message(1, 2, 3, 4, "First"),
            Message(2, 2, 3, 4, "second", is_duplicate=True),
            Message(3, 2, 3, 4, "third", is_duplicate=True),
        ]

        with patch("antispam.libs.dpy.DPY.delete_message",
                   new_callable=AsyncMock) as delete_call:
            await create_dpy_lib_handler.delete_member_messages(member)
            assert delete_call.call_count == 2
Esempio n. 4
0
    def test_calculate_ratios(self, create_core):
        member = Member(1, 1)
        member.messages = [
            Message(1, 1, 1, 1, "Hello world", datetime.datetime.now())
        ]
        message = Message(2, 1, 1, 1, "Hello world", datetime.datetime.now())

        assert member.duplicate_counter == 1

        create_core._calculate_ratios(message, member, Guild(1))

        assert member.duplicate_counter == 2
        assert message.is_duplicate is True
Esempio n. 5
0
    def test_calculate_ratios_per_channel(self, create_core):
        member = Member(1, 1)
        member.messages = [
            Message(1, 1, 1, 1, "Hello world", datetime.datetime.now())
        ]
        message = Message(2, 2, 1, 1, "Hello world", datetime.datetime.now())
        guild = Guild(1, options=Options(per_channel_spam=True))

        assert member.duplicate_counter == 1

        create_core._calculate_ratios(message, member, guild)

        assert member.duplicate_counter == 1
        assert message.is_duplicate is False
Esempio n. 6
0
    def create_message_from_dict(message_data) -> Message:
        message = Message(
            id=message_data["id"],
            content=message_data["content"],
            guild_id=message_data["guild_id"],
            author_id=message_data["author_id"],
            channel_id=message_data["channel_id"],
        )
        message.is_duplicate = message_data["is_duplicate"]
        message.creation_time = datetime.datetime.strptime(
            message_data["creation_time"], "%f:%S:%M:%H:%d:%m:%Y")
        log.info("Created Message(id=%s) from dict", message.id)

        return message
Esempio n. 7
0
    def test_create_message(self):
        test_dict = {
            "id": 1,
            "content": "Hello World!",
            "guild_id": 2,
            "author_id": 3,
            "channel_id": 4,
            "is_duplicate": True,
            "creation_time": "225596:21:8:3:12:5:2021",
        }
        time = datetime.datetime.strptime("225596:21:8:3:12:5:2021",
                                          "%f:%S:%M:%H:%d:%m:%Y")
        message = Message(
            id=1,
            content="Hello World!",
            guild_id=2,
            author_id=3,
            channel_id=4,
            is_duplicate=True,
            creation_time=time,
        )

        test_message = FactoryBuilder.create_message_from_dict(test_dict)

        assert test_message == message
Esempio n. 8
0
    async def test_add_message_filled(self, create_memory_cache):
        """Test with a pre-filled member"""
        await create_memory_cache.set_member(Member(4, 3))
        await create_memory_cache.add_message(Message(1, 2, 3, 4, "Content"))

        assert len(create_memory_cache.cache[3].members) == 1
        assert len(create_memory_cache.cache[3].members[4].messages) == 1
Esempio n. 9
0
    async def test_add_message_raw(self, create_redis_cache):
        """Test without a pre-filled cache"""
        await create_redis_cache.add_message(Message(1, 2, 3, 4, "Content"))

        r_1 = await create_redis_cache.get_guild(3)
        assert len(r_1.members) == 1
        assert len(r_1.members[4].messages) == 1
Esempio n. 10
0
    async def create_message(self, message: messages.Message) -> Message:
        log.debug(
            "Attempting to create a new message for author(id=%s) in Guild(%s)",
            message.author.id,
            message.guild_id,
        )
        if not bool(message.content and message.content.strip()):
            if not message.embeds:
                raise LogicError

            content = ""
            for embed in message.embeds:
                if not isinstance(embed, embeds.Embed):
                    raise LogicError

                content += await self.embed_to_string(embed)
        else:
            content = message.content

        if self.handler.options.delete_zero_width_chars:
            content = (content.replace("u200B", "").replace(
                "u200C",
                "").replace("u200D",
                            "").replace("u200E",
                                        "").replace("u200F",
                                                    "").replace("uFEFF", ""))

        return Message(
            id=message.id,
            channel_id=message.channel_id,
            guild_id=message.guild_id,
            author_id=message.author.id,
            content=content,
        )
Esempio n. 11
0
    async def test_add_message_filled_guild(self, create_redis_cache):
        """Test with an existing guild"""
        await create_redis_cache.set_guild(Guild(3, Options()))
        await create_redis_cache.add_message(Message(1, 2, 3, 4, "Content"))

        r_1 = await create_redis_cache.get_member(4, 3)
        r_2 = await create_redis_cache.get_guild(3)
        assert len(r_2.members) == 1
        assert len(r_1.messages) == 1
Esempio n. 12
0
    async def create_message(self, message: "UserMessage") -> Message:
        log.debug(
            "Attempting to create a new message for author(id=%s) in Guild(%s)",
            message.author.id,
            message.guild_id,
        )
        # TODO Reimplement once #424 is resolved
        # if message.type not in {
        #     MessageType.DEFAULT,
        #     MessageType.REPLY,
        #     MessageType.APPLICATION_COMMAND,
        #     MessageType.THREAD_STARTER_MESSAGE,
        # }:
        #     raise InvalidMessage(
        #         "Message is a system one, we don't check against those."
        #     )

        content = ""
        if message.sticker_items:
            # 'sticker' names should be unique..
            all_stickers = "|".join(s.name for s in message.sticker_items)
            content += all_stickers

        elif not bool(message.content and message.content.strip()):
            if not message.embeds and not message.attachments:
                raise LogicError

            if not message.embeds:
                # We don't check against attachments
                raise InvalidMessage

            for embed in message.embeds:
                if not isinstance(embed, objects.Embed):
                    raise LogicError

                content += await self.embed_to_string(embed)
        else:
            content += message.content

        if self.handler.options.delete_zero_width_chars:
            content = (content.replace("u200B", "").replace(
                "u200C",
                "").replace("u200D",
                            "").replace("u200E",
                                        "").replace("u200F",
                                                    "").replace("uFEFF", ""))

        return Message(
            id=message.id,
            channel_id=message.channel_id,
            guild_id=message.guild_id,
            author_id=message.author.id,
            content=content,
        )
Esempio n. 13
0
    async def test_set_member(self, create_mongo_cache):
        """Tests set member with an existing guild"""
        with pytest.raises(MemberNotFound):
            await create_mongo_cache.get_member(3, 1)

        await create_mongo_cache.set_member(
            Member(
                3,
                1,
                messages=[
                    Message(1, 1, 1, 1, "Hello world"),
                    Message(2, 1, 1, 1, "foo bar"),
                ],
            )
        )

        r_1 = await create_mongo_cache.get_member(3, 1)
        assert isinstance(r_1, Member)
        assert len(r_1.messages) == 2
        assert r_1.messages[0].content == "Hello world"
Esempio n. 14
0
    async def test_add_message(self, create_mongo_cache):
        r_1 = await create_mongo_cache.get_member(1, 1)
        assert isinstance(r_1, Member)
        assert len(r_1.messages) == 3

        msg = Message(4, 1, 1, 1, "Hello world")
        await create_mongo_cache.add_message(msg)

        r_2 = await create_mongo_cache.get_member(1, 1)
        assert isinstance(r_2, Member)
        assert len(r_2.messages) == 4
        assert r_2.messages[3].content == "Hello world"
Esempio n. 15
0
def create_mongo_cache(create_handler) -> MockedMongoCache:
    guild_data: List[Dict[str, Any]] = [asdict(Guild(1))]
    member_data: List[Dict[str, Any]] = [
        asdict(
            Member(
                1,
                1,
                warn_count=2,
                kick_count=1,
                messages=[
                    Message(1, 1, 1, 1, content="Foo"),
                    Message(2, 1, 1, 1, content="Bar"),
                    Message(3, 1, 1, 1, content="Baz"),
                ],
            ),
            recurse=True,
        ),
        asdict(Member(2, 1)),
    ]

    return MockedMongoCache(create_handler, member_data, guild_data)
Esempio n. 16
0
    def test_calculate_ratio_edge_case(self, create_core):
        """Tests calculate ratios correctly marks an edge case as spam

        See:
        https://mystb.in/HarderTournamentsPrimary.properties

        Previously it would not mark all "Spam tho" as spam when it should have
        """
        member = Member(1, 1)
        member.messages = [
            Message(1, 1, 1, 1, "This is a test", datetime.datetime.now()),
            Message(2, 1, 1, 1, "Heres another message",
                    datetime.datetime.now()),
            Message(3, 1, 1, 1, "Spam tho", datetime.datetime.now()),
            Message(4, 1, 1, 1, "Spam tho", datetime.datetime.now()),
            Message(5, 1, 1, 1, "Spam tho", datetime.datetime.now()),
        ]
        message = Message(6, 1, 1, 1, "Spam tho", datetime.datetime.now())

        create_core._calculate_ratios(message, member, Guild(1))

        assert message.is_duplicate is True
        assert member.messages[0].is_duplicate is False
        assert member.messages[1].is_duplicate is False
        assert member.messages[2].is_duplicate is True
        assert member.messages[3].is_duplicate is True
        assert member.messages[4].is_duplicate is True
Esempio n. 17
0
    async def get_guild(self, guild_id: int) -> Guild:
        log.debug("Attempting to return cached Guild(id=%s)", guild_id)
        guild: Guild = await self.guilds.find({"id": guild_id})

        # This is a dict here actually
        if not guild:
            raise GuildNotFound

        guild.options = Options(**guild.options)  # type: ignore
        members: List[Member] = await self.members.find_many_by_custom(
            {"guild_id": guild_id})
        for member in members:
            messages: List[Message] = []
            for dict_message in member.messages:
                dict_message: dict = dict_message
                msg = Message(**dict_message)
                msg.creation_time = msg.creation_time.replace(tzinfo=pytz.UTC)
                messages.append(msg)
            member.messages = messages
            guild.members[member.id] = member

        return guild
Esempio n. 18
0
    async def get_member(self, member_id: int, guild_id: int) -> Member:
        log.debug(
            "Attempting to return a cached Member(id=%s) for Guild(id=%s)",
            member_id,
            guild_id,
        )
        member: Member = await self.members.find({
            "id": member_id,
            "guild_id": guild_id
        })
        if not member:
            raise MemberNotFound

        messages: List[Message] = []
        for dict_message in member.messages:
            dict_message: dict = dict_message
            msg = Message(**dict_message)
            msg.creation_time = msg.creation_time.replace(tzinfo=pytz.UTC)
            messages.append(msg)
        member.messages = messages

        return member
Esempio n. 19
0
    def test_clean_old_messages(self):
        member = Member(
            1,
            2,
            messages=[
                Message(1, 2, 3, 4, "Hello"),
                Message(
                    2,
                    2,
                    3,
                    4,
                    "World",
                    creation_time=get_aware_time() -
                    datetime.timedelta(seconds=45),
                ),
            ],
        )
        assert len(member.messages) == 2

        FactoryBuilder.clean_old_messages(member, get_aware_time(), Options())

        assert len(member.messages) == 1
Esempio n. 20
0
    async def create_message(self, message: discord.Message) -> Message:
        log.debug(
            "Attempting to create a new message for author(id=%s) in Guild(%s)",
            message.author.id,
            message.guild.id,
        )
        if message.is_system():
            raise InvalidMessage(
                "Message is a system one, we don't check against those.")

        if message.stickers:
            # 'sticker' urls should be unique..
            all_stickers = "|".join(s.url for s in message.stickers)
            content = all_stickers

        elif not bool(message.content and message.content.strip()):
            if not message.embeds and not message.attachments:
                # System message? Like on join trip these
                raise LogicError

            if not message.embeds:
                # We don't check agaisn't attachments
                raise InvalidMessage

            content = ""
            for embed in message.embeds:
                if not isinstance(embed, discord.Embed):
                    raise LogicError

                if embed.type.lower() != "rich":
                    raise LogicError

                content += await self.embed_to_string(embed)
        else:
            content = message.clean_content

        if self.handler.options.delete_zero_width_chars:
            content = (content.replace("u200B", "").replace(
                "u200C",
                "").replace("u200D",
                            "").replace("u200E",
                                        "").replace("u200F",
                                                    "").replace("uFEFF", ""))

        return Message(
            id=message.id,
            channel_id=message.channel.id,
            guild_id=message.guild.id,
            author_id=message.author.id,
            content=content,
        )
Esempio n. 21
0
    async def test_clean_up_duplicate_count(self, create_core):
        member = Member(1, 1)
        messages = [
            Message(
                1,
                1,
                1,
                1,
                "First message",
                datetime.datetime.now() - datetime.timedelta(minutes=1),
            ),
            Message(
                2,
                1,
                1,
                1,
                "Second message",
                datetime.datetime.now() - datetime.timedelta(minutes=1),
            ),
            Message(
                3,
                1,
                1,
                1,
                "Third message",
                datetime.datetime.now() - datetime.timedelta(minutes=1),
                is_duplicate=True,
            ),
            Message(4, 1, 1, 1, "Fourth message", datetime.datetime.now()),
        ]
        member.messages = messages
        member.duplicate_counter = 1

        await create_core.clean_up(member, datetime.datetime.now(), 1,
                                   Guild(1))

        assert member.duplicate_counter == 0
Esempio n. 22
0
    async def test_clean_up(self, create_core):
        member = Member(1, 1)
        messages = [
            Message(
                1,
                1,
                1,
                1,
                "First message",
                datetime.datetime.now() - datetime.timedelta(minutes=1),
            ),
            Message(
                2,
                1,
                1,
                1,
                "Second message",
                datetime.datetime.now() - datetime.timedelta(minutes=1),
            ),
            Message(
                3,
                1,
                1,
                1,
                "Third message",
                datetime.datetime.now() - datetime.timedelta(minutes=1),
            ),
            Message(4, 1, 1, 1, "Fourth message", datetime.datetime.now()),
        ]
        member.messages = messages

        assert len(member.messages) == 4

        await create_core.clean_up(member, datetime.datetime.now(), 1,
                                   Guild(1))

        assert len(member.messages) == 1
Esempio n. 23
0
    async def test_clean_cache_strict_member(self, create_handler):
        """Tests clean_cache on members with strict mode"""
        await create_handler.cache.set_member(Member(1, 1))
        assert bool(create_handler.cache.cache)

        await create_handler.clean_cache(strict=True)
        assert not bool(create_handler.cache.cache)

        await create_handler.cache.set_member(
            Member(1, 1, messages=[Message(1, 2, 3, 4, "Hello")])
        )
        assert bool(create_handler.cache.cache)

        await create_handler.clean_cache(strict=True)
        assert bool(create_handler.cache.cache)
Esempio n. 24
0
    async def test_add_message_no_exist(self, create_mongo_cache):
        """Tests add_message when the member doesnt exist"""
        with pytest.raises(MemberNotFound):
            await create_mongo_cache.get_member(3, 3)

        with pytest.raises(GuildNotFound):
            await create_mongo_cache.get_guild(3)

        await create_mongo_cache.add_message(Message(1, 1, 3, 3, "Foo bar"))

        r_1 = await create_mongo_cache.get_member(3, 3)
        assert isinstance(r_1, Member)
        assert len(r_1.messages) == 1

        assert r_1.messages[0].content == "Foo bar"

        r_2 = await create_mongo_cache.get_guild(3)
        assert isinstance(r_2, Guild)
        assert r_1 in list(r_2.members.values())
Esempio n. 25
0
    async def create_message(self, message: messages.Message) -> Message:
        log.debug(
            "Attempting to create a new message for author(id=%s) in Guild(%s)",
            message.author.id,
            message.guild_id,
        )
        content = ""
        if message.stickers:
            # 'sticker' names should be unique..
            all_stickers = "|".join(s.name for s in message.stickers)
            content += all_stickers

        if not bool(message.content and message.content.strip()):
            if not message.embeds and not message.attachments:
                raise LogicError

            if not message.embeds:
                # We dont check attachments lol
                raise InvalidMessage

            for embed in message.embeds:
                if not isinstance(embed, embeds.Embed):
                    raise LogicError

                content += await self.embed_to_string(embed)
        else:
            content = message.content

        if self.handler.options.delete_zero_width_chars:
            content = (content.replace("u200B", "").replace(
                "u200C",
                "").replace("u200D",
                            "").replace("u200E",
                                        "").replace("u200F",
                                                    "").replace("uFEFF", ""))

        return Message(
            id=message.id,
            channel_id=message.channel_id,
            guild_id=message.guild_id,
            author_id=message.author.id,
            content=content,
        )
Esempio n. 26
0
    async def get_member(self, member_id: int, guild_id: int) -> Member:
        log.debug(
            "Attempting to return a cached Member(id=%s) for Guild(id=%s)",
            member_id,
            guild_id,
        )
        resp = await self.redis.get(f"MEMBER:{guild_id}:{member_id}")
        if not resp:
            raise MemberNotFound

        as_json = json.loads(resp.decode("utf-8"))
        member: Member = Member(**as_json)

        messages: List[Message] = []
        for message in member.messages:
            messages.append(Message(**message))  # type: ignore

        member.messages = messages
        return member
Esempio n. 27
0
    async def test_set_member_no_guild(self, create_mongo_cache):
        """Tests set member with no existing cached guild"""
        with pytest.raises(MemberNotFound):
            await create_mongo_cache.get_member(2, 2)

        with pytest.raises(GuildNotFound):
            await create_mongo_cache.get_guild(2)

        await create_mongo_cache.set_member(
            Member(2, 2, messages=[Message(1, 1, 1, 1, "Hello world")])
        )

        r_1 = await create_mongo_cache.get_guild(2)
        assert isinstance(r_1, Guild)
        assert len(r_1.members) == 1

        r_2 = await create_mongo_cache.get_member(2, 2)
        assert isinstance(r_2, Member)
        assert len(r_2.messages) == 1
        assert r_2.messages[0].content == "Hello world"
Esempio n. 28
0
    def _calculate_ratios(
        self,
        message: Message,
        member: Member,
    ) -> None:
        """
        Calculates a messages relation to other messages
        """
        for message_obj in member.messages:
            # This calculates the relation to each other
            if message == message_obj:
                raise DuplicateObject

            elif (
                self.options.per_channel_spam
                and message.channel_id != message_obj.channel_id
            ):
                # This user's spam should only be counted per channel
                # and these messages are in different channel
                continue

            elif (
                fuzz.token_sort_ratio(message.content, message_obj.content)
                >= self.options.message_duplicate_accuracy
            ):
                """
                The handler works off an internal message duplicate counter
                so just increment that and then let our logic process it later
                """
                self._increment_duplicate_count(member, channel_id=message.channel_id)
                message.is_duplicate = True
                message_obj.is_duplicate = True

                if (
                    self._get_duplicate_count(
                        member,
                        channel_id=message.channel_id,
                    )
                    >= self.options.message_duplicate_count
                ):
                    break
Esempio n. 29
0
 async def test_add_message_filled_guild(self, create_memory_cache):
     """Test with an existing guild"""
     await create_memory_cache.set_guild(Guild(3, Options()))
     await create_memory_cache.add_message(Message(1, 2, 3, 4, "Content"))
     assert len(create_memory_cache.cache[3].members) == 1
     assert len(create_memory_cache.cache[3].members[4].messages) == 1
Esempio n. 30
0
    def test_create_member(self):
        test_data = {
            "id": 1,
            "guild_id": 2,
            "is_in_guild": True,
            "warn_count": 5,
            "kick_count": 6,
            "duplicate_count": 7,
            "duplicate_channel_counter_dict": {},
            "messages": [],
        }
        test_member = FactoryBuilder.create_member_from_dict(test_data)
        member = Member(
            id=1,
            guild_id=2,
            in_guild=True,
            warn_count=5,
            kick_count=6,
            duplicate_counter=7,
            duplicate_channel_counter_dict={},
            messages=[],
        )
        assert test_member == member

        test_data_two = {
            "id":
            1,
            "guild_id":
            2,
            "is_in_guild":
            True,
            "warn_count":
            5,
            "kick_count":
            6,
            "duplicate_count":
            7,
            "duplicate_channel_counter_dict": {},
            "messages": [{
                "id": 1,
                "content": "Hello World!",
                "guild_id": 2,
                "author_id": 3,
                "channel_id": 4,
                "is_duplicate": True,
                "creation_time": "225596:21:8:3:12:5:2021",
            }],
        }
        test_member_two = FactoryBuilder.create_member_from_dict(test_data_two)

        time = datetime.datetime.strptime("225596:21:8:3:12:5:2021",
                                          "%f:%S:%M:%H:%d:%m:%Y")
        message = Message(
            id=1,
            content="Hello World!",
            guild_id=2,
            author_id=3,
            channel_id=4,
            is_duplicate=True,
            creation_time=time,
        )
        member_two = Member(
            id=1,
            guild_id=2,
            in_guild=True,
            warn_count=5,
            kick_count=6,
            duplicate_counter=7,
            duplicate_channel_counter_dict={},
            messages=[message],
        )

        assert member_two == test_member_two