2024-02-28 10:58:57 -05:00
# pylint: disable=cyclic-import
2024-05-04 16:54:12 -04:00
from datetime import datetime , timedelta
2024-06-03 23:46:22 -04:00
from typing import Optional , Tuple , Union
2023-12-18 17:24:40 -05:00
2024-03-08 14:19:48 -05:00
from dateutil . relativedelta import relativedelta as rd
2024-05-24 03:49:55 -04:00
from discord import File , Guild , Interaction , Member , SelectOption , TextChannel , User
2024-05-06 16:34:08 -04:00
from discord . errors import Forbidden
2024-05-03 21:35:29 -04:00
from redbot . core import commands , data_manager
2024-01-05 04:21:05 -05:00
from redbot . core . utils . chat_formatting import error
2023-12-18 17:24:40 -05:00
2024-05-06 21:39:43 -04:00
from . . utilities . config import config
2023-12-17 02:16:44 -05:00
def check_permissions (
user : User ,
2024-06-03 23:46:22 -04:00
permissions : Tuple [ str ] ,
2024-05-06 21:04:08 -04:00
ctx : Union [ commands . Context , Interaction ] | None = None ,
guild : Guild | None = None ,
2024-02-13 18:02:13 -05:00
) - > Union [ bool , str ] :
2023-12-17 02:16:44 -05:00
""" 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 )
2024-02-14 10:35:57 -05:00
and resolved_permissions . administrator is not True
2023-12-17 02:16:44 -05:00
) :
return permission
return False
async def check_moddable (
2024-06-03 23:46:22 -04:00
target : Union [ User , Member , TextChannel ] , interaction : Interaction , permissions : Tuple [ str ]
2024-02-13 18:02:13 -05:00
) - > bool :
2023-12-17 02:16:44 -05:00
""" Checks if a moderator can moderate a target. """
2024-05-24 03:49:55 -04:00
is_channel = isinstance ( target , TextChannel )
2023-12-17 02:16:44 -05:00
if check_permissions ( interaction . client . user , permissions , guild = interaction . guild ) :
await interaction . response . send_message (
2024-02-02 11:22:08 -05:00
error (
f " I do not have the ` { permissions } ` permission, required for this action. "
) ,
2023-12-17 02:16:44 -05:00
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 (
2024-02-02 11:22:08 -05:00
error (
f " You do not have the ` { permissions } ` permission, required for this action. "
) ,
2023-12-17 02:16:44 -05:00
ephemeral = True ,
)
return False
if interaction . user . id == target . id :
await interaction . response . send_message (
content = " You cannot moderate yourself! " , ephemeral = True
)
return False
2024-05-24 03:49:55 -04:00
if not is_channel and target . bot :
2023-12-17 02:16:44 -05:00
await interaction . response . send_message (
content = " You cannot moderate bots! " , ephemeral = True
)
return False
if isinstance ( target , Member ) :
2024-04-05 10:43:58 -04:00
if interaction . user . top_role < = target . top_role and await config . guild ( interaction . guild ) . respect_hierarchy ( ) is True :
2023-12-17 02:16:44 -05:00
await interaction . response . send_message (
2024-02-02 11:22:08 -05:00
content = error (
" You cannot moderate members with a higher role than you! "
) ,
2023-12-17 02:16:44 -05:00
ephemeral = True ,
)
return False
if (
interaction . guild . get_member ( interaction . client . user . id ) . top_role
< = target . top_role
) :
await interaction . response . send_message (
2024-02-02 11:22:08 -05:00
content = error (
" You cannot moderate members with a role higher than the bot! "
) ,
2023-12-17 02:16:44 -05:00
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 (
2024-01-05 04:21:05 -05:00
content = error ( " You cannot moderate members with an immune role! " ) ,
2023-12-17 02:16:44 -05:00
ephemeral = True ,
)
return False
return True
2024-05-06 14:15:05 -04:00
def get_next_case_number ( guild_id : str , cursor = None ) - > int :
2023-12-18 18:33:37 -05:00
""" This function returns the next case number from the MySQL table for a specific guild. """
2024-05-06 21:39:43 -04:00
from . database import connect
2023-12-17 03:11:51 -05:00
2023-12-17 02:16:44 -05:00
if not cursor :
2023-12-28 04:23:55 -05:00
database = connect ( )
2023-12-17 02:16:44 -05:00
cursor = database . cursor ( )
cursor . execute (
f " SELECT moderation_id FROM `moderation_ { guild_id } ` ORDER BY moderation_id DESC LIMIT 1 "
)
2024-01-08 04:38:12 -05:00
result = cursor . fetchone ( )
return ( result [ 0 ] + 1 ) if result else 1
2023-12-17 02:16:44 -05:00
2024-02-13 18:02:13 -05:00
async def log ( interaction : Interaction , moderation_id : int , resolved : bool = False ) - > None :
2023-12-18 18:33:37 -05:00
""" This function sends a message to the guild ' s configured logging channel when an infraction takes place. """
2024-05-06 21:39:43 -04:00
from . . models . moderation import Moderation
from . factory import log_factory
2023-12-17 02:36:18 -05:00
2023-12-17 02:16:44 -05:00
logging_channel_id = await config . guild ( interaction . guild ) . log_channel ( )
if logging_channel_id != " " :
logging_channel = interaction . guild . get_channel ( logging_channel_id )
2024-05-06 16:34:08 -04:00
try :
2024-05-06 16:47:21 -04:00
moderation = Moderation . from_sql ( interaction . client , moderation_id , interaction . guild_id )
2024-02-02 11:22:08 -05:00
embed = await log_factory (
2024-05-06 16:34:08 -04:00
interaction = interaction , moderation = moderation , resolved = resolved
2024-02-02 11:22:08 -05:00
)
2023-12-17 02:16:44 -05:00
try :
await logging_channel . send ( embed = embed )
except Forbidden :
return
2024-05-06 16:34:08 -04:00
except ValueError :
return
2023-12-18 18:33:37 -05:00
2024-02-02 11:22:08 -05:00
2024-05-06 16:34:08 -04:00
async def send_evidenceformat ( interaction : Interaction , moderation_id : int ) - > None :
2023-12-18 18:33:37 -05:00
""" 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. """
2024-05-06 21:39:43 -04:00
from . . models . moderation import Moderation
from . factory import evidenceformat_factory
2023-12-18 18:33:37 -05:00
2024-02-02 11:22:08 -05:00
send_evidence_bool = (
await config . user ( interaction . user ) . auto_evidenceformat ( )
2023-12-18 18:33:37 -05:00
or await config . guild ( interaction . guild ) . auto_evidenceformat ( )
2024-02-02 11:22:08 -05:00
or False
)
2023-12-18 18:33:37 -05:00
if send_evidence_bool is False :
return
2024-05-06 16:47:21 -04:00
moderation = Moderation . from_sql ( interaction . client , moderation_id , interaction . guild . id )
content = await evidenceformat_factory ( moderation = moderation )
2023-12-18 18:33:37 -05:00
await interaction . followup . send ( content = content , ephemeral = True )
2023-12-30 04:10:25 -05:00
2024-02-02 11:22:08 -05:00
2024-04-05 10:42:13 -04:00
def get_bool_emoji ( value : Optional [ bool ] ) - > str :
2024-01-16 09:23:45 -05:00
""" Returns a unicode emoji based on a boolean value. """
if value is True :
return " \N{WHITE HEAVY CHECK MARK} "
if value is False :
return " \N{NO ENTRY SIGN} "
return " \N{BLACK QUESTION MARK ORNAMENT} \N{VARIATION SELECTOR-16} "
2024-02-02 11:22:08 -05:00
2024-01-16 09:23:45 -05:00
def get_pagesize_str ( value : Union [ int , None ] ) - > str :
""" Returns a string based on a pagesize value. """
if value is None :
return " \N{BLACK QUESTION MARK ORNAMENT} \N{VARIATION SELECTOR-16} "
return str ( value ) + " cases per page "
2024-02-02 11:22:08 -05:00
2024-01-16 09:23:45 -05:00
def create_pagesize_options ( ) - > list [ SelectOption ] :
""" Returns a list of SelectOptions for pagesize configuration. """
options = [ ]
options . append (
SelectOption (
label = " Default " ,
value = " default " ,
description = " Reset the pagesize to the default value. " ,
)
)
for i in range ( 1 , 21 ) :
options . append (
SelectOption (
label = str ( i ) ,
value = str ( i ) ,
description = f " Set the pagesize to { i } . " ,
)
)
return options
2024-03-08 14:19:48 -05:00
2024-05-04 16:54:12 -04:00
def timedelta_from_relativedelta ( relativedelta : rd ) - > timedelta :
2024-03-08 14:19:48 -05:00
""" Converts a relativedelta object to a timedelta object. """
now = datetime . now ( )
then = now - relativedelta
return now - then
2024-05-03 21:35:29 -04:00
def get_footer_image ( coginstance : commands . Cog ) - > File :
""" Returns the footer image for the embeds. """
image_path = data_manager . bundled_data_path ( coginstance ) / " arrow.png "
return File ( image_path , filename = " arrow.png " , description = " arrow " )