Compare commits
3 commits
main
...
moderation
Author | SHA1 | Date | |
---|---|---|---|
9f86c20df4 | |||
9ec42f5d60 | |||
b8c3efdedc |
3 changed files with 107 additions and 82 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
galaxy/slashtag arguments.txt
|
||||
.venv
|
||||
*.db
|
||||
|
|
|
@ -4,7 +4,7 @@ from datetime import datetime, timedelta, timezone
|
|||
from typing import Union
|
||||
import discord
|
||||
import humanize
|
||||
import mysql.connector
|
||||
from prisma import Prisma
|
||||
from discord.ext import tasks
|
||||
from pytimeparse2 import disable_dateutil, parse
|
||||
from redbot.core import app_commands, checks, Config, commands
|
||||
|
@ -19,10 +19,12 @@ class Moderation(commands.Cog):
|
|||
self.bot = bot
|
||||
self.config = Config.get_conf(self, identifier=481923957134912)
|
||||
self.config.register_global(
|
||||
mysql_address= " ",
|
||||
mysql_database = " ",
|
||||
mysql_username = " ",
|
||||
mysql_password = " "
|
||||
database_provider = "sqlite",
|
||||
database_address= "file:moderation.db",
|
||||
database_port = " ",
|
||||
database_name = " ",
|
||||
database_username = " ",
|
||||
database_password = " "
|
||||
)
|
||||
self.config.register_guild(
|
||||
ignore_other_bots = True,
|
||||
|
@ -108,67 +110,20 @@ class Moderation(commands.Cog):
|
|||
await self.mysql_log(entry.guild.id, entry.user.id, moderation_type, entry.target.id, duration, reason)
|
||||
|
||||
async def connect(self):
|
||||
"""Connects to the MySQL database, and returns a connection object."""
|
||||
conf = await self.check_conf([
|
||||
'mysql_address',
|
||||
'mysql_database',
|
||||
'mysql_username',
|
||||
'mysql_password'
|
||||
])
|
||||
if conf:
|
||||
raise LookupError("MySQL connection details not set properly!")
|
||||
try:
|
||||
connection = mysql.connector.connect(
|
||||
host=await self.config.mysql_address(),
|
||||
user=await self.config.mysql_username(),
|
||||
password=await self.config.mysql_password(),
|
||||
database=await self.config.mysql_database()
|
||||
)
|
||||
return connection
|
||||
except mysql.connector.ProgrammingError as e:
|
||||
self.logger.fatal("Unable to access the MySQL database!\nError:\n%s", e.msg)
|
||||
raise ConnectionRefusedError(f"Unable to access the MySQL Database!\n{e.msg}") from e
|
||||
|
||||
async def create_guild_table(self, guild: discord.Guild):
|
||||
database = await self.connect()
|
||||
cursor = database.cursor()
|
||||
try:
|
||||
cursor.execute(f"SELECT * FROM `moderation_{guild.id}`")
|
||||
self.logger.info("MySQL Table exists for server %s (%s)", guild.name, guild.id)
|
||||
except mysql.connector.errors.ProgrammingError:
|
||||
query = f"""
|
||||
CREATE TABLE `moderation_{guild.id}` (
|
||||
moderation_id INT UNIQUE PRIMARY KEY NOT NULL,
|
||||
timestamp INT NOT NULL,
|
||||
moderation_type LONGTEXT NOT NULL,
|
||||
target_id LONGTEXT NOT NULL,
|
||||
moderator_id LONGTEXT NOT NULL,
|
||||
duration LONGTEXT,
|
||||
end_timestamp INT,
|
||||
reason LONGTEXT,
|
||||
resolved BOOL NOT NULL,
|
||||
resolved_by LONGTEXT,
|
||||
resolve_reason LONGTEXT,
|
||||
expired BOOL NOT NULL
|
||||
)
|
||||
"""
|
||||
cursor.execute(query)
|
||||
index_query_1 = "CREATE INDEX idx_target_id ON moderation_%s(target_id(25));"
|
||||
cursor.execute(index_query_1, (guild.id,))
|
||||
index_query_2 = "CREATE INDEX idx_moderator_id ON moderation_%s(moderator_id(25));"
|
||||
cursor.execute(index_query_2, (guild.id,))
|
||||
index_query_3 = "CREATE INDEX idx_moderation_id ON moderation_%s(moderation_id);"
|
||||
cursor.execute(index_query_3, (guild.id,))
|
||||
insert_query = f"""
|
||||
INSERT INTO `moderation_{guild.id}`
|
||||
(moderation_id, timestamp, moderation_type, target_id, moderator_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
insert_values = (0, 0, "NULL", 0, 0, "NULL", 0, "NULL", 0, "NULL", "NULL", 0)
|
||||
cursor.execute(insert_query, insert_values)
|
||||
database.commit()
|
||||
self.logger.info("MySQL Table (moderation_%s) created for %s (%s)", guild.id, guild.name, guild.id)
|
||||
database.close()
|
||||
"""Connects to the database, and returns a connection object."""
|
||||
provider = await self.config.database_provider()
|
||||
address = await self.config.database_address()
|
||||
if provider == "sqlite" and address == "file:moderation.db":
|
||||
return await Prisma().connect()
|
||||
else:
|
||||
return await Prisma(
|
||||
provider=provider,
|
||||
address=address,
|
||||
port=await self.config.database_port(),
|
||||
database=await self.config.database_name(),
|
||||
username=await self.config.database_username(),
|
||||
password=await self.config.database_password()
|
||||
).connect()
|
||||
|
||||
async def check_conf(self, config: list):
|
||||
"""Checks if any required config options are not set."""
|
||||
|
@ -193,31 +148,70 @@ class Moderation(commands.Cog):
|
|||
return permission
|
||||
return False
|
||||
|
||||
async def mysql_log(self, guild_id: str, author_id: str, moderation_type: str, target_id: int, duration, reason: str):
|
||||
async def prisma_log(self, guild_id: str, author_id: str, moderation_type: str, target_id: int, duration, reason: str, role_id = None):
|
||||
timestamp = int(time.time())
|
||||
if duration != "NULL":
|
||||
end_timedelta = datetime.fromtimestamp(timestamp) + duration
|
||||
end_timestamp = int(end_timedelta.timestamp())
|
||||
else:
|
||||
end_timestamp = 0
|
||||
database = await self.connect()
|
||||
cursor = database.cursor()
|
||||
moderation_id = await self.get_next_case_number(guild_id=guild_id, cursor=cursor)
|
||||
sql = f"INSERT INTO `moderation_{guild_id}` (moderation_id, timestamp, moderation_type, target_id, moderator_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
|
||||
val = (moderation_id, timestamp, moderation_type, target_id, author_id, duration, end_timestamp, f"{reason}", 0, "NULL", "NULL", 0)
|
||||
cursor.execute(sql, val)
|
||||
database.commit()
|
||||
database.close()
|
||||
self.logger.debug("MySQL row inserted into moderation_%s!\n%s, %s, %s, %s, %s, %s, %s, %s, 0, NULL, NULL, 0", guild_id, moderation_id, timestamp, moderation_type, target_id, author_id, duration, end_timestamp, reason)
|
||||
if not role_id:
|
||||
role_id = "NULL"
|
||||
db = await self.connect()
|
||||
global_id = await self.get_next_global_case_number(database=db)
|
||||
moderation_id = await self.get_next_case_number(guild_id=guild_id, database=db)
|
||||
await db.Case.create(
|
||||
data={
|
||||
'globalId': global_id,
|
||||
'guildId': guild_id,
|
||||
'moderationId': moderation_id,
|
||||
'timestamp': timestamp,
|
||||
'moderationType': moderation_type,
|
||||
'targetId': target_id,
|
||||
'moderatorId': author_id,
|
||||
'roleId': role_id,
|
||||
'duration': duration,
|
||||
'endTimestamp': end_timestamp,
|
||||
'reason': reason,
|
||||
'resolved': False,
|
||||
'resolvedBy': None,
|
||||
'resolveReason': None,
|
||||
'expired': False
|
||||
}
|
||||
)
|
||||
await db.disconnect()
|
||||
return moderation_id
|
||||
|
||||
async def get_next_case_number(self, guild_id: str, cursor = None):
|
||||
"""This method returns the next case number from the MySQL table for a specific guild."""
|
||||
if not cursor:
|
||||
async def get_next_case_number(self, guild_id: str, database = None):
|
||||
"""This method returns the next case number from the database table for a specific guild."""
|
||||
if not database:
|
||||
database = await self.connect()
|
||||
cursor = database.cursor()
|
||||
cursor.execute(f"SELECT moderation_id FROM `moderation_{guild_id}` ORDER BY moderation_id DESC LIMIT 1")
|
||||
return cursor.fetchone()[0] + 1
|
||||
db_not_provided = True
|
||||
else:
|
||||
db_not_provided = False
|
||||
result = await database.Case.find_first(
|
||||
select={"moderationId": True},
|
||||
where={"guildId": guild_id},
|
||||
order=[{"moderationId": "desc"}],
|
||||
)
|
||||
if db_not_provided:
|
||||
await database.disconnect()
|
||||
return result.moderationId + 1 if result else 1
|
||||
|
||||
async def get_next_global_case_number(self, database = None):
|
||||
"""This method returns the next case number from the database table."""
|
||||
if not database:
|
||||
database = await self.connect()
|
||||
db_not_provided = True
|
||||
else:
|
||||
db_not_provided = False
|
||||
result = await database.Case.find_first(
|
||||
select={"globalId": True},
|
||||
order=[{"globalId": "desc"}],
|
||||
)
|
||||
if db_not_provided:
|
||||
await database.disconnect()
|
||||
return result.globalId + 1 if result else 1
|
||||
|
||||
def generate_dict(self, result):
|
||||
case: dict = {
|
||||
|
|
30
moderation/prisma/schema.prisma
Normal file
30
moderation/prisma/schema.prisma
Normal file
|
@ -0,0 +1,30 @@
|
|||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = "file:moderation.db"
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-py"
|
||||
interface = "asyncio"
|
||||
recursive_type_depth = 5
|
||||
}
|
||||
|
||||
model Case {
|
||||
globalId Int @id @unique
|
||||
guildId BigInt
|
||||
moderationId Int
|
||||
timestamp DateTime
|
||||
moderationType String
|
||||
targetId BigInt
|
||||
moderatorId BigInt
|
||||
roleId BigInt?
|
||||
duration String?
|
||||
endTimestamp DateTime?
|
||||
reason String?
|
||||
resolved Boolean
|
||||
resolvedBy BigInt?
|
||||
resolveReason String?
|
||||
expired Boolean
|
||||
|
||||
@@index([guildId, moderationId, targetId, moderatorId])
|
||||
}
|
Loading…
Reference in a new issue