2024-07-06 11:30:37 -04:00
2024-07-12 15:22:24 -04:00
from datetime import timedelta
2024-07-06 13:03:59 -04:00
from math import ceil
2024-07-12 15:22:24 -04:00
from time import time
from typing import Tuple
2024-07-06 13:03:59 -04:00
2024-07-12 15:22:24 -04:00
from discord import AllowedMentions , File , Interaction , Member , Object , Role , TextChannel , User
2024-07-06 13:03:59 -04:00
from discord . abc import Messageable
2024-07-12 15:22:24 -04:00
from discord . errors import Forbidden , HTTPException , NotFound
2024-07-06 11:30:37 -04:00
from redbot . core import app_commands , commands
from redbot . core . bot import Red
2024-07-12 15:22:24 -04:00
from redbot . core . commands . converter import parse_relativedelta , parse_timedelta
2024-07-06 11:30:37 -04:00
from redbot . core . utils . chat_formatting import bold , error , humanize_timedelta , inline
2024-07-12 15:22:24 -04:00
from . . utilities . config import config
from . . utilities . factory import message_factory , resolve_factory
from . . utilities . logger import logger
2024-07-06 11:30:37 -04:00
from . . utilities . utils import get_footer_image , log , send_evidenceformat , timedelta_from_relativedelta
from . moderation import Moderation
2024-07-12 15:22:24 -04:00
from . type import Type , type_registry
2024-07-06 11:30:37 -04:00
def get_icon ( bot : Red ) - > File :
cog = bot . get_cog ( " Aurora " )
if cog :
return get_footer_image ( cog )
raise ValueError ( " Aurora cog not found. How was this managed? " )
2024-07-06 13:03:59 -04:00
class Note ( Type ) :
key = " note "
string = " note "
verb = " noted "
2024-07-12 15:22:24 -04:00
embed_desc = " received a "
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member | User , silent : bool , reason : str ) - > ' Note ' :
response = await ctx . send (
content = f " { target . mention } has { cls . embed_desc } { cls . string } ! \n **Reason** - ` { reason } ` "
)
if silent is False :
try :
embed = await message_factory (
bot = ctx . bot ,
color = await ctx . embed_color ,
guild = ctx . guild ,
moderator = ctx . author ,
reason = reason ,
moderation_type = cls ( ) ,
response = response ,
)
await target . send ( embed = embed , file = get_icon ( ctx . bot ) )
except HTTPException :
pass
moderation = await Moderation . log (
bot = ctx . bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = " user " ,
target_id = target . id ,
role_id = None ,
duration = None ,
reason = reason ,
)
await response . edit (
content = f " { target . mention } has { cls . embed_desc } { cls . string } ! (Case `# { moderation . id : , } `) \n **Reason** - ` { reason } ` "
)
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
return cls ( )
@classmethod
async def resolve_handler ( cls , moderation : Moderation , reason : str ) - > Tuple [ bool , str ] :
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
target = await moderation . bot . fetch_user ( moderation . target_id )
embed = await resolve_factory (
moderation = moderation ,
reason = reason
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except ( Forbidden , HTTPException , NotFound ) :
pass
return True , " "
2024-07-06 13:03:59 -04:00
class Warn ( Type ) :
key = " warn "
string = " warn "
verb = " warned "
2024-07-12 15:22:24 -04:00
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member | User , silent : bool , reason : str ) - > ' Warn ' :
response = await ctx . send (
content = f " { target . mention } has { cls . embed_desc } { cls . verb } ! \n **Reason** - ` { reason } ` "
)
if silent is False :
try :
embed = await message_factory (
bot = ctx . bot ,
color = await ctx . embed_color ,
guild = ctx . guild ,
moderator = ctx . author ,
reason = reason ,
moderation_type = cls ( ) ,
response = response ,
)
await target . send ( embed = embed , file = get_icon ( ctx . bot ) )
except HTTPException :
pass
moderation = await Moderation . log (
bot = ctx . bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = " user " ,
target_id = target . id ,
role_id = None ,
duration = None ,
reason = reason ,
)
await response . edit (
content = f " { target . mention } has { cls . embed_desc } { cls . verb } ! (Case `# { moderation . id : , } `) \n **Reason** - ` { reason } ` "
)
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
return cls ( )
@classmethod
async def resolve_handler ( cls , moderation : Moderation , reason : str ) - > Tuple [ bool , str ] :
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
target = await moderation . bot . fetch_user ( moderation . target_id )
embed = await resolve_factory (
moderation = moderation ,
reason = reason
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except ( Forbidden , HTTPException , NotFound ) :
pass
return True , " "
2024-07-06 13:03:59 -04:00
class AddRole ( Type ) :
key = " addrole "
string = " addrole "
verb = " added a role to "
2024-07-12 15:22:24 -04:00
embed_desc = " been given the "
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member , role : Role , silent : bool , duration : str = None , reason : str = None ) :
addrole_whitelist = await config . guild ( ctx . guild ) . addrole_whitelist ( )
if not addrole_whitelist :
await ctx . send (
content = error ( " There are no whitelisted roles set for this server! " ) ,
ephemeral = True ,
)
return
if duration is not None :
parsed_time = parse_timedelta ( duration )
if parsed_time is None :
await ctx . send (
content = error ( " Please provide a valid duration! " ) , ephemeral = True
)
return
else :
parsed_time = None
if role . id not in addrole_whitelist :
await ctx . send (
content = error ( " That role isn ' t whitelisted! " ) , ephemeral = True
)
return
if role . id in [ user_role . id for user_role in target . roles ] :
await ctx . send (
content = error ( f " { target . mention } already has this role! " ) ,
ephemeral = True ,
)
return
response = await ctx . send (
content = f " { target . mention } has { cls . embed_desc } { role . mention } role { ' for ' + humanize_timedelta ( timedelta = parsed_time ) if parsed_time != ' NULL ' else ' ' } ! \n **Reason** - ` { reason } ` "
)
if silent is False :
try :
embed = await message_factory (
bot = ctx . bot ,
color = await ctx . embed_color ( ) ,
guild = ctx . guild ,
moderator = ctx . author ,
reason = reason ,
moderation_type = cls ( ) ,
response = response ,
duration = parsed_time ,
role = role ,
)
await target . send ( embed = embed , file = get_icon ( ctx . bot ) )
except HTTPException :
pass
await target . add_roles (
role ,
reason = f " Role added by { ctx . author . id } { ' for ' + humanize_timedelta ( timedelta = parsed_time ) if parsed_time != ' NULL ' else ' ' } for: { reason } " ,
)
moderation = await Moderation . log (
bot = ctx . bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = " user " ,
target_id = target . id ,
role_id = role . id ,
duration = parsed_time ,
reason = reason ,
)
await response . edit (
content = f " { target . mention } has { cls . embed_desc } { role . mention } role { ' for ' + humanize_timedelta ( timedelta = parsed_time ) if parsed_time != ' NULL ' else ' ' } ! (Case `# { moderation . id : , } `) \n **Reason** - ` { reason } ` " ,
)
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
return cls ( )
@classmethod
async def duration_edit_handler ( cls , interaction : Interaction , old_moderation : Moderation , new_moderation : Moderation ) - > bool : # pylint: disable=unused-argument
return True
@classmethod
async def expiry_handler ( cls , moderation : Moderation ) - > int :
try :
target = await moderation . get_target ( )
await target . remove_roles (
Object ( moderation . role_id ) , reason = f " Automatic role removal from case # { moderation . id } "
)
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
embed = await message_factory (
bot = moderation . bot ,
color = await moderation . bot . get_embed_color ( moderation . guild . channels [ 0 ] ) ,
guild = moderation . guild ,
reason = f " Automatic role removal from case # { moderation . id } " ,
moderation_type = type_registry [ " removerole " ] ,
moderator = None ,
duration = None ,
response = None ,
case = False ,
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except HTTPException :
pass
logger . trace (
" Removed role %s from %s ( %s ) " ,
moderation . role_id ,
target . name ,
target . id ,
)
return 1
except (
NotFound ,
Forbidden ,
HTTPException ,
) as e :
logger . error (
" Removing the role %s from user %s failed due to: \n %s " ,
moderation . role_id ,
moderation . target_id ,
e ,
)
return 0
2024-07-06 13:03:59 -04:00
class RemoveRole ( Type ) :
key = " removerole "
string = " removerole "
verb = " removed a role from "
2024-07-12 15:22:24 -04:00
embed_desc = " had the "
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member , role : Role , silent : bool , duration : str = None , reason : str = None ) :
addrole_whitelist = await config . guild ( ctx . guild ) . addrole_whitelist ( )
if not addrole_whitelist :
await ctx . send (
content = error ( " There are no whitelisted roles set for this server! " ) ,
ephemeral = True ,
)
return
if duration is not None :
parsed_time = parse_timedelta ( duration )
if parsed_time is None :
await ctx . send (
content = error ( " Please provide a valid duration! " ) , ephemeral = True
)
return
else :
parsed_time = None
if role . id not in addrole_whitelist :
await ctx . send (
content = error ( " That role isn ' t whitelisted! " ) , ephemeral = True
)
return
if role . id not in [ user_role . id for user_role in target . roles ] :
await ctx . send (
content = error ( f " { target . mention } does not have this role! " ) ,
ephemeral = True ,
)
return
response = await ctx . send (
content = f " { target . mention } has { cls . embed_desc } { role . mention } role removed { ' for ' + humanize_timedelta ( timedelta = parsed_time ) if parsed_time != ' NULL ' else ' ' } ! \n **Reason** - ` { reason } ` "
)
if silent is False :
try :
embed = await message_factory (
bot = ctx . bot ,
color = await ctx . embed_color ( ) ,
guild = ctx . guild ,
moderator = ctx . author ,
reason = reason ,
moderation_type = " removerole " ,
response = response ,
duration = parsed_time ,
role = role ,
)
await target . send ( embed = embed , file = get_icon ( ctx . bot ) )
except HTTPException :
pass
await target . remove_roles (
role ,
reason = f " Role removed by { ctx . author . id } { ' for ' + humanize_timedelta ( timedelta = parsed_time ) if parsed_time != ' NULL ' else ' ' } for: { reason } " ,
)
moderation = await Moderation . log (
bot = ctx . bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = " user " ,
target_id = target . id ,
role_id = role . id ,
duration = parsed_time ,
reason = reason ,
)
await response . edit (
content = f " { target . mention } has { cls . embed_desc } { role . mention } role removed { ' for ' + humanize_timedelta ( timedelta = parsed_time ) if parsed_time != ' NULL ' else ' ' } ! (Case `# { moderation . id : , } `) \n **Reason** - ` { reason } ` " ,
)
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
return cls ( )
@classmethod
async def duration_edit_handler ( cls , interaction : Interaction , old_moderation : Moderation , new_moderation : Moderation ) - > bool : # pylint: disable=unused-argument
return True
@classmethod
async def expiry_handler ( cls , moderation : Moderation ) - > int :
try :
target = await moderation . get_target ( )
await target . add_roles (
Object ( moderation . role_id ) , reason = f " Automatic role addition from case # { moderation . id } "
)
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
embed = await message_factory (
bot = moderation . bot ,
color = await moderation . bot . get_embed_color ( moderation . guild . channels [ 0 ] ) ,
guild = moderation . guild ,
reason = f " Automatic role addition from case # { moderation . id } " ,
moderation_type = type_registry [ " addrole " ] ,
moderator = None ,
duration = None ,
response = None ,
case = False ,
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except HTTPException :
pass
logger . trace (
" Added role %s to %s ( %s ) " ,
moderation . role_id ,
target . name ,
target . id ,
)
return 1
except (
NotFound ,
Forbidden ,
HTTPException ,
) as e :
logger . error (
" Adding the role %s to user %s failed due to: \n %s " ,
moderation . role_id ,
moderation . target_id ,
e ,
)
return 0
@classmethod
async def resolve_handler ( cls , moderation : Moderation , reason : str ) - > Tuple [ bool , str ] :
try :
target = await moderation . get_target ( )
await target . add_roles (
Object ( moderation . role_id ) , reason = reason
)
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
embed = await resolve_factory (
moderation = moderation ,
reason = reason
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except HTTPException :
pass
logger . trace (
" Added role %s to %s ( %s ) " ,
moderation . role_id ,
target . name ,
target . id ,
)
return True , " "
except ( NotFound , Forbidden , HTTPException ) as e :
logger . error (
" Failed to add role %s to user %s ( %s ) \n %s " ,
moderation . role_id ,
target . name ,
target . id ,
e ,
)
return False , " Failed to add role to user. "
2024-07-06 13:03:59 -04:00
class Mute ( Type ) :
key = " mute "
string = " mute "
verb = " muted "
2024-07-12 15:22:24 -04:00
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member , silent : bool , duration : str , reason : str = None ) :
if target . is_timed_out ( ) is True :
await ctx . send (
error ( f " { target . mention } is already muted! " ) ,
allowed_mentions = AllowedMentions ( users = False ) ,
ephemeral = True ,
)
return
try :
parsed_time = parse_timedelta ( duration , maximum = timedelta ( days = 28 ) )
if parsed_time is None :
await ctx . send (
error ( " Please provide a valid duration! " ) , ephemeral = True
)
return
except commands . BadArgument :
await ctx . send (
error ( " Please provide a duration that is less than 28 days. " ) , ephemeral = True
)
return
await target . timeout (
parsed_time , reason = f " Muted by { ctx . author . id } for: { reason } "
)
response = await ctx . send (
content = f " { target . mention } has been muted for { humanize_timedelta ( timedelta = parsed_time ) } ! \n **Reason** - ` { reason } ` "
)
if silent is False :
try :
embed = await message_factory (
bot = ctx . bot ,
color = await ctx . embed_color ( ) ,
guild = ctx . guild ,
moderator = ctx . author ,
reason = reason ,
moderation_type = cls ( ) ,
response = response ,
duration = parsed_time ,
)
await target . send ( embed = embed , file = get_icon ( ctx . bot ) )
except HTTPException :
pass
moderation = await Moderation . log (
bot = ctx . bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = " user " ,
target_id = target . id ,
role_id = None ,
duration = parsed_time ,
reason = reason ,
)
await response . edit (
content = f " { target . mention } has been muted for { humanize_timedelta ( timedelta = parsed_time ) } ! (Case `# { moderation . id : , } `) \n **Reason** - ` { reason } ` "
)
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
return cls ( )
@classmethod
async def resolve_handler ( cls , moderation : Moderation , reason : str ) - > Tuple [ bool , str ] :
try :
target = await moderation . guild . fetch_member ( moderation . target_id )
except ( Forbidden , HTTPException , NotFound ) :
return False , " User is not in the server, so I cannot unmute them. "
if target . is_timed_out ( ) is False :
return True , " "
await target . timeout ( None , reason = reason )
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
embed = await resolve_factory (
moderation = moderation ,
reason = reason
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except ( Forbidden , HTTPException ) :
pass
return True , " "
@classmethod
async def duration_edit_handler ( cls , interaction : Interaction , old_moderation : Moderation , new_moderation : Moderation ) - > bool : # pylint: disable=unused-argument
if (
time ( ) - new_moderation . unix_timestamp
) + new_moderation . duration . total_seconds ( ) > 2419200 :
await interaction . response . send_message (
content = error (
" Please provide a duration that is less than 28 days from the initial moderation. "
) ,
ephemeral = True
)
return False
try :
member = await interaction . guild . fetch_member (
new_moderation . target_id
)
await member . timeout (
new_moderation . duration ,
reason = f " Case # { new_moderation . id : , } edited by { interaction . user . id } " ,
)
except NotFound :
pass
return True
2024-07-06 13:03:59 -04:00
class Unmute ( Type ) :
key = " unmute "
string = " unmute "
verb = " unmuted "
2024-07-12 15:22:24 -04:00
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member , silent : bool , reason : str = None ) :
if target . is_timed_out ( ) is False :
await ctx . send (
content = error ( f " { target . mention } is not muted! " ) ,
allowed_mentions = AllowedMentions ( users = False ) ,
ephemeral = True ,
)
return
if reason :
await target . timeout (
None , reason = f " { cls . verb . title ( ) } by { ctx . author . id } for: { reason } "
)
else :
await target . timeout ( None , reason = f " { cls . verb . title ( ) } by { ctx . author . id } " )
reason = " No reason given. "
response_message = await ctx . send (
content = f " { target . mention } has been { cls . verb } ! \n **Reason** - ` { reason } ` "
)
if silent is False :
try :
embed = await message_factory (
bot = ctx . bot ,
color = await ctx . embed_color ( ) ,
guild = ctx . guild ,
moderator = ctx . author ,
reason = reason ,
moderation_type = " unmuted " ,
response = response_message ,
)
await target . send ( embed = embed , file = get_icon ( ctx . bot ) )
except HTTPException :
pass
moderation = await Moderation . log (
bot = ctx . bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = " user " ,
target_id = target . id ,
role_id = None ,
duration = None ,
reason = reason ,
)
await response_message . edit (
content = f " { target . mention } has been { cls . verb } ! (Case `# { moderation . id : , } `) \n **Reason** - ` { reason } ` "
)
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
2024-07-06 13:03:59 -04:00
class Kick ( Type ) :
key = " kick "
string = " kick "
verb = " kicked "
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member | User , silent : bool , reason : str = None ) - > ' Kick ' :
""" Kick a user. """
bot = ctx . bot
response_message = await ctx . send ( f " { target . mention } has been { cls . verb } ! \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
if silent is False :
try :
embed = await message_factory (
2024-07-06 13:39:01 -04:00
bot = bot ,
2024-07-12 15:22:24 -04:00
color = await ctx . embed_color ( ) ,
2024-07-06 13:39:01 -04:00
guild = ctx . guild ,
reason = reason ,
moderation_type = cls ( ) ,
moderator = ctx . author ,
duration = None ,
response = response_message
2024-07-06 13:03:59 -04:00
)
await target . send ( embed = embed , file = get_icon ( bot ) )
except HTTPException :
pass
await target . kick ( reason = f " { str . title ( cls . verb ) } by { ctx . author . id } for: { reason } " )
moderation = await Moderation . log (
2024-07-06 13:39:01 -04:00
bot = bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = ' user ' ,
target_id = target . id ,
role_id = None ,
duration = None ,
reason = reason
2024-07-06 13:03:59 -04:00
)
await response_message . edit ( content = f " { target . mention } has been { cls . verb } ! (Case { inline ( f ' # { moderation . id } ' ) } ) \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
2024-07-12 15:22:24 -04:00
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
2024-07-06 13:03:59 -04:00
return cls
2024-07-12 15:22:24 -04:00
@classmethod
async def resolve_handler ( cls , moderation : Moderation , reason : str ) - > Tuple [ bool , str ] :
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
target = await moderation . bot . fetch_user ( moderation . target_id )
embed = await resolve_factory (
moderation = moderation ,
reason = reason
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except ( Forbidden , HTTPException , NotFound ) :
pass
return True , " "
2024-07-06 11:30:37 -04:00
class Ban ( Type ) :
2024-07-06 12:23:06 -04:00
key = " ban "
string = " ban "
2024-07-06 11:46:13 -04:00
verb = " banned "
2024-07-06 11:30:37 -04:00
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member | User , silent : bool , reason : str = None , delete_messages : app_commands . Choice | None = None ) - > ' Ban ' :
""" Ban a user. """
bot = ctx . bot
try :
await ctx . guild . fetch_ban ( target )
2024-07-06 13:03:59 -04:00
await ctx . send ( content = error ( f " { target . mention } is already { cls . verb } ! " ) , ephemeral = True )
2024-07-06 11:30:37 -04:00
except NotFound :
pass
if delete_messages is None :
delete_messages_seconds = 0
else :
delete_messages_seconds = delete_messages . value
response_message = await ctx . send ( f " { target . mention } has been { cls . verb } ! \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
2024-07-06 11:52:19 -04:00
if silent is False :
2024-07-06 11:30:37 -04:00
try :
embed = await message_factory (
2024-07-06 13:39:01 -04:00
bot = bot ,
2024-07-12 15:22:24 -04:00
color = await ctx . embed_color ( ) ,
2024-07-06 13:39:01 -04:00
guild = ctx . guild ,
reason = reason ,
moderation_type = cls ( ) ,
moderator = ctx . author ,
duration = None ,
response = response_message
2024-07-06 11:30:37 -04:00
)
await target . send ( embed = embed , file = get_icon ( bot ) )
except HTTPException :
pass
2024-07-06 13:03:59 -04:00
await ctx . guild . ban ( target , reason = f " { str . title ( cls . verb ) } by { ctx . author . id } for: { reason } " , delete_message_seconds = delete_messages_seconds )
2024-07-06 11:30:37 -04:00
moderation = await Moderation . log (
2024-07-06 13:39:01 -04:00
bot = bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = ' user ' ,
target_id = target . id ,
role_id = None ,
duration = None ,
reason = reason
2024-07-06 11:30:37 -04:00
)
await response_message . edit ( content = f " { target . mention } has been { cls . verb } ! (Case { inline ( f ' # { moderation . id } ' ) } ) \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
2024-07-12 15:22:24 -04:00
await log ( ctx = ctx , moderation_id = moderation . id )
await send_evidenceformat ( ctx = ctx , moderation_id = moderation . id )
2024-07-06 11:30:37 -04:00
return cls
@classmethod
2024-07-12 15:22:24 -04:00
async def resolve_handler ( cls , moderation : Moderation , reason : str ) - > Tuple [ bool , str ] :
2024-07-06 11:30:37 -04:00
try :
2024-07-12 15:22:24 -04:00
target = await moderation . bot . fetch_user ( moderation . target_id )
except ( HTTPException , NotFound ) :
return False , " Fetching the target failed, so I cannot unban them. "
2024-07-06 11:30:37 -04:00
try :
2024-07-12 15:22:24 -04:00
await moderation . guild . unban ( user = target , reason = reason )
except ( NotFound , Forbidden , HTTPException ) as e :
if e == NotFound :
return True , " "
return False , " I do not have permission to unban this user. "
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
embed = await resolve_factory (
moderation = moderation ,
reason = reason
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except ( Forbidden , HTTPException ) :
pass
return True , " "
2024-07-06 11:30:37 -04:00
class Tempban ( Ban ) :
2024-07-06 12:23:06 -04:00
key = " tempban "
string = " tempban "
2024-07-06 11:46:13 -04:00
verb = " tempbanned "
2024-07-06 11:30:37 -04:00
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member | User , silent : bool , duration : str , reason : str = None , delete_messages : app_commands . Choice | None = None ) - > ' Ban ' :
""" Ban a user. """
bot = ctx . bot
try :
await ctx . guild . fetch_ban ( target )
2024-07-06 13:03:59 -04:00
await ctx . send ( content = error ( f " { target . mention } is already { Ban . verb } ! " ) , ephemeral = True )
2024-07-06 11:30:37 -04:00
except NotFound :
pass
if delete_messages is None :
delete_messages_seconds = 0
else :
delete_messages_seconds = delete_messages . value
parsed_time = parse_relativedelta ( duration )
if not parsed_time :
await ctx . send ( content = error ( " Please provide a valid duration! " ) , ephemeral = True )
try :
parsed_time = timedelta_from_relativedelta ( parsed_time )
except ValueError :
await ctx . send ( content = error ( " Please provide a valid duration! " ) , ephemeral = True )
response_message = await ctx . send ( f " { target . mention } has been { cls . verb } for { humanize_timedelta ( parsed_time ) } ! \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
2024-07-06 11:52:19 -04:00
if silent is False :
2024-07-06 11:30:37 -04:00
try :
embed = await message_factory (
2024-07-06 13:39:01 -04:00
bot = bot ,
2024-07-12 15:22:24 -04:00
color = await ctx . embed_color ( ) ,
2024-07-06 13:39:01 -04:00
guild = ctx . guild ,
reason = reason ,
moderation_type = cls ( ) ,
moderator = ctx . author ,
duration = parsed_time ,
response = response_message
2024-07-06 11:30:37 -04:00
)
await target . send ( embed = embed , file = get_icon ( bot ) )
except HTTPException :
pass
2024-07-06 13:03:59 -04:00
await ctx . guild . ban ( target , reason = f " { str . title ( cls . verb ) } by { ctx . author . id } for: { reason } (Duration: { parsed_time } ) " , delete_message_seconds = delete_messages_seconds )
2024-07-06 11:30:37 -04:00
moderation = await Moderation . log (
2024-07-06 13:39:01 -04:00
bot = bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = ' user ' ,
target_id = target . id ,
role_id = None ,
duration = parsed_time ,
reason = reason
2024-07-06 11:30:37 -04:00
)
await response_message . edit ( content = f " { target . mention } has been { cls . verb } for { humanize_timedelta ( parsed_time ) } ! (Case { inline ( f ' # { moderation . id } ' ) } ) \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
await log ( ctx , moderation . id )
await send_evidenceformat ( ctx , moderation . id )
return cls
2024-07-06 13:03:59 -04:00
2024-07-12 15:22:24 -04:00
@classmethod
async def expiry_handler ( cls , moderation : Moderation ) - > int :
reason = f " Automatic { Unban . string } from case # { moderation . id } "
try :
target = await moderation . get_target ( )
await moderation . guild . unban ( user = target , reason = reason )
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
embed = await message_factory (
bot = moderation . bot ,
color = await moderation . bot . get_embed_color ( moderation . guild . channels [ 0 ] ) ,
guild = moderation . guild ,
reason = reason ,
moderation_type = type_registry [ " unban " ] ,
moderator = None ,
duration = None ,
response = None ,
case = False ,
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except HTTPException :
pass
logger . trace (
" %s %s ( %s ) from %s ( %s ) " ,
Unban . verb . title ( ) ,
target . name ,
target . id ,
moderation . guild . name ,
moderation . guild . id ,
)
return 1
except ( NotFound , Forbidden , HTTPException ) as e :
logger . error (
" Failed to %s %s ( %s ) from %s ( %s ) \n %s " ,
Unban . string ,
target . name ,
target . id ,
moderation . guild . name ,
moderation . guild . id ,
e ,
)
return 0
@classmethod
async def duration_edit_handler ( cls , interaction : Interaction , old_moderation : Moderation , new_moderation : Moderation ) - > bool : # pylint: disable=unused-argument
return True
2024-07-06 13:10:09 -04:00
class Softban ( Type ) :
key = " softban "
string = " softban "
verb = " softbanned "
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member | User , silent : bool , reason : str = None , delete_messages : app_commands . Choice | None = None ) - > ' Softban ' :
""" Softban a user. """
bot = ctx . bot
try :
await ctx . guild . fetch_ban ( target )
await ctx . send ( content = error ( f " { target . mention } is already { Ban . verb } ! " ) , ephemeral = True )
except NotFound :
pass
if delete_messages is None :
delete_messages_seconds = 0
else :
delete_messages_seconds = delete_messages . value
response_message = await ctx . send ( f " { target . mention } has been { cls . verb } ! \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
if silent is False :
try :
embed = await message_factory (
2024-07-06 13:39:01 -04:00
bot = bot ,
2024-07-12 15:22:24 -04:00
color = await ctx . embed_color ( ) ,
2024-07-06 13:39:01 -04:00
guild = ctx . guild ,
reason = reason ,
moderation_type = cls ( ) ,
moderator = ctx . author ,
duration = None ,
response = response_message
2024-07-06 13:10:09 -04:00
)
await target . send ( embed = embed , file = get_icon ( bot ) )
except HTTPException :
pass
await ctx . guild . ban ( target , reason = f " { str . title ( cls . verb ) } by { ctx . author . id } for: { reason } " , delete_message_seconds = delete_messages_seconds )
2024-07-06 13:10:47 -04:00
await ctx . guild . unban ( target , reason = f " { str . title ( cls . verb ) } by { ctx . author . id } for: { reason } " )
2024-07-06 13:10:09 -04:00
moderation = await Moderation . log (
2024-07-06 13:39:01 -04:00
bot = bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = ' user ' ,
target_id = target . id ,
role_id = None ,
duration = None ,
reason = reason
2024-07-06 13:10:09 -04:00
)
await response_message . edit ( content = f " { target . mention } has been { cls . verb } ! (Case { inline ( f ' # { moderation . id } ' ) } ) \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
await log ( ctx , moderation . id )
await send_evidenceformat ( ctx , moderation . id )
return cls
2024-07-12 15:22:24 -04:00
@classmethod
async def resolve_handler ( cls , moderation : Moderation , reason : str ) - > Tuple [ bool , str ] :
if await config . guild ( moderation . guild ) . dm_users ( ) is True :
try :
target = await moderation . bot . fetch_user ( moderation . target_id )
embed = await resolve_factory (
moderation = moderation ,
reason = reason
)
await target . send ( embed = embed , file = get_icon ( bot = moderation . bot ) )
except ( Forbidden , HTTPException , NotFound ) :
pass
return True , " "
2024-07-06 13:03:59 -04:00
class Unban ( Type ) :
key = " unban "
string = " unban "
verb = " unbanned "
@classmethod
async def handler ( cls , ctx : commands . Context , target : Member | User , silent : bool , reason : str = None ) - > ' Unban ' :
""" Unban a user. """
bot = ctx . bot
try :
await ctx . guild . fetch_ban ( target )
except NotFound :
await ctx . send ( content = error ( f " { target . mention } is not { Ban . verb } ! " ) , ephemeral = True )
return
response_message = await ctx . send ( f " { target . mention } has been { cls . verb } ! \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
if silent is False :
try :
embed = await message_factory (
2024-07-06 13:39:01 -04:00
bot = bot ,
2024-07-12 15:22:24 -04:00
color = await ctx . embed_color ( ) ,
2024-07-06 13:39:01 -04:00
guild = ctx . guild ,
reason = reason ,
moderation_type = cls ( ) ,
moderator = ctx . author ,
duration = None ,
response = response_message
2024-07-06 13:03:59 -04:00
)
await target . send ( embed = embed , file = get_icon ( bot ) )
except HTTPException :
pass
await ctx . guild . unban ( target , reason = f " { str . title ( cls . verb ) } by { ctx . author . id } for: { reason } " )
moderation = await Moderation . log (
2024-07-06 13:39:01 -04:00
bot = bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = ' user ' ,
target_id = target . id ,
role_id = None ,
duration = None ,
reason = reason
2024-07-06 13:03:59 -04:00
)
await response_message . edit ( content = f " { target . mention } has been { cls . verb } ! (Case { inline ( f ' # { moderation . id } ' ) } ) \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
await log ( ctx , moderation . id )
await send_evidenceformat ( ctx , moderation . id )
return cls
class Slowmode ( Type ) :
key = " slowmode "
string = " slowmode "
verb = " set the slowmode in "
channel = True
@classmethod
async def handler ( cls , ctx : commands . Context , target : Messageable , silent : bool , duration : str , reason : str ) - > ' Slowmode ' : # pylint: disable=unused-argument
""" Set the slowmode in a channel. """
bot = ctx . bot
parsed_time = parse_relativedelta ( duration )
if not parsed_time :
await ctx . send ( content = error ( " Please provide a valid duration! " ) , ephemeral = True )
try :
parsed_time = timedelta_from_relativedelta ( parsed_time )
except ValueError :
await ctx . send ( content = error ( " Please provide a valid duration! " ) , ephemeral = True )
if ceil ( parsed_time . total_seconds ( ) ) > 21600 :
await ctx . send ( content = error ( " The slowmode duration cannot exceed 6 hours! " ) , ephemeral = True )
return
if isinstance ( target , TextChannel ) :
await target . edit ( slowmode_delay = ceil ( parsed_time . total_seconds ( ) ) )
moderation = await Moderation . log (
2024-07-06 13:39:01 -04:00
bot = bot ,
guild_id = ctx . guild . id ,
moderator_id = ctx . author . id ,
moderation_type = cls ( ) ,
target_type = ' channel ' ,
target_id = target . id ,
role_id = None ,
duration = parsed_time ,
reason = None
2024-07-06 13:03:59 -04:00
)
await ctx . send ( f " { ctx . author . mention } has { cls . verb } { target . mention } to { humanize_timedelta ( parsed_time ) } ! \n { bold ( ' Reason: ' ) } { inline ( reason ) } " )
await log ( ctx , moderation . id )
return cls
class Lockdown ( Type ) :
key = " lockdown "
string = " lockdown "
verb = " locked down "
channel = True