aboutsummaryrefslogtreecommitdiffstats
path: root/bot/cogs/moderation/scheduler.py
diff options
context:
space:
mode:
Diffstat (limited to 'bot/cogs/moderation/scheduler.py')
-rw-r--r--bot/cogs/moderation/scheduler.py79
1 files changed, 55 insertions, 24 deletions
diff --git a/bot/cogs/moderation/scheduler.py b/bot/cogs/moderation/scheduler.py
index f0b6b2c48..d75a72ddb 100644
--- a/bot/cogs/moderation/scheduler.py
+++ b/bot/cogs/moderation/scheduler.py
@@ -91,7 +91,7 @@ class InfractionScheduler(Scheduler):
log.trace(f"Applying {infr_type} infraction #{id_} to {user}.")
# Default values for the confirmation message and mod log.
- confirm_msg = f":ok_hand: applied"
+ confirm_msg = ":ok_hand: applied"
# Specifying an expiry for a note or warning makes no sense.
if infr_type in ("note", "warning"):
@@ -101,11 +101,16 @@ class InfractionScheduler(Scheduler):
dm_result = ""
dm_log_text = ""
- expiry_log_text = f"Expires: {expiry}" if expiry else ""
+ expiry_log_text = f"\nExpires: {expiry}" if expiry else ""
log_title = "applied"
log_content = None
+ failed = False
# DM the user about the infraction if it's not a shadow/hidden infraction.
+ # This needs to happen before we apply the infraction, as the bot cannot
+ # send DMs to user that it doesn't share a guild with. If we were to
+ # 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**"
@@ -122,18 +127,17 @@ class InfractionScheduler(Scheduler):
dm_result = ":incoming_envelope: "
dm_log_text = "\nDM: Sent"
+ end_msg = ""
if infraction["actor"] == self.bot.user.id:
log.trace(
f"Infraction #{id_} actor is bot; including the reason in the confirmation message."
)
-
- end_msg = f" (reason: {infraction['reason']})"
+ if reason:
+ end_msg = f" (reason: {textwrap.shorten(reason, width=1500, placeholder='...')})"
elif ctx.channel.id not in STAFF_CHANNELS:
log.trace(
f"Infraction #{id_} context is not in a staff channel; omitting infraction count."
)
-
- end_msg = ""
else:
log.trace(f"Fetching total infraction count for {user}.")
@@ -154,7 +158,7 @@ class InfractionScheduler(Scheduler):
self.schedule_task(infraction["id"], infraction)
except discord.HTTPException as e:
# Accordingly display that applying the infraction failed.
- confirm_msg = f":x: failed to apply"
+ confirm_msg = ":x: failed to apply"
expiry_msg = ""
log_content = ctx.author.mention
log_title = "failed to apply"
@@ -164,12 +168,23 @@ class InfractionScheduler(Scheduler):
log.warning(f"{log_msg}: bot lacks permissions.")
else:
log.exception(log_msg)
+ failed = True
+
+ if failed:
+ log.trace(f"Deleted infraction {infraction['id']} from database because applying infraction failed.")
+ try:
+ await self.bot.api_client.delete(f"bot/infractions/{id_}")
+ except ResponseCodeError as e:
+ confirm_msg += " and failed to delete"
+ log_title += " and failed to delete"
+ log.error(f"Deletion of {infr_type} infraction #{id_} failed with error code {e.status}.")
+ infr_message = ""
+ else:
+ infr_message = f" **{infr_type}** to {user.mention}{expiry_msg}{end_msg}"
# Send a confirmation message to the invoking context.
log.trace(f"Sending infraction #{id_} confirmation message.")
- await ctx.send(
- f"{dm_result}{confirm_msg} **{infr_type}** to {user.mention}{expiry_msg}{end_msg}."
- )
+ await ctx.send(f"{dm_result}{confirm_msg}{infr_message}.")
# Send a log message to the mod log.
log.trace(f"Sending apply mod log for infraction #{id_}.")
@@ -180,9 +195,8 @@ class InfractionScheduler(Scheduler):
thumbnail=user.avatar_url_as(static_format="png"),
text=textwrap.dedent(f"""
Member: {user.mention} (`{user.id}`)
- Actor: {ctx.message.author}{dm_log_text}
+ Actor: {ctx.message.author}{dm_log_text}{expiry_log_text}
Reason: {reason}
- {expiry_log_text}
"""),
content=log_content,
footer=f"ID {infraction['id']}"
@@ -190,8 +204,19 @@ class InfractionScheduler(Scheduler):
log.info(f"Applied {infr_type} infraction #{id_} to {user}.")
- async def pardon_infraction(self, ctx: Context, infr_type: str, user: UserSnowflake) -> None:
- """Prematurely end an infraction for a user and log the action in the mod log."""
+ async def pardon_infraction(
+ self,
+ ctx: Context,
+ infr_type: str,
+ user: UserSnowflake,
+ send_msg: bool = True
+ ) -> None:
+ """
+ Prematurely end an infraction for a user and log the action in the mod log.
+
+ If `send_msg` is True, then a pardoning confirmation message will be sent to
+ the context channel. Otherwise, no such message will be sent.
+ """
log.trace(f"Pardoning {infr_type} infraction for {user}.")
# Check the current active infraction
@@ -222,7 +247,7 @@ class InfractionScheduler(Scheduler):
# If multiple active infractions were found, mark them as inactive in the database
# and cancel their expiration tasks.
if len(response) > 1:
- log.warning(
+ log.info(
f"Found more than one active {infr_type} infraction for user {user.id}; "
"deactivating the extra active infractions too."
)
@@ -270,17 +295,21 @@ class InfractionScheduler(Scheduler):
log.warning(f"Failed to pardon {infr_type} infraction #{id_} for {user}.")
else:
- confirm_msg = f":ok_hand: pardoned"
+ confirm_msg = ":ok_hand: pardoned"
log_title = "pardoned"
log.info(f"Pardoned {infr_type} infraction #{id_} for {user}.")
# Send a confirmation message to the invoking context.
- log.trace(f"Sending infraction #{id_} pardon confirmation message.")
- await ctx.send(
- f"{dm_emoji}{confirm_msg} infraction **{infr_type}** for {user.mention}. "
- f"{log_text.get('Failure', '')}"
- )
+ if send_msg:
+ log.trace(f"Sending infraction #{id_} pardon confirmation message.")
+ await ctx.send(
+ f"{dm_emoji}{confirm_msg} infraction **{infr_type}** for {user.mention}. "
+ f"{log_text.get('Failure', '')}"
+ )
+
+ # Move reason to end of entry to avoid cutting out some keys
+ log_text["Reason"] = log_text.pop("Reason")
# Send a log message to the mod log.
await self.mod_log.send_log_message(
@@ -341,7 +370,7 @@ class InfractionScheduler(Scheduler):
)
except discord.Forbidden:
log.warning(f"Failed to deactivate infraction #{id_} ({type_}): bot lacks permissions.")
- log_text["Failure"] = f"The bot lacks permissions to do this (role hierarchy?)"
+ log_text["Failure"] = "The bot lacks permissions to do this (role hierarchy?)"
log_content = mod_role.mention
except discord.HTTPException as e:
log.exception(f"Failed to deactivate infraction #{id_} ({type_})")
@@ -390,11 +419,14 @@ class InfractionScheduler(Scheduler):
# Send a log message to the mod log.
if send_log:
- log_title = f"expiration failed" if "Failure" in log_text else "expired"
+ log_title = "expiration failed" if "Failure" in log_text else "expired"
user = self.bot.get_user(user_id)
avatar = user.avatar_url_as(static_format="png") if user else None
+ # Move reason to end so when reason is too long, this is not gonna cut out required items.
+ log_text["Reason"] = log_text.pop("Reason")
+
log.trace(f"Sending deactivation mod log for infraction #{id_}.")
await self.mod_log.send_log_message(
icon_url=utils.INFRACTION_ICONS[type_][1],
@@ -404,7 +436,6 @@ class InfractionScheduler(Scheduler):
text="\n".join(f"{k}: {v}" for k, v in log_text.items()),
footer=f"ID: {id_}",
content=log_content,
-
)
return log_text