diff --git a/cogs/events.py b/cogs/events.py index 5c25224..7cea495 100644 --- a/cogs/events.py +++ b/cogs/events.py @@ -3,7 +3,7 @@ import datetime import discord from discord.ext import commands from functions import checks, easterEggResponses -from functions.database import stats, muttn +from functions.database import stats, muttn, custom_commands import pytz import time import traceback @@ -75,6 +75,12 @@ class Events(commands.Cog): if eER: await message.channel.send(eER) + # Check for custom commands + custom = custom_commands.is_custom_command(message) + + if custom.id is not None: + await message.channel.send(custom.response) + # Earn XP & Message count stats.sentMessage(message) diff --git a/cogs/modCommands.py b/cogs/modCommands.py index 70a6077..df65831 100644 --- a/cogs/modCommands.py +++ b/cogs/modCommands.py @@ -8,6 +8,8 @@ from functions.database import memes, githubs, twitch, dadjoke import json import os +from functions.database.custom_commands import is_name_free, add_command, add_alias + class ModCommands(commands.Cog): @@ -106,13 +108,35 @@ class ModCommands(commands.Cog): return await ctx.send("Ik kan geen bericht zien met dit Id.") await message.add_reaction(emoji) - # Adds stuff into their databases @commands.group(name="Add", usage="[Category] [Args]", case_insensitive=True, invoke_without_command=False) @commands.check(checks.isMe) @help.Category(category=Category.Mod) async def add(self, ctx): + """ + Commands group that adds database entries + """ pass + @add.command(name="Custom", usage="[Name] [Response]") + async def custom(self, ctx, name, *, resp): + err_msg = add_command(name, resp) + + # Something went wrong + if err_msg: + return await ctx.send(err_msg) + else: + await ctx.message.add_reaction("✅") + + @add.command(name="Alias", usage="[Name] [Alias]") + async def add_alias(self, ctx, command, alias): + err_msg = add_alias(command, alias) + + # Something went wrong + if err_msg: + return await ctx.send(err_msg) + else: + await ctx.message.add_reaction("✅") + @add.command(name="Dadjoke", aliases=["Dj", "Dad"], usage="[Joke]") async def dadjoke(self, ctx, *, joke): dadjoke.addJoke(joke) diff --git a/data/database_classes/__init__.py b/data/database_classes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data/database_classes/custom_commands.py b/data/database_classes/custom_commands.py new file mode 100644 index 0000000..8e1ffe8 --- /dev/null +++ b/data/database_classes/custom_commands.py @@ -0,0 +1,12 @@ +from attr import dataclass + + +@dataclass +class CustomCommand: + """ + Class to store custom commands being triggered + """ + id: int = None + name: str = None + response: str = None + alias_used: str = None diff --git a/databases.md b/databases.md index 1e42101..13fd533 100644 --- a/databases.md +++ b/databases.md @@ -40,6 +40,22 @@ Used in all Currency commands (Dinks, Bank, Bitcoin, Gambling, ...) 9 nightly: integer, default 0 | The timestamp when the user last claimed their Nightly 10 nightly_streak: integer, default 0 | The user's current Nightly Streak +### custom_commands + +Used to store custom commands that replace Dyno. + + 0 id: integer, auto-increment, unique, primary key | The id of the command + 1 name: text, unique | The name of the command + 2 response: text | The response sent when the command is used + +### custom_command_aliases + +Used to store aliases for custom commands. + + 0 id: integer, auto-increment, unique, primary key | The id of the alias + 2 command: integer | The id of the command this alias is for + 3 alias: text, unique | The name of the alias + ### dad_jokes Used in fun.py - Dadjoke command. diff --git a/files/help.json b/files/help.json index fd0100b..c80b9b3 100644 --- a/files/help.json +++ b/files/help.json @@ -2,6 +2,8 @@ "8ball": "Magic 8-Ball Didier beantwoordt ja/nee vragen.", "add": "Voegt [Args] toe aan [Categorie].", "add 8-ball": "Voegt een 8-Ball response toe aan de database.", + "add alias": "Voegt een alias voor custom commands toe aan de database.", + "add custom": "Voegt custom commands toe aan de database.", "add dadjoke": "Voegt een Dadjoke toe aan de database.", "add github": "Voegt iemand's GitHub link toe aan de database.", "add meme": "Voegt een meme toe aan de database.", diff --git a/functions/database/custom_commands.py b/functions/database/custom_commands.py new file mode 100644 index 0000000..ea8f172 --- /dev/null +++ b/functions/database/custom_commands.py @@ -0,0 +1,129 @@ +from data.database_classes.custom_commands import CustomCommand +import discord +from functions.database import utils + + +def is_custom_command(message: discord.Message) -> CustomCommand: + """ + Check if a message triggers a custom command + These use "?" as a prefix + """ + content = message.content + # Message didn't call a custom command + if not content.startswith("?"): + return CustomCommand() + + # Can't be invoked by bots to prevent spam (@RPS) + if message.author.bot: + return CustomCommand() + + # Ignore capitals & spaces, strip off prefix + content = content.lower().replace(" ", "")[1:] + + by_name = _find_by_name(content) + + # Command was found by its name + if by_name: + return CustomCommand(*by_name) + + # Check if a command exists with this alias instead + return CustomCommand(*_find_by_alias(content), alias_used=content) + + +def _find_by_name(message): + """ + Find a command by its name + """ + connection = utils.connect() + cursor = connection.cursor() + + cursor.execute("SELECT * FROM custom_commands WHERE name = %s", (message,)) + + return cursor.fetchone() + + +def _find_by_alias(message): + """ + Find a command by one of its aliases + """ + connection = utils.connect() + cursor = connection.cursor() + + cursor.execute("SELECT command FROM custom_command_aliases WHERE alias = %s", (message,)) + + res = cursor.fetchone() + + # No command matched this alias + if not res: + return () + + cursor.execute("SELECT * FROM custom_commands WHERE id = %s", (res,)) + + return cursor.fetchone() + + +def is_name_free(name) -> bool: + """ + Check if a name is already in use by a command + Includes aliases + """ + connection = utils.connect() + cursor = connection.cursor() + + cursor.execute("SELECT id from custom_commands WHERE name = %s", (name,)) + + if cursor.fetchone(): + return False + + cursor.execute("SELECT id FROM custom_command_aliases WHERE alias = %s", (name,)) + + return cursor.fetchone() is None + + +def _clean(inp: str): + """ + Strip markdown and other stuff out of a command name + """ + return "".join(filter(lambda x: x.isalnum(), inp)) + + +def add_command(name: str, response: str): + """ + Add a new custom command + """ + name = _clean(name.lower()) + + if not is_name_free(name): + return "Er is al een commando met deze naam." + + connection = utils.connect() + cursor = connection.cursor() + + cursor.execute("INSERT INTO custom_commands(name, response) VALUES (%s, E%s)", (name, response,)) + connection.commit() + + +def add_alias(command: str, alias: str): + """ + Add an alias for a command + Assumes the command exists + """ + command = _clean(command.lower()) + alias = _clean(alias.lower()) + + # Base command doesn't exist + if is_name_free(command): + return "Er is geen commando met deze naam." + + # Alias already exists + if not is_name_free(alias): + return "Er is al een commando met deze naam." + + # Find the id of the base command + command_id = CustomCommand(*_find_by_name(command)).id + + connection = utils.connect() + cursor = connection.cursor() + + cursor.execute("INSERT INTO custom_command_aliases(command, alias) VALUES(%s, %s)", (command_id, alias,)) + connection.commit()