welcome-mail #489
@ -14,6 +14,58 @@ use super::{family::Family, log::Log, role::Role, user::User};
|
|||||||
pub struct Mail {}
|
pub struct Mail {}
|
||||||
|
|
||||||
impl Mail {
|
impl Mail {
|
||||||
|
pub async fn send_single(
|
||||||
|
db: &SqlitePool,
|
||||||
|
to: &str,
|
||||||
|
subject: &str,
|
||||||
|
body: String,
|
||||||
|
smtp_pw: &str,
|
||||||
|
) {
|
||||||
|
let mut email = Message::builder()
|
||||||
|
.from(
|
||||||
|
"ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.reply_to(
|
||||||
|
"ASKÖ Ruderverein Donau Linz <info@rudernlinz.at>"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.to("ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
|
||||||
|
.parse()
|
||||||
|
.unwrap());
|
||||||
|
let splitted = to.split(',');
|
||||||
|
for single_rec in splitted {
|
||||||
|
match single_rec.parse() {
|
||||||
|
Ok(new_bcc_mail) => email = email.bcc(new_bcc_mail),
|
||||||
|
Err(_) => {
|
||||||
|
Log::create(
|
||||||
|
db,
|
||||||
|
format!("Mail not sent to {single_rec}, because it could not be parsed"),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let email = email
|
||||||
|
.subject(subject)
|
||||||
|
.header(ContentType::TEXT_PLAIN)
|
||||||
|
.body(body)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let creds = Credentials::new("no-reply@rudernlinz.at".to_owned(), smtp_pw.into());
|
||||||
|
|
||||||
|
let mailer = SmtpTransport::relay("mail.your-server.de")
|
||||||
|
.unwrap()
|
||||||
|
.credentials(creds)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Send the email
|
||||||
|
mailer.send(&email).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn send(db: &SqlitePool, data: MailToSend<'_>, smtp_pw: String) -> bool {
|
pub async fn send(db: &SqlitePool, data: MailToSend<'_>, smtp_pw: String) -> bool {
|
||||||
let mut email = Message::builder()
|
let mut email = Message::builder()
|
||||||
.from(
|
.from(
|
||||||
|
@ -69,6 +69,18 @@ impl Notification {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_for_role(
|
||||||
|
db: &SqlitePool,
|
||||||
|
role: &Role,
|
||||||
|
message: &str,
|
||||||
|
category: &str,
|
||||||
|
link: Option<&str>,
|
||||||
|
) {
|
||||||
|
let mut tx = db.begin().await.unwrap();
|
||||||
|
Self::create_for_role_tx(&mut tx, role, message, category, link).await;
|
||||||
|
tx.commit().await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn for_user(db: &SqlitePool, user: &User) -> Vec<Self> {
|
pub async fn for_user(db: &SqlitePool, user: &User) -> Vec<Self> {
|
||||||
let rows = sqlx::query!(
|
let rows = sqlx::query!(
|
||||||
"
|
"
|
||||||
|
@ -14,7 +14,10 @@ use rocket::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||||
|
|
||||||
use super::{family::Family, log::Log, role::Role, tripdetails::TripDetails, Day};
|
use super::{
|
||||||
|
family::Family, log::Log, mail::Mail, notification::Notification, role::Role,
|
||||||
|
tripdetails::TripDetails, Day,
|
||||||
|
};
|
||||||
use crate::tera::admin::user::UserEditForm;
|
use crate::tera::admin::user::UserEditForm;
|
||||||
|
|
||||||
const RENNRUDERBEITRAG: i32 = 11000;
|
const RENNRUDERBEITRAG: i32 = 11000;
|
||||||
@ -137,6 +140,69 @@ impl Fee {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
|
pub async fn send_welcome_email(&self, db: &SqlitePool, smtp_pw: &str) -> Result<(), String> {
|
||||||
|
if !self.has_role(db, "Donau Linz").await {
|
||||||
|
return Err(format!(
|
||||||
|
"Could not send welcome mail, because user {} is not in Donau Linz group",
|
||||||
|
self.name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(mail) = &self.mail else {
|
||||||
|
return Err(format!(
|
||||||
|
"Could not send welcome mail, because user {} has no email address",
|
||||||
|
self.name
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
Mail::send_single(
|
||||||
|
db,
|
||||||
|
mail,
|
||||||
|
"Willkommen im ASKÖ Ruderverein Donau Linz!",
|
||||||
|
format!(
|
||||||
|
"Hallo {0},
|
||||||
|
|
||||||
|
herzlich willkommen im ASKÖ Ruderverein Donau Linz! Wir freuen uns sehr, dich als neues Mitglied in unserem Verein begrüßen zu dürfen.
|
||||||
|
|
||||||
|
Um dir den Einstieg zu erleichtern, findest du in unserem Handbuch alle wichtigen Informationen über unseren Verein: https://rudernlinz.at/book. Bei weiteren Fragen stehen dir die Adressen info@rudernlinz.at und it@rudernlinz.at jederzeit zur Verfügung.
|
||||||
|
|
||||||
|
Du kannst auch gerne unserer Signal-Gruppe beitreten, um auf dem Laufenden zu bleiben und dich mit anderen Mitgliedern auszutauschen: https://signal.group/#CjQKICFrq6zSsRHxrucS3jEcQn6lknEXacAykwwLV3vNLKxPEhA17jxz7cpjfu3JZokLq1TH
|
||||||
|
|
||||||
|
Für die Organisation unserer Ausfahrten nutzen wir app.rudernlinz.at. Logge dich einfach mit deinem Namen ('{0}' ohne Anführungszeichen) ein, beim ersten Mal kannst du das Passwortfeld leer lassen. Unter 'Geplante Ausfahrten' kannst du dich jederzeit zu den Ausfahrten anmelden.
|
||||||
|
|
||||||
|
Beim nächsten Treffen im Verein, erinnere mich (Philipp Hofer) bitte daran, deinen Fingerabdruck zu registrieren, damit du eigenständig Zugang zum Bootshaus erhältst.
|
||||||
|
|
||||||
|
Wir freuen uns darauf, dich bald am Wasser zu sehen und gemeinsam tolle Erfahrungen zu sammeln!
|
||||||
|
|
||||||
|
Riemen- & Dollenbruch
|
||||||
|
ASKÖ Ruderverein Donau Linz
|
||||||
|
", self.name),
|
||||||
|
smtp_pw,
|
||||||
|
).await;
|
||||||
|
|
||||||
|
Log::create(
|
||||||
|
db,
|
||||||
|
format!("Willkommensemail wurde an {} versandt", self.name),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let coxes = Role::find_by_name(db, "cox").await.unwrap();
|
||||||
|
Notification::create_for_role(
|
||||||
|
db,
|
||||||
|
&coxes,
|
||||||
|
&format!(
|
||||||
|
"Liebe Steuerberechtigte, seit {} gibt es ein neues Mitglied: {}",
|
||||||
|
self.member_since_date.clone().unwrap(),
|
||||||
|
self.name
|
||||||
|
),
|
||||||
|
"Neues Vereinsmitglied",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn fee(&self, db: &SqlitePool) -> Option<Fee> {
|
pub async fn fee(&self, db: &SqlitePool) -> Option<Fee> {
|
||||||
if !self.has_role(db, "Donau Linz").await {
|
if !self.has_role(db, "Donau Linz").await {
|
||||||
return None;
|
return None;
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::model::{
|
use crate::{
|
||||||
family::Family,
|
model::{
|
||||||
log::Log,
|
family::Family,
|
||||||
logbook::Logbook,
|
log::Log,
|
||||||
role::Role,
|
logbook::Logbook,
|
||||||
user::{
|
role::Role,
|
||||||
AdminUser, User, UserWithDetails, UserWithMembershipPdf, UserWithRolesAndMembershipPdf,
|
user::{
|
||||||
VorstandUser,
|
AdminUser, User, UserWithDetails, UserWithMembershipPdf, UserWithRolesAndMembershipPdf,
|
||||||
|
VorstandUser,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
tera::Config,
|
||||||
};
|
};
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
@ -202,6 +205,26 @@ async fn fees_paid(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/user/<user>/send-welcome-mail")]
|
||||||
|
async fn send_welcome_mail(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
_admin: AdminUser,
|
||||||
|
config: &State<Config>,
|
||||||
|
user: i32,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
let Some(user) = User::find_by_id(db, user).await else {
|
||||||
|
return Flash::error(Redirect::to("/admin/user"), "User does not exist");
|
||||||
|
};
|
||||||
|
|
||||||
|
match user.send_welcome_email(db, &config.smtp_pw).await {
|
||||||
|
Ok(()) => Flash::success(
|
||||||
|
Redirect::to("/admin/user"),
|
||||||
|
format!("Willkommens-Email wurde an {} versandt.", user.name),
|
||||||
|
),
|
||||||
|
Err(e) => Flash::error(Redirect::to("/admin/user"), e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/user/<user>/reset-pw")]
|
#[get("/user/<user>/reset-pw")]
|
||||||
async fn resetpw(db: &State<SqlitePool>, _admin: AdminUser, user: i32) -> Flash<Redirect> {
|
async fn resetpw(db: &State<SqlitePool>, _admin: AdminUser, user: i32) -> Flash<Redirect> {
|
||||||
let user = User::find_by_id(db, user).await;
|
let user = User::find_by_id(db, user).await;
|
||||||
@ -332,6 +355,7 @@ pub fn routes() -> Vec<Route> {
|
|||||||
fees,
|
fees,
|
||||||
fees_paid,
|
fees_paid,
|
||||||
scheckbuch,
|
scheckbuch,
|
||||||
download_membership_pdf
|
download_membership_pdf,
|
||||||
|
send_welcome_mail
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,10 @@
|
|||||||
<a class="block mt-1 font-normal text-primary-600 dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline"
|
<a class="block mt-1 font-normal text-primary-600 dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline"
|
||||||
href="/admin/user/{{ user.id }}/reset-pw">Passwort zurücksetzen</a>
|
href="/admin/user/{{ user.id }}/reset-pw">Passwort zurücksetzen</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if not user.last_access and "Donau Linz" in user.roles and "admin" in loggedin_user.roles %}
|
||||||
|
<a class="block mt-1 font-normal text-primary-600 dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline"
|
||||||
|
href="/admin/user/{{ user.id }}/send-welcome-mail">Willkommensmail verschicken</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
||||||
{% for role in roles %}
|
{% for role in roles %}
|
||||||
|
Loading…
Reference in New Issue
Block a user