diff options
| author | 2020-07-01 16:37:48 +0000 | |
|---|---|---|
| committer | 2020-07-01 16:37:48 +0000 | |
| commit | bd041ef4363ad8750d619d97fb7e8f3a4c6ae757 (patch) | |
| tree | a3336e27cc7aea31af80eab97d303d370c1316a7 | |
| parent | Add some logging for the Slowmode cog (diff) | |
Create DurationDelta converter and humanize timedelta output for Slowmode cog.
The DurationDelta converter will allow the Slowmode cog to use a formatted timestamp instead of an integer representing seconds. I created a new converter because the Duration converter returned a datetime.datetime object, instead of a time delta.
Joe mentioned that I could just subtract the datetime.datetime object from datetime.utcnow(), but there is a small delay between conversion and when the function is actually executed.
This caused something like `!slowmode set #python-general 5s` to set the slowmode delay to 4 seconds instead of 5.
Now, with this new converter, the set command can be invoked using a formatted timestamp like so: `!slowmode set #python-general 4h23M19s`. This would set the slowmode delay in #python-general to 4 hours, 23 minutes, and 19 seconds.
Of course that delay would be quite overkill for #python-general, but that's just for the sake of this example.
| -rw-r--r-- | bot/cogs/slowmode.py | 31 | ||||
| -rw-r--r-- | bot/converters.py | 22 |
2 files changed, 39 insertions, 14 deletions
diff --git a/bot/cogs/slowmode.py b/bot/cogs/slowmode.py index 7bbd61623..898f4bf52 100644 --- a/bot/cogs/slowmode.py +++ b/bot/cogs/slowmode.py @@ -1,11 +1,15 @@ import logging +from datetime import datetime +from dateutil.relativedelta import relativedelta from discord import TextChannel from discord.ext.commands import Cog, Context, group from bot.bot import Bot from bot.constants import Emojis, MODERATION_ROLES +from bot.converters import DurationDelta from bot.decorators import with_role +from bot.utils import time log = logging.getLogger(__name__) @@ -24,28 +28,35 @@ class Slowmode(Cog): @slowmode_group.command(name='get', aliases=['g']) async def get_slowmode(self, ctx: Context, channel: TextChannel) -> None: """Get the slowmode delay for a given text channel.""" - slowmode_delay = channel.slowmode_delay - await ctx.send(f'The slowmode delay for {channel.mention} is {slowmode_delay} seconds.') + delay = relativedelta(seconds=channel.slowmode_delay) + await ctx.send(f'The slowmode delay for {channel.mention} is {time.humanize_delta(delay, precision=3)}.') @slowmode_group.command(name='set', aliases=['s']) @with_role(*MODERATION_ROLES) - async def set_slowmode(self, ctx: Context, channel: TextChannel, seconds: int) -> None: + async def set_slowmode(self, ctx: Context, channel: TextChannel, delay: DurationDelta) -> None: """Set the slowmode delay for a given text channel.""" - if 0 <= seconds <= 21600: - await channel.edit(slowmode_delay=seconds) + # Convert `dateutil.relativedelta.relativedelta` to `datetime.timedelta` + # Must do this to get the delta in a particular unit of time + utcnow = datetime.utcnow() + slowmode_delay = (utcnow + delay - utcnow).seconds + + humanized_delay = time.humanize_delta(delay, precision=3) + + if 0 <= slowmode_delay <= 21600: + await channel.edit(slowmode_delay=slowmode_delay) await ctx.send( - f'{Emojis.check_mark} The slowmode delay for {channel.mention} is now {seconds} seconds.' + f'{Emojis.check_mark} The slowmode delay for {channel.mention} is now {humanized_delay}.' ) - log.info(f'{ctx.author} set the slowmode delay for #{channel} to {seconds} seconds.') + log.info(f'{ctx.author} set the slowmode delay for #{channel} to {humanized_delay}.') else: await ctx.send( - f'{Emojis.cross_mark} The slowmode delay must be between 0 and 21600 seconds.' + f'{Emojis.cross_mark} The slowmode delay must be between 0 and 6 hours.' ) log.info( - f'{ctx.author} tried to set the slowmode delay of #{channel} to {seconds} seconds, ' - 'which is not between 0 and 21600 seconds.' + f'{ctx.author} tried to set the slowmode delay of #{channel} to {humanized_delay}, ' + 'which is not between 0 and 6 hours.' ) @slowmode_group.command(name='reset', aliases=['r']) diff --git a/bot/converters.py b/bot/converters.py index 4deb59f87..65963f513 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -181,8 +181,8 @@ class TagContentConverter(Converter): return tag_content -class Duration(Converter): - """Convert duration strings into UTC datetime.datetime objects.""" +class DurationDelta(Converter): + """Convert duration strings into dateutil.relativedelta.relativedelta objects.""" duration_parser = re.compile( r"((?P<years>\d+?) ?(years|year|Y|y) ?)?" @@ -194,9 +194,9 @@ class Duration(Converter): r"((?P<seconds>\d+?) ?(seconds|second|S|s))?" ) - async def convert(self, ctx: Context, duration: str) -> datetime: + async def convert(self, ctx: Context, duration: str) -> relativedelta: """ - Converts a `duration` string to a datetime object that's `duration` in the future. + Converts a `duration` string to a relativedelta object. The converter supports the following symbols for each unit of time: - years: `Y`, `y`, `year`, `years` @@ -215,6 +215,20 @@ class Duration(Converter): duration_dict = {unit: int(amount) for unit, amount in match.groupdict(default=0).items()} delta = relativedelta(**duration_dict) + + return delta + + +class Duration(DurationDelta): + """Convert duration strings into UTC datetime.datetime objects.""" + + async def convert(self, ctx: Context, duration: str) -> datetime: + """ + Converts a `duration` string to a datetime object that's `duration` in the future. + + The converter supports the same symbols for each unit of time as its parent class. + """ + delta = super().convert(ctx, duration) now = datetime.utcnow() try: |