feat(aurora): migrated to aiosqlite

This commit is contained in:
Seaswimmer 2024-06-05 00:14:43 -04:00
parent 027144f35d
commit 5cbf4e7e47
Signed by: cswimr
GPG key ID: 5D671B5D03D65A7F
9 changed files with 127 additions and 116 deletions

View file

@ -7,11 +7,11 @@
import json import json
import os import os
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
import aiosqlite
import discord import discord
from discord import Object from discord import Object
from discord.ext import tasks from discord.ext import tasks
@ -50,21 +50,21 @@ class Aurora(commands.Cog):
if requester == "discord_deleted_user": if requester == "discord_deleted_user":
await config.user_from_id(user_id).clear() await config.user_from_id(user_id).clear()
database = connect() database = await connect()
cursor = database.cursor() cursor = await database.cursor()
cursor.execute("SHOW TABLES;") await cursor.execute("SHOW TABLES;")
tables = [table[0] for table in cursor.fetchall()] tables = [table[0] for table in cursor.fetchall()]
condition = "target_id = %s OR moderator_id = %s;" condition = "target_id = %s OR moderator_id = %s;"
for table in tables: for table in tables:
delete_query = f"DELETE FROM {table[0]} WHERE {condition}" delete_query = f"DELETE FROM {table[0]} WHERE {condition}"
cursor.execute(delete_query, (user_id, user_id)) await cursor.execute(delete_query, (user_id, user_id))
database.commit() await database.commit()
cursor.close() await cursor.close()
database.close() await database.close()
if requester == "owner": if requester == "owner":
await config.user_from_id(user_id).clear() await config.user_from_id(user_id).clear()
if requester == "user": if requester == "user":
@ -121,15 +121,13 @@ class Aurora(commands.Cog):
async def addrole_on_member_join(self, member: discord.Member): async def addrole_on_member_join(self, member: discord.Member):
"""This method automatically adds roles to users when they join the server.""" """This method automatically adds roles to users when they join the server."""
if not await self.bot.cog_disabled_in_guild(self, member.guild): if not await self.bot.cog_disabled_in_guild(self, member.guild):
async with connect() as database:
query = f"""SELECT moderation_id, role_id, reason FROM moderation_{member.guild.id} WHERE target_id = ? AND moderation_type = 'ADDROLE' AND expired = 0 AND resolved = 0;""" query = f"""SELECT moderation_id, role_id, reason FROM moderation_{member.guild.id} WHERE target_id = ? AND moderation_type = 'ADDROLE' AND expired = 0 AND resolved = 0;"""
database = connect() async with database.execute(query, (member.id,)) as cursor:
cursor = database.cursor() async for row in cursor:
cursor.execute(query, (member.id,)) role = member.guild.get_role(row[1])
results = cursor.fetchall() reason = row[2]
for result in results: await member.add_roles(role, reason=f"Role automatically added on member rejoin for: {reason} (Case #{row[0]:,})")
role = member.guild.get_role(result[1])
reason = result[2]
await member.add_roles(role, reason=f"Role automatically added on member rejoin for: {reason} (Case #{result[0]:,})")
@commands.Cog.listener("on_audit_log_entry_create") @commands.Cog.listener("on_audit_log_entry_create")
async def autologger(self, entry: discord.AuditLogEntry): async def autologger(self, entry: discord.AuditLogEntry):
@ -175,7 +173,7 @@ class Aurora(commands.Cog):
else: else:
return return
Moderation.log( await Moderation.log(
self.bot, self.bot,
entry.guild.id, entry.guild.id,
entry.user.id, entry.user.id,
@ -233,7 +231,7 @@ class Aurora(commands.Cog):
except discord.errors.HTTPException: except discord.errors.HTTPException:
pass pass
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -292,7 +290,7 @@ class Aurora(commands.Cog):
except discord.errors.HTTPException: except discord.errors.HTTPException:
pass pass
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -398,7 +396,7 @@ class Aurora(commands.Cog):
content=f"{target.mention} has been given the {role.mention} role{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`" content=f"{target.mention} has been given the {role.mention} role{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`"
) )
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -504,7 +502,7 @@ class Aurora(commands.Cog):
content=f"{target.mention} has had the {role.mention} role removed{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`" content=f"{target.mention} has had the {role.mention} role removed{' for ' + humanize_timedelta(timedelta=parsed_time) if parsed_time != 'NULL' else ''}!\n**Reason** - `{reason}`"
) )
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -592,7 +590,7 @@ class Aurora(commands.Cog):
except discord.errors.HTTPException: except discord.errors.HTTPException:
pass pass
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -728,7 +726,7 @@ class Aurora(commands.Cog):
await target.kick(reason=f"Kicked by {interaction.user.id} for: {reason}") await target.kick(reason=f"Kicked by {interaction.user.id} for: {reason}")
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -836,7 +834,7 @@ class Aurora(commands.Cog):
delete_message_seconds=delete_messages_seconds, delete_message_seconds=delete_messages_seconds,
) )
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -880,7 +878,7 @@ class Aurora(commands.Cog):
delete_message_seconds=delete_messages_seconds, delete_message_seconds=delete_messages_seconds,
) )
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -957,7 +955,7 @@ class Aurora(commands.Cog):
except discord.errors.HTTPException: except discord.errors.HTTPException:
pass pass
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -1001,7 +999,7 @@ class Aurora(commands.Cog):
await channel.edit(slowmode_delay=interval) await channel.edit(slowmode_delay=interval)
await interaction.response.send_message(f"Slowmode in {channel.mention} has been set to {interval} seconds!\n**Reason** - `{reason}`") await interaction.response.send_message(f"Slowmode in {channel.mention} has been set to {interval} seconds!\n**Reason** - `{reason}`")
moderation = Moderation.log( moderation = await Moderation.log(
interaction.client, interaction.client,
interaction.guild.id, interaction.guild.id,
interaction.user.id, interaction.user.id,
@ -1089,7 +1087,7 @@ class Aurora(commands.Cog):
) )
return return
database = connect() database = await connect()
if export: if export:
try: try:
@ -1099,7 +1097,7 @@ class Aurora(commands.Cog):
+ f"moderation_{interaction.guild.id}.json" + f"moderation_{interaction.guild.id}.json"
) )
cases = Moderation.get_latest(bot=interaction.client, guild_id=interaction.guild.id) cases = await Moderation.get_latest(bot=interaction.client, guild_id=interaction.guild.id)
with open(filename, "w", encoding="utf-8") as f: with open(filename, "w", encoding="utf-8") as f:
dump(obj=cases, fp=f, indent=2) dump(obj=cases, fp=f, indent=2)
@ -1120,15 +1118,15 @@ class Aurora(commands.Cog):
+ box(e, "py"), + box(e, "py"),
ephemeral=ephemeral, ephemeral=ephemeral,
) )
database.close() await database.close()
return return
if target: if target:
moderations = Moderation.find_by_target(interaction.client, interaction.guild.id, target.id) moderations = await Moderation.find_by_target(interaction.client, interaction.guild.id, target.id)
elif moderator: elif moderator:
moderations = Moderation.find_by_moderator(interaction.client, interaction.guild.id, moderator.id) moderations = await Moderation.find_by_moderator(interaction.client, interaction.guild.id, moderator.id)
else: else:
moderations = Moderation.get_latest(interaction.client, interaction.guild.id) moderations = await Moderation.get_latest(interaction.client, interaction.guild.id)
case_quantity = len(moderations) case_quantity = len(moderations)
page_quantity = ceil(case_quantity / pagesize) page_quantity = ceil(case_quantity / pagesize)
@ -1214,7 +1212,7 @@ class Aurora(commands.Cog):
return return
try: try:
moderation = Moderation.find_by_id(interaction.client, case, interaction.guild.id) moderation = await Moderation.find_by_id(interaction.client, case, interaction.guild.id)
except ValueError: except ValueError:
await interaction.response.send_message( await interaction.response.send_message(
content=error(f"Case #{case:,} does not exist!"), ephemeral=True content=error(f"Case #{case:,} does not exist!"), ephemeral=True
@ -1298,7 +1296,7 @@ class Aurora(commands.Cog):
) )
try: try:
mod = Moderation.find_by_id(interaction.client, case, interaction.guild.id) mod = await Moderation.find_by_id(interaction.client, case, interaction.guild.id)
except ValueError: except ValueError:
await interaction.response.send_message( await interaction.response.send_message(
content=error(f"Case #{case:,} does not exist!"), ephemeral=True content=error(f"Case #{case:,} does not exist!"), ephemeral=True
@ -1391,7 +1389,7 @@ class Aurora(commands.Cog):
return return
try: try:
moderation = Moderation.find_by_id(interaction.client, case, interaction.guild.id) moderation = await Moderation.find_by_id(interaction.client, case, interaction.guild.id)
old_moderation = moderation old_moderation = moderation
except ValueError: except ValueError:
await interaction.response.send_message( await interaction.response.send_message(
@ -1469,7 +1467,7 @@ class Aurora(commands.Cog):
"end_timestamp": moderation.end_timestamp, "end_timestamp": moderation.end_timestamp,
})) }))
moderation.update() await moderation.update()
embed = await case_factory(interaction=interaction, moderation=moderation) embed = await case_factory(interaction=interaction, moderation=moderation)
await interaction.response.send_message( await interaction.response.send_message(
@ -1485,8 +1483,8 @@ class Aurora(commands.Cog):
async def handle_expiry(self): async def handle_expiry(self):
await self.bot.wait_until_red_ready() await self.bot.wait_until_red_ready()
current_time = time.time() current_time = time.time()
database = connect() database = await connect()
cursor = database.cursor() cursor = await database.cursor()
global_unban_num = 0 global_unban_num = 0
global_addrole_num = 0 global_addrole_num = 0
global_removerole_num = 0 global_removerole_num = 0
@ -1499,9 +1497,9 @@ class Aurora(commands.Cog):
tempban_query = f"SELECT target_id, moderation_id FROM moderation_{guild.id} WHERE end_timestamp IS NOT NULL 0 AND end_timestamp <= ? AND moderation_type = 'TEMPBAN' AND expired = 0" tempban_query = f"SELECT target_id, moderation_id FROM moderation_{guild.id} WHERE end_timestamp IS NOT NULL 0 AND end_timestamp <= ? AND moderation_type = 'TEMPBAN' AND expired = 0"
try: try:
cursor.execute(tempban_query, (time.time(),)) await cursor.execute(tempban_query, (time.time(),))
result = cursor.fetchall() result = cursor.fetchall()
except sqlite3.OperationalError: except aiosqlite.OperationalError:
continue continue
target_ids = [row[0] for row in result] target_ids = [row[0] for row in result]
@ -1558,9 +1556,9 @@ class Aurora(commands.Cog):
removerole_num = 0 removerole_num = 0
addrole_query = f"SELECT target_id, moderation_id, role_id FROM moderation_{guild.id} WHERE end_timestamp IS NOT NULL AND end_timestamp <= ? AND moderation_type = 'ADDROLE' AND expired = 0" addrole_query = f"SELECT target_id, moderation_id, role_id FROM moderation_{guild.id} WHERE end_timestamp IS NOT NULL AND end_timestamp <= ? AND moderation_type = 'ADDROLE' AND expired = 0"
try: try:
cursor.execute(addrole_query, (time.time(),)) await cursor.execute(addrole_query, (time.time(),))
result = cursor.fetchall() result = await cursor.fetchall()
except sqlite3.OperationalError: except aiosqlite.OperationalError:
continue continue
target_ids = [row[0] for row in result] target_ids = [row[0] for row in result]
moderation_ids = [row[1] for row in result] moderation_ids = [row[1] for row in result]
@ -1593,9 +1591,9 @@ class Aurora(commands.Cog):
addrole_num = 0 addrole_num = 0
removerole_query = f"SELECT target_id, moderation_id, role_id FROM moderation_{guild.id} WHERE end_timestamp IS NOT NULL 0 AND end_timestamp <= ? AND moderation_type = 'REMOVEROLE' AND expired = 0" removerole_query = f"SELECT target_id, moderation_id, role_id FROM moderation_{guild.id} WHERE end_timestamp IS NOT NULL 0 AND end_timestamp <= ? AND moderation_type = 'REMOVEROLE' AND expired = 0"
try: try:
cursor.execute(removerole_query, (time.time(),)) await cursor.execute(removerole_query, (time.time(),))
result = cursor.fetchall() result = await cursor.fetchall()
except sqlite3.OperationalError: except aiosqlite.OperationalError:
continue continue
target_ids = [row[0] for row in result] target_ids = [row[0] for row in result]
moderation_ids = [row[1] for row in result] moderation_ids = [row[1] for row in result]
@ -1621,7 +1619,7 @@ class Aurora(commands.Cog):
continue continue
expiry_query = f"UPDATE `moderation_{guild.id}` SET expired = 1 WHERE (end_timestamp IS NOT NULL AND end_timestamp <= ? AND expired = 0) OR (expired = 0 AND resolved = 1);" expiry_query = f"UPDATE `moderation_{guild.id}` SET expired = 1 WHERE (end_timestamp IS NOT NULL AND end_timestamp <= ? AND expired = 0) OR (expired = 0 AND resolved = 1);"
cursor.execute(expiry_query, (time.time(),)) await cursor.execute(expiry_query, (time.time(),))
per_guild_completion_time = (time.time() - time_per_guild) * 1000 per_guild_completion_time = (time.time() - time_per_guild) * 1000
logger.debug( logger.debug(
@ -1637,9 +1635,9 @@ class Aurora(commands.Cog):
global_addrole_num = global_addrole_num + addrole_num global_addrole_num = global_addrole_num + addrole_num
global_removerole_num = global_removerole_num + removerole_num global_removerole_num = global_removerole_num + removerole_num
database.commit() await database.commit()
cursor.close() await cursor.close()
database.close() await database.close()
completion_time = (time.time() - current_time) * 1000 completion_time = (time.time() - current_time) * 1000
logger.debug( logger.debug(

View file

@ -27,13 +27,9 @@ class ImportAuroraView(ui.View):
"Deleting original table...", ephemeral=True "Deleting original table...", ephemeral=True
) )
database = connect() async with connect() as database:
cursor = database.cursor()
query = f"DROP TABLE IF EXISTS moderation_{self.ctx.guild.id};" query = f"DROP TABLE IF EXISTS moderation_{self.ctx.guild.id};"
cursor.execute(query) database.execute(query)
cursor.close()
database.commit() database.commit()
await interaction.edit_original_response(content="Creating new table...") await interaction.edit_original_response(content="Creating new table...")
@ -96,7 +92,7 @@ class ImportAuroraView(ui.View):
duration = None duration = None
try: try:
Moderation.log( await Moderation.log(
bot=interaction.client, bot=interaction.client,
guild_id=self.ctx.guild.id, guild_id=self.ctx.guild.id,
moderator_id=case["moderator_id"], moderator_id=case["moderator_id"],

View file

@ -26,14 +26,14 @@ class ImportGalacticBotView(ui.View):
"Deleting original table...", ephemeral=True "Deleting original table...", ephemeral=True
) )
database = connect() database = await connect()
cursor = database.cursor() cursor = await database.cursor()
query = f"DROP TABLE IF EXISTS moderation_{self.ctx.guild.id};" query = f"DROP TABLE IF EXISTS moderation_{self.ctx.guild.id};"
cursor.execute(query) await cursor.execute(query)
cursor.close() await cursor.close()
database.commit() await database.commit()
await interaction.edit_original_response(content="Creating new table...") await interaction.edit_original_response(content="Creating new table...")
@ -124,7 +124,7 @@ class ImportGalacticBotView(ui.View):
else: else:
reason = None reason = None
Moderation.log( await Moderation.log(
self.ctx.guild.id, self.ctx.guild.id,
case["executor"], case["executor"],
case["type"], case["type"],

View file

@ -9,7 +9,7 @@
"disabled": false, "disabled": false,
"min_bot_version": "3.5.0", "min_bot_version": "3.5.0",
"min_python_version": [3, 10, 0], "min_python_version": [3, 10, 0],
"requirements": ["pydantic"], "requirements": ["pydantic", "aiosqlite"],
"tags": [ "tags": [
"mod", "mod",
"moderate", "moderate",

View file

@ -1,11 +1,11 @@
import json import json
import sqlite3 import sqlite3
from datetime import datetime, timedelta from datetime import datetime, timedelta
from sqlite3 import Cursor
from time import time from time import time
from typing import Dict, Iterable, List, Optional, Tuple, Union from typing import Dict, Iterable, List, Optional, Tuple, Union
import discord import discord
from aiosqlite import Cursor
from discord import NotFound from discord import NotFound
from redbot.core.bot import Red from redbot.core.bot import Red
@ -115,15 +115,15 @@ class Moderation(AuroraGuildModel):
"user_id": resolved_by, "user_id": resolved_by,
})) }))
self.update() await self.update()
def update(self) -> None: async def update(self) -> None:
from ..utilities.database import connect from ..utilities.database import connect
from ..utilities.json import dumps from ..utilities.json import dumps
query = f"UPDATE moderation_{self.guild_id} SET timestamp = ?, moderation_type = ?, target_type = ?, moderator_id = ?, role_id = ?, duration = ?, end_timestamp = ?, reason = ?, resolved = ?, resolved_by = ?, resolve_reason = ?, expired = ?, changes = ?, metadata = ? WHERE moderation_id = ?;" query = f"UPDATE moderation_{self.guild_id} SET timestamp = ?, moderation_type = ?, target_type = ?, moderator_id = ?, role_id = ?, duration = ?, end_timestamp = ?, reason = ?, resolved = ?, resolved_by = ?, resolve_reason = ?, expired = ?, changes = ?, metadata = ? WHERE moderation_id = ?;"
with connect() as database: async with connect() as database:
database.execute(query, ( await database.execute(query, (
self.timestamp.timestamp(), self.timestamp.timestamp(),
self.moderation_type, self.moderation_type,
self.target_type, self.target_type,
@ -206,7 +206,7 @@ class Moderation(AuroraGuildModel):
return cls.from_dict(bot=bot, data=case) return cls.from_dict(bot=bot, data=case)
@classmethod @classmethod
def execute(cls, bot: Red, guild_id: int, query: str, parameters: tuple | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]: async def execute(cls, bot: Red, guild_id: int, query: str, parameters: tuple | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
from ..utilities.database import connect from ..utilities.database import connect
logger.trace("Executing query: %s", query) logger.trace("Executing query: %s", query)
logger.trace("With parameters: %s", parameters) logger.trace("With parameters: %s", parameters)
@ -214,16 +214,16 @@ class Moderation(AuroraGuildModel):
parameters = () parameters = ()
if not cursor: if not cursor:
no_cursor = True no_cursor = True
database = connect() database = await connect()
cursor = database.cursor() cursor = await database.cursor()
else: else:
no_cursor = False no_cursor = False
cursor.execute(query, parameters) await cursor.execute(query, parameters)
results = cursor.fetchall() results = await cursor.fetchall()
if no_cursor: if no_cursor:
cursor.close() await cursor.close()
database.close() await database.close()
if results: if results:
cases = [] cases = []
@ -235,7 +235,7 @@ class Moderation(AuroraGuildModel):
return () return ()
@classmethod @classmethod
def get_latest(cls, bot: Red, guild_id: int, limit: int | None = None, offset: int = 0, types: Iterable | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]: async def get_latest(cls, bot: Red, guild_id: int, limit: int | None = None, offset: int = 0, types: Iterable | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
params = [] params = []
query = f"SELECT * FROM moderation_{guild_id} ORDER BY moderation_id DESC" query = f"SELECT * FROM moderation_{guild_id} ORDER BY moderation_id DESC"
if types: if types:
@ -245,41 +245,41 @@ class Moderation(AuroraGuildModel):
query += " LIMIT ? OFFSET ?" query += " LIMIT ? OFFSET ?"
params.extend((limit, offset)) params.extend((limit, offset))
query += ";" query += ";"
return cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=tuple(params) if params else (), cursor=cursor) return await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=tuple(params) if params else (), cursor=cursor)
@classmethod @classmethod
def get_next_case_number(cls, bot: Red, guild_id: int, cursor: Cursor | None = None) -> int: async def get_next_case_number(cls, bot: Red, guild_id: int, cursor: Cursor | None = None) -> int:
result = cls.get_latest(bot=bot, guild_id=guild_id, cursor=cursor, limit=1) result = await cls.get_latest(bot=bot, guild_id=guild_id, cursor=cursor, limit=1)
return (result[0].moderation_id + 1) if result else 1 return (result[0].moderation_id + 1) if result else 1
@classmethod @classmethod
def find_by_id(cls, bot: Red, moderation_id: int, guild_id: int, cursor: Cursor | None = None) -> "Moderation": async def find_by_id(cls, bot: Red, moderation_id: int, guild_id: int, cursor: Cursor | None = None) -> "Moderation":
query = f"SELECT * FROM moderation_{guild_id} WHERE moderation_id = ?;" query = f"SELECT * FROM moderation_{guild_id} WHERE moderation_id = ?;"
case = cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(moderation_id,), cursor=cursor) case = await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(moderation_id,), cursor=cursor)
if case: if case:
return case[0] return case[0]
raise ValueError(f"Case {moderation_id} not found in moderation_{guild_id}!") raise ValueError(f"Case {moderation_id} not found in moderation_{guild_id}!")
@classmethod @classmethod
def find_by_target(cls, bot: Red, guild_id: int, target: int, types: Iterable | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]: async def find_by_target(cls, bot: Red, guild_id: int, target: int, types: Iterable | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
query = f"SELECT * FROM moderation_{guild_id} WHERE target_id = ?" query = f"SELECT * FROM moderation_{guild_id} WHERE target_id = ?"
if types: if types:
query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})" query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})"
query += " ORDER BY moderation_id DESC;" query += " ORDER BY moderation_id DESC;"
return cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(target, *types) if types else (target,), cursor=cursor) return await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(target, *types) if types else (target,), cursor=cursor)
@classmethod @classmethod
def find_by_moderator(cls, bot: Red, guild_id: int, moderator: int, types: Iterable | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]: async def find_by_moderator(cls, bot: Red, guild_id: int, moderator: int, types: Iterable | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
query = f"SELECT * FROM moderation_{guild_id} WHERE moderator_id = ?" query = f"SELECT * FROM moderation_{guild_id} WHERE moderator_id = ?"
if types: if types:
query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})" query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})"
query += " ORDER BY moderation_id DESC;" query += " ORDER BY moderation_id DESC;"
return cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(moderator, *types) if types else (moderator,), cursor=cursor) return await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(moderator, *types) if types else (moderator,), cursor=cursor)
@classmethod @classmethod
def log( async def log(
cls, cls,
bot: Red, bot: Red,
guild_id: int, guild_id: int,
@ -335,13 +335,12 @@ class Moderation(AuroraGuildModel):
role_id = None role_id = None
if not database: if not database:
database = connect() database = await connect()
close_db = True close_db = True
else: else:
close_db = False close_db = False
cursor = database.cursor()
moderation_id = cls.get_next_case_number(bot=bot, guild_id=guild_id, cursor=cursor) moderation_id = cls.get_next_case_number(bot=bot, guild_id=guild_id)
case = { case = {
"moderation_id": moderation_id, "moderation_id": moderation_id,
@ -363,12 +362,12 @@ class Moderation(AuroraGuildModel):
} }
sql = f"INSERT INTO `moderation_{guild_id}` (moderation_id, timestamp, moderation_type, target_type, target_id, moderator_id, role_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired, changes, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" sql = f"INSERT INTO `moderation_{guild_id}` (moderation_id, timestamp, moderation_type, target_type, target_id, moderator_id, role_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired, changes, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
cursor.execute(sql, tuple(case.values())) await database.execute(sql, tuple(case.values()))
cursor.close() await database.close()
database.commit() await database.commit()
if close_db: if close_db:
database.close() await database.close()
logger.debug( logger.debug(
"Row inserted into moderation_%s!\n%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s", "Row inserted into moderation_%s!\n%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
@ -392,5 +391,5 @@ class Moderation(AuroraGuildModel):
) )
if return_obj: if return_obj:
return cls.find_by_id(bot=bot, moderation_id=moderation_id, guild_id=guild_id) return await cls.find_by_id(bot=bot, moderation_id=moderation_id, guild_id=guild_id)
return moderation_id return moderation_id

View file

@ -1,22 +1,22 @@
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
import json import json
import sqlite3
import aiosqlite
from discord import Guild from discord import Guild
from redbot.core import data_manager from redbot.core import data_manager
from .logger import logger from .logger import logger
def connect() -> sqlite3.Connection: async def connect() -> aiosqlite.Connection:
"""Connects to the SQLite database, and returns a connection object.""" """Connects to the SQLite database, and returns a connection object."""
try: try:
connection = sqlite3.connect( connection = await aiosqlite.connect(
database=data_manager.cog_data_path(raw_name="Aurora") / "aurora.db" database=data_manager.cog_data_path(raw_name="Aurora") / "aurora.db"
) )
return connection return connection
except sqlite3.OperationalError as e: except aiosqlite.OperationalError as e:
logger.error("Unable to access the SQLite database!\nError:\n%s", e.msg) logger.error("Unable to access the SQLite database!\nError:\n%s", e.msg)
raise ConnectionRefusedError( raise ConnectionRefusedError(
f"Unable to access the SQLite Database!\n{e.msg}" f"Unable to access the SQLite Database!\n{e.msg}"
@ -24,14 +24,13 @@ def connect() -> sqlite3.Connection:
async def create_guild_table(guild: Guild): async def create_guild_table(guild: Guild):
database = connect() database = await connect()
cursor = database.cursor()
try: try:
cursor.execute(f"SELECT * FROM `moderation_{guild.id}`") await database.execute(f"SELECT * FROM `moderation_{guild.id}`")
logger.debug("SQLite Table exists for server %s (%s)", guild.name, guild.id) logger.debug("SQLite Table exists for server %s (%s)", guild.name, guild.id)
except sqlite3.OperationalError: except aiosqlite.OperationalError:
query = f""" query = f"""
CREATE TABLE `moderation_{guild.id}` ( CREATE TABLE `moderation_{guild.id}` (
moderation_id INTEGER PRIMARY KEY, moderation_id INTEGER PRIMARY KEY,
@ -52,16 +51,16 @@ async def create_guild_table(guild: Guild):
metadata JSON NOT NULL metadata JSON NOT NULL
) )
""" """
cursor.execute(query) await database.execute(query)
index_query_1 = f"CREATE INDEX IF NOT EXISTS idx_target_id ON moderation_{guild.id}(target_id);" index_query_1 = f"CREATE INDEX IF NOT EXISTS idx_target_id ON moderation_{guild.id}(target_id);"
cursor.execute(index_query_1) await database.execute(index_query_1)
index_query_2 = f"CREATE INDEX IF NOT EXISTS idx_moderator_id ON moderation_{guild.id}(moderator_id);" index_query_2 = f"CREATE INDEX IF NOT EXISTS idx_moderator_id ON moderation_{guild.id}(moderator_id);"
cursor.execute(index_query_2) await database.execute(index_query_2)
index_query_3 = f"CREATE INDEX IF NOT EXISTS idx_moderation_id ON moderation_{guild.id}(moderation_id);" index_query_3 = f"CREATE INDEX IF NOT EXISTS idx_moderation_id ON moderation_{guild.id}(moderation_id);"
cursor.execute(index_query_3) await database.execute(index_query_3)
insert_query = f""" insert_query = f"""
INSERT INTO `moderation_{guild.id}` INSERT INTO `moderation_{guild.id}`
@ -86,9 +85,9 @@ async def create_guild_table(guild: Guild):
json.dumps([]), json.dumps([]),
json.dumps({}), json.dumps({}),
) )
cursor.execute(insert_query, insert_values) await database.execute(insert_query, insert_values)
database.commit() await database.commit()
logger.debug( logger.debug(
"SQLite Table (moderation_%s) created for %s (%s)", "SQLite Table (moderation_%s) created for %s (%s)",

View file

@ -120,7 +120,7 @@ async def log(interaction: Interaction, moderation_id: int, resolved: bool = Fal
logging_channel = interaction.guild.get_channel(logging_channel_id) logging_channel = interaction.guild.get_channel(logging_channel_id)
try: try:
moderation = Moderation.find_by_id(interaction.client, moderation_id, interaction.guild_id) moderation = await Moderation.find_by_id(interaction.client, moderation_id, interaction.guild_id)
embed = await log_factory( embed = await log_factory(
interaction=interaction, moderation=moderation, resolved=resolved interaction=interaction, moderation=moderation, resolved=resolved
) )
@ -145,7 +145,7 @@ async def send_evidenceformat(interaction: Interaction, moderation_id: int) -> N
if send_evidence_bool is False: if send_evidence_bool is False:
return return
moderation = Moderation.find_by_id(interaction.client, moderation_id, interaction.guild.id) moderation = await Moderation.find_by_id(interaction.client, moderation_id, interaction.guild.id)
content = await evidenceformat_factory(moderation=moderation) content = await evidenceformat_factory(moderation=moderation)
await interaction.followup.send(content=content, ephemeral=True) await interaction.followup.send(content=content, ephemeral=True)

20
poetry.lock generated
View file

@ -123,6 +123,24 @@ files = [
[package.dependencies] [package.dependencies]
frozenlist = ">=1.1.0" frozenlist = ">=1.1.0"
[[package]]
name = "aiosqlite"
version = "0.20.0"
description = "asyncio bridge to the standard sqlite3 module"
optional = false
python-versions = ">=3.8"
files = [
{file = "aiosqlite-0.20.0-py3-none-any.whl", hash = "sha256:36a1deaca0cac40ebe32aac9977a6e2bbc7f5189f23f4a54d5908986729e5bd6"},
{file = "aiosqlite-0.20.0.tar.gz", hash = "sha256:6d35c8c256637f4672f843c31021464090805bf925385ac39473fb16eaaca3d7"},
]
[package.dependencies]
typing_extensions = ">=4.0"
[package.extras]
dev = ["attribution (==1.7.0)", "black (==24.2.0)", "coverage[toml] (==7.4.1)", "flake8 (==7.0.0)", "flake8-bugbear (==24.2.6)", "flit (==3.9.0)", "mypy (==1.8.0)", "ufmt (==2.3.0)", "usort (==1.0.8.post1)"]
docs = ["sphinx (==7.2.6)", "sphinx-mdinclude (==0.5.3)"]
[[package]] [[package]]
name = "annotated-types" name = "annotated-types"
version = "0.7.0" version = "0.7.0"
@ -2655,4 +2673,4 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.11,<3.12" python-versions = ">=3.11,<3.12"
content-hash = "3f732c0b0b0eb2a31fb9484c7cf699cd3c26474d6779528102af4c509a48351e" content-hash = "22b824824f73dc3dc1a9a0a01060371ee1f6414e5bef39cb7455d21121988b47"

View file

@ -18,6 +18,7 @@ pydantic = "^2.7.1"
colorthief = "^0.2.1" colorthief = "^0.2.1"
beautifulsoup4 = "^4.12.3" beautifulsoup4 = "^4.12.3"
markdownify = "^0.12.1" markdownify = "^0.12.1"
aiosqlite = "^0.20.0"
[tool.poetry.group.dev] [tool.poetry.group.dev]
optional = true optional = true