From 0c28d362befefc213994cc157e7e1c5eaf33bd0f Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 15 Dec 2023 21:31:00 -0500 Subject: [PATCH] feat(moderation): added galacticbot importing --- moderation/moderation.py | 148 ++++++++++++++++++++++++++++++++------- 1 file changed, 124 insertions(+), 24 deletions(-) diff --git a/moderation/moderation.py b/moderation/moderation.py index bb87145..c9e0a9b 100644 --- a/moderation/moderation.py +++ b/moderation/moderation.py @@ -313,8 +313,9 @@ class Moderation(commands.Cog): return True - async def mysql_log(self, guild_id: str, author_id: str, moderation_type: str, target_id: int, role_id: int, duration, reason: str, database: mysql.connector.MySQLConnection = None): - timestamp = int(time.time()) + async def mysql_log(self, guild_id: str, author_id: str, moderation_type: str, target_id: int, role_id: int, duration, reason: str, database: mysql.connector.MySQLConnection = None, timestamp: int = None, resolved: bool = False, resolved_by: str = None, resolved_reason: str = None, expired: bool = None, changes: list = []): + if not timestamp: + timestamp = int(time.time()) if duration != "NULL": end_timedelta = datetime.fromtimestamp(timestamp) + duration @@ -322,21 +323,37 @@ class Moderation(commands.Cog): else: end_timestamp = 0 + if not expired: + if int(time.time()) > end_timestamp: + expired = 1 + else: + expired = 0 + + if resolved_by is None: + resolved_by = "NULL" + + if resolved_reason is None: + resolved_reason = "NULL" + if not database: database = await self.connect() + close_db = True + else: + close_db = False 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, role_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired, changes) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" - val = (moderation_id, timestamp, moderation_type, target_id, author_id, role_id, duration, end_timestamp, f"{reason}", 0, "NULL", "NULL", 0, json.dumps([])) + val = (moderation_id, timestamp, moderation_type, target_id, author_id, role_id, duration, end_timestamp, {reason}, int(resolved), resolved_by, resolved_reason, expired, json.dumps(changes)) cursor.execute(sql, val) cursor.close() database.commit() - database.close() + if close_db: + database.close() - self.logger.debug("MySQL row inserted into moderation_%s!\n%s, %s, %s, %s, %s, %s, %s, %s, %s, 0, NULL, NULL, 0, []", guild_id, moderation_id, timestamp, moderation_type, target_id, author_id, role_id, duration, end_timestamp, reason) + self.logger.debug("MySQL row inserted into moderation_%s!\n%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s", guild_id, moderation_id, timestamp, moderation_type, target_id, author_id, role_id, duration, end_timestamp, reason, int(resolved), resolved_by, resolved_reason, expired, changes) return moderation_id @@ -369,23 +386,31 @@ class Moderation(commands.Cog): async def fetch_user_dict(self, interaction: discord.Interaction, user_id: str): """This method returns a dictionary containing either user information or a standard deleted user template.""" - try: - user = interaction.client.get_user(user_id) - if user is None: - user = await interaction.client.fetch_user(user_id) - + if user_id == '?': user_dict = { - 'id': user.id, - 'name': user.name, - 'discriminator': user.discriminator + 'id': '?', + 'name': 'Unknown User', + 'discriminator':'0' } - except discord.errors.NotFound: - user_dict = { - 'id': user_id, - 'name': 'Deleted User', - 'discriminator': '0' - } + else: + try: + user = interaction.client.get_user(user_id) + if user is None: + user = await interaction.client.fetch_user(user_id) + + user_dict = { + 'id': user.id, + 'name': user.name, + 'discriminator': user.discriminator + } + + except discord.errors.NotFound: + user_dict = { + 'id': user_id, + 'name': 'Deleted User', + 'discriminator': '0' + } return user_dict @@ -1106,7 +1131,7 @@ class Moderation(commands.Cog): except discord.NotFound: pass - resolve_query = f"UPDATE `{db}`.`moderation_{interaction.guild.id}` SET resolved = 1, expired = 1, changes = %s, resolved_by = %s, resolve_reason = %s WHERE moderation_id = %s" + resolve_query = f"UPDATE `{db}`.`moderation_{interaction.guild.id}` SET resolved = 1, changes = %s, resolved_by = %s, resolve_reason = %s WHERE moderation_id = %s" else: resolve_query = f"UPDATE `{db}`.`moderation_{interaction.guild.id}` SET resolved = 1, changes = %s, resolved_by = %s, resolve_reason = %s WHERE moderation_id = %s" @@ -1641,23 +1666,98 @@ class Moderation(commands.Cog): @checks.admin() async def moderationset_import_galacticbot(self, ctx: commands.Context): """Import moderations from GalacticBot. **UNFINISHED!**""" - message = await ctx.send("Are you sure you want to import GalacticBot moderations? **This will overwrite any moderations that already exist in this guild's moderation table.**") - await message.edit(view=self.GalacticBotImportButtons(60, message)) + if ctx.message.attachments and ctx.message.attachments[0].content_type == 'application/json; charset=utf-8': + message = await ctx.send("Are you sure you want to import GalacticBot moderations? **This will overwrite any moderations that already exist in this guild's moderation table.**") + await message.edit(view=self.GalacticBotImportButtons(60, ctx, message, self)) + else: + await ctx.send("Please provide a valid GalacticBot moderation export file.") class GalacticBotImportButtons(discord.ui.View): - def __init__(self, timeout, message): + def __init__(self, timeout, ctx, message, cog_instance): super().__init__() + self.cog_instance = cog_instance + self.ctx: commands.Context = ctx self.message: discord.Message = message self.config = Config.get_conf(None, cog_name='Moderation', identifier=481923957134912) @discord.ui.button(label="Yes", style=discord.ButtonStyle.success) async def import_button_y(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument - await self.message.edit("This command does nothing at the moment.", view=None) + await self.message.delete() + await interaction.response.send_message("Deleting original table...", ephemeral=True) + + database = await Moderation.connect(self.cog_instance) + cursor = database.cursor() + + query = f"DROP TABLE IF EXISTS moderation_{self.ctx.guild.id};" + cursor.execute(query) + + cursor.close() + database.commit() + database.close() + + await interaction.edit_original_response(content="Creating new table...") + + await Moderation.create_guild_table(self.cog_instance, self.ctx.guild) + + await interaction.edit_original_response(content="Importing moderations...") + + accepted_types = [ + 'NOTE', + 'WARN', + 'MUTE', + 'UNMUTE', + 'KICK', + 'SOFTBAN', + 'BAN', + 'UNBAN' + ] + file = await self.ctx.message.attachments[0].read() + data = sorted(json.loads(file), key=lambda x: x['case']) + for case in data: + if case['type'] not in accepted_types: + continue + + timestamp = case['timestamp'] / 1000 + + if case['duration']: + duration = timedelta(milliseconds=case['duration']) + + if case['resolved']: + resolved = 1 + for change in case['changes']: + if change['type'] == 'RESOLVE': + resolved_by = change['staff'] + resolved_reason = change['reason'] + resolve_timestamp = change['timestamp'] / 1000 + break + if resolved_by is None: + resolved_by = '?' + if resolved_reason is None: + resolved_reason = 'Could not get resolve reason during moderation import.' + changes = [ + { + 'type': "ORIGINAL", + 'reason': case['reason'], + 'user_id': case['executor'], + 'timestamp': timestamp + }, + { + 'type': "RESOLVE", + 'reason': resolved_reason, + 'user_id': resolved_by, + 'timestamp': resolve_timestamp + } + ] + + await Moderation.mysql_log(self.cog_instance, self.ctx.guild, case['executor'], case['type'], case['target'], 0, duration, case['reason'], timestamp=timestamp, resolved=resolved, resolved_by=resolved_by, resolved_reason=resolved_reason, changes=changes) + + await interaction.edit_original_response(content="Import complete.") @discord.ui.button(label="No", style=discord.ButtonStyle.danger) async def import_button_n(self, interaction: discord.Interaction, button: discord.ui.Button): # pylint: disable=unused-argument await self.message.edit("Import cancelled.", view=None) await self.message.delete(10) + await self.ctx.message.delete(10) @commands.command(aliases=["tdc"]) async def timedeltaconvert(self, ctx: commands.Context, *, duration: str):