From 42c54ba6a07401747ce54d23186c7d33cfa6d40a Mon Sep 17 00:00:00 2001 From: jakubmanczak Date: Fri, 3 Apr 2026 12:33:06 +0200 Subject: [PATCH] logs database schema & method shifts --- src/database/migrations/2026-03-07--01.sql | 19 +++++---- src/logs.rs | 49 +++++++++++++++++----- src/web/pages/logs.rs | 2 +- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/database/migrations/2026-03-07--01.sql b/src/database/migrations/2026-03-07--01.sql index 5b87c0e..f8c584c 100644 --- a/src/database/migrations/2026-03-07--01.sql +++ b/src/database/migrations/2026-03-07--01.sql @@ -76,14 +76,17 @@ CREATE TABLE quote_tags ( ) WITHOUT ROWID; CREATE INDEX quote_tags_reverse_index ON quote_tags(tag_id, quote_id); --- CREATE TABLE logs ( --- id BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes --- actor BLOB NOT NULL REFERENCES users(id), -- UUIDv7 as bytes --- -- (userID with special cases: UUID::nil if system, UUID::max if infradmin) --- -- ((infradmin & system shall both be users)) --- target BLOB, -- Option --- change TEXT NOT NULL --- ); +CREATE TABLE logs ( + id BLOB NOT NULL UNIQUE PRIMARY KEY, -- UUIDv7 as bytes + actor BLOB NOT NULL REFERENCES users(id), -- UUIDv7 as bytes + -- (userID with special cases: UUID::nil if system, UUID::max if infradmin) + -- ((infradmin & system shall both be users)) + target BLOB, -- Option + actiontype TEXT NOT NULL, + payload TEXT +); +CREATE INDEX logs_by_actor ON logs(actor); +CREATE INDEX logs_by_target ON logs(target); -- all this to be followed by: -- - a better access scoping mechanism (role-based like discord) diff --git a/src/logs.rs b/src/logs.rs index e8a1b2c..864a9a9 100644 --- a/src/logs.rs +++ b/src/logs.rs @@ -1,16 +1,35 @@ use std::fmt::Display; +use serde::{Deserialize, Serialize}; +use strum::{AsRefStr, IntoStaticStr}; use uuid::Uuid; -use crate::users::User; +use crate::{database, users::User}; +#[derive(Debug)] pub struct LogEntry { pub id: Uuid, pub actor: User, pub data: LogAction, } -#[derive(Debug)] +impl LogEntry { + pub fn new(actor: User, data: LogAction) -> Result { + let log = LogEntry { + id: Uuid::now_v7(), + actor, + data, + }; + let conn = database::conn()?; + conn.prepare( + "INSERT INTO logs(id, actor, target, actiontype, payload) VALUES (?1,?2,?3,?4,?5)", + )? + .execute((&log.id, &log.actor.id, log.data.get_target_id(), "a", "b"))?; + Ok(log) + } +} + +#[derive(Debug, IntoStaticStr, Serialize, Deserialize)] pub enum LogAction { Initialize, RegenInfradmin, @@ -19,23 +38,31 @@ pub enum LogAction { CreatePerson { id: Uuid, pname: String }, ChangeUserHandle { id: Uuid, old: String, new: String }, } - -impl Display for LogAction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl LogAction { + pub fn get_target_id(&self) -> Option { match self { - LogAction::Initialize => write!(f, "Initialized Mnemosyne."), - LogAction::RegenInfradmin => write!(f, "Regenerated the Infradmin account."), + Self::Initialize | Self::RegenInfradmin => None, + Self::CreateUser { id, .. } => Some(*id), + Self::CreateTag { id, .. } => Some(*id), + Self::CreatePerson { id, .. } => Some(*id), + Self::ChangeUserHandle { id, .. } => Some(*id), + } + } + pub fn get_humanreadable_payload(&self) -> String { + match self { + LogAction::Initialize => format!("Initialized Mnemosyne."), + LogAction::RegenInfradmin => format!("Regenerated the Infradmin account."), LogAction::CreateUser { id, handle } => { - write!(f, "Created user @{handle} (uid: {id})") + format!("Created user @{handle} (uid: {id})") } LogAction::CreateTag { id, name } => { - write!(f, "Created tag #{name} (id: {id})") + format!("Created tag #{name} (id: {id})") } LogAction::CreatePerson { id, pname } => { - write!(f, "Created person ~{pname} (id: {id})") + format!("Created person ~{pname} (id: {id})") } LogAction::ChangeUserHandle { id, old, new } => { - write!(f, "Changed user handle @{old} -> @{new} (uid: {id})") + format!("Changed user handle @{old} -> @{new} (uid: {id})") } } } diff --git a/src/web/pages/logs.rs b/src/web/pages/logs.rs index 8497d77..f0aec8f 100644 --- a/src/web/pages/logs.rs +++ b/src/web/pages/logs.rs @@ -67,7 +67,7 @@ pub async fn page(req: Request) -> Result { .unwrap_or_else(|| "no timestamp".to_string())) } div class="p-2 font-light" style=(s) {(log.actor.handle)} - div class="p-2 font-light" style=(s) {(log.data)} + div class="p-2 font-light" style=(s) {(log.data.get_humanreadable_payload())} } @if true { div class="p-2 col-span-3 text-center font-light text-neutral-400" {"You've reached the end of all logs."}