Ejemplo n.º 1
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
Ejemplo n.º 2
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
Ejemplo n.º 3
0
    async def clean_cache(self, strict=False) -> None:
        """
        Cleans the internal cache, pruning
        any old/un-needed entries.

        Non Strict mode:
         - Member deletion criteria:
            - warn_count == default
            - kick_count == default
            - duplicate_counter == default
            - duplicate_channel_counter_dict == default
            - addons dict == default
            - Also must have no active messages after cleaning.

         - Guild deletion criteria:
            - options are not custom
            - log_channel_id is not set
            - addons dict == default
            - Also must have no members stored

        Strict mode:
         - Member deletion criteria
            - Has no active messages

         - Guild deletion criteria
            - Does not have custom options
            - log_channel_id is not set
            - Has no active members

        Parameters
        ----------
        strict : bool
            Toggles the above


        Notes
        -----
        This is expensive, and likely
        only required to be run every so often
        depending on how high traffic your bot is.
        """
        # In a nutshell,
        # Get entire cache and loop over
        # Build a list of 'still valid' cache entries
        # Drop the previous cache
        # Insert the new list of 'still valid' entries, this is now the cache

        # Ideally I don't want to load this cache into memory
        cache = []
        async for guild in self.cache.get_all_guilds():
            new_guild = Guild(guild.id)
            for member in guild.members.values():
                FactoryBuilder.clean_old_messages(member, get_aware_time(),
                                                  self.options)

                if strict and len(member.messages) != 0:
                    new_guild.members[member.id] = member
                elif (len(member.messages) != 0 or member.kick_count != 0
                      or member.warn_count != 0
                      or member.duplicate_counter != 1
                      or bool(member.duplicate_channel_counter_dict)
                      or bool(member.addons)):
                    new_guild.members[member.id] = member

            # Clean guild
            predicate = (guild.options != Options()
                         or guild.log_channel_id is not None
                         or bool(new_guild.members))
            if strict and predicate:
                new_guild.options = guild.options
                new_guild.log_channel_id = guild.log_channel_id
                cache.append(new_guild)
            elif predicate or bool(guild.addons):
                new_guild.addons = guild.addons
                new_guild.options = guild.options
                new_guild.log_channel_id = guild.log_channel_id
                cache.append(new_guild)

        await self.cache.drop()

        for guild in cache:
            await self.cache.set_guild(guild)

        log.info("Cleaned the internal cache")
Ejemplo n.º 4
0
    async def load_from_dict(
        bot,
        data: dict,
        *,
        raise_on_exception: bool = True,
        plugins: Set[Type[BasePlugin]] = None,
    ):
        """
        Can be used as an entry point when starting your bot
        to reload a previous state so you don't lose all of
        the previous punishment records, etc, etc

        Parameters
        ----------
        bot
            The bot instance
        data : dict
            The data to load AntiSpamHandler from
        raise_on_exception : bool
            Whether or not to raise if an issue is encountered
            while trying to rebuild ``AntiSpamHandler`` from a saved state

            If you set this to False, and an exception occurs during the
            build process. This will return an ``AntiSpamHandler`` instance
            **without** any of the saved state and is equivalent to simply
            doing ``AntiSpamHandler(bot)``
        plugins : Set[Type[BasePlugin]]
            A set for plugin lookups if you want to initialise
            plugins from an initial saved state. This should follow the format.

            .. code-block:: python

                {ClassReference}

            So for example:

            .. code-block:: python
                :linenos:

                class Plugin(BasePlugin):
                    pass

                # Where you load ASH
                await AntiSpamHandler.load_from_dict(..., ..., plugins={Plugin}

        Returns
        -------
        AntiSpamHandler
            A new AntiSpamHandler instance where
            the state is equal to the provided dict

        Warnings
        --------
        Don't provide data that was not given to you
        outside of the ``save_to_dict`` method unless
        you are maintaining the correct format.

        Notes
        -----
        This method does not check for data conformity.
        Any invalid input will error unless you set
        ``raise_on_exception`` to ``False`` in which case
        the following occurs

        If you set ``raise_on_exception`` to ``False``, and an exception occurs during the
        build process. This method will return an ``AntiSpamHandler`` instance
        **without** any of the saved state and is equivalent to simply
        doing ``AntiSpamHandler(bot)``

        This will simply ignore the saved state of plugins that don't have
        a ``plugins`` mapping.

        """
        # TODO Add redis cache here
        plugins = plugins or {}
        plugins: Dict[str, Type[BasePlugin]] = {
            class_ref.__name__: class_ref
            for class_ref in plugins
        }

        caches = {"MemoryCache": MemoryCache}

        try:
            ash = AntiSpamHandler(bot=bot, options=Options(**data["options"]))
            cache_type = data["cache"]
            ash.cache = caches[cache_type](ash)
            for guild in data["guilds"]:
                await ash.cache.set_guild(
                    FactoryBuilder.create_guild_from_dict(guild))

            if pre_invoke_plugins := data.get("pre_invoke_plugins"):
                for plugin, plugin_data in pre_invoke_plugins.items():
                    if plugin_class_ref := plugins.get(plugin):
                        ash.register_plugin(await
                                            plugin_class_ref.load_from_dict(
                                                ash, plugin_data))
                    else:
                        log.debug("Skipping state loading for %s", plugin)
Ejemplo n.º 5
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