diff --git a/aurora/aurora.py b/aurora/aurora.py index 0cc9546..1572195 100644 --- a/aurora/aurora.py +++ b/aurora/aurora.py @@ -27,13 +27,13 @@ from aurora.menus.addrole import Addrole from aurora.menus.guild import Guild from aurora.menus.immune import Immune from aurora.menus.overrides import Overrides -from aurora.models import Moderation +from aurora.models import Change, Moderation from aurora.utilities.config import config, register_config from aurora.utilities.database import connect, create_guild_table, fetch_case, mysql_log from aurora.utilities.factory import addrole_embed, case_factory, changes_factory, evidenceformat_factory, guild_embed, immune_embed, message_factory, overrides_embed from aurora.utilities.json import dump, dumps from aurora.utilities.logger import logger -from aurora.utilities.utils import check_moddable, check_permissions, convert_timedelta_to_str, fetch_channel_dict, fetch_user_dict, generate_dict, get_footer_image, log, send_evidenceformat, timedelta_from_relativedelta +from aurora.utilities.utils import check_moddable, check_permissions, fetch_channel_dict, fetch_user_dict, generate_dict, get_footer_image, log, send_evidenceformat, timedelta_from_relativedelta class Aurora(commands.Cog): @@ -1490,107 +1490,77 @@ class Aurora(commands.Cog): return if case != 0: - parsed_time = None - case_dict = await fetch_case(case, interaction.guild.id) - if case_dict: - if duration: - parsed_time = parse_timedelta(duration) - if parsed_time is None: - await interaction.response.send_message( - error("Please provide a valid duration!"), ephemeral=True - ) - return - - end_timestamp = case_dict["timestamp"] + parsed_time.total_seconds() - - if case_dict["moderation_type"] == "MUTE": - if ( - time.time() - case_dict["timestamp"] - ) + parsed_time.total_seconds() > 2419200: - await interaction.response.send_message( - error( - "Please provide a duration that is less than 28 days from the initial moderation." - ) - ) - return - - try: - member = await interaction.guild.fetch_member( - case_dict["target_id"] - ) - - await member.timeout( - parsed_time, - reason=f"Case #{case:,} edited by {interaction.user.id}", - ) - except discord.NotFound: - pass - - changes: list = case_dict["changes"] - if len(changes) > 25: - await interaction.response.send_message( + moderation = Moderation.from_sql(interaction.client, case, interaction.guild.id) + old_moderation = moderation + if moderation: + if len(moderation.changes) > 25: + return await interaction.response.send_message( content=error( "Due to limitations with Discord's embed system, you cannot edit a case more than 25 times." ), ephemeral=True, ) - return - if not changes: - changes.append( - { - "type": "ORIGINAL", - "timestamp": case_dict["timestamp"], - "reason": case_dict["reason"], - "user_id": case_dict["moderator_id"], - "duration": case_dict["duration"], - "end_timestamp": case_dict["end_timestamp"], - } - ) - if parsed_time: - changes.append( - { + if duration: + moderation.duration = parse_timedelta(duration) + if moderation.duration is None: + return await interaction.response.send_message( + error("Please provide a valid duration!"), ephemeral=True + ) + + moderation.end_timestamp = moderation.timestamp + moderation.duration.total_seconds() + + if moderation.type == "MUTE": + if ( + time.time() - moderation.unix_timestamp + ) + moderation.duration.total_seconds() > 2419200: + return await interaction.response.send_message( + error( + "Please provide a duration that is less than 28 days from the initial moderation." + ) + ) + + try: + member = await interaction.guild.fetch_member( + moderation.target_id + ) + + await member.timeout( + moderation.duration, + reason=f"Case #{case:,} edited by {interaction.user.id}", + ) + except discord.NotFound: + pass + + if not moderation.changes: + moderation.changes.append(Change.from_dict(interaction.client, { + "type": "ORIGINAL", + "timestamp": old_moderation.timestamp, + "reason": old_moderation.reason, + "user_id": old_moderation.moderator_id, + "duration": old_moderation.duration, + "end_timestamp": old_moderation.end_timestamp, + })) + if duration: + moderation.changes.append(Change.from_dict(interaction.client, { "type": "EDIT", "timestamp": int(time.time()), "reason": reason, "user_id": interaction.user.id, - "duration": convert_timedelta_to_str(parsed_time), - "end_timestamp": end_timestamp, - } - ) + "duration": moderation.duration, + "end_timestamp": moderation.end_timestamp, + })) else: - changes.append( - { + moderation.changes.append(Change.from_dict(interaction.client, { "type": "EDIT", "timestamp": int(time.time()), "reason": reason, "user_id": interaction.user.id, - "duration": case_dict["duration"], - "end_timestamp": case_dict["end_timestamp"], - } - ) + "duration": moderation.duration, + "end_timestamp": moderation.end_timestamp, + })) - database = connect() - cursor = database.cursor() - - if parsed_time: - update_query = f"UPDATE `moderation_{interaction.guild.id}` SET changes = ?, reason = ?, duration = ?, end_timestamp = ? WHERE moderation_id = ?" - cursor.execute( - update_query, - ( - dumps(changes), - reason, - convert_timedelta_to_str(parsed_time), - end_timestamp, - case, - ), - ) - else: - update_query = f"UPDATE `moderation_{interaction.guild.id}` SET changes = ?, reason = ? WHERE moderation_id = ?" - cursor.execute(update_query, (dumps(changes), reason, case)) - database.commit() - - new_case = await fetch_case(case, interaction.guild.id) - embed = await case_factory(interaction=interaction, case_dict=new_case) + moderation.update() + embed = await case_factory(interaction=interaction, moderation=moderation) await interaction.response.send_message( content=f"✅ Moderation #{case:,} edited!", @@ -1599,8 +1569,6 @@ class Aurora(commands.Cog): ) await log(interaction, case) - cursor.close() - database.close() return await interaction.response.send_message( content=error(f"No case with case number `{case}` found."), ephemeral=True diff --git a/aurora/models.py b/aurora/models.py index f00f0b5..dad4028 100644 --- a/aurora/models.py +++ b/aurora/models.py @@ -77,6 +77,16 @@ class Moderation(AuroraGuildModel): def __str__(self): return f"{self.moderation_type} {self.target_type} {self.target_id} {self.reason}" + def update(self): + from aurora.utilities.database import connect + query = f"UPDATE moderation_{self.guild_id} SET timestamp = ?, moderation_type = ?, target_type = ?, moderator_id = ?, role_id = ?, duration = ?, end_timestamp = ?, reason = ?, resolved = ?, resolved_by = ?, resolve_reason = ?, expired = ?, changes = ?, metadata = ? WHERE moderation_id = ?;" + changes = [change.to_json() for change in self.changes] + + with connect() as database: + cursor = database.cursor() + cursor.execute(query, (self.timestamp, self.moderation_type, self.target_type, self.moderator_id, self.role_id, self.duration, self.end_timestamp, self.reason, self.resolved, self.resolved_by, self.resolve_reason, self.expired, changes, self.metadata, self.moderation_id)) + cursor.close() + @classmethod def from_sql(cls, bot: Red, moderation_id: int, guild_id: int) -> Optional["Moderation"]: from aurora.utilities.database import connect @@ -118,14 +128,29 @@ class Change(AuroraBaseModel): @classmethod def from_dict(cls, bot: Red, data: dict) -> "Change": - if "duration" in data and data["duration"] is not None: + if "duration" in data and data["duration"] and not isinstance(data["duration"], timedelta): hours, minutes, seconds = map(int, data["duration"].split(':')) duration = timedelta(hours=hours, minutes=minutes, seconds=seconds) + elif duration in data and isinstance(data["duration"], timedelta): + duration = data["duration"] else: duration = None + + if "end_timestamp" in data and data["end_timestamp"] and not isinstance(data["end_timestamp"], datetime): + end_timestamp = datetime.fromtimestamp(data["end_timestamp"]) + elif "end_timestamp" in data and isinstance(data["end_timestamp"], datetime): + end_timestamp = data["end_timestamp"] + else: + end_timestamp = None + + if not isinstance(data["timestamp"], datetime): + timestamp = datetime.fromtimestamp(data["timestamp"]) + else: + timestamp = data["timestamp"] + data.update({ - "timestamp": datetime.fromtimestamp(data["timestamp"]), - "end_timestamp": datetime.fromtimestamp(data["end_timestamp"]) if "end_timestamp" in data and data["end_timestamp"] else None, + "timestamp": timestamp, + "end_timestamp": end_timestamp, "duration": duration }) return cls(bot=bot, **data)