Refactor command definitions across multiple cogs to replace hybrid commands with regular commands for consistency. This change enhances clarity and standardizes command handling throughout the bot.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 8s

This commit is contained in:
TheOnlyMace
2026-07-21 22:50:11 +02:00
parent 20193404e8
commit 1da2085087
47 changed files with 203 additions and 153 deletions

View File

@@ -51,10 +51,24 @@ TICKET_LIMIT_PER_USER = 3
# --- Database Class ---
class TicketDatabase:
def __init__(self, path):
self.conn = sqlite3.connect(path, check_same_thread=False)
self.path = path
self.conn = None
self._connect()
def _connect(self):
self.conn = sqlite3.connect(self.path, check_same_thread=False)
self.conn.row_factory = sqlite3.Row
self._create_tables()
def _ensure_open(self):
if self.conn is None:
self._connect()
return
try:
self.conn.execute("SELECT 1")
except (sqlite3.ProgrammingError, sqlite3.OperationalError):
self._connect()
def _create_tables(self):
with self.conn:
self.conn.execute("CREATE TABLE IF NOT EXISTS guild_configs (guild_id INTEGER PRIMARY KEY, panel_channel_id INTEGER, logging_channel_id INTEGER, panel_message_id INTEGER, panel_type TEXT, embed_title TEXT, embed_description TEXT, embed_color INTEGER, embed_image_url TEXT, embed_thumbnail_url TEXT, closed_category_id INTEGER)")
@@ -63,13 +77,29 @@ class TicketDatabase:
self.conn.execute("CREATE TABLE IF NOT EXISTS user_ticket_counts (guild_id INTEGER, user_id INTEGER, ticket_count INTEGER DEFAULT 0, PRIMARY KEY (guild_id, user_id))")
def execute(self, q, p=()):
with self.conn: return self.conn.execute(q, p)
self._ensure_open()
with self.conn:
return self.conn.execute(q, p)
def fetchone(self, q, p=()):
cur = self.conn.cursor(); cur.execute(q, p); return cur.fetchone()
self._ensure_open()
cur = self.conn.cursor()
cur.execute(q, p)
return cur.fetchone()
def fetchall(self, q, p=()):
cur = self.conn.cursor(); cur.execute(q, p); return cur.fetchall()
self._ensure_open()
cur = self.conn.cursor()
cur.execute(q, p)
return cur.fetchall()
def close(self):
if self.conn: self.conn.close()
if self.conn is not None:
try:
self.conn.close()
except Exception:
pass
self.conn = None
# --- Utility Functions ---
async def get_or_create_log_channel(db, guild):
@@ -270,13 +300,30 @@ class CategoryConfigView(discord.ui.View):
class TicketCog(commands.Cog, name="Ticket System"):
def __init__(self, bot):
self.bot, self.db = bot, TicketDatabase(DB_PATH)
self.bot.loop.create_task(self.load_persistent_views())
self.bot = bot
self.db = TicketDatabase(DB_PATH)
self._views_task: asyncio.Task | None = None
async def cog_load(self):
# Start after inject succeeds — avoids closed-DB race when add_cog fails/unloads
self._views_task = asyncio.create_task(self.load_persistent_views())
async def load_persistent_views(self):
await self.bot.wait_until_ready()
for config in self.db.fetchall("SELECT guild_id, panel_message_id FROM guild_configs WHERE panel_message_id IS NOT NULL"):
if view := self.create_panel_view(config['guild_id']): self.bot.add_view(view, message_id=config['panel_message_id'])
try:
await self.bot.wait_until_ready()
configs = self.db.fetchall(
"SELECT guild_id, panel_message_id FROM guild_configs WHERE panel_message_id IS NOT NULL"
)
for config in configs:
if view := self.create_panel_view(config["guild_id"]):
self.bot.add_view(view, message_id=config["panel_message_id"])
except asyncio.CancelledError:
raise
except sqlite3.ProgrammingError:
# Cog unloaded / DB closed before ready — ignore
return
except Exception as e:
print(f"Ticket persistent views load failed: {e}")
def create_panel_view(self, guild_id):
config = self.db.fetchone("SELECT panel_type FROM guild_configs WHERE guild_id=?", (guild_id,))
@@ -290,7 +337,10 @@ class TicketCog(commands.Cog, name="Ticket System"):
for c in categories: view.add_item(discord.ui.Button(label=c['name'], style=discord.ButtonStyle(c['button_style']), emoji=c['emoji'], custom_id=f"create_ticket_{c['category_id']}"))
return view
def cog_unload(self): self.db.close()
def cog_unload(self):
if self._views_task and not self._views_task.done():
self._views_task.cancel()
self.db.close()
@commands.Cog.listener()
async def on_interaction(self, inter):