board members can delete trips, proper notification + succ message is created #1047
@ -1,6 +1,7 @@
|
|||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
logbook::{Logbook, LogbookWithBoatAndRowers},
|
||||||
role::Role,
|
role::Role,
|
||||||
user::{ManageUserUser, User},
|
user::{ManageUserUser, User},
|
||||||
};
|
};
|
||||||
@ -42,6 +43,7 @@ impl From<Activity> for ActivityWithDetails {
|
|||||||
// 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> {
|
||||||
Auth(ReasonAuth<'a>),
|
Auth(ReasonAuth<'a>),
|
||||||
|
Logbook(ReasonLogbook<'a>),
|
||||||
// `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
|
||||||
@ -55,10 +57,11 @@ impl From<Reason<'_>> for ActivityBuilder {
|
|||||||
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}"
|
||||||
))
|
))
|
||||||
.relevant_for_user(changed_user),
|
.user(changed_user),
|
||||||
Reason::NewUserNote(changed_by, user, explanation) => {
|
Reason::NewUserNote(changed_by, user, explanation) => {
|
||||||
Self::new(&format!("({changed_by}) {explanation}")).relevant_for_user(user)
|
Self::new(&format!("({changed_by}) {explanation}")).user(user)
|
||||||
}
|
}
|
||||||
|
Reason::Logbook(logbook) => logbook.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,18 +86,42 @@ impl From<ReasonAuth<'_>> for ActivityBuilder {
|
|||||||
match value {
|
match value {
|
||||||
ReasonAuth::SuccLogin(user, agent) => {
|
ReasonAuth::SuccLogin(user, agent) => {
|
||||||
Self::new(&format!("{user} hat sich eingeloggt (User-Agent: {agent})"))
|
Self::new(&format!("{user} hat sich eingeloggt (User-Agent: {agent})"))
|
||||||
.relevant_for_user(user)
|
.user(user)
|
||||||
.keep_until_days(7)
|
.keep_until_days(7)
|
||||||
}
|
}
|
||||||
ReasonAuth::DeletedUserLogin(user) => Self::new(&format!(
|
ReasonAuth::DeletedUserLogin(user) => Self::new(&format!(
|
||||||
"{user} wollte sich einloggen, klappte jedoch nicht weil der Account gelöscht wurde."
|
"{user} wollte sich einloggen, klappte jedoch nicht weil der Account gelöscht wurde."
|
||||||
))
|
))
|
||||||
.relevant_for_user(user)
|
.user(user)
|
||||||
.keep_until_days(30),
|
.keep_until_days(30),
|
||||||
ReasonAuth::WrongPw(user) => Self::new(&format!(
|
ReasonAuth::WrongPw(user) => Self::new(&format!(
|
||||||
"User {user} wollte sich einloggen, hat jedoch das falsche Passwort angegeben."
|
"User {user} wollte sich einloggen, hat jedoch das falsche Passwort angegeben."
|
||||||
))
|
))
|
||||||
.relevant_for_user(user)
|
.user(user)
|
||||||
|
.keep_until_days(7),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ReasonLogbook<'a> {
|
||||||
|
// `User` tried to login with `String` as UserAgent
|
||||||
|
BoardOrAdminDeleted(&'a User, &'a LogbookWithBoatAndRowers),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<ReasonLogbook<'a>> for Reason<'a> {
|
||||||
|
fn from(logbook_reason: ReasonLogbook<'a>) -> Self {
|
||||||
|
Reason::Logbook(logbook_reason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReasonLogbook<'_>> for ActivityBuilder {
|
||||||
|
fn from(value: ReasonLogbook<'_>) -> Self {
|
||||||
|
match value {
|
||||||
|
ReasonLogbook::BoardOrAdminDeleted(user, logbook) => Self::new(&format!(
|
||||||
|
"{user} hat den Logbuch-Eintrag gelöscht: {logbook}"
|
||||||
|
))
|
||||||
|
.user(user)
|
||||||
|
.logbook(&logbook.logbook)
|
||||||
.keep_until_days(7),
|
.keep_until_days(7),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +145,7 @@ impl ActivityBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn relevant_for_user(self, user: &User) -> Self {
|
pub fn user(self, user: &User) -> Self {
|
||||||
Self {
|
Self {
|
||||||
relevant_for: format!("{}user-{};", self.relevant_for, user.id),
|
relevant_for: format!("{}user-{};", self.relevant_for, user.id),
|
||||||
..self
|
..self
|
||||||
@ -126,13 +153,21 @@ impl ActivityBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn relevant_for_role(self, role: &Role) -> Self {
|
pub fn role(self, role: &Role) -> Self {
|
||||||
Self {
|
Self {
|
||||||
relevant_for: format!("{}role-{};", self.relevant_for, role.id),
|
relevant_for: format!("{}role-{};", self.relevant_for, role.id),
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn logbook(self, logbook: &Logbook) -> Self {
|
||||||
|
Self {
|
||||||
|
relevant_for: format!("{}logbook-{};", self.relevant_for, logbook.id),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn keep_until_days(self, days: i64) -> Self {
|
pub fn keep_until_days(self, days: i64) -> Self {
|
||||||
let now = Utc::now().naive_utc();
|
let now = Utc::now().naive_utc();
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use rocket::FromForm;
|
|
||||||
use rocket::serde::{Deserialize, Serialize};
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
use rocket::FromForm;
|
||||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
use crate::model::boathouse::Boathouse;
|
use crate::model::boathouse::Boathouse;
|
||||||
|
|
||||||
use super::location::Location;
|
use super::location::Location;
|
||||||
use super::user::User;
|
use super::user::User;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(FromRow, Debug, Serialize, Deserialize, Eq, Hash, PartialEq, Clone)]
|
#[derive(FromRow, Debug, Serialize, Deserialize, Eq, Hash, PartialEq, Clone)]
|
||||||
pub struct Boat {
|
pub struct Boat {
|
||||||
@ -31,6 +32,17 @@ pub struct Boat {
|
|||||||
pub deleted: bool,
|
pub deleted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Boat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let private_or_club_boat = if self.owner.is_some() {
|
||||||
|
"privat"
|
||||||
|
} else {
|
||||||
|
"Vereinsboot"
|
||||||
|
};
|
||||||
|
write!(f, "{} ({}, {private_or_club_boat})", self.name, self.cat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum BoatDamage {
|
pub enum BoatDamage {
|
||||||
@ -178,8 +190,10 @@ AND date('now') BETWEEN start_date AND end_date;",
|
|||||||
"Vereinsfremde Boote".to_string()
|
"Vereinsfremde Boote".to_string()
|
||||||
} else if self.default_shipmaster_only_steering {
|
} else if self.default_shipmaster_only_steering {
|
||||||
format!("{}+", self.amount_seats - 1)
|
format!("{}+", self.amount_seats - 1)
|
||||||
} else {
|
} else if self.skull {
|
||||||
format!("{}x", self.amount_seats)
|
format!("{}x", self.amount_seats)
|
||||||
|
} else {
|
||||||
|
format!("{}-", self.amount_seats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::ops::DerefMut;
|
use std::{fmt::Display, ops::DerefMut};
|
||||||
|
|
||||||
use chrono::{Datelike, Duration, Local, NaiveDateTime};
|
use chrono::{Datelike, Duration, Local, NaiveDateTime};
|
||||||
use rocket::FromForm;
|
use rocket::FromForm;
|
||||||
@ -6,8 +6,15 @@ use serde::{Deserialize, Serialize};
|
|||||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
boat::Boat, log::Log, notification::Notification, role::Role, rower::Rower, user::User,
|
activity::{ActivityBuilder, ReasonLogbook},
|
||||||
|
boat::Boat,
|
||||||
|
log::Log,
|
||||||
|
notification::Notification,
|
||||||
|
role::Role,
|
||||||
|
rower::Rower,
|
||||||
|
user::User,
|
||||||
};
|
};
|
||||||
|
use crate::model::user::VecUser;
|
||||||
|
|
||||||
#[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
|
#[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Logbook {
|
pub struct Logbook {
|
||||||
@ -115,6 +122,54 @@ pub struct LogbookWithBoatAndRowers {
|
|||||||
pub rowers: Vec<User>,
|
pub rowers: Vec<User>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for LogbookWithBoatAndRowers {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if let Some(arrival) = self.logbook.arrival {
|
||||||
|
let departure_date = format!("{}", self.logbook.departure.format("%Y-%m-%d"));
|
||||||
|
let arrival_date = format!("{}", arrival.format("%Y-%m-%d"));
|
||||||
|
if departure_date == arrival_date {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Datum: {}: Start: {}, Ende: {}; ",
|
||||||
|
&self.logbook.departure.format("%d. %m. %Y"),
|
||||||
|
&self.logbook.departure.format("%H:%M"),
|
||||||
|
&arrival.format("%H:%M")
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} - {}; ",
|
||||||
|
&self.logbook.departure.format("%d. %m. %Y"),
|
||||||
|
&arrival.format("%d. %m. %Y"),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Start: {}",
|
||||||
|
&self.logbook.departure.format("%d. %m. %Y %H:%M")
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(destination) = &self.logbook.destination {
|
||||||
|
write!(f, "Ziel: {destination}; ")?;
|
||||||
|
}
|
||||||
|
write!(f, "Boot: {}; ", self.boat)?;
|
||||||
|
if let Some(distance) = self.logbook.distance_in_km {
|
||||||
|
write!(f, "Distanz: {distance} km; ")?;
|
||||||
|
}
|
||||||
|
write!(f, "Schiffsführer: {}; ", self.shipmaster_user)?;
|
||||||
|
write!(f, "Steuerperson: {}; ", self.steering_user)?;
|
||||||
|
write!(f, "Rudernde: {}; ", VecUser(&self.rowers))?;
|
||||||
|
if let Some(comments) = &self.logbook.comments {
|
||||||
|
if !comments.trim().is_empty() {
|
||||||
|
write!(f, "Kommentar: {comments}; ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LogbookWithBoatAndRowers {
|
impl LogbookWithBoatAndRowers {
|
||||||
pub(crate) async fn from(db: &SqlitePool, log: Logbook) -> Self {
|
pub(crate) async fn from(db: &SqlitePool, log: Logbook) -> Self {
|
||||||
let mut tx = db.begin().await.unwrap();
|
let mut tx = db.begin().await.unwrap();
|
||||||
@ -811,43 +866,22 @@ ORDER BY departure DESC
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(&self, db: &SqlitePool, user: &User) -> Result<(), LogbookDeleteError> {
|
pub async fn delete(&self, db: &SqlitePool, user: &User) -> Result<(), LogbookDeleteError> {
|
||||||
Log::create(db, format!("{} deleted trip: {self:?}", user.name)).await;
|
|
||||||
|
|
||||||
if self.arrival.is_none() {
|
if self.arrival.is_none() {
|
||||||
if user.has_role(db, "admin").await
|
if user.has_role(db, "admin").await
|
||||||
|| user.has_role(db, "Vorstand").await
|
|| user.has_role(db, "Vorstand").await
|
||||||
|| user.id == self.shipmaster
|
|| user.id == self.shipmaster
|
||||||
{
|
{
|
||||||
|
Log::create(db, format!("{} deleted trip: {self:?}", user.name)).await;
|
||||||
let now = Local::now().naive_local();
|
let now = Local::now().naive_local();
|
||||||
let difference = now - self.departure;
|
let difference = now - self.departure;
|
||||||
if difference > Duration::hours(1) {
|
if difference > Duration::hours(1) {
|
||||||
let vorstand = Role::find_by_name(db, "Vorstand").await.unwrap();
|
let vorstand = Role::find_by_name(db, "Vorstand").await.unwrap();
|
||||||
let logbook = LogbookWithBoatAndRowers::from(db, self.clone()).await;
|
let logbook = LogbookWithBoatAndRowers::from(db, self.clone()).await;
|
||||||
let mut msg = format!(
|
|
||||||
"{} hat folgenden Logbuch-Eintrag jetzt gelöscht, welcher bereits vor über einer Stunde begonnen wurde: Schiffsführer: {}, Steuerperson: {}, Abfahrt: {}",
|
|
||||||
user.name,
|
|
||||||
logbook.steering_user.name,
|
|
||||||
logbook.steering_user.name,
|
|
||||||
logbook.logbook.departure.format("%Y-%m-%d %H:%M")
|
|
||||||
);
|
|
||||||
if let Some(destination) = logbook.logbook.destination {
|
|
||||||
msg.push_str(&format!(", Ziel: {}", destination));
|
|
||||||
} else {
|
|
||||||
msg.push_str(", kein Ziel eingegeben");
|
|
||||||
}
|
|
||||||
msg.push_str(", Ruderer: ");
|
|
||||||
let mut it = logbook.rowers.clone().into_iter().peekable();
|
|
||||||
while let Some(rower) = it.next() {
|
|
||||||
msg.push_str(&rower.name);
|
|
||||||
if it.peek().is_some() {
|
|
||||||
msg.push_str(" + ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Notification::create_for_role(
|
Notification::create_for_role(
|
||||||
db,
|
db,
|
||||||
&vorstand,
|
&vorstand,
|
||||||
&msg,
|
&format!("{user} hat folgenden Logbuch-Eintrag jetzt gelöscht, welcher bereits vor über einer Stunde begonnen wurde: {logbook}"),
|
||||||
"Ungewöhnliches Verhalten",
|
"Ungewöhnliches Verhalten",
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -862,8 +896,24 @@ ORDER BY departure DESC
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Only admins can delete completed logbook entries
|
// Only admins+Vorstand can delete completed logbook entries
|
||||||
if user.has_role(db, "admin").await {
|
if user.has_role(db, "admin").await || user.has_role(db, "Vorstand").await {
|
||||||
|
let logbookdetails = LogbookWithBoatAndRowers::from(db, self.clone()).await;
|
||||||
|
ActivityBuilder::from(ReasonLogbook::BoardOrAdminDeleted(user, &logbookdetails))
|
||||||
|
.save(db)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let vorstand = Role::find_by_name(db, "Vorstand").await.unwrap();
|
||||||
|
Notification::create_for_role(
|
||||||
|
db,
|
||||||
|
&vorstand,
|
||||||
|
&format!("{user} hat den Logbuch-Eintrag gelöscht: {logbookdetails}"),
|
||||||
|
"Logbuch gelöscht",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
sqlx::query!("DELETE FROM logbook WHERE id=?", self.id)
|
sqlx::query!("DELETE FROM logbook WHERE id=?", self.id)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await
|
.await
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::{error::Error, fs};
|
use std::{error::Error, fs};
|
||||||
|
|
||||||
use lettre::{
|
use lettre::{
|
||||||
Address, Message, SmtpTransport, Transport,
|
message::{header::ContentType, Attachment, MultiPart, SinglePart},
|
||||||
message::{Attachment, MultiPart, SinglePart, header::ContentType},
|
|
||||||
transport::smtp::authentication::Credentials,
|
transport::smtp::authentication::Credentials,
|
||||||
|
Address, Message, SmtpTransport, Transport,
|
||||||
};
|
};
|
||||||
use sqlx::{Sqlite, SqlitePool, Transaction};
|
use sqlx::{Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ Der Vorstand");
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{user} hat die Info-Mail bzgl. Gebühren gesendet bekommen."
|
"{user} hat die Info-Mail bzgl. Gebühren gesendet bekommen."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&user)
|
.user(&user)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -388,7 +388,7 @@ Der Vorstand");
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{user} hat die Mahn-Mail bzgl. Gebühren gesendet bekommen."
|
"{user} hat die Mahn-Mail bzgl. Gebühren gesendet bekommen."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&user)
|
.user(&user)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ WHERE name like ?
|
|||||||
|
|
||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat Rolle {self} von {self:#?} auf FORMATTED_NAME={formatted_name}, DESC={desc} aktualisiert."
|
"{updated_by} hat Rolle {self} von {self:#?} auf FORMATTED_NAME={formatted_name}, DESC={desc} aktualisiert."
|
||||||
)).relevant_for_role(self).save(db).await;
|
)).role(self).save(db).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -138,10 +138,7 @@ impl User {
|
|||||||
None => format!("{updated_by} hat eine Adresse für {self} hinzugefügt: {new_address}"),
|
None => format!("{updated_by} hat eine Adresse für {self} hinzugefügt: {new_address}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
ActivityBuilder::new(&msg)
|
ActivityBuilder::new(&msg).user(self).save(db).await;
|
||||||
.relevant_for_user(self)
|
|
||||||
.save(db)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn update_nickname(
|
pub(crate) async fn update_nickname(
|
||||||
@ -174,10 +171,7 @@ impl User {
|
|||||||
"{updated_by} hat einen neuen Spitznamen für {self} hinzugefügt: {new_nickname}"
|
"{updated_by} hat einen neuen Spitznamen für {self} hinzugefügt: {new_nickname}"
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
ActivityBuilder::new(&msg)
|
ActivityBuilder::new(&msg).user(self).save(db).await;
|
||||||
.relevant_for_user(self)
|
|
||||||
.save(db)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -206,10 +200,7 @@ impl User {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
ActivityBuilder::new(&msg)
|
ActivityBuilder::new(&msg).user(self).save(db).await;
|
||||||
.relevant_for_user(self)
|
|
||||||
.save(db)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn update_birthdate(
|
pub(crate) async fn update_birthdate(
|
||||||
@ -236,10 +227,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ActivityBuilder::new(&msg)
|
ActivityBuilder::new(&msg).user(self).save(db).await;
|
||||||
.relevant_for_user(self)
|
|
||||||
.save(db)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn update_family(
|
pub(crate) async fn update_family(
|
||||||
@ -261,7 +249,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat {self} zu einer Familie hinzugefügt."
|
"{updated_by} hat {self} zu einer Familie hinzugefügt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
} else {
|
} else {
|
||||||
@ -272,7 +260,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat die Familienzugehörigkeit von {self} gelöscht."
|
"{updated_by} hat die Familienzugehörigkeit von {self} gelöscht."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
};
|
};
|
||||||
@ -318,7 +306,7 @@ impl User {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
ActivityBuilder::new(&format!("{updated_by} hat {self} zur Steuerperson gemacht"))
|
ActivityBuilder::new(&format!("{updated_by} hat {self} zur Steuerperson gemacht"))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -337,7 +325,7 @@ impl User {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
ActivityBuilder::new(&format!("{updated_by} hat {self} zum Bootsführer gemacht"))
|
ActivityBuilder::new(&format!("{updated_by} hat {self} zum Bootsführer gemacht"))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -355,7 +343,7 @@ impl User {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
ActivityBuilder::new(&format!("{updated_by} hat {self} zum normalen Mitglied gemacht (keine Steuerperson/Schiffsführer mehr)"))
|
ActivityBuilder::new(&format!("{updated_by} hat {self} zum normalen Mitglied gemacht (keine Steuerperson/Schiffsführer mehr)"))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -392,7 +380,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat die Ermäßigung von {self} von {old} auf {new} geändert"
|
"{updated_by} hat die Ermäßigung von {self} von {old} auf {new} geändert"
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -424,7 +412,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat die Rolle {role} von {self} entfernt."
|
"{updated_by} hat die Rolle {role} von {self} entfernt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -451,7 +439,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat den Bezahlstatus von {self} auf 'nicht bezahlt' gesetzt."
|
"{updated_by} hat den Bezahlstatus von {self} auf 'nicht bezahlt' gesetzt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -474,7 +462,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat den Bezahlstatus von {self} auf 'bezahlt' gesetzt."
|
"{updated_by} hat den Bezahlstatus von {self} auf 'bezahlt' gesetzt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -511,7 +499,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat die Rolle '{role}' dem Benutzer {self} hinzugefügt."
|
"{updated_by} hat die Rolle '{role}' dem Benutzer {self} hinzugefügt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -556,7 +544,7 @@ impl User {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{updated_by} hat die Mitgliedserklärung (PDF) für user {self} hinzugefügt."
|
"{updated_by} hat die Mitgliedserklärung (PDF) für user {self} hinzugefügt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ impl ClubMemberUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{modified_by} hat {self} zu einem regulären hochgestuft."
|
"{modified_by} hat {self} zu einem regulären hochgestuft."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ impl ClubMemberUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{modified_by} hat {self} zu einem unterstützenden Mitglied gemacht."
|
"{modified_by} hat {self} zu einem unterstützenden Mitglied gemacht."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ impl ClubMemberUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{modified_by} hat {self} zu ein förderndes Mitglied gemacht."
|
"{modified_by} hat {self} zu ein förderndes Mitglied gemacht."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use super::{ManageUserUser, User, regular::ClubMember};
|
use super::{regular::ClubMember, ManageUserUser, User};
|
||||||
use crate::{
|
use crate::{
|
||||||
NonEmptyString,
|
|
||||||
model::{activity::ActivityBuilder, mail::Mail, notification::Notification, role::Role},
|
model::{activity::ActivityBuilder, mail::Mail, notification::Notification, role::Role},
|
||||||
special_user,
|
special_user, NonEmptyString,
|
||||||
};
|
};
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use rocket::{async_trait, fs::TempFile};
|
use rocket::{async_trait, fs::TempFile};
|
||||||
@ -45,7 +44,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"User {self} hat die Info-Mail bzgl. neues förderndes Mitglied (Handbuch und WLAN Infos) an {mail} gesendet bekommen"
|
"User {self} hat die Info-Mail bzgl. neues förderndes Mitglied (Handbuch und WLAN Infos) an {mail} gesendet bekommen"
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
use std::{fmt::Display, ops::DerefMut};
|
use std::{fmt::Display, ops::DerefMut};
|
||||||
|
|
||||||
use argon2::{Argon2, PasswordHasher, password_hash::SaltString};
|
use argon2::{password_hash::SaltString, Argon2, PasswordHasher};
|
||||||
use chrono::{Datelike, Local, NaiveDate};
|
use chrono::{Datelike, Local, NaiveDate};
|
||||||
use log::info;
|
use log::info;
|
||||||
use rocket::async_trait;
|
use rocket::async_trait;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
Request,
|
|
||||||
http::{Cookie, Status},
|
http::{Cookie, Status},
|
||||||
request::{FromRequest, Outcome},
|
request::{FromRequest, Outcome},
|
||||||
time::{Duration, OffsetDateTime},
|
time::{Duration, OffsetDateTime},
|
||||||
|
Request,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
use super::activity::{ActivityBuilder, ReasonAuth};
|
use super::activity::{ActivityBuilder, ReasonAuth};
|
||||||
use super::{
|
use super::{
|
||||||
Day,
|
|
||||||
log::Log,
|
log::Log,
|
||||||
logbook::Logbook,
|
logbook::Logbook,
|
||||||
mail::Mail,
|
mail::Mail,
|
||||||
@ -24,6 +23,7 @@ use super::{
|
|||||||
role::Role,
|
role::Role,
|
||||||
stat::Stat,
|
stat::Stat,
|
||||||
tripdetails::TripDetails,
|
tripdetails::TripDetails,
|
||||||
|
Day,
|
||||||
};
|
};
|
||||||
use crate::AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
|
use crate::AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
|
||||||
use scheckbuch::ScheckbuchUser;
|
use scheckbuch::ScheckbuchUser;
|
||||||
@ -65,6 +65,21 @@ impl Display for User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct VecUser<'a>(pub &'a Vec<User>);
|
||||||
|
impl Display for VecUser<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.map(|user| user.name.as_str())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct UserWithDetails {
|
pub struct UserWithDetails {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@ -457,7 +472,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
smtp_pw,
|
smtp_pw,
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
ActivityBuilder::new(&format!("User {self} hat eine Mail bekommen, dass seine 5 Ausfahrten mit der heutigen Ausfahrt aufgebraucht sind, und dass der nächste Schritt eine Vereinsmitgliedschaft wäre (inkl. Links zu Beitrittserklärung + Info, dass sie an info@ geschickt werden soll.")).relevant_for_user(self).save_tx(db).await;
|
ActivityBuilder::new(&format!("User {self} hat eine Mail bekommen, dass seine 5 Ausfahrten mit der heutigen Ausfahrt aufgebraucht sind, und dass der nächste Schritt eine Vereinsmitgliedschaft wäre (inkl. Links zu Beitrittserklärung + Info, dass sie an info@ geschickt werden soll.")).user(self).save_tx(db).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -515,7 +530,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat das Passwort von User {self} zurückgesetzt."
|
"{changed_by} hat das Passwort von User {self} zurückgesetzt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -527,7 +542,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
.await
|
.await
|
||||||
.unwrap(); //Okay, because we can only create a User of a valid id
|
.unwrap(); //Okay, because we can only create a User of a valid id
|
||||||
ActivityBuilder::new(&format!("{self} hat sein Passwort geändert."))
|
ActivityBuilder::new(&format!("{self} hat sein Passwort geändert."))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -557,7 +572,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
.await
|
.await
|
||||||
.unwrap(); //Okay, because we can only create a User of a valid id
|
.unwrap(); //Okay, because we can only create a User of a valid id
|
||||||
ActivityBuilder::new(&format!("User {self} wurde von {deleted_by} gelöscht."))
|
ActivityBuilder::new(&format!("User {self} wurde von {deleted_by} gelöscht."))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -652,7 +667,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
ActivityBuilder::new(&format!("5 Scheckbuchausfahrten von {self} wurden mit der heutigen Ausfahrt aufgebraucht. Info-Mail wurde an {self} geschickt + alle Steuerberechtigten informiert, dass wir pot. ein neues Mitglied haben"))
|
ActivityBuilder::new(&format!("5 Scheckbuchausfahrten von {self} wurden mit der heutigen Ausfahrt aufgebraucht. Info-Mail wurde an {self} geschickt + alle Steuerberechtigten informiert, dass wir pot. ein neues Mitglied haben"))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save_tx(db)
|
.save_tx(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -670,7 +685,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
ActivityBuilder::new(&format!("{self} hat nun bereits die {amount_trips}. seiner 5 Scheckbuchausfahrten absolviert. Vorstand wurde via Notification informiert."))
|
ActivityBuilder::new(&format!("{self} hat nun bereits die {amount_trips}. seiner 5 Scheckbuchausfahrten absolviert. Vorstand wurde via Notification informiert."))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save_tx(db)
|
.save_tx(db)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -695,7 +710,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{self} hat das heurige Fahrtenabzeichen geschafft! Der Vorstand + {self} wurde via Notification informiert."
|
"{self} hat das heurige Fahrtenabzeichen geschafft! Der Vorstand + {self} wurde via Notification informiert."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save_tx(db)
|
.save_tx(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -717,7 +732,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
ActivityBuilder::new(&format!("{self} hat den Äquatorpreis in {level} geschafft! Der Vorstand + {self} wurde via Notification informiert."))
|
ActivityBuilder::new(&format!("{self} hat den Äquatorpreis in {level} geschafft! Der Vorstand + {self} wurde via Notification informiert."))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save_tx(db)
|
.save_tx(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -835,8 +850,8 @@ special_user!(SteeringUser, +"cox", +"Bootsführer");
|
|||||||
special_user!(AdminUser, +"admin");
|
special_user!(AdminUser, +"admin");
|
||||||
special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch", +"Förderndes Mitglied");
|
special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch", +"Förderndes Mitglied");
|
||||||
special_user!(DonauLinzUser, +"Donau Linz", -"Unterstützend", -"Förderndes Mitglied"); // TODO:
|
special_user!(DonauLinzUser, +"Donau Linz", -"Unterstützend", -"Förderndes Mitglied"); // TODO:
|
||||||
// remove ->
|
// remove ->
|
||||||
// RegularUser
|
// RegularUser
|
||||||
special_user!(SchnupperBetreuerUser, +"schnupper-betreuer");
|
special_user!(SchnupperBetreuerUser, +"schnupper-betreuer");
|
||||||
special_user!(VorstandUser, +"admin", +"Vorstand");
|
special_user!(VorstandUser, +"admin", +"Vorstand");
|
||||||
special_user!(EventUser, +"manage_events");
|
special_user!(EventUser, +"manage_events");
|
||||||
@ -950,21 +965,17 @@ mod test {
|
|||||||
#[sqlx::test]
|
#[sqlx::test]
|
||||||
fn wrong_pw() {
|
fn wrong_pw() {
|
||||||
let pool = testdb!();
|
let pool = testdb!();
|
||||||
assert!(
|
assert!(User::login(&pool, "admin".into(), "admi".into())
|
||||||
User::login(&pool, "admin".into(), "admi".into())
|
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[sqlx::test]
|
#[sqlx::test]
|
||||||
fn wrong_username() {
|
fn wrong_username() {
|
||||||
let pool = testdb!();
|
let pool = testdb!();
|
||||||
assert!(
|
assert!(User::login(&pool, "admi".into(), "admin".into())
|
||||||
User::login(&pool, "admi".into(), "admin".into())
|
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[sqlx::test]
|
#[sqlx::test]
|
||||||
@ -984,11 +995,9 @@ mod test {
|
|||||||
let pool = testdb!();
|
let pool = testdb!();
|
||||||
let user = User::find_by_id(&pool, 1).await.unwrap();
|
let user = User::find_by_id(&pool, 1).await.unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(User::login(&pool, "admin".into(), "abc".into())
|
||||||
User::login(&pool, "admin".into(), "abc".into())
|
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err());
|
||||||
);
|
|
||||||
|
|
||||||
user.update_pw(&pool, "abc".into()).await;
|
user.update_pw(&pool, "abc".into()).await;
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use super::{ManageUserUser, User};
|
use super::{ManageUserUser, User};
|
||||||
use crate::{
|
use crate::{
|
||||||
NonEmptyString,
|
|
||||||
model::{activity::ActivityBuilder, mail::Mail, notification::Notification, role::Role},
|
model::{activity::ActivityBuilder, mail::Mail, notification::Notification, role::Role},
|
||||||
special_user,
|
special_user, NonEmptyString,
|
||||||
};
|
};
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use rocket::{async_trait, fs::TempFile, tokio::io::AsyncReadExt};
|
use rocket::{async_trait, fs::TempFile, tokio::io::AsyncReadExt};
|
||||||
@ -52,7 +51,7 @@ pub trait ClubMember {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{created_by} hat Mitglied {user} mit der Rolle {role} angelegt."
|
"{created_by} hat Mitglied {user} mit der Rolle {role} angelegt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&user)
|
.user(&user)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
ActivityBuilder::new(&format!("Willkommensmail für {self} wurde an {mail} verschickt (Handbuch, Signal-Gruppe, App-Info, Fingerprint, WLAN)."))
|
ActivityBuilder::new(&format!("Willkommensmail für {self} wurde an {mail} verschickt (Handbuch, Signal-Gruppe, App-Info, Fingerprint, WLAN)."))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -2,13 +2,12 @@ use super::foerdernd::FoerderndUser;
|
|||||||
use super::regular::RegularUser;
|
use super::regular::RegularUser;
|
||||||
use super::unterstuetzend::UnterstuetzendUser;
|
use super::unterstuetzend::UnterstuetzendUser;
|
||||||
use super::{ManageUserUser, User};
|
use super::{ManageUserUser, User};
|
||||||
use crate::NonEmptyString;
|
|
||||||
use crate::model::activity::ActivityBuilder;
|
use crate::model::activity::ActivityBuilder;
|
||||||
use crate::model::role::Role;
|
use crate::model::role::Role;
|
||||||
|
use crate::NonEmptyString;
|
||||||
use crate::{
|
use crate::{
|
||||||
SCHECKBUCH,
|
|
||||||
model::{mail::Mail, notification::Notification},
|
model::{mail::Mail, notification::Notification},
|
||||||
special_user,
|
special_user, SCHECKBUCH,
|
||||||
};
|
};
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use rocket::async_trait;
|
use rocket::async_trait;
|
||||||
@ -88,7 +87,7 @@ impl ScheckbuchUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat den Scheckbuch-User {self} auf ein reguläres Mitglied upgegraded! Die Steuerpersonen wurden via Notification informiert."
|
"{changed_by} hat den Scheckbuch-User {self} auf ein reguläres Mitglied upgegraded! Die Steuerpersonen wurden via Notification informiert."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -144,7 +143,7 @@ impl ScheckbuchUser {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActivityBuilder::new(&format!("{changed_by} hat den Scheckbuch-User {self} auf ein unterstützendes Mitglied upgegraded!"))
|
ActivityBuilder::new(&format!("{changed_by} hat den Scheckbuch-User {self} auf ein unterstützendes Mitglied upgegraded!"))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -200,7 +199,7 @@ impl ScheckbuchUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat den Scheckbuch-User {self} auf ein förderndes Mitglied upgegraded!"
|
"{changed_by} hat den Scheckbuch-User {self} auf ein förderndes Mitglied upgegraded!"
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -215,7 +214,7 @@ impl ScheckbuchUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{self} hat eine Info-Mail bekommen (Erklärung Scheckbuch, Ruderapp) und alle Steuerberechtigten wurden informiert."
|
"{self} hat eine Info-Mail bekommen (Erklärung Scheckbuch, Ruderapp) und alle Steuerberechtigten wurden informiert."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -295,7 +294,7 @@ ASKÖ Ruderverein Donau Linz", self.name, SCHECKBUCH/100),
|
|||||||
user.notify(db, smtp_pw).await?;
|
user.notify(db, smtp_pw).await?;
|
||||||
|
|
||||||
ActivityBuilder::new(&format!("{created_by} hat Scheckbuch {user} angelegt."))
|
ActivityBuilder::new(&format!("{created_by} hat Scheckbuch {user} angelegt."))
|
||||||
.relevant_for_user(&user)
|
.user(&user)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ use super::scheckbuch::ScheckbuchUser;
|
|||||||
use super::schnupperinterest::SchnupperInterestUser;
|
use super::schnupperinterest::SchnupperInterestUser;
|
||||||
use super::unterstuetzend::UnterstuetzendUser;
|
use super::unterstuetzend::UnterstuetzendUser;
|
||||||
use super::{ManageUserUser, User};
|
use super::{ManageUserUser, User};
|
||||||
use crate::NonEmptyString;
|
|
||||||
use crate::model::activity::ActivityBuilder;
|
use crate::model::activity::ActivityBuilder;
|
||||||
use crate::model::role::Role;
|
use crate::model::role::Role;
|
||||||
|
use crate::NonEmptyString;
|
||||||
use crate::{
|
use crate::{
|
||||||
model::{mail::Mail, notification::Notification},
|
model::{mail::Mail, notification::Notification},
|
||||||
special_user,
|
special_user,
|
||||||
@ -101,7 +101,7 @@ impl SchnupperantUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat den Schnupperant {self} auf ein reguläres Mitglied upgegraded!"
|
"{changed_by} hat den Schnupperant {self} auf ein reguläres Mitglied upgegraded!"
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ impl SchnupperantUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat dem ehemaligen Schnupperant {self} nun ein Scheckbuch gegeben"
|
"{changed_by} hat dem ehemaligen Schnupperant {self} nun ein Scheckbuch gegeben"
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ impl SchnupperantUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat dem eigentlichen Schnupperanten {self} wieder auf die 'Interessierten'-Liste zurückgegeben."
|
"{changed_by} hat dem eigentlichen Schnupperanten {self} wieder auf die 'Interessierten'-Liste zurückgegeben."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -253,7 +253,7 @@ impl SchnupperantUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat den Schnupperant {self} auf ein unterstützendes Mitglied upgegraded!"
|
"{changed_by} hat den Schnupperant {self} auf ein unterstützendes Mitglied upgegraded!"
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ impl SchnupperantUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{changed_by} hat den Schnupperant {self} auf ein förderndes Mitglied upgegraded!"
|
"{changed_by} hat den Schnupperant {self} auf ein förderndes Mitglied upgegraded!"
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ impl SchnupperantUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{self} hat eine Mail bekommen (Inhalt: wir freuen uns auf ihn + senden detailliertere Infos später zu) und die Schnupperbetreuer wurden via Notification informiert."
|
"{self} hat eine Mail bekommen (Inhalt: wir freuen uns auf ihn + senden detailliertere Infos später zu) und die Schnupperbetreuer wurden via Notification informiert."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -423,7 +423,7 @@ ASKÖ Ruderverein Donau Linz",
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{created_by} hat {user} zur fixen Schnupperkurs-Anmeldung hinzugefügt."
|
"{created_by} hat {user} zur fixen Schnupperkurs-Anmeldung hinzugefügt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&user)
|
.user(&user)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use super::scheckbuch::ScheckbuchUser;
|
use super::scheckbuch::ScheckbuchUser;
|
||||||
use super::schnupperant::SchnupperantUser;
|
use super::schnupperant::SchnupperantUser;
|
||||||
use super::{ManageUserUser, User};
|
use super::{ManageUserUser, User};
|
||||||
use crate::NonEmptyString;
|
|
||||||
use crate::model::activity::ActivityBuilder;
|
use crate::model::activity::ActivityBuilder;
|
||||||
use crate::model::role::Role;
|
use crate::model::role::Role;
|
||||||
|
use crate::NonEmptyString;
|
||||||
use crate::{model::notification::Notification, special_user};
|
use crate::{model::notification::Notification, special_user};
|
||||||
use rocket::async_trait;
|
use rocket::async_trait;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
@ -44,7 +44,7 @@ impl SchnupperInterestUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"Der Schnupperinteressierte {self} hat sich (ohne Schnupperkurs) doch gleich direkt für ein Scheckbuch entschieden. {changed_by} hat dieses eingerichtet."
|
"Der Schnupperinteressierte {self} hat sich (ohne Schnupperkurs) doch gleich direkt für ein Scheckbuch entschieden. {changed_by} hat dieses eingerichtet."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ impl SchnupperInterestUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"Der Schnupperinteressierte {self} hat sich zum Schnupperkurs angemeldet."
|
"Der Schnupperinteressierte {self} hat sich zum Schnupperkurs angemeldet."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&self)
|
.user(&self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ impl SchnupperInterestUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"Der Schnupperbetreuer hat eine Info via Notification bekommen, dass {self} Interesse an einen Schnupperkurs hat."
|
"Der Schnupperbetreuer hat eine Info via Notification bekommen, dass {self} Interesse an einen Schnupperkurs hat."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ impl SchnupperInterestUser {
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{created_by} hat Schnupper-Interessierten {user} angelegt."
|
"{created_by} hat Schnupper-Interessierten {user} angelegt."
|
||||||
))
|
))
|
||||||
.relevant_for_user(&user)
|
.user(&user)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use super::{ManageUserUser, User, regular::ClubMember};
|
use super::{regular::ClubMember, ManageUserUser, User};
|
||||||
use crate::{
|
use crate::{
|
||||||
NonEmptyString,
|
|
||||||
model::{activity::ActivityBuilder, mail::Mail, notification::Notification, role::Role},
|
model::{activity::ActivityBuilder, mail::Mail, notification::Notification, role::Role},
|
||||||
special_user,
|
special_user, NonEmptyString,
|
||||||
};
|
};
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use rocket::{async_trait, fs::TempFile};
|
use rocket::{async_trait, fs::TempFile};
|
||||||
@ -45,7 +44,7 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
|||||||
ActivityBuilder::new(&format!(
|
ActivityBuilder::new(&format!(
|
||||||
"{self} hat eine Mail an {mail} bekommen, mit Infos dass er/sie nun ein unterstützendes Mitglied ist (Handbuch, WLAN)."
|
"{self} hat eine Mail an {mail} bekommen, mit Infos dass er/sie nun ein unterstützendes Mitglied ist (Handbuch, WLAN)."
|
||||||
))
|
))
|
||||||
.relevant_for_user(self)
|
.user(self)
|
||||||
.save(db)
|
.save(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use rocket::{
|
use rocket::{
|
||||||
Request, Route, State,
|
|
||||||
form::Form,
|
form::Form,
|
||||||
get,
|
get,
|
||||||
http::{Cookie, CookieJar},
|
http::{Cookie, CookieJar},
|
||||||
@ -10,8 +9,9 @@ use rocket::{
|
|||||||
response::{Flash, Redirect},
|
response::{Flash, Redirect},
|
||||||
routes,
|
routes,
|
||||||
time::{Duration, OffsetDateTime},
|
time::{Duration, OffsetDateTime},
|
||||||
|
Request, Route, State,
|
||||||
};
|
};
|
||||||
use rocket_dyn_templates::{Template, context};
|
use rocket_dyn_templates::{context, Template};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
|
|
||||||
@ -108,26 +108,50 @@ async fn index(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/show", rank = 3)]
|
#[get("/show", rank = 3)]
|
||||||
async fn show(db: &State<SqlitePool>, user: DonauLinzUser) -> Template {
|
async fn show(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
flash: Option<FlashMessage<'_>>,
|
||||||
|
user: DonauLinzUser,
|
||||||
|
) -> Template {
|
||||||
let logs = Logbook::completed(db).await;
|
let logs = Logbook::completed(db).await;
|
||||||
let boats = Boat::all(db).await;
|
let boats = Boat::all(db).await;
|
||||||
let users = User::all(db).await;
|
let users = User::all(db).await;
|
||||||
let logtypes = LogType::all(db).await;
|
let logtypes = LogType::all(db).await;
|
||||||
|
|
||||||
Template::render(
|
let mut context = Context::new();
|
||||||
"log.completed",
|
if let Some(msg) = flash {
|
||||||
context!(logs, boats, users, logtypes, loggedin_user: &UserWithDetails::from_user(user.into_inner(), db).await),
|
context.insert("flash", &msg.into_inner());
|
||||||
)
|
}
|
||||||
|
context.insert("logs", &logs);
|
||||||
|
context.insert("boats", &boats);
|
||||||
|
context.insert("users", &users);
|
||||||
|
context.insert("logtypes", &logtypes);
|
||||||
|
context.insert(
|
||||||
|
"loggedin_user",
|
||||||
|
&UserWithDetails::from_user(user.into_inner(), db).await,
|
||||||
|
);
|
||||||
|
Template::render("log.completed", context.into_json())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/show?<year>", rank = 2)]
|
#[get("/show?<year>", rank = 2)]
|
||||||
async fn show_for_year(db: &State<SqlitePool>, user: VorstandUser, year: i32) -> Template {
|
async fn show_for_year(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
flash: Option<FlashMessage<'_>>,
|
||||||
|
user: VorstandUser,
|
||||||
|
year: i32,
|
||||||
|
) -> Template {
|
||||||
let logs = Logbook::completed_in_year(db, year).await;
|
let logs = Logbook::completed_in_year(db, year).await;
|
||||||
|
|
||||||
Template::render(
|
let mut context = Context::new();
|
||||||
"log.completed",
|
if let Some(msg) = flash {
|
||||||
context!(logs, loggedin_user: &UserWithDetails::from_user(user.user, db).await),
|
context.insert("flash", &msg.into_inner());
|
||||||
)
|
}
|
||||||
|
context.insert("logs", &logs);
|
||||||
|
context.insert(
|
||||||
|
"loggedin_user",
|
||||||
|
&UserWithDetails::from_user(user.into_inner(), db).await,
|
||||||
|
);
|
||||||
|
Template::render("log.completed", context.into_json())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/show")]
|
#[get("/show")]
|
||||||
@ -513,10 +537,7 @@ async fn delete(db: &State<SqlitePool>, logbook_id: i64, user: DonauLinzUser) ->
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
match logbook.delete(db, &user).await {
|
match logbook.delete(db, &user).await {
|
||||||
Ok(_) => Flash::success(
|
Ok(_) => Flash::success(Redirect::to(redirect), "Erfolgreich gelöscht"),
|
||||||
Redirect::to(redirect),
|
|
||||||
format!("Eintrag {} von {} gelöscht!", logbook_id, user.name),
|
|
||||||
),
|
|
||||||
Err(LogbookDeleteError::NotYourEntry) => Flash::error(
|
Err(LogbookDeleteError::NotYourEntry) => Flash::error(
|
||||||
Redirect::to(redirect),
|
Redirect::to(redirect),
|
||||||
"Du hast nicht die Berechtigung, den Eintrag zu löschen!",
|
"Du hast nicht die Berechtigung, den Eintrag zu löschen!",
|
||||||
@ -585,7 +606,7 @@ mod test {
|
|||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::model::logbook::Logbook;
|
use crate::model::logbook::Logbook;
|
||||||
use crate::tera::{User, log::Boat};
|
use crate::tera::{log::Boat, User};
|
||||||
use crate::testdb;
|
use crate::testdb;
|
||||||
|
|
||||||
#[sqlx::test]
|
#[sqlx::test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user