From 9d551cc69c1935165389f26f52753895604dd3f5 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Wed, 11 Dec 2019 20:26:26 -0800 Subject: Add a generic converter for only allowing certain string values --- bot/cogs/moderation/management.py | 13 ++----------- bot/converters.py | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/bot/cogs/moderation/management.py b/bot/cogs/moderation/management.py index abfe5c2b3..50bce3981 100644 --- a/bot/cogs/moderation/management.py +++ b/bot/cogs/moderation/management.py @@ -9,7 +9,7 @@ from discord.ext import commands from discord.ext.commands import Context from bot import constants -from bot.converters import InfractionSearchQuery +from bot.converters import InfractionSearchQuery, string from bot.pagination import LinePaginator from bot.utils import time from bot.utils.checks import in_channel_check, with_role_check @@ -22,15 +22,6 @@ log = logging.getLogger(__name__) UserConverter = t.Union[discord.User, utils.proxy_user] -def permanent_duration(expires_at: str) -> str: - """Only allow an expiration to be 'permanent' if it is a string.""" - expires_at = expires_at.lower() - if expires_at != "permanent": - raise commands.BadArgument - else: - return expires_at - - class ModManagement(commands.Cog): """Management of infractions.""" @@ -61,7 +52,7 @@ class ModManagement(commands.Cog): self, ctx: Context, infraction_id: int, - duration: t.Union[utils.Expiry, permanent_duration, None], + duration: t.Union[utils.Expiry, string("permanent"), None], *, reason: str = None ) -> None: diff --git a/bot/converters.py b/bot/converters.py index cf0496541..2cfc42903 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -1,8 +1,8 @@ import logging import re +import typing as t from datetime import datetime from ssl import CertificateError -from typing import Union import dateutil.parser import dateutil.tz @@ -15,6 +15,25 @@ from discord.ext.commands import BadArgument, Context, Converter log = logging.getLogger(__name__) +def string(*values, preserve_case: bool = False) -> t.Callable[[str], str]: + """ + Return a converter which only allows arguments equal to one of the given values. + + Unless preserve_case is True, the argument is converter to lowercase. All values are then + expected to have already been given in lowercase too. + """ + def converter(arg: str) -> str: + if not preserve_case: + arg = arg.lower() + + if arg not in values: + raise BadArgument(f"Only the following values are allowed:\n```{', '.join(values)}```") + else: + return arg + + return converter + + class ValidPythonIdentifier(Converter): """ A converter that checks whether the given string is a valid Python identifier. @@ -70,7 +89,7 @@ class InfractionSearchQuery(Converter): """A converter that checks if the argument is a Discord user, and if not, falls back to a string.""" @staticmethod - async def convert(ctx: Context, arg: str) -> Union[discord.Member, str]: + async def convert(ctx: Context, arg: str) -> t.Union[discord.Member, str]: """Check if the argument is a Discord user, and if not, falls back to a string.""" try: maybe_snowflake = arg.strip("<@!>") -- cgit v1.2.3 From 729ac3d83a3bd4620d1e9b24769466e219d45de6 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Wed, 11 Dec 2019 21:00:47 -0800 Subject: ModManagement: allow "recent" as ID to edit infraction (#624) It will attempt to find the most recent infraction authored by the invoker of the edit command. --- bot/cogs/moderation/management.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/bot/cogs/moderation/management.py b/bot/cogs/moderation/management.py index 50bce3981..35832ded5 100644 --- a/bot/cogs/moderation/management.py +++ b/bot/cogs/moderation/management.py @@ -51,7 +51,7 @@ class ModManagement(commands.Cog): async def infraction_edit( self, ctx: Context, - infraction_id: int, + infraction_id: t.Union[int, string("recent")], duration: t.Union[utils.Expiry, string("permanent"), None], *, reason: str = None @@ -69,6 +69,9 @@ class ModManagement(commands.Cog): \u2003`M` - minutes∗ \u2003`s` - seconds + Use "recent" as the infraction ID to specify that the ost recent infraction authored by the + command invoker should be edited. + Use "permanent" to mark the infraction as permanent. Alternatively, an ISO 8601 timestamp can be provided for the duration. """ @@ -77,7 +80,23 @@ class ModManagement(commands.Cog): raise commands.BadArgument("Neither a new expiry nor a new reason was specified.") # Retrieve the previous infraction for its information. - old_infraction = await self.bot.api_client.get(f'bot/infractions/{infraction_id}') + if infraction_id == "recent": + params = { + "actor__id": ctx.author.id, + "ordering": "-inserted_at" + } + infractions = await self.bot.api_client.get(f"bot/infractions", params=params) + + if infractions: + old_infraction = infractions[0] + infraction_id = old_infraction["id"] + else: + await ctx.send( + f":x: Couldn't find most recent infraction; you have never given an infraction." + ) + return + else: + old_infraction = await self.bot.api_client.get(f"bot/infractions/{infraction_id}") request_data = {} confirm_messages = [] -- cgit v1.2.3 From c1bf0a48692d87c5cbe9ee310cd0120bda339a96 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Wed, 11 Dec 2019 21:01:16 -0800 Subject: ModManagement: display ID of edited infraction in confirmation message --- bot/cogs/moderation/management.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bot/cogs/moderation/management.py b/bot/cogs/moderation/management.py index 35832ded5..904611e13 100644 --- a/bot/cogs/moderation/management.py +++ b/bot/cogs/moderation/management.py @@ -139,7 +139,8 @@ class ModManagement(commands.Cog): New expiry: {new_infraction['expires_at'] or "Permanent"} """.rstrip() - await ctx.send(f":ok_hand: Updated infraction: {' & '.join(confirm_messages)}") + changes = ' & '.join(confirm_messages) + await ctx.send(f":ok_hand: Updated infraction #{infraction_id}: {changes}") # Get information about the infraction's user user_id = new_infraction['user'] -- cgit v1.2.3 From 56833bbe99ce3cd93af87e9d33cec47a059b61f3 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Wed, 11 Dec 2019 21:52:57 -0800 Subject: ModManagement: add more aliases for "special" params of infraction edit --- bot/cogs/moderation/management.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bot/cogs/moderation/management.py b/bot/cogs/moderation/management.py index 904611e13..37bdb1934 100644 --- a/bot/cogs/moderation/management.py +++ b/bot/cogs/moderation/management.py @@ -51,8 +51,8 @@ class ModManagement(commands.Cog): async def infraction_edit( self, ctx: Context, - infraction_id: t.Union[int, string("recent")], - duration: t.Union[utils.Expiry, string("permanent"), None], + infraction_id: t.Union[int, string("l", "last", "recent")], + duration: t.Union[utils.Expiry, string("p", "permanent"), None], *, reason: str = None ) -> None: @@ -69,18 +69,18 @@ class ModManagement(commands.Cog): \u2003`M` - minutes∗ \u2003`s` - seconds - Use "recent" as the infraction ID to specify that the ost recent infraction authored by the - command invoker should be edited. + Use "l", "last", or "recent" as the infraction ID to specify that the most recent infraction + authored by the command invoker should be edited. - Use "permanent" to mark the infraction as permanent. Alternatively, an ISO 8601 timestamp - can be provided for the duration. + Use "p" or "permanent" to mark the infraction as permanent. Alternatively, an ISO 8601 + timestamp can be provided for the duration. """ if duration is None and reason is None: # Unlike UserInputError, the error handler will show a specified message for BadArgument raise commands.BadArgument("Neither a new expiry nor a new reason was specified.") # Retrieve the previous infraction for its information. - if infraction_id == "recent": + if isinstance(infraction_id, str): params = { "actor__id": ctx.author.id, "ordering": "-inserted_at" @@ -102,7 +102,7 @@ class ModManagement(commands.Cog): confirm_messages = [] log_text = "" - if duration == "permanent": + if isinstance(duration, str): request_data['expires_at'] = None confirm_messages.append("marked as permanent") elif duration is not None: -- cgit v1.2.3 From eb53a4594dff20372574058ec90062995362b098 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Wed, 11 Dec 2019 22:03:20 -0800 Subject: Converters: rename string to allowed_strings --- bot/cogs/moderation/management.py | 6 +++--- bot/converters.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/cogs/moderation/management.py b/bot/cogs/moderation/management.py index 37bdb1934..20ff25ba1 100644 --- a/bot/cogs/moderation/management.py +++ b/bot/cogs/moderation/management.py @@ -9,7 +9,7 @@ from discord.ext import commands from discord.ext.commands import Context from bot import constants -from bot.converters import InfractionSearchQuery, string +from bot.converters import InfractionSearchQuery, allowed_strings from bot.pagination import LinePaginator from bot.utils import time from bot.utils.checks import in_channel_check, with_role_check @@ -51,8 +51,8 @@ class ModManagement(commands.Cog): async def infraction_edit( self, ctx: Context, - infraction_id: t.Union[int, string("l", "last", "recent")], - duration: t.Union[utils.Expiry, string("p", "permanent"), None], + infraction_id: t.Union[int, allowed_strings("l", "last", "recent")], + duration: t.Union[utils.Expiry, allowed_strings("p", "permanent"), None], *, reason: str = None ) -> None: diff --git a/bot/converters.py b/bot/converters.py index 2cfc42903..8d2ab7eb8 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -15,11 +15,11 @@ from discord.ext.commands import BadArgument, Context, Converter log = logging.getLogger(__name__) -def string(*values, preserve_case: bool = False) -> t.Callable[[str], str]: +def allowed_strings(*values, preserve_case: bool = False) -> t.Callable[[str], str]: """ Return a converter which only allows arguments equal to one of the given values. - Unless preserve_case is True, the argument is converter to lowercase. All values are then + Unless preserve_case is True, the argument is converted to lowercase. All values are then expected to have already been given in lowercase too. """ def converter(arg: str) -> str: -- cgit v1.2.3