more-activities #1035
@ -17,10 +17,31 @@ pub struct Activity {
|
|||||||
pub keep_until: Option<NaiveDateTime>,
|
pub keep_until: Option<NaiveDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ActivityWithDetails {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub(crate) activity: Activity,
|
||||||
|
keep_until_days: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Activity> for ActivityWithDetails {
|
||||||
|
fn from(activity: Activity) -> Self {
|
||||||
|
let keep_until_days = activity.keep_until.map(|keep_until| {
|
||||||
|
let now = Utc::now().naive_utc();
|
||||||
|
let duration = keep_until.signed_duration_since(now);
|
||||||
|
duration.num_days()
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
keep_until_days,
|
||||||
|
activity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: add `reason` as additional db field, to be able to query and show this to the users
|
// TODO: add `reason` as additional db field, to be able to query and show this to the users
|
||||||
pub enum Reason<'a> {
|
pub enum Reason<'a> {
|
||||||
// `User` tried to login with `String` as UserAgent
|
Auth(ReasonAuth<'a>),
|
||||||
SuccLogin(&'a User, String),
|
|
||||||
// `User` changed the data of `User`, explanation in `String`
|
// `User` changed the data of `User`, explanation in `String`
|
||||||
UserDataChange(&'a ManageUserUser, &'a User, String),
|
UserDataChange(&'a ManageUserUser, &'a User, String),
|
||||||
// New Note for User
|
// New Note for User
|
||||||
@ -30,11 +51,7 @@ pub enum Reason<'a> {
|
|||||||
impl From<Reason<'_>> for ActivityBuilder {
|
impl From<Reason<'_>> for ActivityBuilder {
|
||||||
fn from(value: Reason<'_>) -> Self {
|
fn from(value: Reason<'_>) -> Self {
|
||||||
match value {
|
match value {
|
||||||
Reason::SuccLogin(user, agent) => {
|
Reason::Auth(auth) => auth.into(),
|
||||||
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!(
|
Reason::UserDataChange(changed_by, changed_user, explanation) => Self::new(&format!(
|
||||||
"{changed_by} hat die Daten von {changed_user} aktualisiert: {explanation}"
|
"{changed_by} hat die Daten von {changed_user} aktualisiert: {explanation}"
|
||||||
))
|
))
|
||||||
@ -46,6 +63,43 @@ impl From<Reason<'_>> for ActivityBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ReasonAuth<'a> {
|
||||||
|
// `User` tried to login with `String` as UserAgent
|
||||||
|
SuccLogin(&'a User, String),
|
||||||
|
// `User` tried to login which was already deleted
|
||||||
|
DeletedUserLogin(&'a User),
|
||||||
|
// `User` tried to login, supplied wrong PW
|
||||||
|
WrongPw(&'a User),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<ReasonAuth<'a>> for Reason<'a> {
|
||||||
|
fn from(auth_reason: ReasonAuth<'a>) -> Self {
|
||||||
|
Reason::Auth(auth_reason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReasonAuth<'_>> for ActivityBuilder {
|
||||||
|
fn from(value: ReasonAuth<'_>) -> Self {
|
||||||
|
match value {
|
||||||
|
ReasonAuth::SuccLogin(user, agent) => {
|
||||||
|
Self::new(&format!("{user} hat sich eingeloggt (User-Agent: {agent})"))
|
||||||
|
.relevant_for_user(user)
|
||||||
|
.keep_until_days(7)
|
||||||
|
}
|
||||||
|
ReasonAuth::DeletedUserLogin(user) => Self::new(&format!(
|
||||||
|
"User {user} wollte sich einloggen, klappte jedoch nicht weil er gelöscht wurde."
|
||||||
|
))
|
||||||
|
.relevant_for_user(user)
|
||||||
|
.keep_until_days(30),
|
||||||
|
ReasonAuth::WrongPw(user) => Self::new(&format!(
|
||||||
|
"User {user} wollte sich einloggen, hat jedoch das falsche Passwort angegeben."
|
||||||
|
))
|
||||||
|
.relevant_for_user(user)
|
||||||
|
.keep_until_days(7),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ActivityBuilder {
|
pub struct ActivityBuilder {
|
||||||
text: String,
|
text: String,
|
||||||
relevant_for: String,
|
relevant_for: String,
|
||||||
|
@ -13,7 +13,7 @@ use rocket::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
use super::activity::ActivityBuilder;
|
use super::activity::{ActivityBuilder, ReasonAuth};
|
||||||
use super::{
|
use super::{
|
||||||
log::Log,
|
log::Log,
|
||||||
logbook::Logbook,
|
logbook::Logbook,
|
||||||
@ -465,49 +465,25 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
pub async fn login(db: &SqlitePool, name: &str, pw: &str) -> Result<Self, LoginError> {
|
pub async fn login(db: &SqlitePool, name: &str, pw: &str) -> Result<Self, LoginError> {
|
||||||
let name = name.trim().to_lowercase(); // just to make sure...
|
let name = name.trim().to_lowercase(); // just to make sure...
|
||||||
let Some(user) = User::find_by_name(db, &name).await else {
|
let Some(user) = User::find_by_name(db, &name).await else {
|
||||||
if ![
|
|
||||||
"n-sageder",
|
|
||||||
"p-hofer",
|
|
||||||
"marie-birner",
|
|
||||||
"daniel-kortschak",
|
|
||||||
"rudernlinz",
|
|
||||||
"m-birner",
|
|
||||||
"s-sollberger",
|
|
||||||
"d-kortschak",
|
|
||||||
"wwwadmin",
|
|
||||||
"wadminw",
|
|
||||||
"admin",
|
|
||||||
"m sageder",
|
|
||||||
"d kortschak",
|
|
||||||
"a almousa",
|
|
||||||
"p hofer",
|
|
||||||
"s sollberger",
|
|
||||||
"n sageder",
|
|
||||||
"wp-system",
|
|
||||||
"s.sollberger",
|
|
||||||
"m.birner",
|
|
||||||
"m-sageder",
|
|
||||||
"a-almousa",
|
|
||||||
"m.sageder",
|
|
||||||
"n.sageder",
|
|
||||||
"a.almousa",
|
|
||||||
"p.hofer",
|
|
||||||
"philipp-hofer",
|
|
||||||
"d.kortschak",
|
|
||||||
"[login]",
|
|
||||||
]
|
|
||||||
.contains(&name.as_str())
|
|
||||||
{
|
|
||||||
Log::create(db, format!("Username ({name}) not found (tried to login)")).await;
|
Log::create(db, format!("Username ({name}) not found (tried to login)")).await;
|
||||||
}
|
|
||||||
return Err(LoginError::InvalidAuthenticationCombo); // Username not found
|
return Err(LoginError::InvalidAuthenticationCombo); // Username not found
|
||||||
};
|
};
|
||||||
|
|
||||||
if user.deleted {
|
if user.deleted {
|
||||||
ActivityBuilder::new(&format!(
|
if let Some(board) = Role::find_by_name(db, "Vorstand").await {
|
||||||
|
Notification::create_for_role(
|
||||||
|
db,
|
||||||
|
&board,
|
||||||
|
&format!(
|
||||||
"User {user} wollte sich einloggen, klappte jedoch nicht weil er gelöscht wurde."
|
"User {user} wollte sich einloggen, klappte jedoch nicht weil er gelöscht wurde."
|
||||||
))
|
),
|
||||||
.relevant_for_user(&user)
|
"Fehlgeschlagener Login",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActivityBuilder::from(ReasonAuth::DeletedUserLogin(&user))
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
return Err(LoginError::InvalidAuthenticationCombo); //User existed sometime ago; has
|
return Err(LoginError::InvalidAuthenticationCombo); //User existed sometime ago; has
|
||||||
@ -519,10 +495,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
if password_hash == user_pw {
|
if password_hash == user_pw {
|
||||||
return Ok(user);
|
return Ok(user);
|
||||||
}
|
}
|
||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::from(ReasonAuth::WrongPw(&user))
|
||||||
"User {user} wollte sich einloggen, hat jedoch das falsche Passwort angegeben."
|
|
||||||
))
|
|
||||||
.relevant_for_user(&user)
|
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
Err(LoginError::InvalidAuthenticationCombo)
|
Err(LoginError::InvalidAuthenticationCombo)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
model::{
|
model::{
|
||||||
activity::Activity,
|
activity::{Activity, ActivityWithDetails},
|
||||||
family::Family,
|
family::Family,
|
||||||
log::Log,
|
log::Log,
|
||||||
logbook::Logbook,
|
logbook::Logbook,
|
||||||
@ -141,7 +141,11 @@ async fn view(
|
|||||||
|
|
||||||
let member = Member::from(db, user.clone()).await;
|
let member = Member::from(db, user.clone()).await;
|
||||||
let fee = user.fee(db).await;
|
let fee = user.fee(db).await;
|
||||||
let activities = Activity::for_user(db, &user).await;
|
let activities: Vec<ActivityWithDetails> = Activity::for_user(db, &user)
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect();
|
||||||
let financial = Role::all_cluster(db, "financial").await;
|
let financial = Role::all_cluster(db, "financial").await;
|
||||||
let user_financial = user.financial(db).await;
|
let user_financial = user.financial(db).await;
|
||||||
let skill = Role::all_cluster(db, "skill").await;
|
let skill = Role::all_cluster(db, "skill").await;
|
||||||
|
@ -14,7 +14,7 @@ use rocket_dyn_templates::{context, tera, Template};
|
|||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
activity::{self, ActivityBuilder},
|
activity::{self, ActivityBuilder, ReasonAuth},
|
||||||
log::Log,
|
log::Log,
|
||||||
user::{LoginError, User},
|
user::{LoginError, User},
|
||||||
};
|
};
|
||||||
@ -83,7 +83,7 @@ async fn login(
|
|||||||
|
|
||||||
cookies.add_private(Cookie::new("loggedin_user", format!("{}", user.id)));
|
cookies.add_private(Cookie::new("loggedin_user", format!("{}", user.id)));
|
||||||
|
|
||||||
ActivityBuilder::from(activity::Reason::SuccLogin(&user, agent.0))
|
ActivityBuilder::from(ReasonAuth::SuccLogin(&user, agent.0))
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -411,7 +411,11 @@
|
|||||||
<ul class="list-disc ms-4">
|
<ul class="list-disc ms-4">
|
||||||
{% for activity in activities %}
|
{% for activity in activities %}
|
||||||
<li>
|
<li>
|
||||||
<strong>{{ activity.created_at | date(format="%d. %m. %Y") }}:</strong> <small>{{ activity.text }}</small>
|
<strong>{{ activity.created_at | date(format="%d. %m. %Y") }}:</strong> <small>{{ activity.text }}
|
||||||
|
{% if activity.keep_until_days %}
|
||||||
|
(⏳ {{ activity.keep_until_days }} Tage)
|
||||||
|
{% endif %}
|
||||||
|
</small>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>Noch keine Aktivität... Stay tuned 😆</li>
|
<li>Noch keine Aktivität... Stay tuned 😆</li>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user