From 9f86c20df4652a49779c1950cfc8acc7c75cb319 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 27 Oct 2023 10:40:18 -0400 Subject: [PATCH] feat(moderation): updated prisma_log (mysql_log) and get_next_case_number to use prisma, added get_next_global_case_number BREAKING: changed database schema --- moderation/moderation.py | 152 +++++++++++++++----------------- moderation/prisma/schema.prisma | 8 +- 2 files changed, 77 insertions(+), 83 deletions(-) diff --git a/moderation/moderation.py b/moderation/moderation.py index b01fea5..a696cb6 100644 --- a/moderation/moderation.py +++ b/moderation/moderation.py @@ -22,9 +22,9 @@ class Moderation(commands.Cog): database_provider = "sqlite", database_address= "file:moderation.db", database_port = " ", - database_name = "moderation", - database_username = "red", - database_password = "red" + database_name = " ", + database_username = " ", + database_password = " " ) self.config.register_guild( ignore_other_bots = True, @@ -110,67 +110,20 @@ class Moderation(commands.Cog): await self.mysql_log(entry.guild.id, entry.user.id, moderation_type, entry.target.id, duration, reason) async def connect(self): - """Connects to the MySQL database, and returns a connection object.""" - conf = await self.check_conf([ - 'mysql_address', - 'mysql_database', - 'mysql_username', - 'mysql_password' - ]) - if conf: - raise LookupError("MySQL connection details not set properly!") - try: - connection = mysql.connector.connect( - host=await self.config.mysql_address(), - user=await self.config.mysql_username(), - password=await self.config.mysql_password(), - database=await self.config.mysql_database() - ) - return connection - except mysql.connector.ProgrammingError as e: - self.logger.fatal("Unable to access the MySQL database!\nError:\n%s", e.msg) - raise ConnectionRefusedError(f"Unable to access the MySQL Database!\n{e.msg}") from e - - async def create_guild_table(self, guild: discord.Guild): - database = await self.connect() - cursor = database.cursor() - try: - cursor.execute(f"SELECT * FROM `moderation_{guild.id}`") - self.logger.info("MySQL Table exists for server %s (%s)", guild.name, guild.id) - except mysql.connector.errors.ProgrammingError: - query = f""" - CREATE TABLE `moderation_{guild.id}` ( - moderation_id INT UNIQUE PRIMARY KEY NOT NULL, - timestamp INT NOT NULL, - moderation_type LONGTEXT NOT NULL, - target_id LONGTEXT NOT NULL, - moderator_id LONGTEXT NOT NULL, - duration LONGTEXT, - end_timestamp INT, - reason LONGTEXT, - resolved BOOL NOT NULL, - resolved_by LONGTEXT, - resolve_reason LONGTEXT, - expired BOOL NOT NULL - ) - """ - cursor.execute(query) - index_query_1 = "CREATE INDEX idx_target_id ON moderation_%s(target_id(25));" - cursor.execute(index_query_1, (guild.id,)) - index_query_2 = "CREATE INDEX idx_moderator_id ON moderation_%s(moderator_id(25));" - cursor.execute(index_query_2, (guild.id,)) - index_query_3 = "CREATE INDEX idx_moderation_id ON moderation_%s(moderation_id);" - cursor.execute(index_query_3, (guild.id,)) - insert_query = f""" - INSERT INTO `moderation_{guild.id}` - (moderation_id, timestamp, moderation_type, target_id, moderator_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) - """ - insert_values = (0, 0, "NULL", 0, 0, "NULL", 0, "NULL", 0, "NULL", "NULL", 0) - cursor.execute(insert_query, insert_values) - database.commit() - self.logger.info("MySQL Table (moderation_%s) created for %s (%s)", guild.id, guild.name, guild.id) - database.close() + """Connects to the database, and returns a connection object.""" + provider = await self.config.database_provider() + address = await self.config.database_address() + if provider == "sqlite" and address == "file:moderation.db": + return await Prisma().connect() + else: + return await Prisma( + provider=provider, + address=address, + port=await self.config.database_port(), + database=await self.config.database_name(), + username=await self.config.database_username(), + password=await self.config.database_password() + ).connect() async def check_conf(self, config: list): """Checks if any required config options are not set.""" @@ -195,31 +148,70 @@ class Moderation(commands.Cog): return permission return False - async def mysql_log(self, guild_id: str, author_id: str, moderation_type: str, target_id: int, duration, reason: str): + async def prisma_log(self, guild_id: str, author_id: str, moderation_type: str, target_id: int, duration, reason: str, role_id = None): timestamp = int(time.time()) if duration != "NULL": end_timedelta = datetime.fromtimestamp(timestamp) + duration end_timestamp = int(end_timedelta.timestamp()) else: end_timestamp = 0 - database = await self.connect() - cursor = database.cursor() - moderation_id = await self.get_next_case_number(guild_id=guild_id, cursor=cursor) - sql = f"INSERT INTO `moderation_{guild_id}` (moderation_id, timestamp, moderation_type, target_id, moderator_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" - val = (moderation_id, timestamp, moderation_type, target_id, author_id, duration, end_timestamp, f"{reason}", 0, "NULL", "NULL", 0) - cursor.execute(sql, val) - database.commit() - database.close() - self.logger.debug("MySQL row inserted into moderation_%s!\n%s, %s, %s, %s, %s, %s, %s, %s, 0, NULL, NULL, 0", guild_id, moderation_id, timestamp, moderation_type, target_id, author_id, duration, end_timestamp, reason) + if not role_id: + role_id = "NULL" + db = await self.connect() + global_id = await self.get_next_global_case_number(database=db) + moderation_id = await self.get_next_case_number(guild_id=guild_id, database=db) + await db.Case.create( + data={ + 'globalId': global_id, + 'guildId': guild_id, + 'moderationId': moderation_id, + 'timestamp': timestamp, + 'moderationType': moderation_type, + 'targetId': target_id, + 'moderatorId': author_id, + 'roleId': role_id, + 'duration': duration, + 'endTimestamp': end_timestamp, + 'reason': reason, + 'resolved': False, + 'resolvedBy': None, + 'resolveReason': None, + 'expired': False + } + ) + await db.disconnect() return moderation_id - async def get_next_case_number(self, guild_id: str, cursor = None): - """This method returns the next case number from the MySQL table for a specific guild.""" - if not cursor: + async def get_next_case_number(self, guild_id: str, database = None): + """This method returns the next case number from the database table for a specific guild.""" + if not database: database = await self.connect() - cursor = database.cursor() - cursor.execute(f"SELECT moderation_id FROM `moderation_{guild_id}` ORDER BY moderation_id DESC LIMIT 1") - return cursor.fetchone()[0] + 1 + db_not_provided = True + else: + db_not_provided = False + result = await database.Case.find_first( + select={"moderationId": True}, + where={"guildId": guild_id}, + order=[{"moderationId": "desc"}], + ) + if db_not_provided: + await database.disconnect() + return result.moderationId + 1 if result else 1 + + async def get_next_global_case_number(self, database = None): + """This method returns the next case number from the database table.""" + if not database: + database = await self.connect() + db_not_provided = True + else: + db_not_provided = False + result = await database.Case.find_first( + select={"globalId": True}, + order=[{"globalId": "desc"}], + ) + if db_not_provided: + await database.disconnect() + return result.globalId + 1 if result else 1 def generate_dict(self, result): case: dict = { diff --git a/moderation/prisma/schema.prisma b/moderation/prisma/schema.prisma index 07d2fce..75629bb 100644 --- a/moderation/prisma/schema.prisma +++ b/moderation/prisma/schema.prisma @@ -9,8 +9,10 @@ generator client { recursive_type_depth = 5 } -model Moderation { - moderationId Int @id @unique +model Case { + globalId Int @id @unique + guildId BigInt + moderationId Int timestamp DateTime moderationType String targetId BigInt @@ -24,5 +26,5 @@ model Moderation { resolveReason String? expired Boolean - @@index([moderationId, targetId, moderatorId]) + @@index([guildId, moderationId, targetId, moderatorId]) }