WIP: Refactor Aurora (3.0.0) #29
2 changed files with 199 additions and 305 deletions
237
aurora/aurora.py
237
aurora/aurora.py
|
@ -11,6 +11,7 @@ import sqlite3
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import Object
|
from discord import Object
|
||||||
|
@ -19,8 +20,7 @@ from redbot.core import app_commands, commands, data_manager
|
||||||
from redbot.core.app_commands import Choice
|
from redbot.core.app_commands import Choice
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.commands.converter import parse_relativedelta, parse_timedelta
|
from redbot.core.commands.converter import parse_relativedelta, parse_timedelta
|
||||||
from redbot.core.utils.chat_formatting import (box, error, humanize_list,
|
from redbot.core.utils.chat_formatting import box, error, humanize_list, humanize_timedelta, warning
|
||||||
humanize_timedelta, warning)
|
|
||||||
|
|
||||||
from aurora.importers.aurora import ImportAuroraView
|
from aurora.importers.aurora import ImportAuroraView
|
||||||
from aurora.importers.galacticbot import ImportGalacticBotView
|
from aurora.importers.galacticbot import ImportGalacticBotView
|
||||||
|
@ -30,19 +30,11 @@ from aurora.menus.immune import Immune
|
||||||
from aurora.menus.overrides import Overrides
|
from aurora.menus.overrides import Overrides
|
||||||
from aurora.models import Change, Moderation
|
from aurora.models import Change, Moderation
|
||||||
from aurora.utilities.config import config, register_config
|
from aurora.utilities.config import config, register_config
|
||||||
from aurora.utilities.database import (connect, create_guild_table, fetch_case,
|
from aurora.utilities.database import connect, create_guild_table, fetch_case, mysql_log
|
||||||
mysql_log)
|
from aurora.utilities.factory import addrole_embed, case_factory, changes_factory, evidenceformat_factory, guild_embed, immune_embed, message_factory, overrides_embed
|
||||||
from aurora.utilities.factory import (addrole_embed, case_factory,
|
from aurora.utilities.json import dump
|
||||||
changes_factory, evidenceformat_factory,
|
|
||||||
guild_embed, immune_embed,
|
|
||||||
message_factory, overrides_embed)
|
|
||||||
from aurora.utilities.json import dump, dumps
|
|
||||||
from aurora.utilities.logger import logger
|
from aurora.utilities.logger import logger
|
||||||
from aurora.utilities.utils import (check_moddable, check_permissions,
|
from aurora.utilities.utils import check_moddable, check_permissions, get_footer_image, log, send_evidenceformat, timedelta_from_relativedelta
|
||||||
fetch_channel_dict, fetch_user_dict,
|
|
||||||
generate_dict, get_footer_image, log,
|
|
||||||
send_evidenceformat,
|
|
||||||
timedelta_from_relativedelta)
|
|
||||||
|
|
||||||
|
|
||||||
class Aurora(commands.Cog):
|
class Aurora(commands.Cog):
|
||||||
|
@ -1122,15 +1114,15 @@ class Aurora(commands.Cog):
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
|
|
||||||
results = cursor.fetchall()
|
results = cursor.fetchall()
|
||||||
result_dict_list = []
|
moderation_list: List[Moderation] = []
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
case_dict = generate_dict(result)
|
if result["moderation_id"] != 0:
|
||||||
if case_dict["moderation_id"] == 0:
|
result.update({"guild_id": interaction.guild.id})
|
||||||
continue
|
moderation = Moderation.from_dict(interaction.client, dict(result))
|
||||||
result_dict_list.append(case_dict)
|
moderation_list.append(moderation)
|
||||||
|
|
||||||
case_quantity = len(result_dict_list)
|
case_quantity = len(moderation_list)
|
||||||
page_quantity = ceil(case_quantity / pagesize)
|
page_quantity = ceil(case_quantity / pagesize)
|
||||||
start_index = (page - 1) * pagesize
|
start_index = (page - 1) * pagesize
|
||||||
end_index = page * pagesize
|
end_index = page * pagesize
|
||||||
|
@ -1143,74 +1135,44 @@ class Aurora(commands.Cog):
|
||||||
|
|
||||||
memory_dict = {}
|
memory_dict = {}
|
||||||
|
|
||||||
for case in result_dict_list[start_index:end_index]:
|
for mod in moderation_list[start_index:end_index]:
|
||||||
if case["target_id"] not in memory_dict:
|
if mod.target_id not in memory_dict:
|
||||||
if case["target_type"] == "USER":
|
memory_dict.update({
|
||||||
memory_dict[str(case["target_id"])] = await fetch_user_dict(
|
str(mod.target_id): await mod.get_target()
|
||||||
interaction.client, case["target_id"]
|
})
|
||||||
)
|
target = memory_dict[str(mod.target_id)]
|
||||||
elif case["target_type"] == "CHANNEL":
|
|
||||||
memory_dict[str(case["target_id"])] = await fetch_channel_dict(
|
|
||||||
interaction.guild, case["target_id"]
|
|
||||||
)
|
|
||||||
target_user = memory_dict[str(case["target_id"])]
|
|
||||||
|
|
||||||
if case["target_type"] == "USER":
|
if mod.moderator_id not in memory_dict:
|
||||||
target_name = (
|
memory_dict.update({
|
||||||
f"`{target_user['name']}`"
|
str(mod.moderator_id): await mod.get_moderator()
|
||||||
if target_user["discriminator"] == "0"
|
})
|
||||||
else f"`{target_user['name']}#{target_user['discriminator']}`"
|
moderator = memory_dict[str(mod.moderator_id)]
|
||||||
)
|
|
||||||
elif case["target_type"] == "CHANNEL":
|
|
||||||
target_name = f"`{target_user['mention']}`"
|
|
||||||
|
|
||||||
if case["moderator_id"] not in memory_dict:
|
|
||||||
memory_dict[str(case["moderator_id"])] = await fetch_user_dict(
|
|
||||||
interaction.client, case["moderator_id"]
|
|
||||||
)
|
|
||||||
moderator_user = memory_dict[str(case["moderator_id"])]
|
|
||||||
moderator_name = (
|
|
||||||
f"`{moderator_user['name']}`"
|
|
||||||
if moderator_user["discriminator"] == "0"
|
|
||||||
else f"`{moderator_user['name']}#{moderator_user['discriminator']}`"
|
|
||||||
)
|
|
||||||
|
|
||||||
field_name = f"Case #{case['moderation_id']:,} ({str.title(case['moderation_type'])})"
|
field_name = f"Case #{case['moderation_id']:,} ({str.title(case['moderation_type'])})"
|
||||||
field_value = f"**Target:** {target_name} ({target_user['id']})\n**Moderator:** {moderator_name} ({moderator_user['id']})"
|
field_value = f"**Target:** `{target.name}` ({target.id})\n**Moderator:** `{moderator.name}` ({moderator.id})"
|
||||||
|
|
||||||
if len(case["reason"]) > 125:
|
if len(case["reason"]) > 125:
|
||||||
field_value += f"\n**Reason:** `{str(case['reason'])[:125]}...`"
|
field_value += f"\n**Reason:** `{str(mod.reason)[:125]}...`"
|
||||||
else:
|
else:
|
||||||
field_value += f"\n**Reason:** `{str(case['reason'])}`"
|
field_value += f"\n**Reason:** `{str(mod.reason)}`"
|
||||||
|
|
||||||
if case["duration"] != "NULL":
|
if mod.duration:
|
||||||
td = timedelta(
|
|
||||||
**{
|
|
||||||
unit: int(val)
|
|
||||||
for unit, val in zip(
|
|
||||||
["hours", "minutes", "seconds"], case["duration"].split(":")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
duration_embed = (
|
duration_embed = (
|
||||||
f"{humanize_timedelta(timedelta=td)} | <t:{case['end_timestamp']}:R>"
|
f"{humanize_timedelta(timedelta=mod.duration)} | <t:{int(mod.end_timestamp.timestamp())}:R>"
|
||||||
if bool(case["expired"]) is False
|
if mod.expired is False
|
||||||
else f"{humanize_timedelta(timedelta=td)} | Expired"
|
else f"{humanize_timedelta(timedelta=mod.duration)} | Expired"
|
||||||
)
|
)
|
||||||
field_value += f"\n**Duration:** {duration_embed}"
|
field_value += f"\n**Duration:** {duration_embed}"
|
||||||
|
|
||||||
field_value += (
|
field_value += (
|
||||||
f"\n**Timestamp:** <t:{case['timestamp']}> | <t:{case['timestamp']}:R>"
|
f"\n**Timestamp:** <t:{int(mod.timestamp.timestamp())}> | <t:{int(mod.timestamp.timestamp())}:R>"
|
||||||
)
|
)
|
||||||
|
|
||||||
if case["role_id"] != "0":
|
if mod.role_id:
|
||||||
role = interaction.guild.get_role(int(case["role_id"]))
|
role = await mod.get_role()
|
||||||
if role is not None:
|
field_value += f"\n**Role:** {role.mention} ({role.id})"
|
||||||
field_value += f"\n**Role:** {role.mention}"
|
|
||||||
else:
|
|
||||||
field_value += f"\n**Role:** Deleted Role ({case['role_id']})"
|
|
||||||
|
|
||||||
if bool(case["resolved"]):
|
if mod.resolved:
|
||||||
field_value += "\n**Resolved:** True"
|
field_value += "\n**Resolved:** True"
|
||||||
|
|
||||||
embed.add_field(name=field_name, value=field_value, inline=inline)
|
embed.add_field(name=field_name, value=field_value, inline=inline)
|
||||||
|
@ -1243,39 +1205,14 @@ class Aurora(commands.Cog):
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
database = connect()
|
try:
|
||||||
cursor = database.cursor()
|
moderation = Moderation.from_sql(interaction.client, case, interaction.guild.id)
|
||||||
|
except ValueError:
|
||||||
query_1 = (
|
|
||||||
f"SELECT * FROM moderation_{interaction.guild.id} WHERE moderation_id = ?;"
|
|
||||||
)
|
|
||||||
cursor.execute(query_1, (case,))
|
|
||||||
result_1 = cursor.fetchone()
|
|
||||||
if result_1 is None or case == 0:
|
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
content=error(f"There is no moderation with a case number of {case}."),
|
content=error(f"Case #{case:,} does not exist!"), ephemeral=True
|
||||||
ephemeral=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
if len(moderation.changes) > 25:
|
||||||
query_2 = f"SELECT * FROM moderation_{interaction.guild.id} WHERE moderation_id = ? AND resolved = 0;"
|
|
||||||
cursor.execute(query_2, (case,))
|
|
||||||
result_2 = cursor.fetchone()
|
|
||||||
if result_2 is None:
|
|
||||||
await interaction.response.send_message(
|
|
||||||
content=error(
|
|
||||||
f"This moderation has already been resolved!\nUse `/case {case}` for more information."
|
|
||||||
),
|
|
||||||
ephemeral=True,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
case_dict = generate_dict(result_2)
|
|
||||||
if reason is None:
|
|
||||||
reason = "No reason given."
|
|
||||||
|
|
||||||
changes: list = case_dict["changes"]
|
|
||||||
if len(changes) > 25:
|
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
content=error(
|
content=error(
|
||||||
"Due to limitations with Discord's embed system, you cannot edit a case more than 25 times."
|
"Due to limitations with Discord's embed system, you cannot edit a case more than 25 times."
|
||||||
|
@ -1283,69 +1220,19 @@ class Aurora(commands.Cog):
|
||||||
ephemeral=True,
|
ephemeral=True,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if not changes:
|
|
||||||
changes.append(
|
|
||||||
{
|
|
||||||
"type": "ORIGINAL",
|
|
||||||
"timestamp": case_dict["timestamp"],
|
|
||||||
"reason": case_dict["reason"],
|
|
||||||
"user_id": case_dict["moderator_id"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
changes.append(
|
|
||||||
{
|
|
||||||
"type": "RESOLVE",
|
|
||||||
"timestamp": int(time.time()),
|
|
||||||
"reason": reason,
|
|
||||||
"user_id": interaction.user.id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if case_dict["moderation_type"] in ["UNMUTE", "UNBAN"]:
|
try:
|
||||||
|
await moderation.resolve(interaction.user.id, reason)
|
||||||
|
except (ValueError, TypeError) as e:
|
||||||
|
if e == ValueError:
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
content=error("You cannot resolve this type of moderation!"),
|
content=error("This case has already been resolved!"), ephemeral=True
|
||||||
ephemeral=True,
|
|
||||||
)
|
)
|
||||||
return
|
elif e == TypeError:
|
||||||
|
await interaction.response.send_message(
|
||||||
if case_dict["moderation_type"] in ["MUTE", "TEMPBAN", "BAN"]:
|
content=error("This case type cannot be resolved!"), ephemeral=True
|
||||||
if case_dict["moderation_type"] == "MUTE":
|
|
||||||
try:
|
|
||||||
member = await interaction.guild.fetch_member(
|
|
||||||
case_dict["target_id"]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await member.timeout(
|
|
||||||
None, reason=f"Case #{case:,} resolved by {interaction.user.id}"
|
|
||||||
)
|
|
||||||
except discord.NotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if case_dict["moderation_type"] in ["TEMPBAN", "BAN"]:
|
|
||||||
try:
|
|
||||||
user = await interaction.client.fetch_user(case_dict["target_id"])
|
|
||||||
|
|
||||||
await interaction.guild.unban(
|
|
||||||
user, reason=f"Case #{case} resolved by {interaction.user.id}"
|
|
||||||
)
|
|
||||||
except discord.NotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
resolve_query = f"UPDATE `moderation_{interaction.guild.id}` SET resolved = 1, changes = ?, resolved_by = ?, resolve_reason = ? WHERE moderation_id = ?"
|
|
||||||
else:
|
|
||||||
resolve_query = f"UPDATE `moderation_{interaction.guild.id}` SET resolved = 1, changes = ?, resolved_by = ?, resolve_reason = ? WHERE moderation_id = ?"
|
|
||||||
|
|
||||||
cursor.execute(
|
|
||||||
resolve_query,
|
|
||||||
(
|
|
||||||
dumps(changes),
|
|
||||||
interaction.user.id,
|
|
||||||
reason,
|
|
||||||
case_dict["moderation_id"],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
database.commit()
|
|
||||||
|
|
||||||
embed = await case_factory(
|
embed = await case_factory(
|
||||||
interaction=interaction,
|
interaction=interaction,
|
||||||
case_dict=await fetch_case(case, interaction.guild.id),
|
case_dict=await fetch_case(case, interaction.guild.id),
|
||||||
|
@ -1355,9 +1242,6 @@ class Aurora(commands.Cog):
|
||||||
)
|
)
|
||||||
await log(interaction, case, resolved=True)
|
await log(interaction, case, resolved=True)
|
||||||
|
|
||||||
cursor.close()
|
|
||||||
database.close()
|
|
||||||
|
|
||||||
@app_commands.command(name="case")
|
@app_commands.command(name="case")
|
||||||
@app_commands.choices(
|
@app_commands.choices(
|
||||||
export=[
|
export=[
|
||||||
|
@ -1405,9 +1289,14 @@ class Aurora(commands.Cog):
|
||||||
or False
|
or False
|
||||||
)
|
)
|
||||||
|
|
||||||
if case != 0:
|
try:
|
||||||
mod = Moderation.from_sql(interaction.client, case, interaction.guild.id)
|
mod = Moderation.from_sql(interaction.client, case, interaction.guild.id)
|
||||||
if mod:
|
except ValueError:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
content=error(f"Case #{case:,} does not exist!"), ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if export:
|
if export:
|
||||||
if export.value == "file" or len(mod.to_json(2)) > 1800:
|
if export.value == "file" or len(mod.to_json(2)) > 1800:
|
||||||
filename = (
|
filename = (
|
||||||
|
@ -1463,9 +1352,6 @@ class Aurora(commands.Cog):
|
||||||
embed=embed, ephemeral=ephemeral
|
embed=embed, ephemeral=ephemeral
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
await interaction.response.send_message(
|
|
||||||
content=f"No case with case number `{case}` found.", ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@app_commands.command(name="edit")
|
@app_commands.command(name="edit")
|
||||||
async def edit(
|
async def edit(
|
||||||
|
@ -1498,10 +1384,15 @@ class Aurora(commands.Cog):
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if case != 0:
|
try:
|
||||||
moderation = Moderation.from_sql(interaction.client, case, interaction.guild.id)
|
moderation = Moderation.from_sql(interaction.client, case, interaction.guild.id)
|
||||||
old_moderation = moderation
|
old_moderation = moderation
|
||||||
if moderation:
|
except ValueError:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
content=error(f"Case #{case:,} does not exist!"), ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if len(moderation.changes) > 25:
|
if len(moderation.changes) > 25:
|
||||||
return await interaction.response.send_message(
|
return await interaction.response.send_message(
|
||||||
content=error(
|
content=error(
|
||||||
|
@ -1509,6 +1400,7 @@ class Aurora(commands.Cog):
|
||||||
),
|
),
|
||||||
ephemeral=True,
|
ephemeral=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
if duration:
|
if duration:
|
||||||
moderation.duration = parse_timedelta(duration)
|
moderation.duration = parse_timedelta(duration)
|
||||||
if moderation.duration is None:
|
if moderation.duration is None:
|
||||||
|
@ -1582,9 +1474,6 @@ class Aurora(commands.Cog):
|
||||||
await log(interaction, case)
|
await log(interaction, case)
|
||||||
|
|
||||||
return
|
return
|
||||||
await interaction.response.send_message(
|
|
||||||
content=error(f"No case with case number `{case}` found."), ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@tasks.loop(minutes=1)
|
@tasks.loop(minutes=1)
|
||||||
async def handle_expiry(self):
|
async def handle_expiry(self):
|
||||||
|
|
|
@ -90,6 +90,9 @@ class Moderation(AuroraGuildModel):
|
||||||
self.resolved_by = resolved_by
|
self.resolved_by = resolved_by
|
||||||
self.resolve_reason = reason
|
self.resolve_reason = reason
|
||||||
|
|
||||||
|
if self.type in ["UNMUTE", "UNBAN"]:
|
||||||
|
raise TypeError("Cannot resolve an unmute or unban case!")
|
||||||
|
|
||||||
if self.type == "MUTE":
|
if self.type == "MUTE":
|
||||||
try:
|
try:
|
||||||
guild: discord.Guild = await self.bot.fetch_guild(self.guild_id)
|
guild: discord.Guild = await self.bot.fetch_guild(self.guild_id)
|
||||||
|
@ -176,7 +179,7 @@ class Moderation(AuroraGuildModel):
|
||||||
return cls(bot=bot, **data)
|
return cls(bot=bot, **data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_sql(cls, bot: Red, moderation_id: int, guild_id: int) -> Optional["Moderation"]:
|
def from_sql(cls, bot: Red, moderation_id: int, guild_id: int) -> "Moderation":
|
||||||
from aurora.utilities.database import connect
|
from aurora.utilities.database import connect
|
||||||
query = f"SELECT * FROM moderation_{guild_id} WHERE moderation_id = ?;"
|
query = f"SELECT * FROM moderation_{guild_id} WHERE moderation_id = ?;"
|
||||||
|
|
||||||
|
@ -184,13 +187,13 @@ class Moderation(AuroraGuildModel):
|
||||||
cursor = database.cursor()
|
cursor = database.cursor()
|
||||||
cursor.execute(query, (moderation_id,))
|
cursor.execute(query, (moderation_id,))
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
|
|
||||||
if result:
|
|
||||||
case = generate_dict(bot, result, guild_id)
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
|
if result and not moderation_id == 0:
|
||||||
|
case = generate_dict(bot, result, guild_id)
|
||||||
return cls.from_dict(bot, case)
|
return cls.from_dict(bot, case)
|
||||||
|
|
||||||
return None
|
raise ValueError(f"Case {moderation_id} not found in moderation_{guild_id}!")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def log(
|
def log(
|
||||||
|
@ -411,6 +414,8 @@ class PartialRole(AuroraGuildModel):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mention(self):
|
def mention(self):
|
||||||
|
if self.name == "Deleted Role" or self.name == "Forbidden Role":
|
||||||
|
return self.name
|
||||||
return f"<@&{self.id}>"
|
return f"<@&{self.id}>"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
Loading…
Reference in a new issue