-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdatabase.py
More file actions
300 lines (268 loc) · 8.63 KB
/
database.py
File metadata and controls
300 lines (268 loc) · 8.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
import os
import sqlite3
import dotenv
from utils.logging_config import get_logger
# Charger les variables d'environnement depuis le fichier .env
dotenv.load_dotenv()
# Configure logging for this module
logger = get_logger(__name__)
# Chemin vers la base de données SQLite
# Convertir en chemin absolu pour éviter les problèmes de localisation
_db_path = os.getenv("db_path")
if _db_path:
# Si le chemin est relatif, le rendre absolu par rapport au répertoire du script
if not os.path.isabs(_db_path):
script_dir = os.path.dirname(__file__)
DB_PATH = os.path.abspath(os.path.join(script_dir, _db_path))
else:
DB_PATH = _db_path
else:
DB_PATH = None
def get_db_connection():
"""Crée une connexion à la base de données SQLite."""
if not DB_PATH:
raise ValueError(
"Le chemin de la base de données n'est pas défini "
"dans les variables d'environnement."
)
conn = None
try:
conn = sqlite3.connect(DB_PATH, timeout=10.0)
conn.row_factory = sqlite3.Row # Permet d'accéder aux colonnes par nom
return conn
except sqlite3.Error as e:
# Fermer la connexion si elle a été créée mais que la configuration a échoué
if conn:
conn.close()
raise RuntimeError(f"Impossible de se connecter à la base de données {DB_PATH}: {e}")
def create_database():
"""Crée la base de données et les tables nécessaires."""
if not DB_PATH:
raise ValueError(
"Le chemin de la base de données n'est pas défini "
"dans les variables d'environnement."
)
db_existed = os.path.exists(DB_PATH)
if db_existed:
logger.debug(f"La base de données existe déjà à l'emplacement: {DB_PATH}")
else:
logger.info(f"Création de la base de données à l'emplacement: {DB_PATH}")
# Créer les tables nécessaires (toujours exécuter cette partie)
# CREATE TABLE IF NOT EXISTS permet de créer uniquement si la table n'existe pas
# et ne supprime PAS les données existantes
conn = get_db_connection()
cursor = conn.cursor()
# Création de la table des utilisateurs
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS users (
guildId TEXT NOT NULL,
userId TEXT NOT NULL,
xp REAL DEFAULT 0,
level INTEGER DEFAULT 1,
messages INTEGER DEFAULT 0,
coins REAL DEFAULT 0,
corners INTEGER DEFAULT 0,
PRIMARY KEY (guildId, userId)
)
"""
)
# Création de la table des streamers
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS streamers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
streamerName TEXT NOT NULL,
streamChannelId TEXT,
roleId TEXT,
announced INTEGER DEFAULT 0,
startTime TEXT
)
"""
)
# Création de la table des chaînes YouTube
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS youtube_channels (
id INTEGER PRIMARY KEY AUTOINCREMENT,
channelId TEXT NOT NULL,
channelName TEXT NOT NULL,
discordChannelId TEXT NOT NULL,
roleId TEXT,
lastVideoId TEXT,
lastShortId TEXT,
lastLiveId TEXT,
notifyVideos INTEGER DEFAULT 1,
notifyShorts INTEGER DEFAULT 1,
notifyLive INTEGER DEFAULT 1
)
"""
)
# Création de la table pour le jeu du compteur
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS counter_game (
guildId TEXT NOT NULL,
channelId TEXT NOT NULL,
messageId TEXT DEFAULT '',
userId TEXT NOT NULL,
lastUserId TEXT DEFAULT '0',
count INTEGER DEFAULT 0,
PRIMARY KEY (guildId, channelId)
)
"""
)
# --- MODERATION SYSTEM TABLES ---
# Table des avertissements (warnings)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS warnings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL,
user_id TEXT NOT NULL,
warn_count INTEGER DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE(guild_id, user_id)
)
"""
)
# Index pour les recherches fréquentes
cursor.execute(
"""
CREATE INDEX IF NOT EXISTS idx_warnings_guild_user
ON warnings(guild_id, user_id)
"""
)
# Historique des avertissements (audit trail immuable)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS warning_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL,
user_id TEXT NOT NULL,
action TEXT NOT NULL,
warn_count_before INTEGER NOT NULL,
warn_count_after INTEGER NOT NULL,
moderator_id TEXT,
reason TEXT,
created_at TEXT NOT NULL
)
"""
)
# Index pour les recherches d'historique
cursor.execute(
"""
CREATE INDEX IF NOT EXISTS idx_history_guild_user
ON warning_history(guild_id, user_id)
"""
)
# Table des appels (appeals)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS moderation_appeals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL,
user_id TEXT NOT NULL,
warning_history_id INTEGER,
appeal_reason TEXT NOT NULL,
moderator_id TEXT,
status TEXT DEFAULT 'pending',
moderator_decision TEXT,
created_at TEXT NOT NULL,
reviewed_at TEXT,
FOREIGN KEY(warning_history_id) REFERENCES warning_history(id)
)
"""
)
# Index pour les appels en attente
cursor.execute(
"""
CREATE INDEX IF NOT EXISTS idx_appeals_status
ON moderation_appeals(guild_id, status)
"""
)
# Configuration de modération par serveur
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS moderation_config (
guild_id TEXT PRIMARY KEY,
log_channel_id TEXT,
appeal_channel_id TEXT,
ai_enabled INTEGER DEFAULT 1,
ai_confidence_threshold INTEGER DEFAULT 60,
ai_flag_channel_id TEXT,
ai_model TEXT DEFAULT 'llama2',
ollama_host TEXT DEFAULT 'http://localhost:11434',
decay_multiplier REAL DEFAULT 1.0,
warn_1_decay_days INTEGER DEFAULT 7,
warn_2_decay_days INTEGER DEFAULT 14,
warn_3_decay_days INTEGER DEFAULT 21,
mute_duration_warn_2 INTEGER DEFAULT 3600,
mute_duration_warn_3 INTEGER DEFAULT 86400,
rules_message_id TEXT,
created_at TEXT NOT NULL
)
"""
)
# Table des messages signalés par l'IA
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS ai_flags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL,
message_id TEXT NOT NULL,
channel_id TEXT NOT NULL,
user_id TEXT NOT NULL,
message_content TEXT NOT NULL,
ai_score INTEGER NOT NULL,
ai_category TEXT NOT NULL,
ai_reason TEXT NOT NULL,
moderator_action TEXT DEFAULT 'pending',
moderator_id TEXT,
created_at TEXT NOT NULL,
reviewed_at TEXT,
UNIQUE(message_id)
)
"""
)
# Index pour les flags en attente
cursor.execute(
"""
CREATE INDEX IF NOT EXISTS idx_ai_flags_status
ON ai_flags(guild_id, moderator_action)
"""
)
# Table des mutes actifs
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS active_mutes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL,
user_id TEXT NOT NULL,
moderator_id TEXT,
reason TEXT NOT NULL,
expires_at TEXT NOT NULL,
created_at TEXT NOT NULL,
UNIQUE(guild_id, user_id)
)
"""
)
# Index pour les recherches d'expiration
cursor.execute(
"""
CREATE INDEX IF NOT EXISTS idx_mutes_expires
ON active_mutes(expires_at)
"""
)
conn.commit()
conn.close()
if db_existed:
logger.debug(
"Tables vérifiées et créées si nécessaire "
"(données existantes préservées)"
)
else:
logger.info("Base de données et tables créées avec succès")
if __name__ == "__main__":
create_database()