228 lines
6.5 KiB
Python
228 lines
6.5 KiB
Python
# pylint: disable=cyclic-import
|
|
|
|
import json
|
|
import time
|
|
from datetime import datetime
|
|
import mysql.connector
|
|
from discord import Guild
|
|
from .utils import generate_dict, get_next_case_number, check_conf
|
|
from .config import config
|
|
from .logger import logger
|
|
|
|
|
|
async def connect():
|
|
"""Connects to the MySQL database, and returns a connection object."""
|
|
conf = await 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 config.mysql_address(),
|
|
user=await config.mysql_username(),
|
|
password=await config.mysql_password(),
|
|
database=await config.mysql_database(),
|
|
)
|
|
|
|
return connection
|
|
|
|
except mysql.connector.ProgrammingError as e:
|
|
logger.error("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(guild: Guild):
|
|
database = await connect()
|
|
cursor = database.cursor()
|
|
|
|
try:
|
|
cursor.execute(f"SELECT * FROM `moderation_{guild.id}`")
|
|
logger.debug("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_type LONGTEXT NOT NULL,
|
|
target_id LONGTEXT NOT NULL,
|
|
moderator_id LONGTEXT NOT NULL,
|
|
role_id LONGTEXT,
|
|
duration LONGTEXT,
|
|
end_timestamp INT,
|
|
reason LONGTEXT,
|
|
resolved BOOL NOT NULL,
|
|
resolved_by LONGTEXT,
|
|
resolve_reason LONGTEXT,
|
|
expired BOOL NOT NULL,
|
|
changes JSON NOT NULL,
|
|
metadata JSON 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_type, target_id, moderator_id, role_id, duration, end_timestamp, reason, resolved, resolved_by, resolve_reason, expired, changes, metadata)
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
|
"""
|
|
insert_values = (
|
|
0,
|
|
0,
|
|
"NULL",
|
|
"NULL",
|
|
0,
|
|
0,
|
|
0,
|
|
"NULL",
|
|
0,
|
|
"NULL",
|
|
0,
|
|
"NULL",
|
|
"NULL",
|
|
0,
|
|
json.dumps([]), # pylint: disable=dangerous-default-value
|
|
json.dumps({}), # pylint: disable=dangerous-default-value
|
|
)
|
|
cursor.execute(insert_query, insert_values)
|
|
|
|
database.commit()
|
|
|
|
logger.debug(
|
|
"MySQL Table (moderation_%s) created for %s (%s)",
|
|
guild.id,
|
|
guild.name,
|
|
guild.id,
|
|
)
|
|
|
|
database.close()
|
|
|
|
|
|
async def mysql_log(
|
|
guild_id: str,
|
|
author_id: str,
|
|
moderation_type: str,
|
|
target_type: str,
|
|
target_id: int,
|
|
role_id: int,
|
|
duration,
|
|
reason: str,
|
|
database: mysql.connector.MySQLConnection = None,
|
|
timestamp: int = None,
|
|
resolved: bool = False,
|
|
resolved_by: str = None,
|
|
resolved_reason: str = None,
|
|
expired: bool = None,
|
|
changes: list = [],
|
|
metadata: dict = {},
|
|
): # pylint: disable=dangerous-default-value
|
|
if not timestamp:
|
|
timestamp = int(time.time())
|
|
|
|
if duration != "NULL":
|
|
end_timedelta = datetime.fromtimestamp(timestamp) + duration
|
|
end_timestamp = int(end_timedelta.timestamp())
|
|
else:
|
|
end_timestamp = 0
|
|
|
|
if not expired:
|
|
if int(time.time()) > end_timestamp:
|
|
expired = 1
|
|
else:
|
|
expired = 0
|
|
|
|
if resolved_by is None:
|
|
resolved_by = "NULL"
|
|
|
|
if resolved_reason is None:
|
|
resolved_reason = "NULL"
|
|
|
|
if not database:
|
|
database = await connect()
|
|
close_db = True
|
|
else:
|
|
close_db = False
|
|
cursor = database.cursor()
|
|
|
|
moderation_id = await get_next_case_number(guild_id=guild_id, cursor=cursor)
|
|
|
|
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 (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
|
|
val = (
|
|
moderation_id,
|
|
timestamp,
|
|
moderation_type,
|
|
target_type,
|
|
target_id,
|
|
author_id,
|
|
role_id,
|
|
duration,
|
|
end_timestamp,
|
|
reason,
|
|
int(resolved),
|
|
resolved_by,
|
|
resolved_reason,
|
|
expired,
|
|
json.dumps(changes),
|
|
json.dumps(metadata),
|
|
)
|
|
cursor.execute(sql, val)
|
|
|
|
cursor.close()
|
|
database.commit()
|
|
if close_db:
|
|
database.close()
|
|
|
|
logger.debug(
|
|
"MySQL row inserted into moderation_%s!\n%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
|
|
guild_id,
|
|
moderation_id,
|
|
timestamp,
|
|
moderation_type,
|
|
target_type,
|
|
target_id,
|
|
author_id,
|
|
role_id,
|
|
duration,
|
|
end_timestamp,
|
|
reason,
|
|
int(resolved),
|
|
resolved_by,
|
|
resolved_reason,
|
|
expired,
|
|
changes,
|
|
metadata,
|
|
)
|
|
|
|
return moderation_id
|
|
|
|
|
|
async def fetch_case(moderation_id: int, guild_id: str):
|
|
"""This method fetches a case from the database and returns the case's dictionary."""
|
|
database = await connect()
|
|
cursor = database.cursor()
|
|
|
|
query = "SELECT * FROM moderation_%s WHERE moderation_id = %s;"
|
|
cursor.execute(query, (guild_id, moderation_id))
|
|
result = cursor.fetchone()
|
|
|
|
cursor.close()
|
|
database.close()
|
|
|
|
return generate_dict(result)
|