Compare commits

..

No commits in common. "e7e8d60f3b56d33baead9915aa70a52b4c827453" and "2c336ff70c143abea2a605ded05b934ad185e9cb" have entirely different histories.

3 changed files with 72 additions and 100 deletions

View file

@ -1,5 +1,5 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any, ClassVar, Dict, List, Literal, Optional, Union from typing import Any, ClassVar, Dict, List, Optional, Union
from discord import Forbidden, HTTPException, InvalidData, NotFound from discord import Forbidden, HTTPException, InvalidData, NotFound
from pydantic import BaseModel from pydantic import BaseModel
@ -10,11 +10,6 @@ from aurora.utilities.utils import generate_dict
class AuroraBaseModel(BaseModel): class AuroraBaseModel(BaseModel):
"""Base class for all models in Aurora.""" """Base class for all models in Aurora."""
def to_json(self, indent: int = None, file: Any = None, **kwargs):
from aurora.utilities.json import dump, dumps
return dump(self.model_dump(), file, indent=indent, **kwargs) if file else dumps(self.model_dump(), indent=indent, **kwargs)
class Moderation(AuroraBaseModel): class Moderation(AuroraBaseModel):
bot: ClassVar[Red] bot: ClassVar[Red]
moderation_id: int moderation_id: int
@ -57,11 +52,6 @@ class Moderation(AuroraBaseModel):
return await PartialUser.from_id(self.bot, self.resolved_by) return await PartialUser.from_id(self.bot, self.resolved_by)
return None return None
async def get_role(self) -> Optional["PartialRole"]:
if self.role_id:
return await PartialRole.from_id(self.bot, self.guild_id, self.role_id)
return None
def __str__(self): def __str__(self):
return f"{self.moderation_type} {self.target_type} {self.target_id} {self.reason}" return f"{self.moderation_type} {self.target_type} {self.target_id} {self.reason}"
@ -86,26 +76,11 @@ class Moderation(AuroraBaseModel):
def from_dict(cls, bot: Red, data: dict) -> "Moderation": def from_dict(cls, bot: Red, data: dict) -> "Moderation":
return cls(bot=bot, **data) return cls(bot=bot, **data)
def to_json(self, indent: int = None, file: Any = None, **kwargs): def to_json(self, indent: int = None, file: Any = None):
from aurora.utilities.json import dump, dumps from aurora.utilities.json import dump, dumps
return dump(self.model_dump(exclude={"bot", "guild_id"}), file, indent=indent, **kwargs) if file else dumps(self.model_dump(exclude={"bot", "guild_id"}), indent=indent, **kwargs) return dump(self.model_dump(exclude={"bot", "guild_id"}), file, indent=indent) if file else dumps(self.model_dump(exclude={"bot", "guild_id"}), indent=indent)
class Change(AuroraBaseModel):
type: Literal["ORIGINAL", "RESOLVE", "EDIT"]
timestamp: datetime
reason: str
user_id: int
duration: Optional[timedelta]
end_timestamp: Optional[datetime]
def __str__(self):
return f"{self.type} {self.user_id} {self.reason}"
@classmethod
def from_dict(cls, data: dict) -> "Change":
return cls(**data)
class PartialUser(AuroraBaseModel): class PartialUser(AuroraBaseModel):
id: int id: int
username: str username: str
@ -128,7 +103,6 @@ class PartialUser(AuroraBaseModel):
except NotFound: except NotFound:
return cls(id=user_id, username="Deleted User", discriminator=0) return cls(id=user_id, username="Deleted User", discriminator=0)
class PartialChannel(AuroraBaseModel): class PartialChannel(AuroraBaseModel):
id: int id: int
name: str name: str
@ -153,26 +127,3 @@ class PartialChannel(AuroraBaseModel):
if e == Forbidden: if e == Forbidden:
return cls(id=channel_id, name="Forbidden Channel") return cls(id=channel_id, name="Forbidden Channel")
return cls(id=channel_id, name="Deleted Channel") return cls(id=channel_id, name="Deleted Channel")
class PartialRole(AuroraBaseModel):
id: int
guild_id: int
name: str
@property
def mention(self):
return f"<@&{self.id}>"
def __str__(self):
return self.mention
@classmethod
async def from_id(cls, bot: Red, guild_id: int, role_id: int) -> "PartialRole":
try:
guild = await bot.fetch_guild(guild_id, with_counts=False)
except (Forbidden, HTTPException):
return cls(id=role_id, guild_id=guild_id, name="Forbidden Role")
role = guild.get_role(role_id)
if not role:
return cls(id=role_id, guild_id=guild_id, name="Deleted Role")
return cls(id=role.id, guild_id=guild_id, name=role.name)

View file

@ -2,13 +2,17 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Union from typing import Union
from discord import Color, Embed, Guild, Interaction, InteractionMessage, Member, Role, User from discord import (Color, Embed, Guild, Interaction, InteractionMessage,
Member, Role, User)
from redbot.core import commands from redbot.core import commands
from redbot.core.utils.chat_formatting import bold, box, error, humanize_timedelta, warning from redbot.core.utils.chat_formatting import (bold, box, error,
humanize_timedelta, warning)
from aurora.models import Moderation from aurora.models import Moderation
from aurora.utilities.config import config from aurora.utilities.config import config
from aurora.utilities.utils import fetch_channel_dict, fetch_user_dict, get_bool_emoji, get_next_case_number, get_pagesize_str from aurora.utilities.utils import (fetch_channel_dict, fetch_user_dict,
get_bool_emoji, get_next_case_number,
get_pagesize_str)
async def message_factory( async def message_factory(
@ -151,79 +155,105 @@ async def log_factory(
return embed return embed
async def case_factory(interaction: Interaction, moderation: Moderation) -> Embed: async def case_factory(interaction: Interaction, case_dict: dict) -> Embed:
"""This function creates a case embed from set parameters. """This function creates a case embed from set parameters.
Args: Args:
interaction (discord.Interaction): The interaction object. interaction (Interaction): The interaction object.
moderation (aurora.models.Moderation): The moderation object. case_dict (dict): The case dictionary.
""" """
target = await moderation.get_target() if case_dict["target_type"] == "USER":
moderator = await moderation.get_moderator() target_user = await fetch_user_dict(interaction.client, 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.guild, 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.client, 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( embed = Embed(
title=f"📕 Case #{moderation.id:,}", title=f"📕 Case #{case_dict['moderation_id']:,}",
color=await interaction.client.get_embed_color(interaction.channel), color=await interaction.client.get_embed_color(interaction.channel),
) )
embed.description = f"**Type:** {str.title(moderation.type)}\n**Target:** {target.name} ({target.id})\n**Moderator:** {moderator.name} ({moderator.id})\n**Resolved:** {moderation.resolved}\n**Timestamp:** <t:{moderation.timestamp}> | <t:{moderation.timestamp}:R>" 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:** <t:{case_dict['timestamp']}> | <t:{case_dict['timestamp']}:R>"
if moderation.duration: if case_dict["duration"] != "NULL":
duration_embed = ( td = timedelta(
f"{humanize_timedelta(timedelta=moderation.duration)} | <t:{moderation.timestamp}:R>" **{
if moderation.expired is False unit: int(val)
else str(humanize_timedelta(timedelta=moderation.duration)) for unit, val in zip(
["hours", "minutes", "seconds"], case_dict["duration"].split(":")
)
}
) )
embed.description += f"\n**Duration:** {duration_embed}\n**Expired:** {moderation.expired}" duration_embed = (
f"{humanize_timedelta(timedelta=td)} | <t:{case_dict['end_timestamp']}:R>"
if bool(case_dict["expired"]) is False
else str(humanize_timedelta(timedelta=td))
)
embed.description += f"\n**Duration:** {duration_embed}\n**Expired:** {bool(case_dict['expired'])}"
embed.description += ( embed.description += (
f"\n**Changes:** {len(moderation.changes) - 1}" f"\n**Changes:** {len(case_dict['changes']) - 1}"
if moderation.changes if case_dict["changes"]
else "\n**Changes:** 0" else "\n**Changes:** 0"
) )
if moderation.role_id: if case_dict["role_id"]:
role = await moderation.get_role() embed.description += f"\n**Role:** <@&{case_dict['role_id']}>"
embed.description += f"\n**Role:** {role.name}"
if moderation.metadata: if case_dict["metadata"]:
if moderation.metadata["imported_from"]: if case_dict["metadata"]["imported_from"]:
embed.description += ( embed.description += (
f"\n**Imported From:** {moderation.metadata['imported_from']}" f"\n**Imported From:** {case_dict['metadata']['imported_from']}"
)
if moderation.metadata["imported_timestamp"]:
embed.description += (
f"\n**Imported Timestamp:** <t:{moderation.metadata['imported_timestamp']}> | <t:{moderation.metadata['imported_timestamp']}:R>"
) )
embed.add_field(name="Reason", value=box(moderation.reason), inline=False) embed.add_field(name="Reason", value=box(case_dict["reason"]), inline=False)
if moderation.resolved: if case_dict["resolved"] == 1:
resolved_user = await moderation.get_resolved_by() resolved_user = await fetch_user_dict(interaction.client, 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( embed.add_field(
name="Resolve Reason", name="Resolve Reason",
value=f"Resolved by {resolved_user.name} ({resolved_user.id}) for:\n{box(moderation.resolve_reason)}", value=f"Resolved by {resolved_name} ({resolved_user['id']}) for:\n{box(case_dict['resolve_reason'])}",
inline=False, inline=False,
) )
return embed return embed
async def changes_factory(interaction: Interaction, moderation: Moderation) -> Embed: async def changes_factory(interaction: Interaction, case_dict: dict) -> Embed:
"""This function creates a changes embed from set parameters. """This function creates a changes embed from set parameters.
Args: Args:
interaction (discord.Interaction): The interaction object. interaction (Interaction): The interaction object.
moderation (aurora.models.Moderation): The moderation object. case_dict (dict): The case dictionary.
""" """
embed = Embed( embed = Embed(
title=f"📕 Case #{moderation.id:,} Changes", title=f"📕 Case #{case_dict['moderation_id']:,} Changes",
color=await interaction.client.get_embed_color(interaction.channel), color=await interaction.client.get_embed_color(interaction.channel),
) )
memory_dict = {} memory_dict = {}
if moderation.changes: if case_dict["changes"]:
for change in moderation.changes: for change in case_dict["changes"]:
if change["user_id"] not in memory_dict: if change["user_id"] not in memory_dict:
memory_dict[str(change["user_id"])] = await fetch_user_dict( memory_dict[str(change["user_id"])] = await fetch_user_dict(
interaction.client, change["user_id"] interaction.client, change["user_id"]

View file

@ -9,11 +9,9 @@ from discord.errors import Forbidden, NotFound
from redbot.core import commands, data_manager from redbot.core import commands, data_manager
from redbot.core.utils.chat_formatting import error from redbot.core.utils.chat_formatting import error
from aurora.models import Change
from aurora.utilities.config import config from aurora.utilities.config import config
def check_permissions( def check_permissions(
user: User, user: User,
permissions: list, permissions: list,
@ -132,13 +130,6 @@ def generate_dict(result: dict, guild_id: int) -> dict:
duration = timedelta(hours=hours, minutes=minutes, seconds=seconds) duration = timedelta(hours=hours, minutes=minutes, seconds=seconds)
else: else:
duration = None duration = None
if result[14] is not None:
changes = json.loads(result[14].strip('"').replace('\\"', '"'))
change_obj_list = []
for change in changes:
change_obj_list.append(Change(**change))
case = { case = {
"moderation_id": int(result[0]), "moderation_id": int(result[0]),
"guild_id": int(guild_id), "guild_id": int(guild_id),
@ -155,7 +146,7 @@ def generate_dict(result: dict, guild_id: int) -> dict:
"resolved_by": result[11], "resolved_by": result[11],
"resolve_reason": result[12], "resolve_reason": result[12],
"expired": bool(result[13]), "expired": bool(result[13]),
"changes": change_obj_list if result[14] else [], "changes": json.loads(result[14].strip('"').replace('\\"', '"')) if result[14] else [],
"metadata": json.loads(result[15].strip('"').replace('\\"', '"')) if result[15] else {}, "metadata": json.loads(result[15].strip('"').replace('\\"', '"')) if result[15] else {},
} }
return case return case