Changed Incidents to work with both a TimeFrame and last 50 messages.

This commit is contained in:
advtech 2025-01-29 15:45:48 -05:00
parent 6f2b13f055
commit 31913db64f
2 changed files with 142 additions and 42 deletions

View File

@ -8,6 +8,16 @@ from utils.database import Database
db = Database() db = Database()
import discord
from discord import app_commands
from typing import Optional, List
from datetime import datetime
import logging
import uuid
from utils.database import Database
db = Database()
class IncidentModal(discord.ui.Modal): class IncidentModal(discord.ui.Modal):
def __init__(self): def __init__(self):
super().__init__(title="Log Incident") super().__init__(title="Log Incident")
@ -17,24 +27,75 @@ class IncidentModal(discord.ui.Modal):
required=True required=True
) )
self.message_count = discord.ui.TextInput( self.message_count = discord.ui.TextInput(
label="Messages to capture (1-50)", label="Recent messages to capture (1-50)",
default="10", placeholder="Leave blank to use timeframe",
required=True default="",
required=False
)
self.start_time = discord.ui.TextInput(
label="Start time (YYYY-MM-DD HH:MM)",
placeholder="Optional - Example: 2024-05-10 14:30",
required=False
)
self.end_time = discord.ui.TextInput(
label="End time (YYYY-MM-DD HH:MM)",
placeholder="Optional - Example: 2024-05-10 15:00",
required=False
) )
self.add_item(self.reason) self.add_item(self.reason)
self.add_item(self.message_count) self.add_item(self.message_count)
self.add_item(self.start_time)
self.add_item(self.end_time)
async def on_submit(self, interaction: discord.Interaction): async def on_submit(self, interaction: discord.Interaction):
try: try:
count = int(self.message_count.value) messages = []
if not 1 <= count <= 50: capture_mode = "count"
raise ValueError capture_param = ""
start_time = None
end_time = None
messages = [ # Determine capture mode
msg async for msg in interaction.channel.history(limit=count) if self.start_time.value or self.end_time.value:
][::-1] if not all([self.start_time.value, self.end_time.value]):
raise ValueError("Both start and end times required for timeframe")
start_time = datetime.strptime(self.start_time.value, "%Y-%m-%d %H:%M")
end_time = datetime.strptime(self.end_time.value, "%Y-%m-%d %H:%M")
if start_time >= end_time:
raise ValueError("End time must be after start time")
if (end_time - start_time).total_seconds() > 86400:
raise ValueError("Maximum timeframe duration is 24 hours")
async for msg in interaction.channel.history(
limit=None,
after=start_time,
before=end_time
):
messages.append(msg)
messages = messages[::-1] # Oldest first
capture_mode = "timeframe"
capture_param = f"{start_time.strftime('%Y-%m-%d %H:%M')} to {end_time.strftime('%Y-%m-%d %H:%M')}"
else:
if not self.message_count.value:
raise ValueError("Please provide either message count or timeframe")
count = int(self.message_count.value)
if not 1 <= count <= 50:
raise ValueError("Message count must be between 1-50")
messages = [
msg async for msg in interaction.channel.history(limit=count)
][::-1]
capture_mode = "count"
capture_param = str(count)
# Format messages
formatted_messages = [{ formatted_messages = [{
"id": msg.id, "id": msg.id,
"author_id": msg.author.id, "author_id": msg.author.id,
@ -42,34 +103,45 @@ class IncidentModal(discord.ui.Modal):
"timestamp": msg.created_at "timestamp": msg.created_at
} for msg in messages] } for msg in messages]
incident_id = f"incident_{int(datetime.now().timestamp())}" # Generate unique ID
incident_id = f"incident_{uuid.uuid4().hex[:8]}"
success = db.add_incident( success = db.add_incident(
incident_id=incident_id, incident_id=incident_id,
reason=self.reason.value, reason=self.reason.value,
moderator_id=interaction.user.id, moderator_id=interaction.user.id,
messages=formatted_messages messages=formatted_messages,
capture_mode=capture_mode,
capture_param=capture_param,
start_time=start_time,
end_time=end_time
) )
if not success: if not success:
raise Exception("Database storage failed") raise Exception("Database storage failed - check server logs")
embed = discord.Embed( embed = discord.Embed(
title="Incident Logged", title="Incident Logged",
description=f"**ID:** `{incident_id}`\n**Reason:** {self.reason.value}", description=f"**ID:** `{incident_id}`\n**Mode:** {capture_mode.title()}",
color=0xff0000 color=0xff0000
) )
preview = messages[0].content[:50] + "..." if messages else "No messages" embed.add_field(name="Reason", value=self.reason.value[:500], inline=False)
embed.add_field(name="First Message", value=preview, inline=False)
if messages:
preview = f"{messages[0].content[:100]}..." if len(messages[0].content) > 100 else messages[0].content
embed.add_field(name="First Message", value=preview, inline=False)
await interaction.response.send_message(embed=embed, ephemeral=True)
except ValueError as e:
await interaction.response.send_message( await interaction.response.send_message(
embed=embed, f"❌ Validation Error: {str(e)}",
ephemeral=True ephemeral=True
) )
except Exception as e:
except ValueError: logging.error(f"Incident submission error: {str(e)}", exc_info=True)
await interaction.response.send_message( await interaction.response.send_message(
"❌ Please enter a number between 1-50", "⚠️ Failed to log incident - please check input format",
ephemeral=True ephemeral=True
) )
@ -158,9 +230,14 @@ async def setup(client):
embed = discord.Embed( embed = discord.Embed(
title=f"Incident {incident_id}", title=f"Incident {incident_id}",
description=f"**Reason:** {incident['details']['reason']}", description=(
color=0xff0000 f"**Reason:** {incident['details']['reason']}\n"
) f"**Capture Mode:** {incident['details']['capture_mode'].title()}\n"
f"**Params:** {incident['details']['capture_param']}"
),
color=0xff0000
)
embed.add_field( embed.add_field(
name="Messages", name="Messages",
value=messages[:1020] + "..." if len(messages) > 1024 else messages, value=messages[:1020] + "..." if len(messages) > 1024 else messages,

View File

@ -4,6 +4,11 @@ from datetime import datetime
from typing import List, Dict, Optional from typing import List, Dict, Optional
import sqlite3
import logging
from datetime import datetime
from typing import List, Dict, Optional
class Database: class Database:
def __init__(self, db_path: str = "data/moments.db"): def __init__(self, db_path: str = "data/moments.db"):
self.db_path = db_path self.db_path = db_path
@ -12,6 +17,10 @@ class Database:
def _init_db(self): def _init_db(self):
"""Initialize database tables""" """Initialize database tables"""
with self._get_connection() as conn: with self._get_connection() as conn:
# Drop tables if they exist (for development)
conn.execute("DROP TABLE IF EXISTS incidents")
conn.execute("DROP TABLE IF EXISTS incident_messages")
conn.execute(""" conn.execute("""
CREATE TABLE IF NOT EXISTS funny_moments ( CREATE TABLE IF NOT EXISTS funny_moments (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -27,7 +36,11 @@ class Database:
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
reason TEXT NOT NULL, reason TEXT NOT NULL,
moderator_id INTEGER NOT NULL, moderator_id INTEGER NOT NULL,
timestamp DATETIME NOT NULL timestamp DATETIME NOT NULL,
capture_mode TEXT NOT NULL,
capture_param TEXT,
start_time DATETIME,
end_time DATETIME
) )
""") """)
@ -42,34 +55,32 @@ class Database:
FOREIGN KEY (incident_id) REFERENCES incidents(id) FOREIGN KEY (incident_id) REFERENCES incidents(id)
) )
""") """)
conn.commit() conn.commit()
def _get_connection(self): def _get_connection(self):
return sqlite3.connect(self.db_path) return sqlite3.connect(self.db_path)
def add_funny_moment(self, message_link: str, author_id: int, description: str = None) -> int: def add_incident(self, incident_id: str, reason: str, moderator_id: int,
"""Store a funny moment in database""" messages: List[Dict], capture_mode: str, capture_param: str,
with self._get_connection() as conn: start_time: datetime = None, end_time: datetime = None) -> bool:
cursor = conn.cursor()
cursor.execute("""
INSERT INTO funny_moments
(message_link, description, author_id, timestamp)
VALUES (?, ?, ?, ?)
""", (message_link, description, author_id, datetime.now()))
conn.commit()
return cursor.lastrowid
def add_incident(self, incident_id: str, reason: str, moderator_id: int, messages: List[Dict]) -> bool:
"""Store an incident with related messages""" """Store an incident with related messages"""
try: try:
with self._get_connection() as conn: with self._get_connection() as conn:
# Add incident record # Add incident record
conn.execute(""" conn.execute("""
INSERT INTO incidents INSERT INTO incidents
(id, reason, moderator_id, timestamp) (id, reason, moderator_id, timestamp, capture_mode, capture_param, start_time, end_time)
VALUES (?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (incident_id, reason, moderator_id, datetime.now())) """, (
incident_id,
reason,
moderator_id,
datetime.now(),
capture_mode,
capture_param,
start_time,
end_time
))
# Add incident messages # Add incident messages
for msg in messages: for msg in messages:
@ -88,9 +99,21 @@ class Database:
conn.commit() conn.commit()
return True return True
except Exception as e: except Exception as e:
logging.error(f"Failed to save incident: {e}") logging.error(f"Failed to save incident: {str(e)}")
return False return False
def add_funny_moment(self, message_link: str, author_id: int, description: str = None) -> int:
"""Store a funny moment in database"""
with self._get_connection() as conn:
cursor = conn.cursor()
cursor.execute("""
INSERT INTO funny_moments
(message_link, description, author_id, timestamp)
VALUES (?, ?, ?, ?)
""", (message_link, description, author_id, datetime.now()))
conn.commit()
return cursor.lastrowid
def get_incident(self, incident_id: str) -> Optional[Dict]: def get_incident(self, incident_id: str) -> Optional[Dict]:
"""Retrieve an incident with its messages""" """Retrieve an incident with its messages"""
with self._get_connection() as conn: with self._get_connection() as conn: