# pylint: disable=cyclic-import import json from typing import Union from discord import Guild, Interaction, Member, User from discord.errors import Forbidden, NotFound from redbot.core import commands from .config import config async def check_conf(config_list: list): """Checks if any required config options are not set.""" not_found_list = [] for item in config_list: if await config.item() == " ": not_found_list.append(item) return not_found_list def check_permissions( user: User, permissions: list, ctx: Union[commands.Context, Interaction] = None, guild: Guild = None, ): """Checks if a user has a specific permission (or a list of permissions) in a channel.""" if ctx: member = ctx.guild.get_member(user.id) resolved_permissions = ctx.channel.permissions_for(member) elif guild: member = guild.get_member(user.id) resolved_permissions = member.guild_permissions else: raise (KeyError) for permission in permissions: if ( not getattr(resolved_permissions, permission, False) and not resolved_permissions.administrator is True ): return permission return False async def check_moddable( target: Union[User, Member], interaction: Interaction, permissions: list ): """Checks if a moderator can moderate a target.""" if check_permissions(interaction.client.user, permissions, guild=interaction.guild): await interaction.response.send_message( f"I do not have the `{permissions}` permission, required for this action.", ephemeral=True, ) return False if await config.guild(interaction.guild).use_discord_permissions() is True: if check_permissions(interaction.user, permissions, guild=interaction.guild): await interaction.response.send_message( f"You do not have the `{permissions}` permission, required for this action.", ephemeral=True, ) return False if interaction.user.id == target.id: await interaction.response.send_message( content="You cannot moderate yourself!", ephemeral=True ) return False if target.bot: await interaction.response.send_message( content="You cannot moderate bots!", ephemeral=True ) return False if isinstance(target, Member): if interaction.user.top_role <= target.top_role: await interaction.response.send_message( content="You cannot moderate members with a higher role than you!", ephemeral=True, ) return False if ( interaction.guild.get_member(interaction.client.user.id).top_role <= target.top_role ): await interaction.response.send_message( content="You cannot moderate members with a role higher than the bot!", ephemeral=True, ) return False immune_roles = await config.guild(target.guild).immune_roles() for role in target.roles: if role.id in immune_roles: await interaction.response.send_message( content="You cannot moderate members with an immune role!", ephemeral=True, ) return False return True async def get_next_case_number(guild_id: str, cursor=None): """This function returns the next case number from the MySQL table for a specific guild.""" from .database import connect if not cursor: database = await 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 def generate_dict(result): case: dict = { "moderation_id": result[0], "timestamp": result[1], "moderation_type": result[2], "target_type": result[3], "target_id": result[4], "moderator_id": result[5], "role_id": result[6], "duration": result[7], "end_timestamp": result[8], "reason": result[9], "resolved": result[10], "resolved_by": result[11], "resolve_reason": result[12], "expired": result[13], "changes": json.loads(result[14]), "metadata": json.loads(result[15]) } return case async def fetch_user_dict(interaction: Interaction, user_id: str): """This function returns a dictionary containing either user information or a standard deleted user template.""" if user_id == "?": user_dict = {"id": "?", "name": "Unknown 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 NotFound: user_dict = { "id": user_id, "name": "Deleted User", "discriminator": "0", } return user_dict async def fetch_channel_dict(interaction: Interaction, channel_id: str): """This function returns a dictionary containing either channel information or a standard deleted channel template.""" try: channel = interaction.guild.get_channel(channel_id) if not channel: channel = await interaction.guild.fetch_channel(channel_id) channel_dict = {"id": channel.id, "name": channel.name, "mention": channel.mention} except NotFound: channel_dict = {"id": channel_id, "name": "Deleted Channel", "mention": None} return channel_dict async def fetch_role_dict(interaction: Interaction, role_id: str): """This function returns a dictionary containing either role information or a standard deleted role template.""" role = interaction.guild.get_role(role_id) if not role: role_dict = {"id": role_id, "name": "Deleted Role"} role_dict = {"id": role.id, "name": role.name} return role_dict 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 logging_channel_id = await config.guild(interaction.guild).log_channel() if logging_channel_id != " ": logging_channel = interaction.guild.get_channel(logging_channel_id) 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 ) try: await logging_channel.send(embed=embed) except Forbidden: return 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 send_evidence_bool = (await config.user(interaction.user).auto_evidenceformat() or await config.guild(interaction.guild).auto_evidenceformat() or False) 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 ) await interaction.followup.send(content=content, ephemeral=True)