Merge pull request 'send scheckbuch people mail after using all trips' (#742) from mail-end-scheckbuch into main
Reviewed-on: #742
This commit is contained in:
commit
5727c0c9ce
@ -118,11 +118,20 @@ pub struct LogbookWithBoatAndRowers {
|
||||
|
||||
impl LogbookWithBoatAndRowers {
|
||||
pub(crate) async fn from(db: &SqlitePool, log: Logbook) -> Self {
|
||||
let mut tx = db.begin().await.unwrap();
|
||||
let ret = Self::from_tx(&mut tx, log).await;
|
||||
tx.commit().await.unwrap();
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) async fn from_tx(db: &mut Transaction<'_, Sqlite>, log: Logbook) -> Self {
|
||||
Self {
|
||||
rowers: Rower::for_log(db, &log).await,
|
||||
boat: Boat::find_by_id(db, log.boat_id as i32).await.unwrap(),
|
||||
shipmaster_user: User::find_by_id(db, log.shipmaster as i32).await.unwrap(),
|
||||
steering_user: User::find_by_id(db, log.steering_person as i32)
|
||||
rowers: Rower::for_log_tx(db, &log).await,
|
||||
boat: Boat::find_by_id_tx(db, log.boat_id as i32).await.unwrap(),
|
||||
shipmaster_user: User::find_by_id_tx(db, log.shipmaster as i32)
|
||||
.await
|
||||
.unwrap(),
|
||||
steering_user: User::find_by_id_tx(db, log.steering_person as i32)
|
||||
.await
|
||||
.unwrap(),
|
||||
logbook: log,
|
||||
@ -278,6 +287,16 @@ ORDER BY departure DESC
|
||||
pub async fn completed_with_user(
|
||||
db: &SqlitePool,
|
||||
user: &User,
|
||||
) -> Vec<LogbookWithBoatAndRowers> {
|
||||
let mut tx = db.begin().await.unwrap();
|
||||
let ret = Self::completed_with_user_tx(&mut tx, user).await;
|
||||
tx.commit().await.unwrap();
|
||||
ret
|
||||
}
|
||||
|
||||
pub async fn completed_with_user_tx(
|
||||
db: &mut Transaction<'_, Sqlite>,
|
||||
user: &User,
|
||||
) -> Vec<LogbookWithBoatAndRowers> {
|
||||
let logs = sqlx::query_as(
|
||||
&format!("
|
||||
@ -288,13 +307,13 @@ ORDER BY departure DESC
|
||||
ORDER BY arrival DESC
|
||||
", user.id)
|
||||
)
|
||||
.fetch_all(db)
|
||||
.fetch_all(db.deref_mut())
|
||||
.await
|
||||
.unwrap(); //TODO: fixme
|
||||
|
||||
let mut ret = Vec::new();
|
||||
for log in logs {
|
||||
ret.push(LogbookWithBoatAndRowers::from(db, log).await);
|
||||
ret.push(LogbookWithBoatAndRowers::from_tx(db, log).await);
|
||||
}
|
||||
ret
|
||||
}
|
||||
@ -415,6 +434,7 @@ ORDER BY departure DESC
|
||||
db: &SqlitePool,
|
||||
mut log: LogToAdd,
|
||||
created_by_user: &User,
|
||||
smtp_pw: &str,
|
||||
) -> Result<String, LogbookCreateError> {
|
||||
let Some(boat) = Boat::find_by_id(db, log.boat_id).await else {
|
||||
return Err(LogbookCreateError::BoatNotFound);
|
||||
@ -462,7 +482,7 @@ ORDER BY departure DESC
|
||||
.unwrap(); //ok
|
||||
|
||||
return match logbook
|
||||
.home_with_transaction(&mut tx, created_by_user, log_to_finalize)
|
||||
.home_with_transaction(&mut tx, created_by_user, log_to_finalize, smtp_pw)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
@ -613,9 +633,11 @@ ORDER BY departure DESC
|
||||
db: &SqlitePool,
|
||||
user: &User,
|
||||
log: LogToFinalize,
|
||||
smtp_pw: &str,
|
||||
) -> Result<(), LogbookUpdateError> {
|
||||
let mut tx = db.begin().await.unwrap();
|
||||
self.home_with_transaction(&mut tx, user, log).await?;
|
||||
self.home_with_transaction(&mut tx, user, log, smtp_pw)
|
||||
.await?;
|
||||
tx.commit().await.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
@ -625,6 +647,7 @@ ORDER BY departure DESC
|
||||
db: &mut Transaction<'_, Sqlite>,
|
||||
user: &User,
|
||||
mut log: LogToFinalize,
|
||||
smtp_pw: &str,
|
||||
) -> Result<(), LogbookUpdateError> {
|
||||
//TODO: extract common tests with `create()`
|
||||
if !user.has_role_tx(db, "Vorstand").await && user.id != self.shipmaster {
|
||||
@ -778,6 +801,11 @@ ORDER BY departure DESC
|
||||
).await;
|
||||
}
|
||||
|
||||
for rower in &log.rowers {
|
||||
let user = User::find_by_id_tx(db, *rower as i32).await.unwrap();
|
||||
user.received_new_logentry(db, smtp_pw).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -914,6 +942,7 @@ mod test {
|
||||
rowers: vec![4],
|
||||
},
|
||||
&User::find_by_id(&pool, 4).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -945,6 +974,7 @@ mod test {
|
||||
departure: format!("{}T10:00", start_date),
|
||||
arrival: format!("{}T12:00", current_date),
|
||||
},
|
||||
"",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -965,6 +995,7 @@ mod test {
|
||||
rowers: vec![2],
|
||||
},
|
||||
&User::find_by_id(&pool, 1).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -994,6 +1025,7 @@ mod test {
|
||||
rowers: vec![5],
|
||||
},
|
||||
&User::find_by_id(&pool, 4).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1020,6 +1052,7 @@ mod test {
|
||||
rowers: vec![5],
|
||||
},
|
||||
&User::find_by_id(&pool, 4).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1046,6 +1079,7 @@ mod test {
|
||||
rowers: vec![5],
|
||||
},
|
||||
&User::find_by_id(&pool, 5).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1072,6 +1106,7 @@ mod test {
|
||||
rowers: vec![5],
|
||||
},
|
||||
&User::find_by_id(&pool, 5).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1098,6 +1133,7 @@ mod test {
|
||||
rowers: Vec::new(),
|
||||
},
|
||||
&User::find_by_id(&pool, 2).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1124,6 +1160,7 @@ mod test {
|
||||
rowers: vec![5],
|
||||
},
|
||||
&User::find_by_id(&pool, 5).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1150,6 +1187,7 @@ mod test {
|
||||
rowers: vec![1, 5],
|
||||
},
|
||||
&User::find_by_id(&pool, 5).await.unwrap(),
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1181,6 +1219,7 @@ mod test {
|
||||
departure: format!("{}T10:00", current_date),
|
||||
arrival: format!("{}T12:00", current_date),
|
||||
},
|
||||
"",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@ -1209,6 +1248,7 @@ mod test {
|
||||
departure: "1990-01-01T10:00".into(),
|
||||
arrival: "1990-01-01T12:00".into(),
|
||||
},
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -1238,6 +1278,7 @@ mod test {
|
||||
departure: "1990-01-01T10:00".into(),
|
||||
arrival: "1990-01-01T12:00".into(),
|
||||
},
|
||||
"",
|
||||
)
|
||||
.await;
|
||||
|
||||
|
@ -5,7 +5,7 @@ use lettre::{
|
||||
transport::smtp::authentication::Credentials,
|
||||
Message, SmtpTransport, Transport,
|
||||
};
|
||||
use sqlx::SqlitePool;
|
||||
use sqlx::{Sqlite, SqlitePool, Transaction};
|
||||
|
||||
use crate::tera::admin::mail::MailToSend;
|
||||
|
||||
@ -20,6 +20,19 @@ impl Mail {
|
||||
subject: &str,
|
||||
body: String,
|
||||
smtp_pw: &str,
|
||||
) -> Result<(), String> {
|
||||
let mut tx = db.begin().await.unwrap();
|
||||
let ret = Self::send_single_tx(&mut tx, to, subject, body, smtp_pw).await;
|
||||
tx.commit().await.unwrap();
|
||||
ret
|
||||
}
|
||||
|
||||
pub async fn send_single_tx(
|
||||
db: &mut Transaction<'_, Sqlite>,
|
||||
to: &str,
|
||||
subject: &str,
|
||||
body: String,
|
||||
smtp_pw: &str,
|
||||
) -> Result<(), String> {
|
||||
let mut email = Message::builder()
|
||||
.from(
|
||||
@ -40,7 +53,7 @@ impl Mail {
|
||||
match single_rec.parse() {
|
||||
Ok(new_bcc_mail) => email = email.bcc(new_bcc_mail),
|
||||
Err(_) => {
|
||||
Log::create(
|
||||
Log::create_with_tx(
|
||||
db,
|
||||
format!("Mail not sent to {single_rec}, because it could not be parsed"),
|
||||
)
|
||||
|
@ -13,6 +13,13 @@ pub struct Rower {
|
||||
|
||||
impl Rower {
|
||||
pub async fn for_log(db: &SqlitePool, log: &Logbook) -> Vec<User> {
|
||||
let mut tx = db.begin().await.unwrap();
|
||||
let ret = Self::for_log_tx(&mut tx, log).await;
|
||||
tx.commit().await.unwrap();
|
||||
ret
|
||||
}
|
||||
|
||||
pub async fn for_log_tx(db: &mut Transaction<'_, Sqlite>, log: &Logbook) -> Vec<User> {
|
||||
sqlx::query_as!(
|
||||
User,
|
||||
"
|
||||
@ -22,7 +29,7 @@ WHERE id in (SELECT rower_id FROM rower WHERE logbook_id=?)
|
||||
",
|
||||
log.id
|
||||
)
|
||||
.fetch_all(db)
|
||||
.fetch_all(db.deref_mut())
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||
|
||||
use super::{
|
||||
family::Family, log::Log, mail::Mail, notification::Notification, role::Role, stat::Stat,
|
||||
tripdetails::TripDetails, Day,
|
||||
family::Family, log::Log, logbook::Logbook, mail::Mail, notification::Notification, role::Role,
|
||||
stat::Stat, tripdetails::TripDetails, Day,
|
||||
};
|
||||
use crate::{
|
||||
tera::admin::user::UserEditForm, AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD, BOAT_STORAGE,
|
||||
@ -251,6 +251,51 @@ ASKÖ Ruderverein Donau Linz", self.name, SCHECKBUCH/100),
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_end_mail_scheckbuch(
|
||||
&self,
|
||||
db: &mut Transaction<'_, Sqlite>,
|
||||
mail: &str,
|
||||
smtp_pw: &str,
|
||||
) -> Result<(), String> {
|
||||
// 2 things to do:
|
||||
// 1. Send mail to user
|
||||
Mail::send_single_tx(
|
||||
db,
|
||||
mail,
|
||||
"ASKÖ Ruderverein Donau Linz | Deine Mitgliedschaft wartet auf Dich",
|
||||
format!(
|
||||
"Hallo {0},
|
||||
|
||||
herzlichen Glückwunsch---Du hast Deine fünf Scheckbuch-Ausfahrten erfolgreich absolviert! Wir hoffen, dass Du das Rudern bei uns genauso genossen hast wie wir es genossen haben, Dich auf dem Wasser zu begleiten.
|
||||
|
||||
Wir würden uns sehr freuen, Dich als festes Mitglied in unserem Verein willkommen zu heißen! Als Mitglied stehen Dir dann alle unsere Ausfahrten offen, die von unseren Steuerleuten organisiert werden. Im Sommer erwarten Dich zusätzlich spannende Events: Wanderfahrten, Sternfahrten, Fetzenfahrt, .... Im Winter bieten wir Indoor-Ergo-Challenges an, bei denen Du Deine Fitness auf dem Ruderergometer unter Beweis stellen kannst. Alle Details zu diesen Aktionen erfährst Du, sobald Du Teil unseres Vereins bist! :-)
|
||||
|
||||
Alle Informationen zu den Mitgliedsbeiträgen findest Du unter https://rudernlinz.at/unser-verein/gebuhren/ Falls Du Dich entscheidest, unserem Verein beizutreten, fülle bitte unser Beitrittsformular auf https://rudernlinz.at/unser-verein/downloads/ aus und sende es an info@rudernlinz.at.
|
||||
|
||||
Wir freuen uns, Dich bald wieder auf dem Wasser zu sehen.
|
||||
|
||||
Riemen- & Dollenbruch,
|
||||
ASKÖ Ruderverein Donau Linz", self.name),
|
||||
smtp_pw,
|
||||
).await?;
|
||||
|
||||
// 2. Notify all coxes
|
||||
let coxes = Role::find_by_name_tx(db, "cox").await.unwrap();
|
||||
Notification::create_for_role_tx(
|
||||
db,
|
||||
&coxes,
|
||||
&format!(
|
||||
"Liebe Steuerberechtigte, {} hat alle Ausfahrten des Scheckbuchs absolviert. Hoffentlich können wir uns bald über ein neues Mitglied freuen :-)",
|
||||
self.name
|
||||
),
|
||||
"Scheckbuch fertig",
|
||||
None,None
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_welcome_mail_full_member(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
@ -920,6 +965,20 @@ ORDER BY last_access DESC
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) async fn received_new_logentry(
|
||||
&self,
|
||||
db: &mut Transaction<'_, Sqlite>,
|
||||
smtp_pw: &str,
|
||||
) {
|
||||
if self.has_role_tx(db, "scheckbuch").await
|
||||
&& Logbook::completed_with_user_tx(db, &self).await.len() == 5
|
||||
{
|
||||
if let Some(mail) = &self.mail {
|
||||
let _ = self.send_end_mail_scheckbuch(db, mail, smtp_pw).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -15,18 +15,21 @@ use rocket_dyn_templates::{context, Template};
|
||||
use sqlx::SqlitePool;
|
||||
use tera::Context;
|
||||
|
||||
use crate::model::{
|
||||
use crate::{
|
||||
model::{
|
||||
boat::Boat,
|
||||
boatreservation::BoatReservation,
|
||||
distance::Distance,
|
||||
log::Log,
|
||||
logbook::{
|
||||
LogToAdd, LogToFinalize, LogToUpdate, Logbook, LogbookAdminUpdateError, LogbookCreateError,
|
||||
LogbookDeleteError, LogbookUpdateError,
|
||||
LogToAdd, LogToFinalize, LogToUpdate, Logbook, LogbookAdminUpdateError,
|
||||
LogbookCreateError, LogbookDeleteError, LogbookUpdateError,
|
||||
},
|
||||
logtype::LogType,
|
||||
trip::Trip,
|
||||
user::{AdminUser, DonauLinzUser, User, UserWithDetails, VorstandUser},
|
||||
},
|
||||
tera::Config,
|
||||
};
|
||||
|
||||
pub struct KioskCookie(());
|
||||
@ -210,11 +213,12 @@ async fn create_logbook(
|
||||
db: &SqlitePool,
|
||||
data: Form<LogToAdd>,
|
||||
user: &DonauLinzUser,
|
||||
smtp_pw: &str,
|
||||
) -> Flash<Redirect> {
|
||||
match Logbook::create(
|
||||
db,
|
||||
data.into_inner(),
|
||||
user
|
||||
user, smtp_pw
|
||||
)
|
||||
.await
|
||||
{
|
||||
@ -244,6 +248,7 @@ async fn create(
|
||||
db: &State<SqlitePool>,
|
||||
data: Form<LogToAdd>,
|
||||
user: DonauLinzUser,
|
||||
config: &State<Config>,
|
||||
) -> Flash<Redirect> {
|
||||
Log::create(
|
||||
db,
|
||||
@ -251,7 +256,7 @@ async fn create(
|
||||
)
|
||||
.await;
|
||||
|
||||
create_logbook(db, data, &user).await
|
||||
create_logbook(db, data, &user, &config.smtp_pw).await
|
||||
}
|
||||
|
||||
#[post("/", data = "<data>")]
|
||||
@ -259,6 +264,7 @@ async fn create_kiosk(
|
||||
db: &State<SqlitePool>,
|
||||
data: Form<LogToAdd>,
|
||||
_kiosk: KioskCookie,
|
||||
config: &State<Config>,
|
||||
) -> Flash<Redirect> {
|
||||
let Some(boat) = Boat::find_by_id(db, data.boat_id).await else {
|
||||
return Flash::error(Redirect::to("/log"), "Boot gibt's nicht");
|
||||
@ -287,7 +293,13 @@ async fn create_kiosk(
|
||||
)
|
||||
.await;
|
||||
|
||||
create_logbook(db, data, &DonauLinzUser::new(db, creator).await.unwrap()).await
|
||||
create_logbook(
|
||||
db,
|
||||
data,
|
||||
&DonauLinzUser::new(db, creator).await.unwrap(),
|
||||
&config.smtp_pw,
|
||||
)
|
||||
.await
|
||||
//TODO: fixme
|
||||
}
|
||||
|
||||
@ -331,6 +343,7 @@ async fn home_logbook(
|
||||
data: Form<LogToFinalize>,
|
||||
logbook_id: i64,
|
||||
user: &DonauLinzUser,
|
||||
smtp_pw: &str,
|
||||
) -> Flash<Redirect> {
|
||||
let logbook: Option<Logbook> = Logbook::find_by_id(db, logbook_id).await;
|
||||
let Some(logbook) = logbook else {
|
||||
@ -340,7 +353,7 @@ async fn home_logbook(
|
||||
);
|
||||
};
|
||||
|
||||
match logbook.home(db,user, data.into_inner()).await {
|
||||
match logbook.home(db,user, data.into_inner(), smtp_pw).await {
|
||||
Ok(_) => Flash::success(Redirect::to("/log"), "Ausfahrt korrekt eingetragen"),
|
||||
Err(LogbookUpdateError::TooManyRowers(expected, actual)) => Flash::error(Redirect::to("/log"), format!("Zu viele Ruderer (Boot fasst maximal {expected}, es wurden jedoch {actual} Ruderer ausgewählt)")),
|
||||
Err(LogbookUpdateError::OnlyAllowedToEndTripsEndingToday) => Flash::error(Redirect::to("/log"), "Nur Ausfahrten, die heute enden dürfen eingetragen werden. Für einen Nachtrag schreibe alle Daten Philipp (Tel. nr. siehe Signal oder it@rudernlinz.at)."),
|
||||
@ -361,6 +374,7 @@ async fn home_kiosk(
|
||||
data: Form<LogToFinalize>,
|
||||
logbook_id: i64,
|
||||
_kiosk: KioskCookie,
|
||||
config: &State<Config>,
|
||||
) -> Flash<Redirect> {
|
||||
let logbook = Logbook::find_by_id(db, logbook_id).await.unwrap(); //TODO: fixme
|
||||
|
||||
@ -382,6 +396,7 @@ async fn home_kiosk(
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
&config.smtp_pw,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -392,6 +407,7 @@ async fn home(
|
||||
data: Form<LogToFinalize>,
|
||||
logbook_id: i64,
|
||||
user: DonauLinzUser,
|
||||
config: &State<Config>,
|
||||
) -> Flash<Redirect> {
|
||||
Log::create(
|
||||
db,
|
||||
@ -402,7 +418,7 @@ async fn home(
|
||||
)
|
||||
.await;
|
||||
|
||||
home_logbook(db, data, logbook_id, &user).await
|
||||
home_logbook(db, data, logbook_id, &user, &config.smtp_pw).await
|
||||
}
|
||||
|
||||
#[get("/<logbook_id>/delete", rank = 2)]
|
||||
|
Loading…
Reference in New Issue
Block a user