aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/exts/moderation/infraction/_utils.py22
-rw-r--r--bot/exts/moderation/infraction/infractions.py10
-rw-r--r--bot/exts/moderation/infraction/management.py1
3 files changed, 25 insertions, 8 deletions
diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py
index c3dfb8310..d616e4009 100644
--- a/bot/exts/moderation/infraction/_utils.py
+++ b/bot/exts/moderation/infraction/_utils.py
@@ -1,5 +1,9 @@
+
+import datetime
+
import arrow
import discord
+from dateutil.relativedelta import relativedelta
from discord import Member
from discord.ext.commands import Context
from pydis_core.site_api import ResponseCodeError
@@ -61,6 +65,8 @@ INFRACTION_DESCRIPTION_WARNING_TEMPLATE = (
)
+MAXIMUM_TIMEOUT_DAYS = datetime.timedelta(days=28)
+
async def post_user(ctx: Context, user: MemberOrUser) -> dict | None:
"""
Create a new user in the database.
@@ -301,6 +307,22 @@ async def send_private_embed(user: MemberOrUser, embed: discord.Embed) -> bool:
return False
+def cap_timeout_duration(duration: datetime.datetime | relativedelta) -> tuple[bool, datetime.datetime]:
+ """Caps the duration of a duration to Discord's limit."""
+ now = arrow.utcnow()
+ capped = False
+ if isinstance(duration, relativedelta):
+ duration += now
+
+ if duration > now + MAXIMUM_TIMEOUT_DAYS:
+ duration = now + MAXIMUM_TIMEOUT_DAYS - datetime.timedelta(minutes=1) # Duration cap is exclusive.
+ capped = True
+ elif duration > now + MAXIMUM_TIMEOUT_DAYS - datetime.timedelta(minutes=1):
+ # Duration cap is exclusive. This is to still allow specifying "28d".
+ duration -= datetime.timedelta(minutes=1)
+ return capped, duration
+
+
async def confirm_elevated_user_ban(ctx: Context, user: MemberOrUser) -> bool:
"""
If user has an elevated role, require confirmation before banning.
diff --git a/bot/exts/moderation/infraction/infractions.py b/bot/exts/moderation/infraction/infractions.py
index cf8803487..3b2f2810a 100644
--- a/bot/exts/moderation/infraction/infractions.py
+++ b/bot/exts/moderation/infraction/infractions.py
@@ -230,10 +230,8 @@ class Infractions(InfractionScheduler, commands.Cog):
if duration is None:
duration = await Duration().convert(ctx, "1h")
else:
- now = arrow.utcnow()
- if isinstance(duration, relativedelta):
- duration += now
- if duration > now + MAXIMUM_TIMEOUT_DAYS:
+ capped, duration = _utils.cap_timeout_duration(duration)
+ if capped:
cap_message_for_user = TIMEOUT_CAP_MESSAGE.format(user.mention)
if is_mod_channel(ctx.channel):
await ctx.reply(f":warning: {cap_message_for_user}")
@@ -241,10 +239,6 @@ class Infractions(InfractionScheduler, commands.Cog):
await self.bot.get_channel(Channels.mods).send(
f":warning: {ctx.author.mention} {cap_message_for_user}"
)
- duration = now + MAXIMUM_TIMEOUT_DAYS - timedelta(minutes=1) # Duration cap is exclusive.
- elif duration > now + MAXIMUM_TIMEOUT_DAYS - timedelta(minutes=1):
- # Duration cap is exclusive. This is to still allow specifying "28d".
- duration -= timedelta(minutes=1)
await self.apply_timeout(ctx, user, reason, duration_or_expiry=duration)
diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py
index 0a33c84ab..e5216cac9 100644
--- a/bot/exts/moderation/infraction/management.py
+++ b/bot/exts/moderation/infraction/management.py
@@ -233,6 +233,7 @@ class ModManagement(commands.Cog):
self.infractions_cog.schedule_expiration(new_infraction)
# Timeouts are handled by Discord itself, so we need to edit the expiry in Discord as well
if user and infraction["type"] == "timeout":
+ _, duration = _utils.cap_timeout_duration(expiry)
await user.edit(reason=reason, timed_out_until=expiry)
log_text += f"""