aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cogs/trigger.py305
1 files changed, 305 insertions, 0 deletions
diff --git a/cogs/trigger.py b/cogs/trigger.py
new file mode 100644
index 0000000..daf9e7b
--- /dev/null
+++ b/cogs/trigger.py
@@ -0,0 +1,305 @@
1import os
2
3import discord
4from discord.ext import commands
5import random
6import sqlite3
7import logging
8
9logger = logging.getLogger(__name__)
10
11
12DB_PATH = 'data/triggers.db'
13
14
15def get_connection():
16 return sqlite3.connect(DB_PATH)
17
18
19class Trigger(commands.Cog):
20 def __init__(self, bot):
21 self.bot = bot
22 self.db_check()
23
24 trigger_group = discord.SlashCommandGroup("trigger", "trigger commands")
25
26 @staticmethod
27 def db_check():
28 if not os.path.exists('data'):
29 os.makedirs('data')
30
31 db_exists = os.path.exists(DB_PATH)
32 if not db_exists:
33 logger.warning("Triggers database not found. Creating new database.")
34
35 try:
36 conn = sqlite3.connect(DB_PATH)
37 c = conn.cursor()
38
39 # Enable foreign key constraints
40 c.execute('PRAGMA foreign_keys = ON')
41
42 # Create triggers table
43 c.execute('''
44 CREATE TABLE IF NOT EXISTS triggers (
45 id INTEGER PRIMARY KEY AUTOINCREMENT,
46 name TEXT NOT NULL UNIQUE,
47 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
48 last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
49 )''')
50
51 # Create trigger_keywords table with foreign key constraint
52 c.execute('''
53 CREATE TABLE IF NOT EXISTS trigger_keywords (
54 id INTEGER PRIMARY KEY AUTOINCREMENT,
55 trigger_id INTEGER NOT NULL,
56 keyword TEXT NOT NULL,
57 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
58 FOREIGN KEY (trigger_id) REFERENCES triggers(id) ON DELETE CASCADE,
59 UNIQUE(trigger_id, keyword)
60 )''')
61
62 # Create trigger_responses table with foreign key constraint
63 c.execute('''
64 CREATE TABLE IF NOT EXISTS trigger_responses (
65 id INTEGER PRIMARY KEY AUTOINCREMENT,
66 trigger_id INTEGER NOT NULL,
67 response_text TEXT NOT NULL,
68 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
69 FOREIGN KEY (trigger_id) REFERENCES triggers(id) ON DELETE CASCADE
70 )''')
71
72 # Create indexes for better query performance
73 c.execute('CREATE INDEX IF NOT EXISTS idx_trigger_keywords_trigger_id ON trigger_keywords(trigger_id)')
74 c.execute('CREATE INDEX IF NOT EXISTS idx_trigger_keywords_keyword ON trigger_keywords(keyword)')
75 c.execute('CREATE INDEX IF NOT EXISTS idx_trigger_responses_trigger_id ON trigger_responses(trigger_id)')
76
77 # Run integrity check
78 integrity_check = c.execute('PRAGMA integrity_check').fetchone()
79 if integrity_check and integrity_check[0] == 'ok':
80 logger.info("Triggers database integrity check passed")
81 else:
82 logger.warning(f"Triggers database integrity check: {integrity_check}")
83
84 conn.commit()
85
86 except sqlite3.Error as e:
87 logger.error(f"Triggers database error: {e}")
88 raise
89
90 finally:
91 if 'conn' in locals():
92 conn.close()
93
94 if not db_exists:
95 logger.info("Triggers database initialized successfully")
96
97 @commands.Cog.listener()
98 async def on_message(self, message):
99 if message.author == self.bot.user:
100 return
101
102 await self.trigger(message)
103
104 @staticmethod
105 async def trigger(message):
106 content = message.content.lower()
107 with get_connection() as conn:
108 c = conn.cursor()
109 c.execute("SELECT id, name FROM triggers")
110 for trigger_id, name in c.fetchall():
111 c.execute("SELECT keyword FROM trigger_keywords WHERE trigger_id=?", (trigger_id,))
112 keywords = [row[0] for row in c.fetchall()]
113 if any(keyword in content for keyword in keywords):
114 c.execute("SELECT response_text FROM trigger_responses WHERE trigger_id=?", (trigger_id,))
115 responses = [row[0] for row in c.fetchall()]
116 if responses:
117 await message.channel.send(random.choice(responses).replace('\\n', '\n'))
118 logger.info(f"{message.author} triggered {name}")
119 break
120
121 @staticmethod
122 def get_type(name):
123 with sqlite3.connect(DB_PATH) as conn:
124 c = conn.cursor()
125 c.execute("SELECT name FROM triggers")
126 return [row[0] for row in c.fetchall()]
127
128 @trigger_group.command(
129 description="Create a new trigger",
130 )
131 async def create(
132 self,
133 ctx: discord.ApplicationContext,
134 name = discord.Option(
135 str,
136 "the name of the trigger",
137 autocomplete= discord.utils.basic_autocomplete(get_type),
138 required=True
139 )
140 ):
141 with get_connection() as conn:
142 c = conn.cursor()
143 c.execute("INSERT OR IGNORE INTO triggers (name) VALUES (?)", (name,))
144 conn.commit()
145
146 await ctx.respond("trigger added")
147
148 @trigger_group.command(
149 description="Add a trigger or response to the name",
150 )
151 async def add(
152 self,
153 ctx: discord.ApplicationContext,
154 name = discord.Option(
155 str,
156 "the name of the trigger",
157 autocomplete= discord.utils.basic_autocomplete(get_type),
158 required=True
159 ),
160 trigger = discord.Option(
161 str,
162 "the trigger to add to the name",
163 required=False
164 ),
165 response = discord.Option(
166 str,
167 "the response to add to the name",
168 required=False
169 )
170 ):
171 with get_connection() as conn:
172 c = conn.cursor()
173 c.execute("SELECT id FROM triggers WHERE name=?", (name,))
174 row = c.fetchone()
175 if not row:
176 await ctx.respond("Trigger not found.")
177 logger.warning(f"Trigger not found: {name}")
178 return
179 trigger_id = row[0]
180 if trigger:
181 c.execute("INSERT INTO trigger_keywords (trigger_id, keyword) VALUES (?, ?)", (trigger_id, trigger))
182 if response:
183 c.execute("INSERT INTO trigger_responses (trigger_id, response_text) VALUES (?, ?)", (trigger_id, response))
184 conn.commit()
185
186 await ctx.respond("trigger updated")
187 logger.info(f"Trigger updated: {name}")
188
189 @trigger_group.command(
190 description="Remove a trigger or response from the name",
191 )
192 async def remove(
193 self,
194 ctx: discord.ApplicationContext,
195 name = discord.Option(
196 str,
197 "the name of the trigger",
198 autocomplete= discord.utils.basic_autocomplete(get_type),
199 required=True
200 ),
201 trigger = discord.Option(
202 str,
203 "the trigger to remove from the name",
204 required=False
205 ),
206 response = discord.Option(
207 str,
208 "the response to remove from the name",
209 required=False
210 )
211 ):
212 with get_connection() as conn:
213 c = conn.cursor()
214 c.execute("SELECT id FROM triggers WHERE name=?", (name,))
215 row = c.fetchone()
216 if not row:
217 await ctx.respond("Trigger not found.")
218 logger.warning(f"Trigger not found: {name}")
219 return
220 trigger_id = row[0]
221 if trigger:
222 c.execute("DELETE FROM trigger_keywords WHERE trigger_id=? AND keyword=?", (trigger_id, trigger))
223 if response:
224 c.execute("DELETE FROM trigger_responses WHERE trigger_id=? AND response_text=?", (trigger_id, response))
225 conn.commit()
226
227 await ctx.respond("trigger removed")
228 logger.info(f"Trigger removed: {name}")
229
230 @trigger_group.command(
231 description="Delete the whole trigger",
232 )
233 async def delete(
234 self,
235 ctx: discord.ApplicationContext,
236 name = discord.Option(
237 str,
238 "the name of the trigger",
239 autocomplete= discord.utils.basic_autocomplete(get_type),
240 required=True
241 )
242 ):
243 with get_connection() as conn:
244 c = conn.cursor()
245 c.execute("SELECT id FROM triggers WHERE name=?", (name,))
246 row = c.fetchone()
247 if not row:
248 await ctx.respond("Trigger not found.")
249 return
250 trigger_id = row[0]
251 c.execute("DELETE FROM trigger_keywords WHERE trigger_id=?", (trigger_id,))
252 c.execute("DELETE FROM trigger_responses WHERE trigger_id=?", (trigger_id,))
253 c.execute("DELETE FROM triggers WHERE id=?", (trigger_id,))
254 conn.commit()
255
256 await ctx.respond("trigger deleted")
257 logger.info(f"Trigger deleted: {name}")
258
259
260 @trigger_group.command(
261 description="List all triggers",
262 )
263 async def list(
264 self,
265 ctx: discord.ApplicationContext,
266 name = discord.Option(
267 str,
268 "the name of the trigger",
269 autocomplete=discord.utils.basic_autocomplete(get_type),
270 required=True
271 )
272 ):
273 with get_connection() as conn:
274 c = conn.cursor()
275 if name:
276 c.execute("SELECT id FROM triggers WHERE name=?", (name,))
277 row = c.fetchone()
278 if not row:
279 await ctx.respond("Trigger not found.")
280 logger.warning(f"Trigger not found: {name}")
281 return
282 trigger_id = row[0]
283 c.execute("SELECT keyword FROM trigger_keywords WHERE trigger_id=?", (trigger_id,))
284 triggers = [row[0] for row in c.fetchall()]
285 c.execute("SELECT response_text FROM trigger_responses WHERE trigger_id=?", (trigger_id,))
286 responses = [row[0] for row in c.fetchall()]
287 trigger_list = "\n\n".join(triggers)
288 response_list = "\n\n".join(responses)
289 message = f"**Trigger: {name}**\n**Triggers:**\n{trigger_list}\n**Responses:**\n{response_list}"
290 await ctx.respond(message)
291 logger.info(f"Trigger listed: {name}")
292 else:
293 c.execute("SELECT id, name FROM triggers")
294 messages = []
295 for trigger_id, name in c.fetchall():
296 c.execute("SELECT keyword FROM trigger_keywords WHERE trigger_id=?", (trigger_id,))
297 triggers = ", ".join([row[0] for row in c.fetchall()])
298 c.execute("SELECT response_text FROM trigger_responses WHERE trigger_id=?", (trigger_id,))
299 responses = ", ".join([row[0] for row in c.fetchall()])
300 messages.append(f"**{name}**\nTriggers: {triggers}\nResponses: {responses}")
301 await ctx.respond("\n\n".join(messages))
302 logger.info(f"Triggers listed")
303
304def setup(bot):
305 bot.add_cog(Trigger(bot)) \ No newline at end of file