add audit logs channel
This commit is contained in:
parent
17d9094084
commit
1a17fad4a9
4 changed files with 86 additions and 1 deletions
57
src/core/audit.py
Normal file
57
src/core/audit.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import logging
|
||||
from src.core.base import MigrationContext
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def log_audit_event(context: MigrationContext, title: str, description: str) -> None:
|
||||
"""
|
||||
Logs an event by sending a summary to the `#fluxer-reaper` audit channel.
|
||||
If the channel does not exist, it will dynamically create it and hide it from @everyone.
|
||||
"""
|
||||
# 1. Initialize channel if not tracked
|
||||
if not context.state.audit_log_channel:
|
||||
logger.info("Audit log channel not found in state. Checking Fluxer community...")
|
||||
try:
|
||||
# Check if it already exists in the community but isn't in state
|
||||
channels = await context.fluxer_writer.get_channels()
|
||||
channel_id = None
|
||||
|
||||
for ch in channels:
|
||||
name = str(ch.get("name", "")).lower()
|
||||
if name in ["fluxer-reaper", "fluxer_reaper"]:
|
||||
channel_id = str(ch.get("id"))
|
||||
logger.info(f"Found existing audit channel: {channel_id}")
|
||||
break
|
||||
|
||||
if not channel_id:
|
||||
logger.info("Audit log channel not found. Creating #fluxer-reaper.")
|
||||
# Create channel
|
||||
channel_id = await context.fluxer_writer.create_channel(
|
||||
name="fluxer-reaper",
|
||||
topic="Fluxer Reaper - Migration audit logs.",
|
||||
type=0
|
||||
)
|
||||
|
||||
# Immediately lock down 'View Channel' (1024) for @everyone (community_id)
|
||||
await context.fluxer_writer.set_channel_permission(
|
||||
channel_id=channel_id,
|
||||
overwrite_id=context.config.fluxer_community_id, # @everyone matches community ID
|
||||
allow=0,
|
||||
deny=1024,
|
||||
is_role=True
|
||||
)
|
||||
|
||||
# Save permanently
|
||||
context.state.audit_log_channel = channel_id
|
||||
context.state.save_state()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to setup audit log channel: {e}")
|
||||
return
|
||||
|
||||
# 2. Format and send the message natively through FluxerBot (avoiding impersonation webhook for admin logs)
|
||||
content = f"**[{title}]**\n{description}"
|
||||
try:
|
||||
await context.fluxer_writer.send_marker(context.state.audit_log_channel, content)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send audit log event: {e}")
|
||||
|
|
@ -435,6 +435,12 @@ class FluxerWriter:
|
|||
# Delete non-category channels first, then categories
|
||||
sorted_channels = sorted(channels, key=lambda c: 0 if c.get("type") == 4 else -1)
|
||||
for ch in sorted_channels:
|
||||
name = str(ch.get("name", "")).lower()
|
||||
if name in ["fluxer-reaper", "fluxer_reaper"]:
|
||||
logger.info(f"Danger Zone: Skipping deletion of audit channel {name}")
|
||||
total -= 1
|
||||
continue
|
||||
|
||||
try:
|
||||
await self.client.delete_channel(ch["id"])
|
||||
deleted += 1
|
||||
|
|
@ -454,6 +460,12 @@ class FluxerWriter:
|
|||
total = len(channels)
|
||||
processed = 0
|
||||
for ch in channels:
|
||||
name = str(ch.get("name", "")).lower()
|
||||
if name in ["fluxer-reaper", "fluxer_reaper"]:
|
||||
logger.info(f"Danger Zone: Skipping permission reset for audit channel {name}")
|
||||
total -= 1
|
||||
continue
|
||||
|
||||
try:
|
||||
# Fetch existing overwrites and delete each one
|
||||
overwrites = ch.get("permission_overwrites", [])
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ class MigrationState:
|
|||
self.emoji_map: Dict[str, str] = {}
|
||||
self.sticker_map: Dict[str, str] = {}
|
||||
|
||||
# audit log tracking
|
||||
self.audit_log_channel: str | None = None
|
||||
|
||||
# message tracking
|
||||
self.message_map: Dict[str, str] = {}
|
||||
self.last_message_timestamps: Dict[str, str] = {}
|
||||
|
|
@ -35,6 +38,7 @@ class MigrationState:
|
|||
self.role_map = data.get("roles", {})
|
||||
self.emoji_map = data.get("emojis", {})
|
||||
self.sticker_map = data.get("stickers", {})
|
||||
self.audit_log_channel = data.get("audit_log_channel")
|
||||
|
||||
# Check for legacy messages in state.json
|
||||
if "messages" in data or "last_message_timestamps" in data:
|
||||
|
|
@ -79,7 +83,8 @@ class MigrationState:
|
|||
"categories": self.category_map,
|
||||
"roles": self.role_map,
|
||||
"emojis": self.emoji_map,
|
||||
"stickers": self.sticker_map
|
||||
"stickers": self.sticker_map,
|
||||
"audit_log_channel": self.audit_log_channel
|
||||
}
|
||||
with open(self.state_file, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from src.core.emoji_stickers import sync_assets_state, migrate_emojis
|
|||
from src.core.server_metadata import sync_server_metadata
|
||||
from src.core.migrate_message import analyze_migration, migrate_messages
|
||||
from src.core.danger_zone import danger_remove_logo_and_banner, danger_delete_all_channels, danger_reset_channel_permissions, danger_delete_all_roles, danger_delete_all_emojis_and_stickers
|
||||
from src.core.audit import log_audit_event
|
||||
|
||||
class RateLimitHandler(logging.Handler):
|
||||
"""Intersects library logs to print clean rate limit messages."""
|
||||
|
|
@ -417,6 +418,7 @@ class MigrationCLI:
|
|||
await migrate_channels(self.engine, progress_callback=update_progress, force=force)
|
||||
|
||||
console.print("[bold green]Server Template cloned![/bold green]")
|
||||
await log_audit_event(self.engine, "Server Template Cloned", "Successfully cloned channels and categories from Discord.")
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error during channel clone: {str(e)}[/bold red]")
|
||||
|
|
@ -501,6 +503,7 @@ class MigrationCLI:
|
|||
await migrate_roles(self.engine, progress_callback=update_progress, force=force)
|
||||
|
||||
console.print("[bold green]Role migration complete![/bold green]")
|
||||
await log_audit_event(self.engine, "Roles Cloned", "Successfully cloned roles and baseline role permissions from Discord.")
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error during role migration: {str(e)}[/bold red]")
|
||||
|
|
@ -547,6 +550,7 @@ class MigrationCLI:
|
|||
await sync_permissions(self.engine, progress_callback=update_progress)
|
||||
|
||||
console.print("[bold green]Permission synchronization complete![/bold green]")
|
||||
await log_audit_event(self.engine, "Permissions Synced", "Successfully synchronized channel and category permission overrides.")
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error during permission sync: {str(e)}[/bold red]")
|
||||
|
|
@ -656,6 +660,7 @@ class MigrationCLI:
|
|||
)
|
||||
|
||||
console.print("[bold green]Migration complete![/bold green]")
|
||||
await log_audit_event(self.engine, "Emojis & Stickers Cloned", "Successfully synchronized emojis and stickers from Discord.")
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error during emoji migration: {str(e)}[/bold red]")
|
||||
|
|
@ -715,6 +720,7 @@ class MigrationCLI:
|
|||
|
||||
await sync_server_metadata(self.engine, progress_callback, components=components)
|
||||
console.print("[bold green]Server metadata sync finished![/bold green]")
|
||||
await log_audit_event(self.engine, "Server Metadata Synced", "Successfully synchronized the community icon, banner, and name.")
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error during metadata sync: {str(e)}[/bold red]")
|
||||
finally:
|
||||
|
|
@ -962,6 +968,7 @@ class MigrationCLI:
|
|||
)
|
||||
|
||||
console.print(f"\n[bold green]Success! {count} messages migrated to {target_channel.get('name')}.[/bold green]")
|
||||
await log_audit_event(self.engine, "Message History Migrated", f"Successfully migrated {count} messages to #{target_channel.get('name')}.")
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Migration encountered an error: {str(e)}[/bold red]")
|
||||
|
|
@ -1020,6 +1027,7 @@ class MigrationCLI:
|
|||
|
||||
count = await danger_delete_all_channels(self.engine, progress_callback=on_channel_deleted)
|
||||
console.print(f"[bold green]{count} channels/categories deleted.[/bold green]")
|
||||
await log_audit_event(self.engine, "Danger Zone: Channels Wiped", f"Administrators deleted {count} channels and categories from the community.")
|
||||
console.print("[bold green]Done.[/bold green]")
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error: {e}[/bold red]")
|
||||
|
|
@ -1052,6 +1060,7 @@ class MigrationCLI:
|
|||
|
||||
count = await danger_reset_channel_permissions(self.engine, progress_callback=on_perm_reset)
|
||||
console.print(f"[bold green]Permissions reset on {count} channels/categories.[/bold green]")
|
||||
await log_audit_event(self.engine, "Danger Zone: Permissions Wiped", f"Administrators reset permissions on {count} channels and categories.")
|
||||
console.print("[bold green]Done.[/bold green]")
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error: {e}[/bold red]")
|
||||
|
|
@ -1085,6 +1094,7 @@ class MigrationCLI:
|
|||
|
||||
count = await danger_delete_all_roles(self.engine, progress_callback=on_role_deleted)
|
||||
console.print(f"[bold green]{count} roles deleted.[/bold green]")
|
||||
await log_audit_event(self.engine, "Danger Zone: Roles Wiped", f"Administrators deleted {count} roles from the community.")
|
||||
console.print("[bold green]Done.[/bold green]")
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error: {e}[/bold red]")
|
||||
|
|
@ -1118,6 +1128,7 @@ class MigrationCLI:
|
|||
counts = await danger_delete_all_emojis_and_stickers(self.engine, progress_callback=on_asset_deleted)
|
||||
console.print(f"[bold green]{counts.get('emojis', 0)} emojis deleted.[/bold green]")
|
||||
console.print(f"[bold green]{counts.get('stickers', 0)} stickers deleted.[/bold green]")
|
||||
await log_audit_event(self.engine, "Danger Zone: Assets Wiped", f"Administrators deleted {counts.get('emojis', 0)} emojis and {counts.get('stickers', 0)} stickers.")
|
||||
console.print("[bold green]Done.[/bold green]")
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error: {e}[/bold red]")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue