feat: admin audit logging across all admin actions

- AdminLogger: JSON-lines → /var/log/xamxam.log (prod) / storage/logs/admin.log (dev)
  + best-effort DB mirror to admin_audit_log table
- DB: admin_audit_log table, share_links.is_archived column
- ShareLink: archive() replaces delete(), toggleActive() returns new state,
  listActive()/listArchived() split, validateLink blocks archived slugs
- All action handlers wired: publish, unpublish, visibility, delete, csv/db export,
  tfe add/edit, tags, pages, apropos, form-help, access-request, maintenance,
  settings (formulaire toggles, objet types, smtp update), smtp-test
- acces.php: archive button replaces delete; collapsible archived links section
- setup-server.sh: provision /var/log/xamxam.log (www-data:xamxam 640)
This commit is contained in:
Pontoporeia
2026-05-04 17:34:26 +02:00
parent 5f24dcae7e
commit ca5983075d
24 changed files with 521 additions and 33 deletions

View File

@@ -337,6 +337,7 @@ CREATE TABLE IF NOT EXISTS share_links (
objet_restriction TEXT CHECK (objet_restriction IN ('tfe', 'thèse', 'frart')), -- NULL = no restriction
password_hash TEXT, -- bcrypt hash; NULL = no password required
is_active INTEGER NOT NULL DEFAULT 1, -- 1 = active, 0 = disabled
is_archived INTEGER NOT NULL DEFAULT 0, -- 1 = archived (link inaccessible, stats preserved)
usage_count INTEGER NOT NULL DEFAULT 0, -- Number of successful submissions via this link
created_by INTEGER NOT NULL, -- admin user ID
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
@@ -345,6 +346,29 @@ CREATE TABLE IF NOT EXISTS share_links (
CREATE INDEX IF NOT EXISTS idx_share_links_slug ON share_links(slug);
CREATE INDEX IF NOT EXISTS idx_share_links_active ON share_links(is_active);
CREATE INDEX IF NOT EXISTS idx_share_links_archived ON share_links(is_archived);
-- ============================================================================
-- ADMIN AUDIT LOG
-- ============================================================================
-- Mirrors every admin action logged to /var/log/xamxam.log.
-- Best-effort: application never fails if this table is absent.
-- ============================================================================
CREATE TABLE IF NOT EXISTS admin_audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
ip TEXT NOT NULL,
user_agent TEXT,
resource TEXT NOT NULL, -- e.g. thesis, tag, share_link, settings, system
action TEXT NOT NULL, -- e.g. publish, delete, smtp_update
status TEXT NOT NULL, -- success | error
context TEXT -- JSON blob with extra fields
);
CREATE INDEX IF NOT EXISTS idx_admin_audit_log_created_at ON admin_audit_log(created_at);
CREATE INDEX IF NOT EXISTS idx_admin_audit_log_resource ON admin_audit_log(resource);
CREATE INDEX IF NOT EXISTS idx_admin_audit_log_action ON admin_audit_log(action);
-- ============================================================================
-- SMTP SETTINGS