diff --git a/aurora/aurora.py b/aurora/aurora.py index 9f68a28..405372d 100644 --- a/aurora/aurora.py +++ b/aurora/aurora.py @@ -24,7 +24,7 @@ from .importers.galacticbot import ImportGalacticBotView from .importers.aurora import ImportAuroraView from .utilities.config import config, register_config from .utilities.database import connect, create_guild_table, fetch_case, mysql_log -from .utilities.embed_factory import embed_factory +from .utilities.factory import case_factory, changes_factory, evidenceformat_factory, message_factory from .utilities.logger import logger from .utilities.utils import convert_timedelta_to_str, check_moddable, check_permissions, fetch_channel_dict, fetch_user_dict, generate_dict, log, send_evidenceformat @@ -35,7 +35,7 @@ class Aurora(commands.Cog): This cog stores all of its data in an SQLite database.""" __author__ = "SeaswimmerTheFsh" - __version__ = "2.0.0" + __version__ = "2.0.2" async def red_delete_data_for_user(self, *, requester, user_id: int): if requester == "discord_deleted_user": @@ -162,7 +162,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='note', response=await interaction.original_response()) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='note', response=await interaction.original_response()) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -195,7 +195,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='warned', response=await interaction.original_response()) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='warned', response=await interaction.original_response()) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -251,7 +251,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='blacklisted', response=await interaction.original_response(), duration=matching_role['duration']) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='blacklisted', response=await interaction.original_response(), duration=matching_role['duration']) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -306,7 +306,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='muted', response=await interaction.original_response(), duration=parsed_time) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='muted', response=await interaction.original_response(), duration=parsed_time) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -349,7 +349,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='unmuted', response=await interaction.original_response()) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='unmuted', response=await interaction.original_response()) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -382,7 +382,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='kicked', response=await interaction.original_response()) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='kicked', response=await interaction.original_response()) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -445,7 +445,7 @@ class Aurora(commands.Cog): await interaction.response.send_message(content=f"{target.mention} has been banned for {humanize.precisedelta(parsed_time)}!\n**Reason** - `{reason}`") try: - embed = await embed_factory('message', await self.bot.get_embed_color(None) , guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='tempbanned', response=await interaction.original_response(), duration=parsed_time) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel) , guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='tempbanned', response=await interaction.original_response(), duration=parsed_time) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -465,7 +465,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='banned', response=await interaction.original_response()) + embed = embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='banned', response=await interaction.original_response()) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -512,7 +512,7 @@ class Aurora(commands.Cog): silent = not await config.guild(interaction.guild).dm_users() if silent is False: try: - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='unbanned', response=await interaction.original_response()) + embed = await message_factory(await self.bot.get_embed_color(interaction.channel), guild=interaction.guild, moderator=interaction.user, reason=reason, moderation_type='unbanned', response=await interaction.original_response()) await target.send(embed=embed) except discord.errors.HTTPException: pass @@ -585,11 +585,16 @@ class Aurora(commands.Cog): results = cursor.fetchall() + cases = [] + for result in results: + case = dict(result) + cases.append(case) + try: filename = str(data_manager.cog_data_path(cog_instance=self)) + str(os.sep) + f"moderation_{interaction.guild.id}.json" with open(filename, "w", encoding="utf-8") as f: - json.dump(results, f, indent=2) + json.dump(cases, f, indent=2) await interaction.followup.send(file=discord.File(filename, f"moderation_{interaction.guild.id}.json"), ephemeral=ephemeral) @@ -634,7 +639,7 @@ class Aurora(commands.Cog): start_index = (page - 1) * pagesize end_index = page * pagesize - embed = discord.Embed(color=await self.bot.get_embed_color(None)) + embed = discord.Embed(color=await self.bot.get_embed_color(interaction.channel)) embed.set_author(icon_url=interaction.guild.icon.url, name='Infraction History') embed.set_footer(text=f"Page {page:,}/{page_quantity:,} | {case_quantity:,} Results") @@ -765,7 +770,7 @@ class Aurora(commands.Cog): cursor.execute(resolve_query, (json.dumps(changes), interaction.user.id, reason, case_dict['moderation_id'])) database.commit() - embed = await embed_factory('case', await self.bot.get_embed_color(None), interaction=interaction, case_dict=await fetch_case(case, interaction.guild.id)) + embed = await case_factory(interaction=interaction, case_dict=await fetch_case(case, interaction.guild.id)) await interaction.response.send_message(content=f"✅ Moderation #{case:,} resolved!", embed=embed) await log(interaction, case, resolved=True) @@ -822,13 +827,13 @@ class Aurora(commands.Cog): await interaction.response.send_message(content=box({json.dumps(case_dict, indent=2)}), ephemeral=ephemeral) return if changes: - embed = await embed_factory('changes', await self.bot.get_embed_color(None), interaction=interaction, case_dict=case_dict) + embed = await changes_factory(interaction=interaction, case_dict=case_dict) await interaction.response.send_message(embed=embed, ephemeral=ephemeral) elif evidenceformat: - content = await embed_factory('evidenceformat', await self.bot.get_embed_color(None), interaction=interaction, case_dict=case_dict) + content = await evidenceformat_factory(interaction=interaction, case_dict=case_dict) await interaction.response.send_message(content=content, ephemeral=ephemeral) else: - embed = await embed_factory('case', await self.bot.get_embed_color(None), interaction=interaction, case_dict=case_dict) + embed = await case_factory(interaction=interaction, case_dict=case_dict) await interaction.response.send_message(embed=embed, ephemeral=ephemeral) return await interaction.response.send_message(content=f"No case with case number `{case}` found.", ephemeral=True) @@ -925,7 +930,7 @@ class Aurora(commands.Cog): database.commit() new_case = await fetch_case(case, interaction.guild.id) - embed = await embed_factory('case', await self.bot.get_embed_color(None), interaction=interaction, case_dict=new_case) + embed = await case_factory(interaction=interaction, case_dict=new_case) await interaction.response.send_message(content=f"✅ Moderation #{case:,} edited!", embed=embed, ephemeral=True) await log(interaction, case) @@ -965,7 +970,7 @@ class Aurora(commands.Cog): try: await guild.unban(user, reason=f"Automatic unban from case #{moderation_id}") - embed = await embed_factory('message', await self.bot.get_embed_color(None), guild=guild, reason=f'Automatic unban from case #{moderation_id}', moderation_type='unbanned') + embed = await message_factory(await self.bot.get_embed_color(guild.channels[0]), guild=guild, reason=f'Automatic unban from case #{moderation_id}', moderation_type='unbanned') try: await user.send(embed=embed) @@ -1040,7 +1045,7 @@ class Aurora(commands.Cog): for setting in user_settings: user_settings_string += f"**{setting}**: {user_settings[setting]}\n" - embed = discord.Embed(color=await self.bot.get_embed_color(None)) + embed = discord.Embed(color=await self.bot.get_embed_color(ctx.channel)) embed.set_author(icon_url=ctx.guild.icon.url, name=f"{ctx.guild.name} Moderation Settings") if ctx.guild: embed.add_field(name="Guild Settings", value=guild_settings_string) @@ -1206,7 +1211,7 @@ class Aurora(commands.Cog): if role: role_list += f"{role.mention}\n" if role_list: - embed = discord.Embed(title="Immune Roles", description=role_list, color=await self.bot.get_embed_color(None)) + embed = discord.Embed(title="Immune Roles", description=role_list, color=await self.bot.get_embed_color(ctx.channel)) await ctx.send(embed=embed) @auroraset.group(autohelp=True, name='blacklist') @@ -1266,7 +1271,7 @@ class Aurora(commands.Cog): if role: blacklist_list += f"{role.mention} - {blacklist_role['duration']}\n" if blacklist_list: - embed = discord.Embed(title="Blacklist Types", description=blacklist_list, color=await self.bot.get_embed_color(None)) + embed = discord.Embed(title="Blacklist Types", description=blacklist_list, color=await self.bot.get_embed_color(ctx.channel)) await ctx.send(embed=embed) @auroraset.command(name="ignorebots") diff --git a/aurora/utilities/embed_factory.py b/aurora/utilities/embed_factory.py deleted file mode 100644 index 61b0f21..0000000 --- a/aurora/utilities/embed_factory.py +++ /dev/null @@ -1,214 +0,0 @@ -# pylint: disable=cyclic-import - -from typing import Union -from datetime import datetime, timedelta - -import humanize -from discord import Color, Embed, Guild, Interaction, InteractionMessage, User, Member -from redbot.core.utils.chat_formatting import box - -from .config import config -from .utils import fetch_channel_dict, fetch_user_dict, get_next_case_number - - -async def embed_factory(embed_type: str, color: Color, /, interaction: Interaction = None, case_dict: dict = None, guild: Guild = None, reason: str = None, moderator: Union[Member, User] = None, moderation_type: str = None, response: InteractionMessage = None, duration: timedelta = None, resolved: bool = False): - """This method creates an embed from set parameters, meant for either moderation logging or contacting the moderated user. - - Valid arguments for 'embed_type': - - 'message' - - 'log' - - 'case' - - 'changes' - - Required arguments for 'message': - - color - - guild - - reason - - moderation_type - - moderator (optional) - - duration (optional) - - Required arguments for 'log': - - interaction - - case_dict - - resolved (optional) - - Required arguments for 'case', 'changes', and `evidenceformat`: - - interaction - - case_dict""" - if embed_type == 'message': - - if moderation_type in ["kicked", "banned", "tempbanned", "unbanned"]: - guild_name = guild.name - else: - guild_name = f"[{guild.name}]({response.jump_url})" - - if moderation_type in ["tempbanned", "muted"] and duration: - embed_duration = f" for {humanize.precisedelta(duration)}" - else: - embed_duration = "" - - if moderation_type == "note": - embed_desc = "received a" - else: - embed_desc = "been" - - embed = Embed(title=str.title(moderation_type), description=f"You have {embed_desc} {moderation_type}{embed_duration} in {guild_name}.", color=color, timestamp=datetime.now()) - - if await config.guild(guild).show_moderator() and moderator is not None: - embed.add_field(name='Moderator', value=f"`{moderator.name} ({moderator.id})`", inline=False) - - embed.add_field(name='Reason', value=f"`{reason}`", inline=False) - - if guild.icon.url is not None: - embed.set_author(name=guild.name, icon_url=guild.icon.url) - else: - embed.set_author(name=guild.name) - - embed.set_footer(text=f"Case #{await get_next_case_number(guild.id):,}", icon_url="https://cdn.discordapp.com/attachments/1070822161389994054/1159469476773904414/arrow-right-circle-icon-512x512-2p1e2aaw.png?ex=65312319&is=651eae19&hm=3cebdd28e805c13a79ec48ef87c32ca532ffa6b9ede2e48d0cf8e5e81f3a6818&") - - return embed - - if embed_type == 'case': - if case_dict['target_type'] == 'USER': - target_user = await fetch_user_dict(interaction, case_dict['target_id']) - target_name = f"`{target_user['name']}`" if target_user['discriminator'] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`" - elif case_dict['target_type'] == 'CHANNEL': - target_user = await fetch_channel_dict(interaction, case_dict['target_id']) - if target_user['mention']: - target_name = f"{target_user['mention']}" - else: - target_name = f"`{target_user['name']}`" - - moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) - moderator_name = f"`{moderator_user['name']}`" if moderator_user['discriminator'] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`" - - embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,}", color=color) - embed.description = f"**Type:** {str.title(case_dict['moderation_type'])}\n**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})\n**Resolved:** {bool(case_dict['resolved'])}\n**Timestamp:** | " - - if case_dict['duration'] != 'NULL': - td = timedelta(**{unit: int(val) for unit, val in zip(["hours", "minutes", "seconds"], case_dict["duration"].split(":"))}) - duration_embed = f"{humanize.precisedelta(td)} | " if bool(case_dict['expired']) is False else str(humanize.precisedelta(td)) - embed.description += f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}" - - embed.description += f"\n**Changes:** {len(case_dict['changes']) - 1}" if case_dict['changes'] else "\n**Changes:** 0" - - if case_dict['metadata']: - if case_dict['metadata']['imported_from']: - embed.description += f"\n**Imported From:** {case_dict['metadata']['imported_from']}" - - embed.add_field(name='Reason', value=box(case_dict['reason']), inline=False) - - if case_dict['resolved'] == 1: - resolved_user = await fetch_user_dict(interaction, case_dict['resolved_by']) - resolved_name = f"`{resolved_user['name']}`" if resolved_user['discriminator'] == "0" else f"`{resolved_user['name']}#{resolved_user['discriminator']}`" - embed.add_field(name='Resolve Reason', value=f"Resolved by {resolved_name} ({resolved_user['id']}) for:\n{box}{case_dict['resolve_reason']}", inline=False) - - return embed - - if embed_type == 'changes': - embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,} Changes", color=color) - - memory_dict = {} - - if case_dict['changes']: - for change in case_dict['changes']: - if change['user_id'] not in memory_dict: - memory_dict[str(change['user_id'])] = await fetch_user_dict(interaction, change['user_id']) - - user = memory_dict[str(change['user_id'])] - name = user['name'] if user['discriminator'] == "0" else f"{user['name']}#{user['discriminator']}" - - timestamp = f" | " - - if change['type'] == 'ORIGINAL': - embed.add_field(name='Original', value=f"**User:** `{name}` ({user['id']})\n**Reason:** {change['reason']}\n**Timestamp:** {timestamp}", inline=False) - - elif change['type'] == 'EDIT': - embed.add_field(name='Edit', value=f"**User:** `{name}` ({user['id']})\n**Reason:** {change['reason']}\n**Timestamp:** {timestamp}", inline=False) - - elif change['type'] == 'RESOLVE': - embed.add_field(name='Resolve', value=f"**User:** `{name}` ({user['id']})\n**Reason:** {change['reason']}\n**Timestamp:** {timestamp}", inline=False) - - else: - embed.description = "*No changes have been made to this case.* 🙁" - - return embed - - if embed_type == 'evidenceformat': - if case_dict['target_type'] == 'USER': - target_user = await fetch_user_dict(interaction, case_dict['target_id']) - target_name = target_user['name'] if target_user['discriminator'] == "0" else f"{target_user['name']}#{target_user['discriminator']}" - - elif case_dict['target_type'] == 'CHANNEL': - target_user = await fetch_channel_dict(interaction, case_dict['target_id']) - target_name = target_user['name'] - - moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) - moderator_name = moderator_user['name'] if moderator_user['discriminator'] == "0" else f"{moderator_user['name']}#{moderator_user['discriminator']}" - - content = f"Case: {case_dict['moderation_id']:,} ({str.title(case_dict['moderation_type'])})\nTarget: {target_name} ({target_user['id']})\nModerator: {moderator_name} ({moderator_user['id']})" - - if case_dict['duration'] != 'NULL': - hours, minutes, seconds = map(int, case_dict['duration'].split(':')) - td = timedelta(hours=hours, minutes=minutes, seconds=seconds) - content += f"\nDuration: {humanize.precisedelta(td)}" - - content += f"\nReason: {case_dict['reason']}" - - return box(content, 'prolog') - - if embed_type == 'log': - if resolved: - if case_dict['target_type'] == 'USER': - target_user = await fetch_user_dict(interaction, case_dict['target_id']) - target_name = f"`{target_user['name']}`" if target_user['discriminator'] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`" - elif case_dict['target_type'] == 'CHANNEL': - target_user = await fetch_channel_dict(interaction, case_dict['target_id']) - if target_user['mention']: - target_name = f"{target_user['mention']}" - else: - target_name = f"`{target_user['name']}`" - - moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) - moderator_name = f"`{moderator_user['name']}`" if moderator_user['discriminator'] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`" - - embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,} Resolved", color=color) - - embed.description = f"**Type:** {str.title(case_dict['moderation_type'])}\n**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})\n**Timestamp:** | " - - if case_dict['duration'] != 'NULL': - td = timedelta(**{unit: int(val) for unit, val in zip(["hours", "minutes", "seconds"], case_dict["duration"].split(":"))}) - duration_embed = f"{humanize.precisedelta(td)} | " if case_dict["expired"] == '0' else str(humanize.precisedelta(td)) - embed.description = embed.description + f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}" - - embed.add_field(name='Reason', value=box(case_dict['reason']), inline=False) - - resolved_user = await fetch_user_dict(interaction, case_dict['resolved_by']) - resolved_name = resolved_user['name'] if resolved_user['discriminator'] == "0" else f"{resolved_user['name']}#{resolved_user['discriminator']}" - embed.add_field(name='Resolve Reason', value=f"Resolved by {resolved_name} ({resolved_user['id']}) for:\n" + box(case_dict['resolve_reason']), inline=False) - else: - if case_dict['target_type'] == 'USER': - target_user = await fetch_user_dict(interaction, case_dict['target_id']) - target_name = f"`{target_user['name']}`" if target_user['discriminator'] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`" - elif case_dict['target_type'] == 'CHANNEL': - target_user = await fetch_channel_dict(interaction, case_dict['target_id']) - if target_user['mention']: - target_name = target_user['mention'] - else: - target_name = f"`{target_user['name']}`" - - moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) - moderator_name = f"`{moderator_user['name']}`" if moderator_user['discriminator'] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`" - - embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,}", color=color) - embed.description = f"**Type:** {str.title(case_dict['moderation_type'])}\n**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})\n**Timestamp:** | " - - if case_dict['duration'] != 'NULL': - td = timedelta(**{unit: int(val) for unit, val in zip(["hours", "minutes", "seconds"], case_dict["duration"].split(":"))}) - embed.description = embed.description + f"\n**Duration:** {humanize.precisedelta(td)} | " - - embed.add_field(name='Reason', value=box(case_dict['reason']), inline=False) - return embed - - raise(TypeError("'type' argument is invalid!")) diff --git a/aurora/utilities/factory.py b/aurora/utilities/factory.py new file mode 100644 index 0000000..02dbc99 --- /dev/null +++ b/aurora/utilities/factory.py @@ -0,0 +1,225 @@ +# pylint: disable=cyclic-import + +from typing import Union +from datetime import datetime, timedelta + +import humanize +from discord import Color, Embed, Guild, Interaction, InteractionMessage, User, Member +from redbot.core.utils.chat_formatting import box + +from .config import config +from .utils import fetch_channel_dict, fetch_user_dict, get_next_case_number + + +async def message_factory(color: Color, guild: Guild, reason: str, moderation_type: str, moderator: Union[Member, User] = None, duration: timedelta = None, response: InteractionMessage = None) -> Embed: + """This function creates a message from set parameters, meant for contacting the moderated user. + + Args: + color (Color): The color of the embed. + guild (Guild): The guild the moderation occurred in. + reason (str): The reason for the moderation. + moderation_type (str): The type of moderation. + moderator (Union[Member, User], optional): The moderator who performed the moderation. Defaults to None. + duration (timedelta, optional): The duration of the moderation. Defaults to None. + response (InteractionMessage, optional): The response message. Defaults to None. + + Returns: + embed: The message embed. + """ + if response is not None and not moderation_type in ["kicked", "banned", "tempbanned", "unbanned"]: + guild_name = f"[{guild.name}]({response.jump_url})" + else: + guild_name = guild.name + + if moderation_type in ["tempbanned", "muted"] and duration: + embed_duration = f" for {humanize.precisedelta(duration)}" + else: + embed_duration = "" + + if moderation_type == "note": + embed_desc = "received a" + else: + embed_desc = "been" + + embed = Embed(title=str.title(moderation_type), description=f"You have {embed_desc} {moderation_type}{embed_duration} in {guild_name}.", color=color, timestamp=datetime.now()) + + if await config.guild(guild).show_moderator() and moderator is not None: + embed.add_field(name='Moderator', value=f"`{moderator.name} ({moderator.id})`", inline=False) + + embed.add_field(name='Reason', value=f"`{reason}`", inline=False) + + if guild.icon.url is not None: + embed.set_author(name=guild.name, icon_url=guild.icon.url) + else: + embed.set_author(name=guild.name) + + embed.set_footer(text=f"Case #{await get_next_case_number(guild.id):,}", icon_url="https://cdn.discordapp.com/attachments/1070822161389994054/1159469476773904414/arrow-right-circle-icon-512x512-2p1e2aaw.png?ex=65312319&is=651eae19&hm=3cebdd28e805c13a79ec48ef87c32ca532ffa6b9ede2e48d0cf8e5e81f3a6818&") + + return embed + +async def log_factory(interaction: Interaction, case_dict: dict, resolved: bool = False) -> Embed: + """This function creates a log embed from set parameters, meant for moderation logging. + + Args: + interaction (Interaction): The interaction object. + case_dict (dict): The case dictionary. + resolved (bool, optional): Whether the case is resolved or not. Defaults to False. + """ + if resolved: + if case_dict['target_type'] == 'USER': + target_user = await fetch_user_dict(interaction, case_dict['target_id']) + target_name = f"`{target_user['name']}`" if target_user['discriminator'] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`" + elif case_dict['target_type'] == 'CHANNEL': + target_user = await fetch_channel_dict(interaction, case_dict['target_id']) + if target_user['mention']: + target_name = f"{target_user['mention']}" + else: + target_name = f"`{target_user['name']}`" + + moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) + moderator_name = f"`{moderator_user['name']}`" if moderator_user['discriminator'] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`" + + embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,} Resolved", color=await interaction.client.get_embed_color(interaction.channel)) + + embed.description = f"**Type:** {str.title(case_dict['moderation_type'])}\n**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})\n**Timestamp:** | " + + if case_dict['duration'] != 'NULL': + td = timedelta(**{unit: int(val) for unit, val in zip(["hours", "minutes", "seconds"], case_dict["duration"].split(":"))}) + duration_embed = f"{humanize.precisedelta(td)} | " if case_dict["expired"] == '0' else str(humanize.precisedelta(td)) + embed.description = embed.description + f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}" + + embed.add_field(name='Reason', value=box(case_dict['reason']), inline=False) + + resolved_user = await fetch_user_dict(interaction, case_dict['resolved_by']) + resolved_name = resolved_user['name'] if resolved_user['discriminator'] == "0" else f"{resolved_user['name']}#{resolved_user['discriminator']}" + embed.add_field(name='Resolve Reason', value=f"Resolved by `{resolved_name}` ({resolved_user['id']}) for:\n" + box(case_dict['resolve_reason']), inline=False) + else: + if case_dict['target_type'] == 'USER': + target_user = await fetch_user_dict(interaction, case_dict['target_id']) + target_name = f"`{target_user['name']}`" if target_user['discriminator'] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`" + elif case_dict['target_type'] == 'CHANNEL': + target_user = await fetch_channel_dict(interaction, case_dict['target_id']) + if target_user['mention']: + target_name = target_user['mention'] + else: + target_name = f"`{target_user['name']}`" + + moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) + moderator_name = f"`{moderator_user['name']}`" if moderator_user['discriminator'] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`" + + embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,}", color=await interaction.client.get_embed_color(interaction.channel)) + embed.description = f"**Type:** {str.title(case_dict['moderation_type'])}\n**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})\n**Timestamp:** | " + + if case_dict['duration'] != 'NULL': + td = timedelta(**{unit: int(val) for unit, val in zip(["hours", "minutes", "seconds"], case_dict["duration"].split(":"))}) + embed.description = embed.description + f"\n**Duration:** {humanize.precisedelta(td)} | " + + embed.add_field(name='Reason', value=box(case_dict['reason']), inline=False) + return embed + +async def case_factory(interaction: Interaction, case_dict: dict) -> Embed: + """This function creates a case embed from set parameters. + + Args: + interaction (Interaction): The interaction object. + case_dict (dict): The case dictionary. + """ + if case_dict['target_type'] == 'USER': + target_user = await fetch_user_dict(interaction, case_dict['target_id']) + target_name = f"`{target_user['name']}`" if target_user['discriminator'] == "0" else f"`{target_user['name']}#{target_user['discriminator']}`" + elif case_dict['target_type'] == 'CHANNEL': + target_user = await fetch_channel_dict(interaction, case_dict['target_id']) + if target_user['mention']: + target_name = f"{target_user['mention']}" + else: + target_name = f"`{target_user['name']}`" + + moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) + moderator_name = f"`{moderator_user['name']}`" if moderator_user['discriminator'] == "0" else f"`{moderator_user['name']}#{moderator_user['discriminator']}`" + + embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,}", color=await interaction.client.get_embed_color(interaction.channel)) + embed.description = f"**Type:** {str.title(case_dict['moderation_type'])}\n**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})\n**Resolved:** {bool(case_dict['resolved'])}\n**Timestamp:** | " + + if case_dict['duration'] != 'NULL': + td = timedelta(**{unit: int(val) for unit, val in zip(["hours", "minutes", "seconds"], case_dict["duration"].split(":"))}) + duration_embed = f"{humanize.precisedelta(td)} | " if bool(case_dict['expired']) is False else str(humanize.precisedelta(td)) + embed.description += f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}" + + embed.description += f"\n**Changes:** {len(case_dict['changes']) - 1}" if case_dict['changes'] else "\n**Changes:** 0" + + if case_dict['metadata']: + if case_dict['metadata']['imported_from']: + embed.description += f"\n**Imported From:** {case_dict['metadata']['imported_from']}" + + embed.add_field(name='Reason', value=box(case_dict['reason']), inline=False) + + if case_dict['resolved'] == 1: + resolved_user = await fetch_user_dict(interaction, case_dict['resolved_by']) + resolved_name = f"`{resolved_user['name']}`" if resolved_user['discriminator'] == "0" else f"`{resolved_user['name']}#{resolved_user['discriminator']}`" + embed.add_field(name='Resolve Reason', value=f"Resolved by {resolved_name} ({resolved_user['id']}) for:\n{box(case_dict['resolve_reason'])}", inline=False) + + return embed + +async def changes_factory(interaction: Interaction, case_dict: dict) -> Embed: + """This function creates a changes embed from set parameters. + + Args: + interaction (Interaction): The interaction object. + case_dict (dict): The case dictionary. + """ + embed = Embed(title=f"📕 Case #{case_dict['moderation_id']:,} Changes", color=await interaction.client.get_embed_color(interaction.channel)) + + memory_dict = {} + + if case_dict['changes']: + for change in case_dict['changes']: + if change['user_id'] not in memory_dict: + memory_dict[str(change['user_id'])] = await fetch_user_dict(interaction, change['user_id']) + + user = memory_dict[str(change['user_id'])] + name = user['name'] if user['discriminator'] == "0" else f"{user['name']}#{user['discriminator']}" + + timestamp = f" | " + + if change['type'] == 'ORIGINAL': + embed.add_field(name='Original', value=f"**User:** `{name}` ({user['id']})\n**Reason:** {change['reason']}\n**Timestamp:** {timestamp}", inline=False) + + elif change['type'] == 'EDIT': + embed.add_field(name='Edit', value=f"**User:** `{name}` ({user['id']})\n**Reason:** {change['reason']}\n**Timestamp:** {timestamp}", inline=False) + + elif change['type'] == 'RESOLVE': + embed.add_field(name='Resolve', value=f"**User:** `{name}` ({user['id']})\n**Reason:** {change['reason']}\n**Timestamp:** {timestamp}", inline=False) + + else: + embed.description = "*No changes have been made to this case.* 🙁" + + return embed + +async def evidenceformat_factory(interaction: Interaction, case_dict: dict) -> str: + """This function creates a codeblock in evidence format from set parameters. + + Args: + interaction (Interaction): The interaction object. + case_dict (dict): The case dictionary. + """ + if case_dict['target_type'] == 'USER': + target_user = await fetch_user_dict(interaction, case_dict['target_id']) + target_name = target_user['name'] if target_user['discriminator'] == "0" else f"{target_user['name']}#{target_user['discriminator']}" + + elif case_dict['target_type'] == 'CHANNEL': + target_user = await fetch_channel_dict(interaction, case_dict['target_id']) + target_name = target_user['name'] + + moderator_user = await fetch_user_dict(interaction, case_dict['moderator_id']) + moderator_name = moderator_user['name'] if moderator_user['discriminator'] == "0" else f"{moderator_user['name']}#{moderator_user['discriminator']}" + + content = f"Case: {case_dict['moderation_id']:,} ({str.title(case_dict['moderation_type'])})\nTarget: {target_name} ({target_user['id']})\nModerator: {moderator_name} ({moderator_user['id']})" + + if case_dict['duration'] != 'NULL': + hours, minutes, seconds = map(int, case_dict['duration'].split(':')) + td = timedelta(hours=hours, minutes=minutes, seconds=seconds) + content += f"\nDuration: {humanize.precisedelta(td)}" + + content += f"\nReason: {case_dict['reason']}" + + return box(content, 'prolog') diff --git a/aurora/utilities/utils.py b/aurora/utilities/utils.py index ed2de3c..aeab27e 100644 --- a/aurora/utilities/utils.py +++ b/aurora/utilities/utils.py @@ -102,7 +102,7 @@ async def check_moddable( return True -async def get_next_case_number(guild_id: str, cursor=None): +async def get_next_case_number(guild_id: str, cursor = None) -> int: """This function returns the next case number from the MySQL table for a specific guild.""" from .database import connect @@ -112,7 +112,8 @@ async def get_next_case_number(guild_id: str, cursor=None): cursor.execute( f"SELECT moderation_id FROM `moderation_{guild_id}` ORDER BY moderation_id DESC LIMIT 1" ) - return cursor.fetchone()[0] + 1 + result = cursor.fetchone() + return (result[0] + 1) if result else 1 def generate_dict(result): @@ -193,7 +194,7 @@ async def fetch_role_dict(interaction: Interaction, role_id: str): async def log(interaction: Interaction, moderation_id: int, resolved: bool = False): """This function sends a message to the guild's configured logging channel when an infraction takes place.""" from .database import fetch_case - from .embed_factory import embed_factory + from .factory import log_factory logging_channel_id = await config.guild(interaction.guild).log_channel() if logging_channel_id != " ": @@ -201,9 +202,7 @@ async def log(interaction: Interaction, moderation_id: int, resolved: bool = Fal case = await fetch_case(moderation_id, interaction.guild.id) if case: - embed = await embed_factory( - "log", await interaction.client.get_embed_color(None), interaction=interaction, case_dict=case, resolved=resolved - ) + embed = await log_factory(interaction=interaction, case_dict=case, resolved=resolved) try: await logging_channel.send(embed=embed) except Forbidden: @@ -211,7 +210,7 @@ async def log(interaction: Interaction, moderation_id: int, resolved: bool = Fal async def send_evidenceformat(interaction: Interaction, case_dict: dict): """This function sends an ephemeral message to the moderator who took the moderation action, with a pre-made codeblock for use in the mod-evidence channel.""" - from .embed_factory import embed_factory + from .factory import evidenceformat_factory send_evidence_bool = (await config.user(interaction.user).auto_evidenceformat() or await config.guild(interaction.guild).auto_evidenceformat() @@ -219,9 +218,7 @@ async def send_evidenceformat(interaction: Interaction, case_dict: dict): if send_evidence_bool is False: return - content = await embed_factory( - "evidenceformat", await interaction.client.get_embed_color(None), interaction=interaction, case_dict=case_dict - ) + content = await evidenceformat_factory(interaction=interaction, case_dict=case_dict) await interaction.followup.send(content=content, ephemeral=True) def convert_timedelta_to_str(timedelta: td) -> str: