From 509304ae2878561f9648dfcb38e151b4221c547e Mon Sep 17 00:00:00 2001 From: wlinator Date: Thu, 18 Jul 2024 12:14:26 -0400 Subject: [PATCH] refactor moderation commands --- modules/moderation/ban.py | 6 +- modules/moderation/case_handler.py | 94 ------------------- modules/moderation/cases.py | 54 +++++++++++ .../{functions.py => utils/actionable.py} | 0 modules/moderation/utils/case_embed.py | 51 ++++++++++ modules/moderation/utils/case_handler.py | 59 ++++++++++++ 6 files changed, 167 insertions(+), 97 deletions(-) delete mode 100644 modules/moderation/case_handler.py create mode 100644 modules/moderation/cases.py rename modules/moderation/{functions.py => utils/actionable.py} (100%) create mode 100644 modules/moderation/utils/case_embed.py create mode 100644 modules/moderation/utils/case_handler.py diff --git a/modules/moderation/ban.py b/modules/moderation/ban.py index 7b8ebd6..128792e 100644 --- a/modules/moderation/ban.py +++ b/modules/moderation/ban.py @@ -4,8 +4,8 @@ import discord from lib import formatter from lib.constants import CONST from lib.embed_builder import EmbedBuilder -from modules.moderation import functions -from modules.moderation.case_handler import create_case +from modules.moderation.utils import actionable +from modules.moderation.utils.case_handler import create_case from typing import Optional @@ -18,7 +18,7 @@ async def ban_user(cog, ctx, target: discord.User, reason: Optional[str] = None) # member -> user is in the guild, check role hierarchy if member: bot_member = await cog.client.get_or_fetch_member(ctx.guild, ctx.bot.user.id) - functions.actionable(member, ctx.author, bot_member) + actionable.actionable(member, ctx.author, bot_member) try: await member.send( diff --git a/modules/moderation/case_handler.py b/modules/moderation/case_handler.py deleted file mode 100644 index f83b97b..0000000 --- a/modules/moderation/case_handler.py +++ /dev/null @@ -1,94 +0,0 @@ -import discord -from loguru import logger -from services.moderation.case_service import CaseService -from services.moderation.modlog_service import ModLogService -from lib.embed_builder import EmbedBuilder -from lib.constants import CONST -from typing import Optional -from discord.ext.commands import TextChannelConverter - -case_service = CaseService() -modlog_service = ModLogService() - - -async def create_case( - ctx, - target: discord.User, - action_type: str, - reason: Optional[str] = None, - duration: Optional[int] = None, - expires_at: Optional[str] = None, -): - guild_id = ctx.guild.id - moderator_id = ctx.author.id - target_id = target.id - - # Create the case - case_number: int = case_service.create_case( - guild_id=guild_id, - target_id=target_id, - moderator_id=moderator_id, - action_type=action_type, - reason=reason, - duration=duration, - expires_at=expires_at, - modlog_message_id=None, - ) - - logger.info(f"Created case {case_number} for {target.name} in guild {guild_id}") - - # Send the case to the modlog if configured - mod_log_channel_id = modlog_service.fetch_modlog_channel_id(guild_id) - - if mod_log_channel_id: - mod_log_channel = await TextChannelConverter().convert( - ctx, - str(mod_log_channel_id), - ) - - if mod_log_channel: - embed = EmbedBuilder.create_warning_embed( - ctx, - author_text=CONST.STRINGS["case_new_case_author"], - thumbnail_url=target.display_avatar.url, - show_name=False, - ) - embed.add_field( - name=CONST.STRINGS["case_case_field"], - value=CONST.STRINGS["case_case_field_value"].format(case_number), - inline=True, - ) - embed.add_field( - name=CONST.STRINGS["case_type_field"], - value=CONST.STRINGS["case_type_field_value"].format( - action_type.lower().capitalize(), - ), - inline=True, - ) - embed.add_field( - name=CONST.STRINGS["case_moderator_field"], - value=CONST.STRINGS["case_moderator_field_value"].format( - ctx.author.name, - ), - inline=True, - ) - embed.add_field( - name=CONST.STRINGS["case_target_field"], - value=CONST.STRINGS["case_target_field_value"].format(target.name), - inline=False, - ) - embed.add_field( - name=CONST.STRINGS["case_reason_field"], - value=CONST.STRINGS["case_reason_field_value"].format( - reason or CONST.STRINGS["mod_no_reason"], - ), - inline=False, - ) - message = await mod_log_channel.send(embed=embed) - - # Update the case with the modlog_message_id - case_service.edit_case( - guild_id=guild_id, - case_number=case_number, - changes={"modlog_message_id": message.id}, - ) diff --git a/modules/moderation/cases.py b/modules/moderation/cases.py new file mode 100644 index 0000000..1456f91 --- /dev/null +++ b/modules/moderation/cases.py @@ -0,0 +1,54 @@ +from discord.ext import pages +from services.moderation.case_service import CaseService + +case_service = CaseService() + + +async def view_case_by_number(ctx, guild_id: int, case_number: int): + case = case_service.fetch_case_by_guild_and_number(guild_id, case_number) + + if not case: + return await ctx.send("No case found with that ID.") + + await ctx.send( + f"Case {case['case_number']}: {case['action_type']} - {case['reason']}", + ) + + +async def view_all_cases_in_guild(ctx, guild_id: int): + cases = case_service.fetch_all_cases_in_guild(guild_id) + + if not cases: + return await ctx.send("No cases found for this guild.") + + pages_list = [ + f"Case {case['case_number']}: {case['action_type']} - {case['reason']}" + for case in cases + ] + paginator = pages.Paginator(pages=pages_list, loop_pages=True) + await paginator.send(ctx) + + +async def view_all_cases_by_mod(ctx, guild_id: int, mod_id: int): + cases = case_service.fetch_all_cases_by_mod(guild_id, mod_id) + + if not cases: + return await ctx.send("No cases found for this moderator in this guild.") + + pages_list = [ + f"Case {case['case_number']}: {case['action_type']} - {case['reason']}" + for case in cases + ] + paginator = pages.Paginator(pages=pages_list, loop_pages=True) + await paginator.send(ctx) + + +async def edit_case_reason(ctx, guild_id: int, case_number: int, new_reason: str): + changes = {"reason": new_reason} + case_service.edit_case(guild_id, case_number, changes) + await ctx.respond(f"Case {case_number} reason updated to: {new_reason}") + + +async def close_case(ctx, guild_id: int, case_number: int): + case_service.close_case(guild_id, case_number) + await ctx.respond(f"Case {case_number} has been closed.") diff --git a/modules/moderation/functions.py b/modules/moderation/utils/actionable.py similarity index 100% rename from modules/moderation/functions.py rename to modules/moderation/utils/actionable.py diff --git a/modules/moderation/utils/case_embed.py b/modules/moderation/utils/case_embed.py new file mode 100644 index 0000000..78a95c4 --- /dev/null +++ b/modules/moderation/utils/case_embed.py @@ -0,0 +1,51 @@ +import discord +from lib.embed_builder import EmbedBuilder +from lib.constants import CONST +from typing import Optional + + +def create_case_embed( + ctx, + target: discord.User, + case_number: int, + action_type: str, + reason: Optional[str], +) -> discord.Embed: + embed = EmbedBuilder.create_warning_embed( + ctx, + author_text=CONST.STRINGS["case_new_case_author"], + thumbnail_url=target.display_avatar.url, + show_name=False, + ) + embed.add_field( + name=CONST.STRINGS["case_case_field"], + value=CONST.STRINGS["case_case_field_value"].format(case_number), + inline=True, + ) + embed.add_field( + name=CONST.STRINGS["case_type_field"], + value=CONST.STRINGS["case_type_field_value"].format( + action_type.lower().capitalize(), + ), + inline=True, + ) + embed.add_field( + name=CONST.STRINGS["case_moderator_field"], + value=CONST.STRINGS["case_moderator_field_value"].format( + ctx.author.name, + ), + inline=True, + ) + embed.add_field( + name=CONST.STRINGS["case_target_field"], + value=CONST.STRINGS["case_target_field_value"].format(target.name), + inline=False, + ) + embed.add_field( + name=CONST.STRINGS["case_reason_field"], + value=CONST.STRINGS["case_reason_field_value"].format( + reason or CONST.STRINGS["mod_no_reason"], + ), + inline=False, + ) + return embed diff --git a/modules/moderation/utils/case_handler.py b/modules/moderation/utils/case_handler.py new file mode 100644 index 0000000..080202a --- /dev/null +++ b/modules/moderation/utils/case_handler.py @@ -0,0 +1,59 @@ +import discord +from loguru import logger +from services.moderation.case_service import CaseService +from services.moderation.modlog_service import ModLogService +from modules.moderation.utils.case_embed import create_case_embed +from typing import Optional +from discord.ext.commands import TextChannelConverter + +case_service = CaseService() +modlog_service = ModLogService() + + +async def create_case( + ctx, + target: discord.User, + action_type: str, + reason: Optional[str] = None, + duration: Optional[int] = None, + expires_at: Optional[str] = None, +): + guild_id = ctx.guild.id + moderator_id = ctx.author.id + target_id = target.id + + # Create the case + case_number: int = case_service.create_case( + guild_id=guild_id, + target_id=target_id, + moderator_id=moderator_id, + action_type=action_type, + reason=reason, + duration=duration, + expires_at=expires_at, + modlog_message_id=None, + ) + + logger.info(f"Created case {case_number} for {target.name} in guild {guild_id}") + + # Send the case to the modlog if configured + mod_log_channel_id = modlog_service.fetch_modlog_channel_id(guild_id) + + if mod_log_channel_id: + try: + mod_log_channel = await TextChannelConverter().convert( + ctx, + str(mod_log_channel_id), + ) + embed = create_case_embed(ctx, target, case_number, action_type, reason) + message = await mod_log_channel.send(embed=embed) + + # Update the case with the modlog_message_id + case_service.edit_case( + guild_id=guild_id, + case_number=case_number, + changes={"modlog_message_id": message.id}, + ) + + except Exception as e: + logger.error(f"Failed to send case to modlog channel: {e}")