Fixed it so follow-up notes can be added to any incidents

This commit is contained in:
advtech 2025-01-29 17:56:15 -05:00
parent 979e7c74d5
commit 02155f3e0f
2 changed files with 173 additions and 51 deletions

View File

@ -8,6 +8,16 @@ from utils.database import 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()
import discord
from discord import app_commands
from typing import Optional, List
@ -123,7 +133,7 @@ class IncidentModal(discord.ui.Modal):
embed = discord.Embed(
title="✅ Incident Logged",
description=f"**ID:** `{incident_id}`\n**Mode:** {capture_mode.title()}",
color=0xff0000
color=0x00ff00
)
embed.add_field(name="Reason", value=self.reason.value[:500], inline=False)
@ -145,6 +155,41 @@ class IncidentModal(discord.ui.Modal):
ephemeral=True
)
class FollowupModal(discord.ui.Modal):
def __init__(self, incident_id: str):
super().__init__(title=f"Follow-up: {incident_id}")
self.incident_id = incident_id
self.notes = discord.ui.TextInput(
label="Additional notes/actions",
style=discord.TextStyle.long,
required=True
)
self.add_item(self.notes)
async def on_submit(self, interaction: discord.Interaction):
try:
success = db.add_followup(
incident_id=self.incident_id,
moderator_id=interaction.user.id,
notes=self.notes.value
)
if success:
await interaction.response.send_message(
f"✅ Follow-up added to **{self.incident_id}**",
ephemeral=True
)
else:
await interaction.response.send_message(
"❌ Failed to save follow-up",
ephemeral=True
)
except Exception as e:
logging.error(f"Followup error: {str(e)}")
await interaction.response.send_message(
"⚠️ Failed to add follow-up",
ephemeral=True
)
async def setup(client):
# Context menu command
@ -205,31 +250,30 @@ async def setup(client):
name="review",
description="Review a logged incident"
)
@app_commands.describe(
incident_id="The incident ID to review"
)
@app_commands.describe(incident_id="The incident ID to review")
@app_commands.checks.has_permissions(manage_messages=True)
async def review_incident(
interaction: discord.Interaction,
incident_id: str
):
async def review_incident(interaction: discord.Interaction, incident_id: str):
try:
incident = db.get_incident(incident_id)
if not incident:
await interaction.response.send_message(
"❌ Incident not found",
ephemeral=True
)
await interaction.response.send_message("❌ Incident not found", ephemeral=True)
return
# Format messages
messages = "\n\n".join(
f"**{msg['timestamp']}** <@{msg['author_id']}>:\n"
f"{msg['content']}"
f"**<t:{int(msg['timestamp'].timestamp())}:F>** <@{msg['author_id']}>:\n{msg['content']}"
for msg in incident['messages']
)
moderator = await interaction.guild.fetch_member(incident['details']['moderator_id'])
# Format follow-ups
followups = db.get_followups(incident_id)
followup_text = "\n\n".join(
f"**<t:{int(f['timestamp'].timestamp())}:f>** <@{f['moderator_id']}>:\n{f['notes'][:200]}"
for f in followups
) if followups else "No follow-up reports yet"
# Create embed
moderator = await interaction.guild.fetch_member(incident['details']['moderator_id'])
embed = discord.Embed(
title=f"Incident {incident_id}",
description=(
@ -239,39 +283,82 @@ async def setup(client):
),
color=0xff0000
)
embed.add_field(name="Messages", value=messages[:1020] + "..." if len(messages) > 1024 else messages, inline=False)
embed.add_field(name=f"Follow-ups ({len(followups)})", value=followup_text[:1020] + "..." if len(followup_text) > 1024 else followup_text, inline=False)
embed.add_field(
name="Messages",
value=messages[:1020] + "..." if len(messages) > 1024 else messages,
inline=False
)
await interaction.response.send_message(
embed=embed,
ephemeral=True
)
await interaction.response.send_message(embed=embed, ephemeral=True)
except Exception as e:
logging.error(f"Incident review error: {e}")
logging.error(f"Incident review error: {str(e)}", exc_info=True)
await interaction.response.send_message("❌ Failed to retrieve incident", ephemeral=True)
# Followup commands
@moments_group.command(
name="followup",
description="Add follow-up to an incident"
)
@app_commands.describe(
incident_id="The incident ID to follow up on",
notes="Quick note (optional)"
)
@app_commands.checks.has_permissions(manage_messages=True)
async def add_followup(
interaction: discord.Interaction,
incident_id: str,
notes: Optional[str] = None
):
try:
if not db.get_incident(incident_id):
await interaction.response.send_message(
"❌ Incident not found",
ephemeral=True
)
return
if notes:
success = db.add_followup(
incident_id=incident_id,
moderator_id=interaction.user.id,
notes=notes
)
if success:
await interaction.response.send_message(
f"✅ Added quick follow-up to **{incident_id}**",
ephemeral=True
)
else:
await interaction.response.send_message(
"❌ Failed to add follow-up",
ephemeral=True
)
else:
await interaction.response.send_modal(FollowupModal(incident_id))
except Exception as e:
logging.error(f"Followup error: {e}")
await interaction.response.send_message(
"❌ Failed to retrieve incident",
"⚠️ Failed to add follow-up",
ephemeral=True
)
# Autocomplete
@review_incident.autocomplete("incident_id")
@add_followup.autocomplete("incident_id")
async def incident_autocomplete(
interaction: discord.Interaction,
current: str
) -> List[app_commands.Choice[str]]:
# Changed to get all incidents, not just current mod's
incidents = db.get_recent_incidents(25)
return [
app_commands.Choice(
name=f"{inc['id']} (by {await interaction.guild.fetch_member(inc['moderator_id'])})",
value=inc['id']
)
for inc in incidents if current.lower() in inc['id'].lower()
][:25]
choices = []
for inc in incidents:
try:
mod = await interaction.guild.fetch_member(inc['moderator_id'])
name = f"{inc['id']} (by {mod.display_name})"
except:
name = inc['id']
if current.lower() in name.lower():
choices.append(app_commands.Choice(name=name, value=inc['id']))
return choices[:25]
client.tree.add_command(moments_group)
client.tree.add_command(moments_group)

View File

@ -55,6 +55,17 @@ class Database:
FOREIGN KEY (incident_id) REFERENCES incidents(id)
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS incident_followups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
incident_id TEXT NOT NULL,
moderator_id INTEGER NOT NULL,
notes TEXT NOT NULL,
timestamp DATETIME NOT NULL,
FOREIGN KEY (incident_id) REFERENCES incidents(id)
)
""")
conn.commit()
def _get_connection(self):
@ -120,27 +131,25 @@ class Database:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# Get incident details
cursor.execute("""
SELECT * FROM incidents
WHERE id = ?
""", (incident_id,))
# Get incident details and parse timestamp
cursor.execute("SELECT * FROM incidents WHERE id = ?", (incident_id,))
incident = cursor.fetchone()
if not incident:
return None
# Get related messages
cursor.execute("""
SELECT * FROM incident_messages
WHERE incident_id = ?
ORDER BY timestamp ASC
""", (incident_id,))
messages = cursor.fetchall()
incident_details = dict(incident)
incident_details['timestamp'] = datetime.fromisoformat(incident_details['timestamp']) # Convert string to datetime
# Get messages with parsed timestamps
cursor.execute("SELECT * FROM incident_messages WHERE incident_id = ?", (incident_id,))
messages = [
{**dict(msg), 'timestamp': datetime.fromisoformat(msg['timestamp'])}
for msg in cursor.fetchall()
]
return {
"details": dict(incident),
"messages": [dict(msg) for msg in messages]
"details": incident_details,
"messages": messages
}
def get_recent_incidents(self, limit: int = 25):
@ -154,3 +163,29 @@ class Database:
LIMIT ?
""", (limit,))
return [dict(row) for row in cursor.fetchall()]
def add_followup(self, incident_id: str, moderator_id: int, notes: str) -> bool:
"""Add a follow-up report to an incident"""
try:
with self._get_connection() as conn:
conn.execute("""
INSERT INTO incident_followups
(incident_id, moderator_id, notes, timestamp)
VALUES (?, ?, ?, ?)
""", (incident_id, moderator_id, notes, datetime.now()))
conn.commit()
return True
except Exception as e:
logging.error(f"Failed to add followup: {str(e)}")
return False
def get_followups(self, incident_id: str) -> List[Dict]:
"""Get follow-ups with proper timestamps"""
with self._get_connection() as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("SELECT * FROM incident_followups WHERE incident_id = ?", (incident_id,))
return [
{**dict(row), 'timestamp': datetime.fromisoformat(row['timestamp'])}
for row in cursor.fetchall()
]