2024-05-04 14:08:53 -04:00
|
|
|
from datetime import datetime, timedelta
|
2024-05-04 16:54:12 -04:00
|
|
|
from typing import Any, Dict, List, Optional, Union
|
2024-05-04 13:41:11 -04:00
|
|
|
|
2024-05-04 16:54:12 -04:00
|
|
|
from async_property import async_cached_property
|
|
|
|
from discord import Forbidden, HTTPException, InvalidData, NotFound
|
2024-05-04 13:41:11 -04:00
|
|
|
from pydantic import BaseModel
|
2024-05-04 16:54:12 -04:00
|
|
|
from redbot.core.bot import Red
|
2024-05-04 13:42:58 -04:00
|
|
|
|
2024-05-04 16:54:12 -04:00
|
|
|
from aurora.utilities.utils import generate_dict
|
2024-05-04 13:41:11 -04:00
|
|
|
|
2024-05-04 15:37:07 -04:00
|
|
|
|
|
|
|
class AuroraBaseModel(BaseModel):
|
|
|
|
"""Base class for all models in Aurora."""
|
|
|
|
class Moderation(AuroraBaseModel):
|
2024-05-04 16:54:12 -04:00
|
|
|
bot: Red
|
2024-05-04 13:41:11 -04:00
|
|
|
moderation_id: int
|
2024-05-04 14:08:53 -04:00
|
|
|
guild_id: int
|
|
|
|
timestamp: datetime
|
2024-05-04 13:41:11 -04:00
|
|
|
moderation_type: str
|
|
|
|
target_type: str
|
|
|
|
target_id: int
|
|
|
|
moderator_id: int
|
2024-05-04 14:08:53 -04:00
|
|
|
role_id: Optional[int]
|
|
|
|
duration: Optional[timedelta]
|
|
|
|
end_timestamp: Optional[datetime]
|
|
|
|
reason: Optional[str]
|
2024-05-04 13:41:11 -04:00
|
|
|
resolved: bool
|
2024-05-04 14:08:53 -04:00
|
|
|
resolved_by: Optional[int]
|
|
|
|
resolve_reason: Optional[str]
|
2024-05-04 13:41:11 -04:00
|
|
|
expired: bool
|
|
|
|
changes: List[Dict]
|
|
|
|
metadata: Dict
|
|
|
|
|
2024-05-04 16:54:12 -04:00
|
|
|
@property
|
|
|
|
def id(self) -> int:
|
|
|
|
return self.moderation_id
|
|
|
|
|
|
|
|
@property
|
|
|
|
def type(self) -> str:
|
|
|
|
return self.moderation_type
|
|
|
|
|
|
|
|
@async_cached_property
|
|
|
|
async def moderator(self) -> "PartialUser":
|
|
|
|
return await PartialUser.from_id(self.bot, self.moderator_id)
|
|
|
|
|
|
|
|
@async_cached_property
|
|
|
|
async def target(self) -> Union["PartialUser", "PartialChannel"]:
|
|
|
|
if self.target_type == "user":
|
|
|
|
return await PartialUser.from_id(self.bot, self.target_id)
|
|
|
|
else:
|
|
|
|
return await PartialChannel.from_id(self.bot, self.target_id)
|
|
|
|
|
|
|
|
@async_cached_property
|
|
|
|
async def resolved_by_user(self) -> Optional["PartialUser"]:
|
|
|
|
if self.resolved_by:
|
|
|
|
return await PartialUser.from_id(self.bot, self.resolved_by)
|
|
|
|
return None
|
|
|
|
|
2024-05-04 13:41:11 -04:00
|
|
|
def __str__(self):
|
|
|
|
return f"{self.moderation_type} {self.target_type} {self.target_id} {self.reason}"
|
|
|
|
|
2024-05-04 13:47:07 -04:00
|
|
|
@classmethod
|
2024-05-04 16:54:12 -04:00
|
|
|
def from_sql(cls, bot: Red, moderation_id: int, guild_id: int) -> Optional["Moderation"]:
|
2024-05-04 14:08:53 -04:00
|
|
|
from aurora.utilities.database import connect
|
|
|
|
query = f"SELECT * FROM moderation_{guild_id} WHERE moderation_id = ?;"
|
2024-05-04 13:47:07 -04:00
|
|
|
|
2024-05-04 13:48:57 -04:00
|
|
|
with connect() as database:
|
|
|
|
cursor = database.cursor()
|
2024-05-04 13:47:07 -04:00
|
|
|
cursor.execute(query, (moderation_id,))
|
|
|
|
result = cursor.fetchone()
|
|
|
|
|
|
|
|
if result:
|
2024-05-04 16:54:12 -04:00
|
|
|
case = generate_dict(result)
|
2024-05-04 13:48:57 -04:00
|
|
|
cursor.close()
|
2024-05-04 16:54:12 -04:00
|
|
|
return cls.from_dict(bot, case)
|
2024-05-04 13:47:07 -04:00
|
|
|
|
|
|
|
return None
|
2024-05-04 15:08:08 -04:00
|
|
|
|
2024-05-04 16:54:12 -04:00
|
|
|
@classmethod
|
|
|
|
def from_dict(cls, bot: Red, data: dict) -> "Moderation":
|
|
|
|
return cls(bot=bot, **data)
|
|
|
|
|
|
|
|
def to_json(self, indent: int = None, file: Any = None):
|
2024-05-04 15:25:05 -04:00
|
|
|
from aurora.utilities.json import dump, dumps
|
2024-05-04 16:54:12 -04:00
|
|
|
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 PartialUser(AuroraBaseModel):
|
|
|
|
id: int
|
|
|
|
username: str
|
|
|
|
discriminator: int
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return f"{self.username}#{self.discriminator}" if self.discriminator == 0 else self.username
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
async def from_id(cls, bot: Red, user_id: int) -> "PartialUser":
|
|
|
|
user = bot.get_user(user_id)
|
|
|
|
if not user:
|
|
|
|
try:
|
|
|
|
user = await bot.fetch_user(user_id)
|
|
|
|
return cls(id=user.id, username=user.name, discriminator=user.discriminator)
|
|
|
|
except NotFound:
|
|
|
|
return cls(id=user_id, username="Deleted User", discriminator=0)
|
|
|
|
|
|
|
|
class PartialChannel(AuroraBaseModel):
|
|
|
|
id: int
|
|
|
|
name: str
|
|
|
|
|
|
|
|
@property
|
|
|
|
def mention(self):
|
|
|
|
if self.name == "Deleted Channel" or self.name == "Forbidden Channel":
|
|
|
|
return self.name
|
|
|
|
return f"<#{self.id}>"
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.mention
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
async def from_id(cls, bot: Red, channel_id: int) -> "PartialChannel":
|
|
|
|
user = bot.get_channel(channel_id)
|
|
|
|
if not user:
|
|
|
|
try:
|
|
|
|
user = await bot.fetch_channel(channel_id)
|
|
|
|
return cls(id=user.id, username=user.name, discriminator=user.discriminator)
|
|
|
|
except (NotFound, InvalidData, HTTPException, Forbidden) as e:
|
|
|
|
if e == Forbidden:
|
|
|
|
return cls(id=channel_id, name="Forbidden Channel")
|
|
|
|
return cls(id=channel_id, name="Deleted Channel")
|