Beispiel #1
0
class Code(Category):

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Class Fields
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    MAX_BRAINFUCK_LENGTH = 2**15  # 32736

    QR_API_CALL = "https://api.qrserver.com/v1/create-qr-code/?size={0}x{0}&data={1}"
    MORSE_API_CALL = "https://www.fellowhashbrown.com/api/morse/{}?text={}"

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Errors
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    BASE_MISMATCH = "BASE_MISMATCH"
    BASE_OUT_OF_RANGE = "BASE_OUT_OF_RANGE"

    INVALID_LANGUAGE = "INVALID_LANGUAGE"
    INVALID_BASE = "INVALID_BASE"
    INVALID_PARAMETER = "INVALID_PARAMETER"

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Constructor
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    def __init__(self, client):
        super().__init__(client,
                         "Code",
                         description="Commands that have to do with coding!",
                         embed_color=0xFFFF00,
                         locally_inactive_error=Server.getInactiveError,
                         globally_inactive_error=OmegaPsi.getInactiveError,
                         locally_active_check=Server.isCommandActive,
                         globally_active_check=OmegaPsi.isCommandActive)

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

        # Commands
        self._brainfuck = Command(
            commandDict={
                "alternatives": ["brainf", "bf"],
                "info":
                "Runs brainfuck code. Kinda confusing stuff at first glance.",
                "min_parameters": 1,
                "parameters": {
                    "code": {
                        "optional": False,
                        "info": "The code to run."
                    },
                    "parameters": {
                        "optional": True,
                        "info": "The parameters to use in the code."
                    }
                },
                "errors": {
                    Code.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "The brainfuck command requires at least the brainfuck code."
                        ]
                    },
                    Code.TOO_MANY_PARAMETERS: {
                        "messages": [
                            "The brainfuck command only needs the code and the parameters. Make sure you remove spaces from both."
                        ]
                    }
                },
                "command": self.brainfuck
            })

        self._convert = Command(
            commandDict={
                "alternatives":
                ["convert", "conversion", "baseConversion", "baseConverter"],
                "info":
                "Converts a number from one base to another base.",
                "min_parameters":
                2,
                "max_parameters":
                3,
                "parameters": {
                    "startBase": {
                        "info": "The base the number starts at.",
                        "optional": True
                    },
                    "endBase": {
                        "info": "The base the number ends at.",
                        "optional": False
                    },
                    "number": {
                        "info": "The number to convert.",
                        "optional": False
                    }
                },
                "errors": {
                    Code.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "You need at least the end base and the number to convert."
                        ]
                    },
                    Code.TOO_MANY_PARAMETERS: {
                        "messages": [
                            "You only need the start base, the end base, and the number."
                        ]
                    },
                    Code.INVALID_BASE: {
                        "messages":
                        ["A base you entered is not a valid base."]
                    },
                    Code.BASE_MISMATCH: {
                        "messages": [
                            "The number you entered does not match the start base."
                        ]
                    }
                },
                "command":
                self.convert
            })

        self._base64 = Command(
            commandDict={
                "alternatives": ["base64", "b64"],
                "info": "Encodes or decodes text to base64.",
                "min_parameters": 2,
                "parameters": {
                    "conversion": {
                        "info":
                        "Whether to encode/decode text into/from base64.",
                        "optional": False,
                        "accepted_parameters": {
                            "encode": {
                                "alternatives": ["encode", "enc", "e"],
                                "info": "Encode text into base64."
                            },
                            "decode": {
                                "alternatives": ["decode", "dec", "d"],
                                "info": "Decode text from base64."
                            }
                        }
                    },
                    "text": {
                        "info": "The text to encode or decode.",
                        "optional": False
                    }
                },
                "errors": {
                    Code.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to encode or decode text, you need the conversion type and the text."
                        ]
                    },
                    Code.INVALID_PARAMETER: {
                        "messages": ["That is not a valid conversion type."]
                    }
                },
                "command": self.base64
            })

        self._morse = Command(
            commandDict={
                "alternatives": ["morse", "m"],
                "info": "Encodes or decodes text to Morse code.",
                "parameters": {
                    "conversion": {
                        "info":
                        "Whether to encode/decode text into/from Morse Code.",
                        "optional": False,
                        "accepted": {
                            "encode": {
                                "alternatives": ["encode", "enc", "e"],
                                "info": "Encodes text into Morse Code."
                            },
                            "decode": {
                                "alternatives": ["decode", "dec", "d"],
                                "info": "Decodes text from Morse Code."
                            }
                        }
                    },
                    "text": {
                        "info": "The text to encode or decode.",
                        "optional": False
                    }
                },
                "errors": {
                    Code.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to encode or decode text, you need the conversion type and the text."
                        ]
                    },
                    Code.INVALID_PARAMETER: {
                        "messages": ["That is not a valid conversion type."]
                    }
                },
                "command": self.morse
            })

        self._qrCode = Command(
            commandDict={
                "alternatives": ["qrCode", "qr"],
                "info": "Turns text into a QR code.",
                "parameters": {
                    "data": {
                        "info": "The data to set for the QR code.",
                        "optional": False
                    }
                },
                "errors": {
                    Code.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to get the QR code for data, you need to type in the data."
                        ]
                    }
                },
                "command": self.qrCode
            })

        self.setCommands([
            self._brainfuck, self._convert, self._base64, self._morse,
            self._qrCode
        ])

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Command Methods
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    def __brainfuck(self, code, parameters):

        # Keep track of pointers and data
        data = [0] * Code.MAX_BRAINFUCK_LENGTH
        dataPointer = 0
        paramPointer = 0
        output = ""
        loop = 0

        # Iterate through code
        char = 0
        while char < len(code):

            # char is > (move pointer right)
            if code[char] == ">":
                dataPointer = 0 if dataPointer == Code.MAX_BRAINFUCK_LENGTH - 1 else dataPointer + 1

            # char is < (move pointer left)
            elif code[char] == "<":
                dataPointer = Code.MAX_BRAINFUCK_LENGTH - 1 if dataPointer == 0 else dataPointer - 1

            # char is + (increase value at pointer)
            elif code[char] == "+":
                data[dataPointer] += 1
                if data[dataPointer] > 255:
                    data[dataPointer] -= 256

            # char is - (decrease value at pointer)
            elif code[char] == "-":
                data[dataPointer] -= 1
                if data[dataPointer] < 0:
                    data[dataPointer] += 256

            # char is . (add data to output)
            elif code[char] == ".":
                output += str(chr(data[dataPointer]))

            # char is , (add data to input)
            elif code[char] == ",":
                if paramPointer >= len(parameters):
                    data[dataPointer] = 0
                else:
                    data[dataPointer] = ord(parameters[paramPointer])
                paramPointer += 1

            # char is [ (open loop)
            elif code[char] == "[":
                if data[dataPointer] == 0:
                    char += 1
                    while loop > 0 or code[char] != "]":
                        if code[char] == "[":
                            loop += 1
                        if code[char] == "]":
                            loop -= 1
                        char += 1

            # char is ] (close loop)
            elif code[char] == "]":
                if data[dataPointer] != 0:
                    char -= 1
                    while loop > 0 or code[char] != "[":
                        if code[char] == "]":
                            loop += 1
                        if code[char] == "[":
                            loop -= 1
                        char -= 1
                    char -= 1

            char += 1

        return output

    async def brainfuck(self, message, parameters):
        """Runs brainfuck code and returns the result.\n

        Parameters:
            code: The brainfuck code to run.\n
            parameters: The parameters to insert into the brainfuck code.\n
        """

        # Check for not enough parameters
        if len(parameters) < self._brainfuck.getMinParameters():
            embed = getErrorMessage(self._brainfuck,
                                    Code.NOT_ENOUGH_PARAMETERS)

        # Check for too many parameters
        elif len(parameters) > self._brainfuck.getMaxParameters():
            embed = getErrorMessage(self._brainfuck, Code.TOO_MANY_PARAMETERS)

        # There were a proper amount of parameters
        else:

            code = parameters[0]
            if len(parameters) == 2:
                parameters = parameters[1]
            else:
                parameters = []

            # Remove all invalid symbols
            validSymbols = "<>+-.,[]"
            newCode = ""
            for char in code:
                if char in validSymbols:
                    newCode += char
            code = newCode

            try:
                async with async_timeout.timeout(5):
                    description = await loop.run_in_executor(
                        None, self.__brainfuck, code, parameters)
            except:
                description = "Timed out"

            # Create and return embed for result
            embed = discord.Embed(title="Result",
                                  description=description,
                                  colour=self.getEmbedColor() if message.guild
                                  == None else message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def convert(self, message, parameters):
        """Converts a number from the start base to the end base.\n

        Parameters:
            startBase: The base to convert from.\n
            endBase: The base to convert to.\n
            number: The number to convert.\n
        """

        # Check for not enough parameters
        if len(parameters) < self._convert.getMinParameters():
            embed = getErrorMessage(self._convert, Code.NOT_ENOUGH_PARAMETERS)

        # Check for too many parameters
        elif len(parameters) > self._convert.getMaxParameters():
            embed = getErrorMessage(self._convert, Code.TOO_MANY_PARAMETERS)

        # There were the proper amount of parameters
        else:

            startBase = "10"
            endBase = parameters[0]
            number = parameters[1]

            if len(parameters) == 3:
                startBase = parameters[0]
                endBase = parameters[1]
                number = parameters[2]

            # Only run if start base and end base are valid
            if startBase.isdigit() and endBase.isdigit():
                startBase = int(startBase)
                endBase = int(endBase)

                if startBase >= 2 and startBase <= 64 and endBase >= 2 and endBase <= 64:
                    # Try converting number from startBase to base-10
                    # Test to see if number is not zero
                    start = number
                    title = "Base-{} to Base-{}".format(startBase, endBase)
                    description = "`{} --> {}`".format(start, number)

                    # Check if number is not zero; Convert it
                    if number not in ["0", 0]:
                        number = convert(number, startBase, endBase)

                        # Check if number is None; Invalid number for a base
                        if number == None:
                            embed = getErrorMessage(self._convert,
                                                    Code.BASE_MISMATCH)

                        # Number is not None; Valid base
                        else:

                            # Return number
                            description = "`{} --> {}`".format(start, number)

                            embed = discord.Embed(
                                title=title,
                                description=description,
                                colour=self.getEmbedColor() if message.guild
                                == None else message.author.top_role.color)

                    # Number is zero; Just send that
                    else:

                        embed = discord.Embed(
                            title=title,
                            description=description,
                            colour=self.getEmbedColor() if message.guild
                            == None else message.author.top_role.color)

                # Bases were not within range
                else:
                    embed = getErrorMessage(self._convert,
                                            Code.BASE_OUT_OF_RANGE)

            # Bases were not numbers
            else:
                embed = getErrorMessage(self._convert, Code.INVALID_BASE)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def base64(self, message, parameters):
        """Encodes or decodes text to or from base64.\n

        Parameters:
            conversionType: Whether to encode or decode text.\n
            text: The text to encode or decode.\n
        """

        # Check for not enough parameters
        if len(parameters) < self._base64.getMinParameters():
            embed = getErrorMessage(self._base64, Code.NOT_ENOUGH_PARAMETERS)

        # There were enough parameters
        else:

            # Conversion type is first parameter; Text is all parameters after
            conversionType = parameters[0]
            text = " ".join(parameters[1:])

            # Conversion is Encode
            if conversionType in self._base64.getAcceptedParameter(
                    "conversion", "encode").getAlternatives():
                converted = base64.b64encode(text.encode()).decode()
                encoded = True

                embed = discord.Embed(
                    title="`{}` {} Base64".format(
                        text if len(text) < 180 else
                        "[text is greater than 200 characters]",
                        "encoded to" if encoded else "decoded from"),
                    description=converted,
                    colour=self.getEmbedColor() if message.guild == None else
                    message.author.top_role.color)

            # Conversion is Decode
            elif conversionType in self._base64.getAcceptedParameter(
                    "conversion", "decode").getAlternatives():
                converted = base64.b64decode(text.encode()).decode()
                encoded = False

                embed = discord.Embed(
                    title="`{}` {} Base64".format(
                        text if len(text) < 180 else
                        "[text is greater than 200 characters]",
                        "encoded to" if encoded else "decoded from"),
                    description=converted,
                    colour=self.getEmbedColor() if message.guild == None else
                    message.author.top_role.color)

            # Conversion is Invalid
            else:
                embed = getErrorMessage(self._base64, Code.INVALID_PARAMETER)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def morse(self, message, parameters):
        """Turns text into/from morse code
        """

        # Check for not enough parameters
        if len(parameters) < self._morse.getMinParameters():
            embed = getErrorMessage(self._morse, Code.NOT_ENOUGH_PARAMETERS)

        # There were the proper amount of parameters
        else:
            conversion = parameters[0]
            text = " ".join(parameters[1:])

            # Check if the conversion is valid
            valid = True
            if conversion in self._morse.getAcceptedParameter(
                    "conversion", "encode").getAlternatives():
                conversion = "encode"
            elif conversion in self._morse.getAcceptedParameter(
                    "conversion", "decode").getAlternatives():
                conversion = "decode"

            # Conversion is invalid
            else:
                embed = getErrorMessage(self._morse, Code.INVALID_PARAMETER)
                valid = False

            if valid:

                response = await loop.run_in_executor(
                    None, requests.get,
                    Code.MORSE_API_CALL.format(conversion, text))
                response = response.json()

                # Check if the API call was a success
                if response["success"]:
                    value = response["value"]
                else:
                    value = response["error"]

                embed = discord.Embed(
                    title="{}".format("Text to Morse" if conversion ==
                                      "encode" else "Morse To Text")
                    if response["success"] else "Failed to convert",
                    description="`{}`".format(value),
                    colour=self.getEmbedColor() if message.guild == None else
                    message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def qrCode(self, message, parameters):
        """Turns data into a QR code.
        """

        # Check for not enough parameters
        if len(parameters) < self._qrCode.getMinParameters():
            embed = getErrorMessage(self._qrCode, Code.NOT_ENOUGH_PARAMETERS)

        # There were the proper amount of parameters
        else:
            data = " ".join(parameters)

            # The size should be a function of the data's length
            # Use this --> size = 10(length // 20) + 200
            size = 10 * (len(data) // 20) + 200

            embed = discord.Embed(
                title=" ",
                description=" ",
                colour=self.getEmbedColor() if message.guild == None else
                message.author.top_role.color).set_image(
                    url=Code.QR_API_CALL.format(size, data.replace(" ", "+")))

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Parsing
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    async def on_message(self, message):
        """Parses a message and runs a Code Category command if it can

        Parameters:
            message: The Discord Message to parse.\n
        """

        # Make sure message starts with the prefix
        if await Server.startsWithPrefix(
                message.guild, message.content) and not message.author.bot:

            # Split up into command and parameters if possible
            command, parameters = Category.parseText(
                await Server.getPrefixes(message.guild), message.content)

            # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

            # Iterate through commands
            for cmd in self.getCommands():
                if command in cmd.getAlternatives():
                    async with message.channel.typing():

                        # Run the command but don't try running others
                        await self.run(message, cmd, cmd.getCommand(), message,
                                       parameters)
                    break
Beispiel #2
0
class NSFW(Category):

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Class Fields
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    BOOBS_URL = "http://media.oboobs.ru/boobs_preview/{}.jpg"

    BOOTY_URL = "http://media.obutts.ru/butts_preview/{}.jpg"

    URBAN_API_CALL = "https://api.urbandictionary.com/v0/define?term={}"
    URBAN_ICON = "https://vignette.wikia.nocookie.net/creation/images/b/b7/Urban_dictionary_--_logo.jpg/revision/latest?cb=20161002212954"

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Errors
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    NO_TERM = "NO_TERM"

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Constructor
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    def __init__(self, client):
        super().__init__(
            client,
            "NSFW",
            description="An NSFW category for 18+",
            embed_color=0xFFAAAA,
            restriction_info=
            "You should be 18+ to run the commands in this category!",
            nsfw_category=True,
            nsfw_channel_error=Server.getNSFWChannelError)

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

        # Commands

        self._boobs = Command(
            commandDict={
                "alternatives": ["boobs", "boob"],
                "info": "Sends a random picture of boobs.",
                "errors": {
                    NSFW.TOO_MANY_PARAMETERS: {
                        "messages": [
                            "In order to get some boobs, you don't need any parameters."
                        ]
                    }
                },
                "command": self.boobs
            })

        self._booty = Command(
            commandDict={
                "alternatives": ["booty", "ass"],
                "info": "Sends a random picture of some booty.",
                "errors": {
                    NSFW.TOO_MANY_PARAMETERS: {
                        "messages": [
                            "In order to get some booty, you don't need any parameters."
                        ]
                    }
                },
                "command": self.booty
            })

        self._urban = Command(
            commandDict={
                "alternatives": ["urban", "urbanDictionary", "urbanDict"],
                "info":
                "Gives you the top 5 urban dictionary entries for a term.",
                "nsfw": True,
                "parameters": {
                    "term": {
                        "info": "The term to look up in urban dictionary.",
                        "optional": False
                    }
                },
                "errors": {
                    NSFW.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "You need the term to look something up in urban dictionary."
                        ]
                    },
                    NSFW.NO_TERM: {
                        "messages": [
                            "The term you entered does not exist on urban dictionary."
                        ]
                    }
                },
                "command": self.urban
            })

        self.setCommands([self._boobs, self._booty, self._urban])

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Command Methods
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    async def boobs(self, message, parameters):
        """Sends a random picture of some boobs.
        """

        # Check for too many parameters
        if len(parameters) > self._boobs.getMaxParameters():
            embed = getErrorMessage(self._boobs, NSFW.TOO_MANY_PARAMETERS)

        # There were the proper amount of parameters
        else:

            # Load image from URL, temporarily save it, send image
            while True:

                # Generate random number for an image; Add 0's to beginning until pad is reached (5)
                boobNumber = str(random.randint(1, 12500))
                boobNumber = boobNumber.rjust(5, "0")

                # Try loading the Image
                try:
                    loadImageFromUrl(NSFW.BOOBS_URL.format(boobNumber))
                    break

                # Image load failed; Retry using new number.
                except:
                    pass

            embed = discord.Embed(
                title="Boobs Number {}".format(boobNumber),
                description=" ",
                colour=self.getEmbedColor() if message.guild == None else
                message.author.top_role.color).set_image(
                    url=NSFW.BOOBS_URL.format(boobNumber))

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def booty(self, message, parameters):
        """Sends a random picture of some booty.
        """

        # Check for too many parameters
        if len(parameters) > self._booty.getMaxParameters():
            return getErrorMessage(self._booty, NSFW.TOO_MANY_PARAMETERS)

        # There were the proper amount of parameters
        else:

            # Load image from URL, temporarily save it, send image
            while True:

                # Generate random number for an image; Add 0's to beginning until pad is reached (5)
                bootyNumber = str(random.randint(1, 5400))
                bootyNumber = bootyNumber.rjust(5, "0")

                # Try loading the image
                try:
                    loadImageFromUrl(NSFW.BOOTY_URL.format(bootyNumber))
                    break

                # Image load failed; Retry using new number.
                except:
                    pass

            embed = discord.Embed(
                title="Booty Number {}".format(bootyNumber),
                description=" ",
                colour=self.getEmbedColor() if message.guild == None else
                message.author.top_role.color).set_image(
                    url=NSFW.BOOTY_URL.format(bootyNumber))

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def urban(self, message, parameters):
        """Returns the top 5 urban dictionary entries for the specified term.\n

         - term - The term to search on urban dictionary.\n
         - discordChannel - The Discord Channel the definition is being sent in.\n
        """

        # Check for not enough parameters
        if len(parameters) < self._urban.getMinParameters():
            embed = getErrorMessage(self._urban, NSFW.NOT_ENOUGH_PARAMETERS)

        # There were the proper amount of parameters
        else:

            term = " ".join(parameters)

            # Use requests to get the data in JSON
            try:
                urlCall = NSFW.URBAN_API_CALL.format(term.replace(" ", "+"))
                urbanData = await loop.run_in_executor(None, requests.get,
                                                       urlCall)
                urbanData = urbanData.json()

                # Get first 5 values (or values if there are less than 5)
                if len(urbanData["list"]) < 5:
                    definitions = urbanData["list"]
                else:
                    definitions = urbanData["list"][:5]

                # Create discord embed
                embed = discord.Embed(
                    title="{} Results Of `{}`".format(
                        "Top 5" if len(definitions) > 5 else "", term),
                    description=" ",
                    colour=self.getEmbedColor() if message.guild == None else
                    message.author.top_role.color).set_thumbnail(
                        url=NSFW.URBAN_ICON)

                # Add definitions
                defCount = 0
                for definition in definitions:
                    defCount += 1

                    # Get definition; Split up into multiple fields if necessary
                    definitionFields = splitText(definition["definition"],
                                                 OmegaPsi.MESSAGE_THRESHOLD)

                    count = 0
                    for field in definitionFields:
                        count += 1
                        embed.add_field(name="Definition {} {}".format(
                            defCount,
                            "({} / {})".format(count, len(definitionFields))
                            if len(definitionFields) > 1 else ""),
                                        value=field,
                                        inline=False)

            except:
                embed = getErrorMessage(self._urban, NSFW.NO_TERM)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Parsing
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    async def on_message(self, message):
        """Parses a message and runs an NSFW Category command if it can.\n

        message - The Discord Message to parse.\n
        """

        # Make sure message starts with the prefix
        if await Server.startsWithPrefix(
                message.guild, message.content) and not message.author.bot:

            # Split up into command and parameters if possible
            command, parameters = Category.parseText(
                await Server.getPrefixes(message.guild), message.content)

            # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

            # Iterate through commands
            for cmd in self.getCommands():
                if command in cmd.getAlternatives():
                    async with message.channel.typing():

                        # Run the command but don't try running others
                        await self.run(message, cmd, cmd.getCommand(), message,
                                       parameters)
                    break
Beispiel #3
0
class BotModerator(Category):

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Class Fields
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    EMBED_COLOR = 0xA456B0
    BOT_MARKDOWN = "botMarkdown.md"

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Errors
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    CANT_BE_DEACTIVATED = "CANT_BE_DEACTIVATED"

    INVALID_ACTIVITY = "INVALID_ACTIVITY"
    INVALID_COMMAND = "INVALID_COMMAND"

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Constructor
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    def __init__(self, client):
        super().__init__(client,
                         "Bot Moderator",
                         description="Very private stuff.",
                         restriction_info=
                         "You must be a Bot Moderator to run these commands.",
                         bot_mod_category=True,
                         bot_mod_error=OmegaPsi.getNoAccessError,
                         locally_inactive_error=Server.getInactiveError,
                         globally_inactive_error=OmegaPsi.getInactiveError,
                         locally_active_check=Server.isCommandActive,
                         globally_active_check=OmegaPsi.isCommandActive)

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

        # Commands

        self._addModerator = Command(
            commandDict={
                "alternatives": ["addBotModerator", "addBotMod", "abm"],
                "info": "Allows you to add a bot moderator to the bot.",
                "bot_moderator_only": True,
                "min_parameters": 1,
                "parameters": {
                    "member(s)...": {
                        "info": "The member(s) to add as a bot moderator.",
                        "optional": False
                    }
                },
                "errors": {
                    BotModerator.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to add a bot moderator, you need to mention them."
                        ]
                    }
                },
                "command": self.addModerator
            })

        self._removeModerator = Command(
            commandDict={
                "alternatives":
                ["removeBotModerator", "removeBotMod", "remBotMod", "rbm"],
                "info":
                "Allows you to remove a bot moderator from the bot.",
                "bot_moderator_only":
                True,
                "min_parameters":
                1,
                "parameters": {
                    "member(s)...": {
                        "info": "The member(s) to remove as a bot moderator.",
                        "optional": False
                    }
                },
                "errors": {
                    BotModerator.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to remove a bot moderator, you need to mention them."
                        ]
                    }
                },
                "command":
                self.removeModerator
            })

        self._activate = Command(
            commandDict={
                "alternatives": ["activateGlobally", "enableGlobally"],
                "info":
                "Allows you to activate a command, or commands, globally.",
                "bot_moderator_only": True,
                "min_parameters": 1,
                "parameters": {
                    "command(s)": {
                        "info": "The command(s) to activate globally.",
                        "optional": False
                    }
                },
                "errors": {
                    BotModerator.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to activate a command globally, you need to type it in."
                        ]
                    },
                    BotModerator.INVALID_COMMAND: {
                        "messages": ["That is not a valid command."]
                    }
                },
                "command": self.activate
            })

        self._deactivate = Command(
            commandDict={
                "alternatives": ["deactivateGlobally", "disableGlobally"],
                "info": "Allows you to deactivate a command globally.",
                "bot_moderator_only": True,
                "min_parameters": 1,
                "parameters": {
                    "command": {
                        "info": "The command to deactivate globally.",
                        "optional": False
                    },
                    "reason": {
                        "info":
                        "The reason the command is being deactivated globally.",
                        "optional": True
                    }
                },
                "errors": {
                    BotModerator.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to deactivate a command globally, you need to type it in."
                        ]
                    },
                    BotModerator.INVALID_COMMAND: {
                        "messages": ["That is not a valid command."]
                    },
                    BotModerator.CANT_BE_DEACTIVATED: {
                        "messages": ["This command cannot be deactivated."]
                    }
                },
                "command": self.deactivate
            })

        self._servers = Command(
            commandDict={
                "alternatives": ["servers", "botServers"],
                "info": "Allows you to get a list of servers the bot is in.",
                "bot_moderator_only": True,
                "parameters": {
                    "markdown": {
                        "info":
                        "Whether or not to send a markdown version of all the server information.",
                        "optional": True
                    }
                },
                "errors": {
                    BotModerator.TOO_MANY_PARAMETERS: {
                        "messages": [
                            "In order to get a list of servers the bot is in, you only need 1 parameter which is optional."
                        ]
                    }
                },
                "command": self.getServers
            })

        self._status = Command(
            commandDict={
                "alternatives": ["setStatus", "status"],
                "info": "Allows you to change the presence of the bot.",
                "bot_moderator_only": True,
                "min_parameters": 2,
                "parameters": {
                    "activity": {
                        "info": "The activity to set for the presence.",
                        "optional": False,
                        "accepted_parameters": {
                            "playing": {
                                "alternatives": ["playing", "Playing"],
                                "info": "The playing activity type."
                            },
                            "streaming": {
                                "alternatives": ["streaming", "Streaming"],
                                "info": "The streaming activity type."
                            },
                            "listening": {
                                "alternatives": [
                                    "listening", "Listening", "listening to",
                                    "Listening to"
                                ],
                                "info":
                                "The listening activity type."
                            },
                            "watching": {
                                "alternatives": ["watching", "Watching"],
                                "info": "The watching activity type."
                            }
                        }
                    },
                    "text": {
                        "info": "The text to set as the presence.",
                        "optional": False
                    }
                },
                "errors": {
                    BotModerator.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to set the status, you need the status type and the text to set."
                        ]
                    },
                    BotModerator.INVALID_ACTIVITY: {
                        "messages":
                        ["The given activity is not a valid activity."]
                    }
                },
                "command": self.setStatus
            })

        self._todo = Command(
            commandDict={
                "alternatives": ["todo"],
                "info": "Adds, removes, or lists things in the TODO list.",
                "parameters": {
                    "action": {
                        "info": "The action to do.",
                        "optional": True,
                        "accepted": {
                            "add": {
                                "alternatives": ["add", "a"],
                                "info": "Adds something to the TODO list."
                            },
                            "remove": {
                                "alternatives": ["remove", "r"],
                                "info": "Removes something from the TODO list."
                            }
                        }
                    },
                    "item": {
                        "info": "The item to add or remove.",
                        "optional": True
                    }
                },
                "errors": {
                    BotModerator.NOT_ENOUGH_PARAMETERS: {
                        "messages": [
                            "In order to add or remove something, you need the item to add or remove."
                        ]
                    },
                    BotModerator.INVALID_PARAMETER: {
                        "messages": ["That is not a valid parameter."]
                    }
                },
                "command": self.todo
            })

        self._kill = Command(
            commandDict={
                "alternatives": ["stop", "quit", "kill"],
                "info": "Kills the bot.",
                "bot_moderator_only": True,
                "max_parameters": 1,
                "parameters": {
                    "process": {
                        "info": "The process number to kill.",
                        "optional": True
                    }
                },
                "errors": {
                    BotModerator.TOO_MANY_PARAMETERS: {
                        "messages": [
                            "In order to kill the bot, you don't need anything other than the process."
                        ]
                    }
                },
                "command": self.kill
            })

        self._debug = Command(
            commandDict={
                "alternatives": ["debug"],
                "info": "Debugs the bot.",
                "bot_moderator_only": True,
                "max_parameters": 0,
                "errors": {
                    BotModerator.TOO_MANY_PARAMETERS: {
                        "messages":
                        ["To debug the bot, you don't need any parameters."]
                    }
                },
                "command": self.debug
            })

        self.setCommands([
            self._addModerator, self._removeModerator, self._activate,
            self._deactivate, self._servers, self._status, self._todo,
            self._kill, self._debug
        ])

        self._todo.setBotModeratorOnly(False)

        self._categories = {
            "Code": Code(None),
            "Game": Game(None),
            "Image": Image(None),
            "Insult": Insult(None),
            "Internet": Internet(None),
            "Math": Math(None),
            "Meme": Meme(None),
            "Misc": Misc(None),
            "NSFW": NSFW(None),
            "Rank": Rank(None),
            "Updates": Updates(None)
        }

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Command Methods
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    async def addModerator(self, message, parameters):
        """Adds bot moderators to the bot.\n

        Parameters:
            parameters: The Discord Users to add as a bot moderator.\n
        """

        # Check if message has no mentions
        if len(message.mentions) < self._addModerator.getMinParameters():
            return getErrorMessage(self._addModerator,
                                   BotModerator.NOT_ENOUGH_PARAMETERS)

        # There was at least one mention
        else:

            # Iterate through each member
            result = ""
            for member in message.mentions:
                result += "{} {}".format(
                    member.mention,
                    " was successfully added as a bot moderator."
                    if await OmegaPsi.addModerator(member) else
                    (" is already a bot moderator."))

            embed = discord.Embed(name="Added bot Moderators",
                                  description=result,
                                  colour=self.getEmbedColor() if message.guild
                                  == None else message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def removeModerator(self, message, parameters):
        """Removes a bot moderator from the bot.\n

        Parameters:
            parameters: The Discord Users to remove as a bot moderator.\n
        """

        # Check if message has no mentions
        if len(message.mentions) < self._removeModerator.getMinParameters():
            embed = getErrorMessage(self._removeModerator,
                                    BotModerator.NOT_ENOUGH_PARAMETERS)

        # There was at least one mention
        else:

            # Iterate through each member
            result = ""
            for member in message.mentions:
                result += "{} {} a bot moderator.".format(
                    member.mention, "was successfully removed as"
                    if await OmegaPsi.removeModerator(member) else ("is not"))

            embed = discord.Embed(name="Removed Moderators",
                                  description=result,
                                  colour=self.getEmbedColor() if message.guild
                                  == None else message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def activate(self, message, parameters):
        """Activates commands globally in the bot.

        Parameters:
            parameters: The parameters to process.
        """

        # Check if there are not enough parameters
        if len(parameters) < self._activate.getMinParameters():
            embed = getErrorMessage(self._activate,
                                    BotModerator.NOT_ENOUGH_PARAMETERS)

        # Parameters had the minimum amount of parameters
        else:

            # Commands held in each parameter
            commands = parameters

            # Open bot file
            bot = await OmegaPsi.openOmegaPsi()

            # Iterate through commands
            if len(commands) > 0:
                result = ""
                acCommands = []
                for command in commands:

                    # Iterate through categories
                    added = False
                    for category in self._categories:

                        # Check if command was part of category
                        commandObject = self._categories[category].getCommand(
                            command)
                        if commandObject != None:
                            acCommands.append(commandObject)
                            added = True

                    if not added:
                        result += "`{}` is not a valid command.\n".format(
                            command)

                # Activate commands
                for command in acCommands:
                    if command.getAlternatives(
                    )[0] in bot["inactive_commands"]:
                        bot["inactive_commands"].pop(
                            command.getAlternatives()[0])
                        result += "`{}` was activated globally.\n".format(
                            command.getAlternatives()[0])
                    else:
                        result += "`{}` is already globally active.\n".format(
                            command.getAlternatives()[0])

            else:
                result = ""
                for command in bot["inactive_commands"]:
                    result += "`{}` was activated globally.\n".format(command)
                bot["inactive_commands"] = {}

            # Close bot file
            await OmegaPsi.closeOmegaPsi(bot)

            embed = discord.Embed(name="Activated",
                                  description=result,
                                  colour=self.getEmbedColor() if message.guild
                                  == None else message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def deactivate(self, message, parameters):
        """Deactivates a command globally in the bot.\n

        Parameters:
            command: The command to globally deactivate.\n
            reason: The reason the command is being globally deactivated.\n
        """

        # Check for minimum amount of parameters
        if len(parameters) < self._deactivate.getMinParameters():
            embed = getErrorMessage(self._deactivate,
                                    BotModerator.NOT_ENOUGH_PARAMETERS)

        # Parameters had the minimum amount of parameters
        else:

            # Command to be deactivated is first parameter; Reason is every parameter after
            command = parameters[0]
            reason = "No Reason"
            if len(parameters) > 1:
                reason = " ".join(parameters[1:])

            # Open bot file
            bot = await OmegaPsi.openOmegaPsi()

            # Check if command is valid
            commandObject = None
            for category in self._categories:
                commandObject = self._categories[category].getCommand(command)
                if commandObject != None:
                    break
            if commandObject == None:
                result = "`{}` is not a valid command.".format(command)
            else:
                bot["inactive_commands"][commandObject.getAlternatives()
                                         [0]] = reason
                result = "`{}` was globally deactivated.\nReason: {}".format(
                    commandObject.getAlternatives()[0], reason)

            # Close bot file
            await OmegaPsi.closeOmegaPsi(bot)

            embed = discord.Embed(name="Deactivated",
                                  description=result,
                                  colour=self.getEmbedColor() if message.guild
                                  == None else message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def getServers(self, message, parameters):
        """Returns a list of servers the bot is in.\n
        """

        # Check if parameters exceeds maximum parameters
        if len(parameters) > self._servers.getMaxParameters():
            embed = getErrorMessage(self._servers,
                                    BotModerator.TOO_MANY_PARAMETERS)

        # Parameters do not exceed maximum parameters
        else:

            # Getting results through embed
            if len(parameters) == 0:

                # Add results to fields
                fields = []
                fieldText = ""
                for server in self.client.guilds:

                    text = "`{}` | Owner: {}\n".format(server.name,
                                                       server.owner.mention)

                    if len(fieldText) + len(
                            text) >= OmegaPsi.MESSAGE_THRESHOLD:
                        fields.append(fieldText)
                        fieldText = ""

                    fieldText += text

                # Add trailing field text
                if len(fieldText) > 0:
                    fields.append(fieldText)

                # Create embed object
                embed = discord.Embed(
                    title="Servers",
                    description="A list of servers that Omega Psi is in.",
                    colour=self.getEmbedColor() if message.guild == None else
                    message.author.top_role.color)

                # Add fields to embed object
                count = 0
                for field in fields:
                    count += 1
                    embed.add_field(
                        name="Servers {}".format("({} / {})".format(
                            count, len(fields)) if len(fields) > 1 else ""),
                        value=field,
                        inline=False)

            # Getting results through markdown file
            else:

                # Setup markdown text
                markdown = "# Omega Psi Server Information\n"

                # Iterate through servers bot is in
                for guild in self.client.guilds:

                    # Load file
                    server = await Server.openServer(guild)

                    # Add server information (owner, name)
                    try:
                        markdown += "## {} - {}\n".format(
                            guild.name,
                            guild.owner.name + "#" + guild.owner.discriminator)
                    except:
                        markdown += "## {} - No Owner\n".format(guild.name)

                    # Iterate through members in server dictionary
                    for member in server["members"]:
                        member = server["members"][member]
                        discordMember = guild.get_member(int(member["id"]))

                        markdown += (
                            "  * {} ({})\n" + "    * Moderator? {}\n" +
                            "    * Experience: {}\n" + "    * Level: {}\n" +
                            "    * Experience until next level: {}\n").format(
                                discordMember.name + "#" +
                                discordMember.discriminator,
                                discordMember.nick, "Yes"
                                if discordMember.guild_permissions.manage_guild
                                else "No", member["experience"],
                                member["level"],
                                Server.getExpFromLevel(member["level"] + 1) -
                                member["experience"])

                # Save markdown temporarily
                mdFile = open(BotModerator.BOT_MARKDOWN, "w")
                mdFile.write(markdown)
                mdFile.close()

                mdFile = open(BotModerator.BOT_MARKDOWN, "r")

                # Send file to DMs; Then delete
                await message.author.send(file=discord.File(mdFile))
                os.remove(BotModerator.BOT_MARKDOWN)

                embed = discord.Embed(
                    title="File sent.",
                    description=
                    "The server information has been sent to your DM's",
                    colour=self.getEmbedColor() if message.guild == None else
                    message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def setStatus(self, message, parameters):
        """Sets the presence of the bot given the activity type and text.\n

        Parameters:
            activityType: The type of activity to set for the presence.\n
            text: The text to set.\n
        """

        # Check if parameters is less than minimum parameters
        if len(parameters) < self._status.getMinParameters():
            embed = getErrorMessage(self._status,
                                    BotModerator.NOT_ENOUGH_PARAMETERS)

        # Parameters has minumum parameters
        else:

            # Activity type is first parameter; Text is every parameter after
            activityType = parameters[0]
            text = " ".join(parameters[1:])

            # Get the specific activity type
            activityText = activityType
            if activityType in self._status.getAcceptedParameter(
                    "activity", "playing").getAlternatives():
                activityType = discord.ActivityType.playing
                activityText = "Playing"

            elif activityType in self._status.getAcceptedParameter(
                    "activity", "streaming").getAlternatives():
                activityType = discord.ActivityType.streaming
                activityText = "Streaming"

            elif activityType in self._status.getAcceptedParameter(
                    "activity", "listening").getAlternatives():
                activityType = discord.ActivityType.listening
                activityText = "Listening"

            elif activityType in self._status.getAcceptedParameter(
                    "activity", "watching").getAlternatives():
                activityType = discord.ActivityType.watching
                activityText = "Watching"

            # Update the bot's activity setting
            await OmegaPsi.setActivityType(activityType)
            await OmegaPsi.setActivityName(text)

            # Change the presence of the bot
            await self.client.change_presence(
                status=discord.Status.online,
                activity=discord.Activity(
                    name=text,
                    type=activityType,
                    url="https://www.twitch.tv/FellowHashbrown"))

            embed = discord.Embed(
                title="Presence Set",
                description="Activity: {}\nText: {}\n".format(
                    activityText, text),
                colour=self.getEmbedColor()
                if message.guild == None else message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def todo(self, message, parameters):
        """Runs the todo command.

        Parameters:
            action (str): What action to perform for the todo command.
            item (str): The item to add/remove to/from the TODO list.
        """

        # Check for no parameters; list the TODO list
        if len(parameters) == 0:

            todoList = await OmegaPsi.getToDoList()
            todoText = ""
            for item in range(len(todoList)):
                todoText += "`{}.) {}`\n".format(item + 1, todoList[item])

            embed = discord.Embed(
                title="TODO List",
                description=todoText if len(todoText) > 0 else "Nothing Yet",
                colour=self.getEmbedColor()
                if message.guild == None else message.author.top_role.color)

        # Check for 2 or more parameters
        else:

            # Check if author is a bot moderator
            if await OmegaPsi.isAuthorModerator(message.author):

                action = parameters[0]

                # There is nothing to add
                if len(parameters) == 1:
                    embed = getErrorMessage(self._todo,
                                            BotModerator.NOT_ENOUGH_PARAMETERS)

                # Check if action is valid
                elif action in self._todo.getAcceptedParameter(
                        "action", "add").getAlternatives():

                    # Check if index is given
                    if parameters[1].isdigit():
                        index = int(parameters[1])
                        item = " ".join(parameters[2:])
                    else:
                        index = 0
                        item = " ".join(parameters[1:])

                    success = await OmegaPsi.addToDo(item, index)

                    embed = discord.Embed(
                        title="Added TODO Item"
                        if success["success"] else "Failed to add TODO Item",
                        description=success["reason"],
                        colour=self.getEmbedColor() if message.guild == None
                        else message.author.top_role.color)

                elif action in self._todo.getAcceptedParameter(
                        "action", "remove").getAlternatives():
                    success = await OmegaPsi.removeToDo(" ".join(
                        parameters[1:]))

                    embed = discord.Embed(
                        title="Removed TODO Item" if success["success"] else
                        "Failed to remove TODO Item",
                        description=success["reason"],
                        colour=self.getEmbedColor() if message.guild == None
                        else message.author.top_role.color)

                # Action is invalid
                else:
                    embed = getErrorMessage(self._todo,
                                            BotModerator.INVALID_PARAMETER)

            # Author is not bot moderator
            else:
                embed = OmegaPsi.getNoAccessError()

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    async def kill(self, message, parameters):
        """Kills the bot and logs out.
        """

        processId = OmegaPsi.PROCESS_ID

        # Check if parameters exceeds maximum parameters
        if len(parameters) > self._kill.getMaxParameters():
            embed = getErrorMessage(self._kill,
                                    BotModerator.TOO_MANY_PARAMETERS)

        # Parameters do not exceed maximum parameters
        else:
            processId = OmegaPsi.PROCESS_ID if len(
                parameters) == 0 else parameters[0]

            embed = discord.Embed(
                title="Bot Killed",
                description="Omega Psi was killed (Process {})".format(
                    OmegaPsi.PROCESS_ID),
                colour=self.getEmbedColor()
                if message.guild == None else message.author.top_role.color)

        # Only kill if processId is OmegaPsi.PROCESS_ID
        if str(processId) == str(OmegaPsi.PROCESS_ID):

            await sendMessage(
                self.client,
                message,
                embed=embed.set_footer(text="Requested by {}#{}".format(
                    message.author.name, message.author.discriminator),
                                       icon_url=message.author.avatar_url))

            await self.client.logout()

    async def debug(self, message, parameters):
        """Debugs the bot.
        """

        # Check if parameters exceeds maximum parameters
        if len(parameters) > self._debug.getMaxParameters():
            embed = getErrorMessage(self._debug,
                                    BotModerator.TOO_MANY_PARAMETERS)

        # Parameters do not exceed maximum parameters
        else:
            embed = discord.Embed(
                title="Omega Psi Debugging",
                description="Process ID: {}".format(OmegaPsi.PROCESS_ID),
                colour=self.getEmbedColor()
                if message.guild == None else message.author.top_role.color)

        await sendMessage(
            self.client,
            message,
            embed=embed.set_footer(text="Requested by {}#{}".format(
                message.author.name, message.author.discriminator),
                                   icon_url=message.author.avatar_url))

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    # Parsing
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    async def on_message(self, message):
        """Parses a message and runs a Bot Moderator command if it can.\n

        Parameters:
            message: The Discord Message to parse.\n
        """

        # Make sure message starts with the prefix
        if await Server.startsWithPrefix(
                message.guild, message.content) and not message.author.bot:

            # Split up into command and parameters if possible
            command, parameters = Category.parseText(
                await Server.getPrefixes(message.guild), message.content)

            # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

            # Iterate through commands
            for cmd in self.getCommands():
                if command in cmd.getAlternatives():
                    async with message.channel.typing():

                        # Run the command but don't try running others
                        await self.run(message, cmd, cmd.getCommand(), message,
                                       parameters)
                    break