From 77a0929b683df3410429e765ab6dbc7ae1640f4b Mon Sep 17 00:00:00 2001 From: TrustyJAID Date: Fri, 19 Apr 2024 15:52:29 -0600 Subject: [PATCH] Calculate datetime only once by including in the _MuteTime response. - Use the same formatting of time for all mute methods for consistency. - Use ctx.message.created_at to prevent an extremely difficult edge case. - Prevent default duration from exceeding 1000 years so it doesn't get set to a value that would reasonably change to cause defaults to OverFlow. --- redbot/cogs/mutes/converters.py | 3 +- redbot/cogs/mutes/mutes.py | 63 ++++++++++++++++++++------------- redbot/cogs/mutes/voicemutes.py | 24 +++++++------ 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/redbot/cogs/mutes/converters.py b/redbot/cogs/mutes/converters.py index b0f0e9527b6..18a11430d10 100644 --- a/redbot/cogs/mutes/converters.py +++ b/redbot/cogs/mutes/converters.py @@ -29,6 +29,7 @@ def _edgematch(pattern: re.Pattern[str], argument: str) -> Optional[re.Match[str class _MuteTime(TypedDict, total=False): duration: timedelta reason: str + until: datetime class _MuteTimeConverter(Converter): @@ -57,7 +58,7 @@ async def convert(self, ctx: commands.Context, argument: str) -> _MuteTime: ) try: result["duration"] = duration = timedelta(**time_data) - datetime.now(timezone.utc) + duration + result["until"] = ctx.message.created_at + duration # Catch if using the timedelta with the current date will also result in an Overflow error except OverflowError: raise commands.BadArgument( diff --git a/redbot/cogs/mutes/mutes.py b/redbot/cogs/mutes/mutes.py index edf65ee13e9..9608c1081fd 100644 --- a/redbot/cogs/mutes/mutes.py +++ b/redbot/cogs/mutes/mutes.py @@ -1005,13 +1005,18 @@ async def default_mute_time(self, ctx: commands.Context, *, time: Optional[MuteT await self.config.guild(ctx.guild).default_time.clear() await ctx.send(_("Default mute time removed.")) else: - data = time.get("duration", {}) - if not data: + duration = time.get("duration", None) + if not duration: return await ctx.send(_("Please provide a valid time format.")) - await self.config.guild(ctx.guild).default_time.set(data.total_seconds()) + if duration >= timedelta(days=365000): + # prevent setting a default time now that might eventually cause an overflow + # later as the date goes up. 1000 years gives us approximately 8000 more years + # of wiggle room. + return await ctx.send(_("Please provide a more reasonable default time frame.")) + await self.config.guild(ctx.guild).default_time.set(duration.total_seconds()) await ctx.send( _("Default mute time set to {time}.").format( - time=humanize_timedelta(timedelta=data) + time=humanize_timedelta(timedelta=duration) ) ) @@ -1142,15 +1147,15 @@ async def timeout( return await ctx.send(_("You cannot mute me.")) if ctx.author in users: return await ctx.send(_("You cannot mute yourself.")) - duration = time_and_reason.get("duration", None) - if duration and duration > timedelta(days=28): - await ctx.send(_(MUTE_UNMUTE_ISSUES["mute_is_too_long"])) - return + until = time_and_reason.get("until", None) reason = time_and_reason.get("reason", None) time = "" - until = None - if duration: - until = datetime.now(timezone.utc) + duration + duration = None + if until: + duration = time_and_reason.get("duration") + if duration and duration > timedelta(days=28): + await ctx.send(_(MUTE_UNMUTE_ISSUES["mute_is_too_long"])) + return length = humanize_timedelta(timedelta=duration) time = _(" for {length} until {duration}").format( length=length, duration=discord.utils.format_dt(until) @@ -1159,7 +1164,8 @@ async def timeout( else: default_duration = await self.config.guild(ctx.guild).default_time() if default_duration: - until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) + duration = timedelta(seconds=default_duration) + until = ctx.message.created_at + duration length = humanize_timedelta(seconds=default_duration) time = _(" for {length} until {duration}").format( length=length, duration=discord.utils.format_dt(until) @@ -1227,12 +1233,12 @@ async def mute( if not await self._check_for_mute_role(ctx): return async with ctx.typing(): - duration = time_and_reason.get("duration", None) + until = time_and_reason.get("until", None) reason = time_and_reason.get("reason", None) time = "" - until = None - if duration: - until = datetime.now(timezone.utc) + duration + duration = None + if until: + duration = time_and_reason.get("duration") length = humanize_timedelta(timedelta=duration) time = _(" for {length} until {duration}").format( length=length, duration=discord.utils.format_dt(until) @@ -1241,7 +1247,8 @@ async def mute( else: default_duration = await self.config.guild(ctx.guild).default_time() if default_duration: - until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) + duration = timedelta(seconds=default_duration) + until = ctx.message.created_at + duration length = humanize_timedelta(seconds=default_duration) time = _(" for {length} until {duration}").format( length=length, duration=discord.utils.format_dt(until) @@ -1377,18 +1384,26 @@ async def channel_mute( if ctx.author in users: return await ctx.send(_("You cannot mute yourself.")) async with ctx.typing(): - duration = time_and_reason.get("duration", None) + until = time_and_reason.get("until", None) reason = time_and_reason.get("reason", None) time = "" - until = None - if duration: - until = datetime.now(timezone.utc) + duration - time = _(" until {duration}").format(duration=discord.utils.format_dt(until)) + duration = None + if until: + duration = time_and_reason.get("duration") + length = humanize_timedelta(timedelta=duration) + time = _(" for {length} until {duration}").format( + length=length, duration=discord.utils.format_dt(until) + ) + else: default_duration = await self.config.guild(ctx.guild).default_time() if default_duration: - until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) - time = _(" until {duration}").format(duration=discord.utils.format_dt(until)) + duration = timedelta(seconds=default_duration) + until = ctx.message.created_at + duration + length = humanize_timedelta(seconds=default_duration) + time = _(" for {length} until {duration}").format( + length=length, duration=discord.utils.format_dt(until) + ) author = ctx.message.author channel = ctx.message.channel if isinstance(channel, discord.Thread): diff --git a/redbot/cogs/mutes/voicemutes.py b/redbot/cogs/mutes/voicemutes.py index 075c5339d1f..57cf2360656 100644 --- a/redbot/cogs/mutes/voicemutes.py +++ b/redbot/cogs/mutes/voicemutes.py @@ -99,23 +99,25 @@ async def voice_mute( if not can_move: issue_list.append((user, perm_reason)) continue - duration = time_and_reason.get("duration", None) + until = time_and_reason.get("until", None) reason = time_and_reason.get("reason", None) time = "" - until = None - if duration: - until = datetime.now(timezone.utc) + duration - time = _(" for {duration}").format( - duration=humanize_timedelta(timedelta=duration) + duration = None + if until: + duration = time_and_reason.get("duration") + length = humanize_timedelta(timedelta=duration) + time = _(" for {length} until {duration}").format( + length=length, duration=discord.utils.format_dt(until) ) + else: default_duration = await self.config.guild(ctx.guild).default_time() if default_duration: - until = datetime.now(timezone.utc) + timedelta(seconds=default_duration) - time = _(" for {duration}").format( - duration=humanize_timedelta( - timedelta=timedelta(seconds=default_duration) - ) + duration = timedelta(seconds=default_duration) + until = ctx.message.created_at + duration + length = humanize_timedelta(seconds=default_duration) + time = _(" for {length} until {duration}").format( + length=length, duration=discord.utils.format_dt(until) ) guild = ctx.guild author = ctx.author