diff options
| author | 2021-07-15 15:25:12 -0700 | |
|---|---|---|
| committer | 2021-07-15 15:25:12 -0700 | |
| commit | af3c1459ba491e748339545687a8939b4dd70e43 (patch) | |
| tree | f83116fd6804c8f5e2e5d1e6f50122bd6f6bd572 | |
| parent | Remove unnecessary config constant (diff) | |
Add util function to send an infraction using an Infraction dict
There was some redundant pre-processing of arguments happening before
calling `notify_infraction`.
| -rw-r--r-- | bot/exts/moderation/infraction/_scheduler.py | 18 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/_utils.py | 38 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/superstarify.py | 4 | ||||
| -rw-r--r-- | tests/bot/exts/moderation/infraction/test_utils.py | 4 |
4 files changed, 45 insertions, 19 deletions
diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py index 8286d3635..19402d01d 100644 --- a/bot/exts/moderation/infraction/_scheduler.py +++ b/bot/exts/moderation/infraction/_scheduler.py @@ -162,20 +162,12 @@ class InfractionScheduler: # apply kick/ban infractions first, this would mean that we'd make it # impossible for us to deliver a DM. See python-discord/bot#982. if not infraction["hidden"]: - dm_result = f"{constants.Emojis.failmail} " - dm_log_text = "\nDM: **Failed**" - - # Sometimes user is a discord.Object; make it a proper user. - try: - if not isinstance(user, (discord.Member, discord.User)): - user = await self.bot.fetch_user(user.id) - except discord.HTTPException as e: - log.error(f"Failed to DM {user.id}: could not fetch user (status {e.status})") + if await _utils.notify_infraction(infraction, user, user_reason): + dm_result = ":incoming_envelope: " + dm_log_text = "\nDM: Sent" else: - # Accordingly display whether the user was successfully notified via DM. - if await _utils.notify_infraction(user, infr_type.replace("_", " ").title(), expiry, user_reason, icon): - dm_result = ":incoming_envelope: " - dm_log_text = "\nDM: Sent" + dm_result = f"{constants.Emojis.failmail} " + dm_log_text = "\nDM: **Failed**" end_msg = "" if infraction["actor"] == self.bot.user.id: diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py index adbc641fa..a6f180c8c 100644 --- a/bot/exts/moderation/infraction/_utils.py +++ b/bot/exts/moderation/infraction/_utils.py @@ -5,9 +5,11 @@ from datetime import datetime import discord from discord.ext.commands import Context +import bot from bot.api import ResponseCodeError from bot.constants import Colours, Icons from bot.errors import InvalidInfractedUserError +from bot.utils import time log = logging.getLogger(__name__) @@ -152,7 +154,7 @@ async def get_active_infraction( log.trace(f"{user} does not have active infractions of type {infr_type}.") -async def notify_infraction( +async def send_infraction_embed( user: UserObject, infr_type: str, expires_at: t.Optional[str] = None, @@ -188,6 +190,40 @@ async def notify_infraction( return await send_private_embed(user, embed) +async def notify_infraction( + infraction: Infraction, + user: t.Optional[UserSnowflake] = None, + reason: t.Optional[str] = None +) -> bool: + """ + DM a user about their new infraction and return True if the DM is successful. + + `user` and `reason` can be used to override what is in `infraction`. Otherwise, this data will + be retrieved from `infraction`. + + Also return False if the user needs to be fetched but fails to be fetched. + """ + if user is None: + user = discord.Object(infraction["user"]) + + # Sometimes user is a discord.Object; make it a proper user. + try: + if not isinstance(user, (discord.Member, discord.User)): + user = await bot.instance.fetch_user(user.id) + except discord.HTTPException as e: + log.error(f"Failed to DM {user.id}: could not fetch user (status {e.status})") + return False + + type_ = infraction["type"].replace("_", " ").title() + icon = INFRACTION_ICONS[infraction["type"]][0] + expiry = time.format_infraction_with_duration(infraction["expires_at"]) + + if reason is None: + reason = infraction["reason"] + + return await send_infraction_embed(user, type_, expiry, reason, icon) + + async def notify_pardon( user: UserObject, title: str, diff --git a/bot/exts/moderation/infraction/superstarify.py b/bot/exts/moderation/infraction/superstarify.py index 07e79b9fe..6dd9924ad 100644 --- a/bot/exts/moderation/infraction/superstarify.py +++ b/bot/exts/moderation/infraction/superstarify.py @@ -70,15 +70,13 @@ class Superstarify(InfractionScheduler, Cog): ) notified = await _utils.notify_infraction( + infraction=infraction, user=after, - infr_type="Superstarify", - expires_at=format_infraction(infraction["expires_at"]), reason=( "You have tried to change your nickname on the **Python Discord** server " f"from **{before.display_name}** to **{after.display_name}**, but as you " "are currently in superstar-prison, you do not have permission to do so." ), - icon_url=_utils.INFRACTION_ICONS["superstar"][0] ) if not notified: diff --git a/tests/bot/exts/moderation/infraction/test_utils.py b/tests/bot/exts/moderation/infraction/test_utils.py index 50a717bb5..d35120992 100644 --- a/tests/bot/exts/moderation/infraction/test_utils.py +++ b/tests/bot/exts/moderation/infraction/test_utils.py @@ -124,7 +124,7 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase): self.ctx.send.assert_not_awaited() @patch("bot.exts.moderation.infraction._utils.send_private_embed") - async def test_notify_infraction(self, send_private_embed_mock): + async def test_send_infraction_embed(self, send_private_embed_mock): """ Should send an embed of a certain format as a DM and return `True` if DM successful. @@ -230,7 +230,7 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase): send_private_embed_mock.reset_mock() send_private_embed_mock.return_value = case["send_result"] - result = await utils.notify_infraction(*case["args"]) + result = await utils.send_infraction_embed(*case["args"]) self.assertEqual(case["send_result"], result) |