add audit logs channel

This commit is contained in:
rambros 2026-02-23 14:13:08 +05:30
parent 17d9094084
commit 1a17fad4a9
4 changed files with 86 additions and 1 deletions

57
src/core/audit.py Normal file
View 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}")

View file

@ -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", [])

View file

@ -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)

View file

@ -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]")