Merge pull request 'welcome-mail' (#490) from welcome-mail into main
Reviewed-on: #490
This commit is contained in:
commit
d9aa7cafe1
@ -14,6 +14,58 @@ use super::{family::Family, log::Log, role::Role, user::User};
|
||||
pub struct 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 {
|
||||
let mut email = Message::builder()
|
||||
.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> {
|
||||
let rows = sqlx::query!(
|
||||
"
|
||||
|
@ -14,7 +14,10 @@ use rocket::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
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;
|
||||
|
||||
const RENNRUDERBEITRAG: i32 = 11000;
|
||||
@ -137,6 +140,69 @@ impl Fee {
|
||||
}
|
||||
|
||||
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> {
|
||||
if !self.has_role(db, "Donau Linz").await {
|
||||
return None;
|
||||
|
@ -1,14 +1,17 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::model::{
|
||||
family::Family,
|
||||
log::Log,
|
||||
logbook::Logbook,
|
||||
role::Role,
|
||||
user::{
|
||||
AdminUser, User, UserWithDetails, UserWithMembershipPdf, UserWithRolesAndMembershipPdf,
|
||||
VorstandUser,
|
||||
use crate::{
|
||||
model::{
|
||||
family::Family,
|
||||
log::Log,
|
||||
logbook::Logbook,
|
||||
role::Role,
|
||||
user::{
|
||||
AdminUser, User, UserWithDetails, UserWithMembershipPdf, UserWithRolesAndMembershipPdf,
|
||||
VorstandUser,
|
||||
},
|
||||
},
|
||||
tera::Config,
|
||||
};
|
||||
use futures::future::join_all;
|
||||
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")]
|
||||
async fn resetpw(db: &State<SqlitePool>, _admin: AdminUser, user: i32) -> Flash<Redirect> {
|
||||
let user = User::find_by_id(db, user).await;
|
||||
@ -332,6 +355,7 @@ pub fn routes() -> Vec<Route> {
|
||||
fees,
|
||||
fees_paid,
|
||||
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"
|
||||
href="/admin/user/{{ user.id }}/reset-pw">Passwort zurücksetzen</a>
|
||||
{% 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 class="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
||||
{% for role in roles %}
|
||||
|
Loading…
Reference in New Issue
Block a user