aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar MarkKoz <[email protected]>2019-10-21 17:33:27 -0700
committerGravatar MarkKoz <[email protected]>2019-10-25 15:32:20 -0700
commit832c7129d57a919f15919e883607845df6b6dacc (patch)
tree4aceafdc489a484f352aba5a198a41529edb6b3b
parentModeration: create a class to handle scheduling of infractions (diff)
InfractionScheduler: delegate type-specific pardon code to subclasses
* Create an abstract method for performing type-specific infraction deactivation * Move infraction-specific pardon code to separate functions
-rw-r--r--bot/cogs/moderation/infractions.py61
-rw-r--r--bot/cogs/moderation/scheduler.py51
2 files changed, 77 insertions, 35 deletions
diff --git a/bot/cogs/moderation/infractions.py b/bot/cogs/moderation/infractions.py
index 9d65dfa8a..fbfcb8ae3 100644
--- a/bot/cogs/moderation/infractions.py
+++ b/bot/cogs/moderation/infractions.py
@@ -209,7 +209,7 @@ class Infractions(InfractionScheduler, commands.Cog):
await self.pardon_infraction(ctx, "ban", user)
# endregion
- # region: Base infraction functions
+ # region: Base apply functions
async def apply_mute(self, ctx: Context, user: Member, reason: str, **kwargs) -> None:
"""Apply a mute infraction with kwargs passed to `post_infraction`."""
@@ -253,6 +253,65 @@ class Infractions(InfractionScheduler, commands.Cog):
await self.apply_infraction(ctx, infraction, user, action)
# endregion
+ # region: Base pardon functions
+
+ async def pardon_mute(self, user_id: int, guild: discord.Guild, reason: str) -> t.Dict[str, str]:
+ """Remove a user's muted role, DM them a notification, and return a log dict."""
+ user = guild.get_member(user_id)
+ log_text = {}
+
+ if user:
+ # Remove the muted role.
+ self.mod_log.ignore(Event.member_update, user.id)
+ await user.remove_roles(self._muted_role, reason=reason)
+
+ # DM the user about the expiration.
+ notified = await utils.notify_pardon(
+ user=user,
+ title="You have been unmuted.",
+ content="You may now send messages in the server.",
+ icon_url=utils.INFRACTION_ICONS["mute"][1]
+ )
+
+ log_text["Member"] = f"{user.mention}(`{user.id}`)"
+ log_text["DM"] = "Sent" if notified else "**Failed**"
+ else:
+ log.info(f"Failed to unmute user {user_id}: user not found")
+ log_text["Failure"] = "User was not found in the guild."
+
+ return log_text
+
+ async def pardon_ban(self, user_id: int, guild: discord.Guild, reason: str) -> t.Dict[str, str]:
+ """Remove a user's ban on the Discord guild and return a log dict."""
+ user = discord.Object(user_id)
+ log_text = {}
+
+ self.mod_log.ignore(Event.member_unban, user_id)
+
+ try:
+ await guild.unban(user, reason=reason)
+ except discord.NotFound:
+ log.info(f"Failed to unban user {user_id}: no active ban found on Discord")
+ log_text["Note"] = "No active ban found on Discord."
+
+ return log_text
+
+ async def _pardon_action(self, infraction: utils.Infraction) -> t.Optional[t.Dict[str, str]]:
+ """
+ Execute deactivation steps specific to the infraction's type and return a log dict.
+
+ If an infraction type is unsupported, return None instead.
+ """
+ guild = self.bot.get_guild(constants.Guild.id)
+ user_id = infraction["user"]
+ reason = f"Infraction #{infraction['id']} expired or was pardoned."
+
+ if infraction["type"] == "mute":
+ return await self.pardon_mute(user_id, guild, reason)
+ elif infraction["type"] == "ban":
+ return await self.pardon_ban(user_id, guild, reason)
+
+ # endregion
# This cannot be static (must have a __func__ attribute).
def cog_check(self, ctx: Context) -> bool:
diff --git a/bot/cogs/moderation/scheduler.py b/bot/cogs/moderation/scheduler.py
index 408e9943e..045b0bd13 100644
--- a/bot/cogs/moderation/scheduler.py
+++ b/bot/cogs/moderation/scheduler.py
@@ -1,16 +1,16 @@
import logging
import textwrap
import typing as t
+from abc import abstractmethod
from gettext import ngettext
import dateutil.parser
import discord
-from discord.ext import commands
-from discord.ext.commands import Context
+from discord.ext.commands import Bot, Context
from bot import constants
from bot.api import ResponseCodeError
-from bot.constants import Colours, Event, STAFF_CHANNELS
+from bot.constants import Colours, STAFF_CHANNELS
from bot.utils import time
from bot.utils.scheduling import Scheduler
from . import utils
@@ -23,7 +23,7 @@ log = logging.getLogger(__name__)
class InfractionScheduler(Scheduler):
"""Handles the application, pardoning, and expiration of infractions."""
- def __init__(self, bot: commands.Bot):
+ def __init__(self, bot: Bot):
super().__init__()
self.bot = bot
@@ -240,14 +240,13 @@ class InfractionScheduler(Scheduler):
expiration task cancelled. If `send_log` is True, a mod log is sent for the
deactivation of the infraction.
- Supported infraction types are mute and ban. Other types will raise a ValueError.
+ Infractions of unsupported types will raise a ValueError.
"""
guild = self.bot.get_guild(constants.Guild.id)
mod_role = guild.get_role(constants.Roles.moderator)
user_id = infraction["user"]
_type = infraction["type"]
_id = infraction["id"]
- reason = f"Infraction #{_id} expired or was pardoned."
log.debug(f"Marking infraction #{_id} as inactive (expired).")
@@ -259,34 +258,9 @@ class InfractionScheduler(Scheduler):
}
try:
- if _type == "mute":
- user = guild.get_member(user_id)
- if user:
- # Remove the muted role.
- self.mod_log.ignore(Event.member_update, user.id)
- await user.remove_roles(self._muted_role, reason=reason)
-
- # DM the user about the expiration.
- notified = await utils.notify_pardon(
- user=user,
- title="You have been unmuted.",
- content="You may now send messages in the server.",
- icon_url=utils.INFRACTION_ICONS["mute"][1]
- )
-
- log_text["Member"] = f"{user.mention}(`{user.id}`)"
- log_text["DM"] = "Sent" if notified else "**Failed**"
- else:
- log.info(f"Failed to unmute user {user_id}: user not found")
- log_text["Failure"] = "User was not found in the guild."
- elif _type == "ban":
- user = discord.Object(user_id)
- self.mod_log.ignore(Event.member_unban, user_id)
- try:
- await guild.unban(user, reason=reason)
- except discord.NotFound:
- log.info(f"Failed to unban user {user_id}: no active ban found on Discord")
- log_text["Note"] = "No active ban found on Discord."
+ returned_log = await self._pardon_action(infraction)
+ if returned_log is not None:
+ log_text = {**log_text, **returned_log} # Merge the logs together
else:
raise ValueError(
f"Attempted to deactivate an unsupported infraction #{_id} ({_type})!"
@@ -352,6 +326,15 @@ class InfractionScheduler(Scheduler):
return log_text
+ @abstractmethod
+ async def _pardon_action(self, infraction: utils.Infraction) -> t.Optional[t.Dict[str, str]]:
+ """
+ Execute deactivation steps specific to the infraction's type and return a log dict.
+
+ If an infraction type is unsupported, return None instead.
+ """
+ raise NotImplementedError
+
async def _scheduled_task(self, infraction: utils.Infraction) -> None:
"""
Marks an infraction expired after the delay from time of scheduling to time of expiration.