From 3cfc87b7e1e980a690ed02fcbf551b674a011241 Mon Sep 17 00:00:00 2001 From: Stijn De Clercq Date: Mon, 17 May 2021 18:14:33 +0200 Subject: [PATCH 1/4] fetching from db & dataclass --- cogs/events.py | 7 ++- data/database_classes/__init__.py | 0 data/database_classes/custom_commands.py | 15 +++++ functions/database/custom_commands.py | 74 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 data/database_classes/__init__.py create mode 100644 data/database_classes/custom_commands.py create mode 100644 functions/database/custom_commands.py diff --git a/cogs/events.py b/cogs/events.py index 5c25224..77b51f9 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,11 @@ class Events(commands.Cog): if eER: await message.channel.send(eER) + # Check for custom commands + custom = custom_commands.is_custom_command(message.content) + if custom: + await message.channel.send(custom.response) + # Earn XP & Message count stats.sentMessage(message) 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..42421b5 --- /dev/null +++ b/data/database_classes/custom_commands.py @@ -0,0 +1,15 @@ +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 + + def __nonzero__(self): + return self.id is not None diff --git a/functions/database/custom_commands.py b/functions/database/custom_commands.py new file mode 100644 index 0000000..43e7240 --- /dev/null +++ b/functions/database/custom_commands.py @@ -0,0 +1,74 @@ +from data.database_classes.custom_commands import CustomCommand +from functions.database import utils + + +def is_custom_command(message: str) -> CustomCommand: + """ + Check if a message triggers a custom command + These use "?" as a prefix + """ + # Message didn't call a custom command + if not message.startswith("?"): + return CustomCommand() + + # Ignore capitals & spaces, strip off prefix + message = message.lower().replace(" ", "")[1:] + + by_name = _find_by_name(message) + + # 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(message), alias_used=message) + + +def _find_by_name(message): + """ + Find a command by its name + """ + connection = utils.connect() + cursor = connection.cursor() + + cursor.execute("SELECT response 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 response 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 command FROM custom_command_aliases WHERE alias = %s", name) + + return len(cursor.fetchone()) != 0 From 4bcd00826eb6663d522a85642bc11abd6e3571ca Mon Sep 17 00:00:00 2001 From: Stijn De Clercq Date: Mon, 17 May 2021 20:10:07 +0200 Subject: [PATCH 2/4] Adding commands, calling works --- cogs/events.py | 5 +- cogs/modCommands.py | 26 +++++++- data/database_classes/custom_commands.py | 3 - files/help.json | 2 + functions/database/custom_commands.py | 77 ++++++++++++++++++++---- 5 files changed, 96 insertions(+), 17 deletions(-) diff --git a/cogs/events.py b/cogs/events.py index 77b51f9..7cea495 100644 --- a/cogs/events.py +++ b/cogs/events.py @@ -76,8 +76,9 @@ class Events(commands.Cog): await message.channel.send(eER) # Check for custom commands - custom = custom_commands.is_custom_command(message.content) - if custom: + custom = custom_commands.is_custom_command(message) + + if custom.id is not None: await message.channel.send(custom.response) # Earn XP & Message count 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/custom_commands.py b/data/database_classes/custom_commands.py index 42421b5..8e1ffe8 100644 --- a/data/database_classes/custom_commands.py +++ b/data/database_classes/custom_commands.py @@ -10,6 +10,3 @@ class CustomCommand: name: str = None response: str = None alias_used: str = None - - def __nonzero__(self): - return self.id is not None 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 index 43e7240..ea8f172 100644 --- a/functions/database/custom_commands.py +++ b/functions/database/custom_commands.py @@ -1,27 +1,33 @@ from data.database_classes.custom_commands import CustomCommand +import discord from functions.database import utils -def is_custom_command(message: str) -> CustomCommand: +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 message.startswith("?"): + 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 - message = message.lower().replace(" ", "")[1:] + content = content.lower().replace(" ", "")[1:] - by_name = _find_by_name(message) + 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(message), alias_used=message) + return CustomCommand(*_find_by_alias(content), alias_used=content) def _find_by_name(message): @@ -31,7 +37,7 @@ def _find_by_name(message): connection = utils.connect() cursor = connection.cursor() - cursor.execute("SELECT response FROM custom_commands WHERE name = %s", message) + cursor.execute("SELECT * FROM custom_commands WHERE name = %s", (message,)) return cursor.fetchone() @@ -43,7 +49,7 @@ def _find_by_alias(message): connection = utils.connect() cursor = connection.cursor() - cursor.execute("SELECT command FROM custom_command_aliases WHERE alias = %s", message) + cursor.execute("SELECT command FROM custom_command_aliases WHERE alias = %s", (message,)) res = cursor.fetchone() @@ -51,7 +57,7 @@ def _find_by_alias(message): if not res: return () - cursor.execute("SELECT response FROM custom_commands WHERE id = %s", res) + cursor.execute("SELECT * FROM custom_commands WHERE id = %s", (res,)) return cursor.fetchone() @@ -64,11 +70,60 @@ def is_name_free(name) -> bool: connection = utils.connect() cursor = connection.cursor() - cursor.execute("SELECT id from custom_commands WHERE name = %s", name) + cursor.execute("SELECT id from custom_commands WHERE name = %s", (name,)) if cursor.fetchone(): return False - cursor.execute("SELECT command FROM custom_command_aliases WHERE alias = %s", name) + cursor.execute("SELECT id FROM custom_command_aliases WHERE alias = %s", (name,)) - return len(cursor.fetchone()) != 0 + 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() From 3cd2456bbf26f8df35e37083bdd280464a0d26a5 Mon Sep 17 00:00:00 2001 From: Stijn De Clercq Date: Mon, 17 May 2021 20:16:12 +0200 Subject: [PATCH 3/4] Add commands tables to databases.md --- databases.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/databases.md b/databases.md index 1e42101..b9f628f 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 | The name of the alias + ### dad_jokes Used in fun.py - Dadjoke command. From 92048bcd857f42fb7760ab608e07bb68a13beb9e Mon Sep 17 00:00:00 2001 From: Stijn De Clercq Date: Mon, 17 May 2021 20:19:29 +0200 Subject: [PATCH 4/4] Add unique constraint --- databases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/databases.md b/databases.md index b9f628f..13fd533 100644 --- a/databases.md +++ b/databases.md @@ -54,7 +54,7 @@ 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 | The name of the alias + 3 alias: text, unique | The name of the alias ### dad_jokes