aboutsummaryrefslogtreecommitdiffstats
path: root/bot/utils/converters.py
blob: 72b648487439a9536babbd1db5e83977d11eb868 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from datetime import datetime
from typing import Tuple, Union

import discord
from discord.ext import commands


class WrappedMessageConverter(commands.MessageConverter):
    """A converter that handles embed-suppressed links like <http://example.com>."""

    @staticmethod
    async def convert(ctx: commands.Context, argument: str) -> discord.Message:
        """Wrap the commands.MessageConverter to handle <> delimited message links."""
        # It's possible to wrap a message in [<>] as well, and it's supported because its easy
        if argument.startswith("[") and argument.endswith("]"):
            argument = argument[1:-1]
        if argument.startswith("<") and argument.endswith(">"):
            argument = argument[1:-1]

        return await super().convert(ctx, argument)


class CoordinateConverter(commands.Converter):
    """Converter for Coordinates."""

    @staticmethod
    async def convert(ctx: commands.Context, coordinate: str) -> Tuple[int, int]:
        """Take in a coordinate string and turn it into an (x, y) tuple."""
        if len(coordinate) not in (2, 3):
            raise commands.BadArgument("Invalid co-ordinate provided.")

        coordinate = coordinate.lower()
        if coordinate[0].isalpha():
            digit = coordinate[1:]
            letter = coordinate[0]
        else:
            digit = coordinate[:-1]
            letter = coordinate[-1]

        if not digit.isdecimal():
            raise commands.BadArgument

        x = ord(letter) - ord("a")
        y = int(digit) - 1

        if (not 0 <= x <= 9) or (not 0 <= y <= 9):
            raise commands.BadArgument
        return x, y


SourceType = Union[commands.Command, commands.Cog]


class SourceConverter(commands.Converter):
    """Convert an argument into a command or cog."""

    @staticmethod
    async def convert(ctx: commands.Context, argument: str) -> SourceType:
        """Convert argument into source object."""
        cog = ctx.bot.get_cog(argument)
        if cog:
            return cog

        cmd = ctx.bot.get_command(argument)
        if cmd:
            return cmd

        raise commands.BadArgument(
            f"Unable to convert `{argument}` to valid command or Cog."
        )


class DateConverter(commands.Converter):
    """Parse SOL or earth date (in format YYYY-MM-DD) into `int` or `datetime`. When invalid input, raise error."""

    @staticmethod
    async def convert(ctx: commands.Context, argument: str) -> Union[int, datetime]:
        """Parse date (SOL or earth) into `datetime` or `int`. When invalid value, raise error."""
        if argument.isdecimal():
            return int(argument)
        try:
            date = datetime.strptime(argument, "%Y-%m-%d")
        except ValueError:
            raise commands.BadArgument(
                f"Can't convert `{argument}` to `datetime` in format `YYYY-MM-DD` or `int` in SOL."
            )
        return date