diff --git a/src/model/activity.rs b/src/model/activity.rs index 2f49e4d..a2f0759 100644 --- a/src/model/activity.rs +++ b/src/model/activity.rs @@ -1,6 +1,9 @@ use std::ops::DerefMut; -use super::{role::Role, user::User}; +use super::{ + role::Role, + user::{ManageUserUser, User}, +}; use chrono::{DateTime, Duration, Local, NaiveDateTime, TimeZone, Utc}; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; @@ -14,6 +17,29 @@ pub struct Activity { pub keep_until: Option, } +pub enum Reason<'a> { + // `User` tried to login with `String` as UserAgent + SuccLogin(&'a User, String), + // `User` changed the data of `User`, explanation in `String` + UserDataChange(&'a ManageUserUser, &'a User, String), +} + +impl From> for ActivityBuilder { + fn from(value: Reason<'_>) -> Self { + match value { + Reason::SuccLogin(user, agent) => { + Self::new(&format!("{user} hat sich eingeloggt (User-Agent: {agent})")) + .relevant_for_user(user) + .keep_until_days(7) + } + Reason::UserDataChange(changed_by, changed_user, explanation) => Self::new(&format!( + "{changed_by} hat die Daten von {changed_user} aktualisiert: {explanation}" + )) + .relevant_for_user(changed_user), + } + } +} + pub struct ActivityBuilder { text: String, relevant_for: String, @@ -21,6 +47,7 @@ pub struct ActivityBuilder { } impl ActivityBuilder { + /// TODO: maybe make this private, and only allow specific acitivites defined in `Reason` #[must_use] pub fn new(text: &str) -> Self { Self { diff --git a/src/model/user/basic.rs b/src/model/user/basic.rs index 9878d7d..fb9eaad 100644 --- a/src/model/user/basic.rs +++ b/src/model/user/basic.rs @@ -2,7 +2,10 @@ use super::{AllowedToEditPaymentStatusUser, ManageUserUser, User}; use crate::model::{ - activity::ActivityBuilder, family::Family, mail::valid_mails, notification::Notification, + activity::{self, ActivityBuilder}, + family::Family, + mail::valid_mails, + notification::Notification, role::Role, }; use chrono::NaiveDate; @@ -19,10 +22,13 @@ impl User { ) -> Result<(), String> { let note = note.trim(); - ActivityBuilder::new(&format!("({updated_by}) {note}")) - .relevant_for_user(user) - .save(db) - .await; + ActivityBuilder::from(activity::Reason::UserDataChange( + updated_by, + self, + format!("Neue Notizen: {note}"), + )) + .save(db) + .await; Ok(()) } @@ -47,18 +53,11 @@ impl User { .unwrap(); //Okay, because we can only create a User of a valid id let msg = match &self.mail { - Some(old_mail) => { - format!( - "{updated_by} hat die Mail-Adresse von {self} von {old_mail} auf {new_mail} geändert." - ) - } - None => { - format!("{updated_by} eine neue Mail-Adresse für {self} hinzugefügt: {new_mail}") - } + Some(old_mail) => format!("Mail-Adresse von {old_mail} auf {new_mail} geändert."), + None => format!("Neue Mail-Adresse für: {new_mail}"), }; - ActivityBuilder::new(&msg) - .relevant_for_user(self) + ActivityBuilder::from(activity::Reason::UserDataChange(updated_by, self, msg)) .save(db) .await; @@ -89,19 +88,16 @@ impl User { query.execute(db).await.unwrap(); //Okay, because we can only create a User of a valid id let msg = match &self.phone { - Some(old_phone) if new_phone.is_empty() => format!( - "{updated_by} hat die Telefonnummer von {self} entfernt (alte Nummer: {old_phone})" - ), - Some(old_phone) => format!( - "{updated_by} hat die Telefonnummer von {self} von {old_phone} auf {new_phone} geändert." - ), - None => format!( - "{updated_by} hat eine neue Telefonnummer für {self} hinzugefügt: {new_phone}" - ), + Some(old_phone) if new_phone.is_empty() => { + format!("Telefonnummer wurde entfernt (alte Nummer: {old_phone})") + } + Some(old_phone) => { + format!("Telefonnummer wurde von {old_phone} auf {new_phone} geändert.") + } + None => format!("Neue Telefonnummer hinzugefügt: {new_phone}"), }; - ActivityBuilder::new(&msg) - .relevant_for_user(self) + ActivityBuilder::from(activity::Reason::UserDataChange(updated_by, self, msg)) .save(db) .await; } diff --git a/src/tera/auth.rs b/src/tera/auth.rs index 9440942..425ce22 100644 --- a/src/tera/auth.rs +++ b/src/tera/auth.rs @@ -1,5 +1,4 @@ use rocket::{ - FromForm, Request, Route, State, form::Form, get, http::{Cookie, CookieJar}, @@ -9,12 +8,13 @@ use rocket::{ response::{Flash, Redirect}, routes, time::{Duration, OffsetDateTime}, + FromForm, Request, Route, State, }; -use rocket_dyn_templates::{Template, context, tera}; +use rocket_dyn_templates::{context, tera, Template}; use sqlx::SqlitePool; use crate::model::{ - activity::ActivityBuilder, + activity::{self, ActivityBuilder}, log::Log, user::{LoginError, User}, }; @@ -83,13 +83,9 @@ async fn login( cookies.add_private(Cookie::new("loggedin_user", format!("{}", user.id))); - ActivityBuilder::new(&format!( - "{user} hat sich eingeloggt (User-Agent: {})", - agent.0 - )) - .relevant_for_user(&user) - .save(db) - .await; + ActivityBuilder::from(activity::Reason::SuccLogin(&user, agent.0)) + .save(db) + .await; // Check for redirect_url cookie and redirect accordingly match cookies.get_private("redirect_url") {