diff options
Diffstat (limited to 'bot/converters.py')
| -rw-r--r-- | bot/converters.py | 56 | 
1 files changed, 48 insertions, 8 deletions
| diff --git a/bot/converters.py b/bot/converters.py index 2e118d476..80ce99459 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -350,34 +350,45 @@ class Duration(DurationDelta):          try:              return now + delta -        except ValueError: +        except (ValueError, OverflowError):              raise BadArgument(f"`{duration}` results in a datetime outside the supported range.")  class OffTopicName(Converter):      """A converter that ensures an added off-topic name is valid.""" +    ALLOWED_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!?'`-" + +    @classmethod +    def translate_name(cls, name: str, *, from_unicode: bool = True) -> str: +        """ +        Translates `name` into a format that is allowed in discord channel names. + +        If `from_unicode` is True, the name is translated from a discord-safe format, back to normalized text. +        """ +        if from_unicode: +            table = str.maketrans(cls.ALLOWED_CHARACTERS, '๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐นว๏ผโโ-') +        else: +            table = str.maketrans('๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐นว๏ผโโ-', cls.ALLOWED_CHARACTERS) + +        return name.translate(table) +      async def convert(self, ctx: Context, argument: str) -> str:          """Attempt to replace any invalid characters with their approximate Unicode equivalent.""" -        allowed_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!?'`-" -          # Chain multiple words to a single one          argument = "-".join(argument.split())          if not (2 <= len(argument) <= 96):              raise BadArgument("Channel name must be between 2 and 96 chars long") -        elif not all(c.isalnum() or c in allowed_characters for c in argument): +        elif not all(c.isalnum() or c in self.ALLOWED_CHARACTERS for c in argument):              raise BadArgument(                  "Channel name must only consist of "                  "alphanumeric characters, minus signs or apostrophes."              )          # Replace invalid characters with unicode alternatives. -        table = str.maketrans( -            allowed_characters, '๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท๐ธ๐นว๏ผโโ-' -        ) -        return argument.translate(table) +        return self.translate_name(argument)  class ISODateTime(Converter): @@ -549,6 +560,35 @@ def _snowflake_from_regex(pattern: t.Pattern, arg: str) -> int:      return int(match.group(1)) +class Infraction(Converter): +    """ +    Attempts to convert a given infraction ID into an infraction. + +    Alternatively, `l`, `last`, or `recent` can be passed in order to +    obtain the most recent infraction by the actor. +    """ + +    async def convert(self, ctx: Context, arg: str) -> t.Optional[dict]: +        """Attempts to convert `arg` into an infraction `dict`.""" +        if arg in ("l", "last", "recent"): +            params = { +                "actor__id": ctx.author.id, +                "ordering": "-inserted_at" +            } + +            infractions = await ctx.bot.api_client.get("bot/infractions", params=params) + +            if not infractions: +                raise BadArgument( +                    "Couldn't find most recent infraction; you have never given an infraction." +                ) +            else: +                return infractions[0] + +        else: +            return await ctx.bot.api_client.get(f"bot/infractions/{arg}") + +  Expiry = t.Union[Duration, ISODateTime]  FetchedMember = t.Union[discord.Member, FetchedUser]  UserMention = partial(_snowflake_from_regex, RE_USER_MENTION) | 
