diff options
Diffstat (limited to '')
| -rw-r--r-- | bot/cogs/moderation/incidents.py | 55 | 
1 files changed, 52 insertions, 3 deletions
| diff --git a/bot/cogs/moderation/incidents.py b/bot/cogs/moderation/incidents.py index 2186530d9..00cceca7d 100644 --- a/bot/cogs/moderation/incidents.py +++ b/bot/cogs/moderation/incidents.py @@ -160,6 +160,58 @@ class Incidents(Cog):          )          return self.bot.loop.create_task(coroutine) +    async def process_event(self, reaction: str, incident: discord.Message, member: discord.Member) -> None: +        """ +        Process a valid `reaction_add` event in #incidents. + +        First, we check that the reaction is a recognized `Signal` member, and that it was sent by +        a permitted user (at least one role in `ALLOWED_ROLES`). If not, the reaction is removed. + +        If the reaction was either `Signal.ACTIONED` or `Signal.NOT_ACTIONED`, we attempt to relay +        the report to #incidents-archive. If successful, the original message is deleted. + +        We do not release `event_lock` until we receive the corresponding `message_delete` event. +        This ensures that if there is a racing event awaiting the lock, it will fail to find the +        message, and will abort. +        """ +        members_roles: t.Set[int] = {role.id for role in member.roles} +        if not members_roles & ALLOWED_ROLES:  # Intersection is truthy on at least 1 common element +            log.debug(f"Removing invalid reaction: user {member} is not permitted to send signals") +            await incident.remove_reaction(reaction, member) +            return + +        if reaction not in ALLOWED_EMOJI: +            log.debug(f"Removing invalid reaction: emoji {reaction} is not a valid signal") +            await incident.remove_reaction(reaction, member) +            return + +        # If we reach this point, we know that `emoji` is a `Signal` member +        signal = Signal(reaction) +        log.debug(f"Received signal: {signal}") + +        if signal not in (Signal.ACTIONED, Signal.NOT_ACTIONED): +            log.debug("Reaction was valid, but no action is currently defined for it") +            return + +        relay_successful = await self.archive(incident, signal) +        if not relay_successful: +            log.debug("Original message will not be deleted as we failed to relay it to the archive") +            return + +        timeout = 5  # Seconds +        confirmation_task = self.make_confirmation_task(incident, timeout) + +        log.debug("Deleting original message") +        await incident.delete() + +        log.debug(f"Awaiting deletion confirmation: {timeout=} seconds") +        try: +            await confirmation_task +        except asyncio.TimeoutError: +            log.warning(f"Did not receive incident deletion confirmation within {timeout} seconds!") +        else: +            log.debug("Deletion was confirmed") +      async def resolve_message(self, message_id: int) -> t.Optional[discord.Message]:          """          Get `discord.Message` for `message_id` from cache, or API. @@ -191,9 +243,6 @@ class Incidents(Cog):              log.debug("Message fetched successfully!")              return message -    async def process_event(self, reaction: str, message: discord.Message, member: discord.Member) -> None: -        log.debug("Processing event...") -      @Cog.listener()      async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) -> None:          """ | 
