Feature: Reset password
This commit is contained in:
parent
0b99d8d50f
commit
23595f6d3b
|
@ -2,6 +2,8 @@
|
|||
connection_string = "postgresql://postgres:qwertz@localhost:5432/postgres"
|
||||
|
||||
[application]
|
||||
url = "http://localhost:8000/"
|
||||
name = "einsatz.online"
|
||||
default_language = "de-DE"
|
||||
fallback_language = "en-US"
|
||||
loglevel = "debug"
|
||||
|
@ -11,4 +13,8 @@ upload_path = "uploads/"
|
|||
#Maximum login attempts until email is locked for login
|
||||
max_login_attempts = 6
|
||||
#Duration of email lock after max_login_attempts in seconds. Default is 30 minutes
|
||||
login_lock_duration = 1800
|
||||
login_lock_duration = 1800
|
||||
|
||||
[mail]
|
||||
from = "No Reply <noreply@localhost>"
|
||||
reply_to = "support@localhost"
|
|
@ -0,0 +1,7 @@
|
|||
Jemand hat das Zurücksetzen des Passworts auf {{frontpage}} für die Email
|
||||
{{email}}
|
||||
angefordert.
|
||||
Falls dies nicht beabsichtigt war, ignoriere einfach diese E-Mail. Dein altes Passwort bleibt wirksam.
|
||||
|
||||
Um dein Passwort zurückzusetzen, besuche folgende Adresse:
|
||||
{{reset_url}}
|
|
@ -30,11 +30,11 @@
|
|||
</form>
|
||||
</div>
|
||||
<div class="col">
|
||||
<form>
|
||||
<form method="post" action="/password_reset">
|
||||
<h3>Passwort vergessen?</h3>
|
||||
<div class="form-group">
|
||||
<label for="forgot_password_email">E-Mail Adresse</label>
|
||||
<input type="email" class="form-control" name="forgot_password_email" id="forgot_password_email" required>
|
||||
<label for="email">E-Mail Adresse</label>
|
||||
<input type="email" class="form-control" name="email" id="email" required>
|
||||
</div>
|
||||
<button type="submit" class="login_submit btn btn-secondary">Passwort zurücksetzen</button>
|
||||
</form>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{{> header }}
|
||||
<div class="jumbotron">
|
||||
<div class="row">
|
||||
<div class="col-lq">
|
||||
<h1>Willkommen bei einsatz.online!</h1>
|
||||
</div>
|
||||
{{#if logo_path}}
|
||||
<div class="col">
|
||||
<img class="welcome_logo" src="{{logo_path}}">
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<form method="post">
|
||||
{{#if alert}}
|
||||
{{> alert}}
|
||||
{{/if}}
|
||||
<h3>Neues Passwort festlegen</h3>
|
||||
<p>Ihr Passwort muss mindestens 10 Zeichen lang sein und sollte Buchstaben, Zahlen und Sonderzeichen enthalten.</p>
|
||||
<div class="form-group">
|
||||
<label for="password">Passwort</label>
|
||||
<input type="password" class="form-control" name="password" id="password" required>
|
||||
</div>
|
||||
<button type="submit" class="login_submit btn btn-primary">Passwort ändern</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{> footer }}
|
|
@ -1,11 +1,16 @@
|
|||
use crate::helper::settings::Settings;
|
||||
use rocket::State;
|
||||
use crate::database::controller::connector::establish_connection;
|
||||
use crate::schema::password_resets::dsl::password_resets;
|
||||
use crate::schema::password_resets::dsl::{password_resets};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use diesel::{ExpressionMethods, RunQueryDsl};
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::query_dsl::filter_dsl::FilterDsl;
|
||||
use diesel::query_dsl::select_dsl::SelectDsl;
|
||||
use argon2::Config;
|
||||
use crate::schema::users::dsl::users;
|
||||
use diesel::result::Error;
|
||||
|
||||
/// Adds password reset token to database and returns it
|
||||
pub fn add_token(settings: &State<Settings>, user_id: uuid::Uuid) -> Result<String, diesel::result::Error>{
|
||||
|
@ -25,4 +30,71 @@ pub fn add_token(settings: &State<Settings>, user_id: uuid::Uuid) -> Result<Stri
|
|||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_token(settings: &State<Settings>, token2: String) -> Result<(), diesel::result::Error>{
|
||||
let connection = establish_connection(settings);
|
||||
|
||||
match diesel::delete(password_resets).filter(crate::schema::password_resets::dsl::token.eq(token2)).execute(&connection){
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
error!("Couldn't delete token: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_token(settings: &State<Settings>, token2: String) -> Result<uuid::Uuid, diesel::result::Error>{
|
||||
let connection = establish_connection(settings);
|
||||
|
||||
match password_resets.select(crate::schema::password_resets::dsl::user_id).filter(crate::schema::password_resets::dsl::token.eq(token2)).get_result(&connection){
|
||||
Ok(user_id) => Ok(user_id),
|
||||
Err(e) => match e{
|
||||
diesel::result::Error::NotFound => {
|
||||
return Err(e)
|
||||
},
|
||||
_ => {
|
||||
error!("Couldn't validate token: {}", e);
|
||||
return Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_password_with_token(settings: &State<Settings>, token2: String, password: String) -> Result<(), ()>{
|
||||
let user_id = match validate_token(settings, token2.clone()){
|
||||
Ok(user_id) => user_id,
|
||||
Err(e) => return Err(())
|
||||
};
|
||||
|
||||
let connection =establish_connection(settings);
|
||||
let salt = rand::thread_rng().gen::<[u8; 32]>();
|
||||
let hashed_password = match argon2::hash_encoded(password.as_bytes(), &salt, &Config::default()){
|
||||
Ok(pw) => pw,
|
||||
Err(e) => {
|
||||
error!("Couldn't hash password: {}", e);
|
||||
return Err(())
|
||||
}
|
||||
};
|
||||
|
||||
match diesel::update(users).filter(crate::schema::users::dsl::id.eq(user_id)).set(crate::schema::users::dsl::password.eq(hashed_password)).execute(&connection){
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Couldn't set new password: {}", e);
|
||||
return Err(())
|
||||
}
|
||||
};
|
||||
|
||||
match remove_token(settings, token2){
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_password(password: String) -> bool{
|
||||
if password.len() < 10{
|
||||
return false
|
||||
}
|
||||
|
||||
true
|
||||
}
|
|
@ -84,40 +84,19 @@ impl MailQueue{
|
|||
}
|
||||
}
|
||||
|
||||
pub trait CreateMail<T>{
|
||||
fn new(args : T) -> Mail;
|
||||
}
|
||||
|
||||
impl CreateMail<(String, Vec<String>, String, Vec<String>, Vec<String>, Option<String>, String, Option<NaiveDateTime>)> for Mail{
|
||||
impl Mail{
|
||||
/// Create Mail with from, to, subject, cc, bcc, reply_to, deliver_until
|
||||
fn new(args: (String, Vec<String>, String, Vec<String>, Vec<String>, Option<String>, String, Option<NaiveDateTime>)) -> Mail {
|
||||
pub(crate) fn new(from: String, to: Vec<String>, subject: String, cc: Vec<String>, bcc: Vec<String>, reply_to: Option<String>, body: String, deliver_until: Option<NaiveDateTime>) -> Mail {
|
||||
Mail{
|
||||
uuid: uuid::Uuid::new_v4(),
|
||||
from: args.0,
|
||||
to: args.1,
|
||||
subject: args.2,
|
||||
cc: args.3,
|
||||
bcc: args.4,
|
||||
reply_to: args.5,
|
||||
body: args.6,
|
||||
deliver_until: args.7
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CreateMail<(String, Vec<String>, String, Option<String>, String)> for Mail{
|
||||
/// Create Mail with from, to, subject, reply_to
|
||||
fn new(args: (String, Vec<String>, String, Option<String>, String)) -> Mail {
|
||||
Mail{
|
||||
uuid: uuid::Uuid::new_v4(),
|
||||
from: args.0,
|
||||
to: args.1,
|
||||
subject: args.2,
|
||||
cc: vec![],
|
||||
bcc: vec![],
|
||||
reply_to: args.3,
|
||||
body: args.4,
|
||||
deliver_until: None
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
cc,
|
||||
bcc,
|
||||
reply_to,
|
||||
body,
|
||||
deliver_until
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,12 @@ pub fn send_mail(mail: Mail) -> Result<(), ()> {
|
|||
}
|
||||
arg.push_str("' ")
|
||||
}
|
||||
match mail.reply_to{
|
||||
Some(reply_to) => {
|
||||
arg.push_str(&format!("--append='Reply-To: {} ' ", reply_to))
|
||||
},
|
||||
None => ()
|
||||
}
|
||||
arg.push_str("-s \"");
|
||||
arg.push_str(&subject);
|
||||
arg.push_str("\" ");
|
||||
|
@ -38,15 +44,12 @@ pub fn send_mail(mail: Mail) -> Result<(), ()> {
|
|||
arg.push_str(&(receiver+" "));
|
||||
}
|
||||
|
||||
debug!("Trying to send mail: {}", arg);
|
||||
|
||||
match Command::new("sh").arg("-c").arg(arg).output(){
|
||||
Ok(output) => {
|
||||
if !output.status.success(){
|
||||
error!("Couldn't send mail: {} {} {}", output.status, String::from_utf8_lossy(&output.stderr), String::from_utf8_lossy(&output.stdout));
|
||||
Err(())
|
||||
}else {
|
||||
debug!("Mail sent: {}", String::from_utf8_lossy(&output.stdout));
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
use rocket_contrib::templates::handlebars::Handlebars;
|
||||
|
||||
pub struct MailTemplates{
|
||||
pub registry: Handlebars,
|
||||
}
|
|
@ -11,4 +11,5 @@ pub mod settings;
|
|||
pub mod sitebuilder;
|
||||
pub mod translate_diesel_error;
|
||||
pub mod user_request_guard;
|
||||
pub mod mail_queue;
|
||||
pub mod mail_queue;
|
||||
pub mod mail_templates;
|
|
@ -8,6 +8,7 @@ pub struct Database {
|
|||
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
pub struct Application {
|
||||
pub url: String,
|
||||
pub default_language: String,
|
||||
pub fallback_language: String,
|
||||
pub loglevel: String,
|
||||
|
@ -15,12 +16,20 @@ pub struct Application {
|
|||
pub upload_path: String,
|
||||
pub max_login_attempts: i32,
|
||||
pub login_lock_duration: i32,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
pub struct Mail{
|
||||
pub from : String,
|
||||
pub reply_to : String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
pub struct Settings {
|
||||
pub database: Database,
|
||||
pub application: Application,
|
||||
pub mail: Mail
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -25,6 +25,8 @@ use chrono::{DateTime, Utc};
|
|||
use crate::helper::mail_queue::queue::{MailQueue, Mail};
|
||||
use std::sync::{PoisonError, RwLockWriteGuard, Arc};
|
||||
use std::collections::VecDeque;
|
||||
use rocket_contrib::templates::handlebars::{Handlebars, TemplateFileError};
|
||||
use crate::helper::mail_templates::MailTemplates;
|
||||
|
||||
pub mod database;
|
||||
pub mod helper;
|
||||
|
@ -43,27 +45,38 @@ fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
// Initialize storage for session cookies
|
||||
let cookie_storage = SessionCookieStorage::new();
|
||||
|
||||
debug!(
|
||||
"Hello, world! Default Language: {}",
|
||||
settings.application.default_language
|
||||
);
|
||||
|
||||
// Initialize mail queue for second thread handling outgoing mails
|
||||
// We are using Arc to access mail queue in all threads
|
||||
let mail_queue = Arc::new(MailQueue::load_or_create_new());
|
||||
let c_lock = Arc::clone(&mail_queue);
|
||||
|
||||
thread::spawn(move ||{
|
||||
loop {
|
||||
c_lock.process_next();
|
||||
thread::sleep(time::Duration::from_millis(500))
|
||||
match c_lock.process_next(){
|
||||
Ok(_) => {}
|
||||
Err(e) => {error!("MailQueue poisoned: {}", e)}
|
||||
}
|
||||
thread::sleep(time::Duration::from_millis(500)) // Only check for new mails ever 500 ms
|
||||
}
|
||||
});
|
||||
|
||||
let mut mail_templates = MailTemplates{ registry: Handlebars::new() };
|
||||
match mail_templates.registry.register_templates_directory(".hbs", "resources/mail_templates"){
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("Couldn't register mail templates: {}",e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
rocket::ignite()
|
||||
.manage(settings)
|
||||
.manage(cookie_storage)
|
||||
.manage(mail_queue)
|
||||
.manage(mail_templates)
|
||||
.register(catchers![helper::server_errors::unauthorized, helper::server_errors::forbidden, helper::server_errors::notfound, helper::server_errors::notimplemented])
|
||||
.mount(
|
||||
"/",
|
||||
|
@ -71,6 +84,9 @@ fn main() {
|
|||
modules::dashboard::view::dashboard,
|
||||
modules::welcome::view::welcome_get::welcome_get,
|
||||
modules::welcome::view::welcome_post::welcome_post,
|
||||
modules::welcome::view::welcome_post::password_reset_post,
|
||||
modules::welcome::view::welcome_post::password_change_post,
|
||||
modules::welcome::view::welcome_post::password_change_get,
|
||||
modules::welcome::view::login_select_get::login_select_get,
|
||||
modules::welcome::view::logout::logout_get,
|
||||
modules::member_management::view::selection_get::member_management_selection_get,
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
pub mod login;
|
||||
pub mod render;
|
||||
pub mod password_reset;
|
|
@ -0,0 +1,42 @@
|
|||
use crate::helper::settings::Settings;
|
||||
use rocket::State;
|
||||
use crate::database::controller::users::get_user_by_email;
|
||||
use crate::database::controller::password_resets::add_token;
|
||||
use crate::helper::mail_templates::MailTemplates;
|
||||
use crate::helper::mail_queue::queue::{Mail, MailQueue};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct PasswortResetMail{
|
||||
frontpage: String,
|
||||
email: String,
|
||||
reset_url: String,
|
||||
}
|
||||
|
||||
/// Checks if email belongs to user, if so resets password
|
||||
pub fn request_password_reset(settings: &State<Settings>, mt: &State<MailTemplates>, mq: State<Arc<MailQueue>>, email: String) -> Result<(), ()>{
|
||||
let user = match get_user_by_email(email.clone(), settings){ //Check if email belongs to user, if not return
|
||||
Some(user) => user,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
let token = match add_token(settings, user.id){
|
||||
Ok(token) => token,
|
||||
Err(e) => return Err(()),
|
||||
};
|
||||
let pwrm = PasswortResetMail{
|
||||
frontpage: settings.application.url.clone(),
|
||||
email: email.clone(),
|
||||
reset_url: format!("{}password_reset?token={}", settings.application.url.clone(), token)
|
||||
};
|
||||
let body = match mt.registry.render("password-reset-de", &pwrm){
|
||||
Ok(body) => body,
|
||||
Err(e) => return Err(()),
|
||||
};
|
||||
let mail = Mail::new(settings.mail.from.clone(), vec![email], format!("[{}] - Passwort Zurücksetzen", settings.application.name.clone()), vec![], vec![], Some(settings.mail.reply_to.clone()), body, None); //TODO: Add deliver_until
|
||||
|
||||
match mq.add_mail(mail){
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(())
|
||||
}
|
||||
}
|
|
@ -4,8 +4,8 @@ use crate::modules::welcome::model::welcome_module::WelcomeModule;
|
|||
|
||||
pub fn get_context(alert: Option<Alert>) -> WelcomeModule {
|
||||
let header = Header {
|
||||
html_language: "en".to_string(),
|
||||
site_title: "ERRMS".to_string(),
|
||||
html_language: "de".to_string(),
|
||||
site_title: "einsatz.online".to_string(),
|
||||
stylesheets: vec![Stylesheet {
|
||||
path: "/css/errms.css".to_string(),
|
||||
}],
|
||||
|
|
|
@ -2,13 +2,11 @@ use crate::helper::sitebuilder::model::alerts::{Alert, AlertClass};
|
|||
use crate::modules::welcome::controller::render::get_context;
|
||||
use rocket::http::Status;
|
||||
use rocket_contrib::templates::Template;
|
||||
use crate::helper::mail_queue::queue::{MailQueue, Mail, CreateMail};
|
||||
use rocket::State;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[get("/?<error>")]
|
||||
pub fn welcome_get(error: Option<String>, mail_queue: State<Arc<MailQueue>>) -> Result<Template, Status> {
|
||||
mail_queue.add_mail(Mail::new(("noreply@mgs.einsatz.online".to_string(), vec!["ares@anghenfil.de".to_string()], "Test.".to_string(), None, "Das ist eine Testnachricht! \"Zitat\"".to_string())));
|
||||
pub fn welcome_get(error: Option<String>) -> Result<Template, Status> {
|
||||
let alert = match error {
|
||||
Some(error) => match error.as_str() {
|
||||
"unauthorized" => Some(Alert::new(
|
||||
|
@ -19,6 +17,11 @@ pub fn welcome_get(error: Option<String>, mail_queue: State<Arc<MailQueue>>) ->
|
|||
AlertClass::Success,
|
||||
"Sie wurden erfolgreich abgemeldet!".to_string(),
|
||||
)),
|
||||
"password_reset_success" => Some(Alert::new(
|
||||
AlertClass::Success,
|
||||
"Ihr Passwort wurde erfolgreich zurückgesetzt!".to_string(),
|
||||
)),
|
||||
"password_reset_token_invalid" => Some(Alert::new(AlertClass::Danger, "Der Passwort zurücksetzen Token ist ungültig! Bitte einen neuen Anfordern!".to_string())),
|
||||
"notimplemented" => Some(Alert::new(
|
||||
AlertClass::Danger,
|
||||
"Fehler: Diese Funktion wurde noch nicht implementiert!".to_string(),
|
||||
|
|
|
@ -10,6 +10,12 @@ use rocket::response::Redirect;
|
|||
use rocket::State;
|
||||
use rocket_contrib::templates::Template;
|
||||
use crate::modules::welcome::model::login_error_type::LoginError;
|
||||
use crate::modules::welcome::controller::password_reset::request_password_reset;
|
||||
use crate::helper::mail_templates::MailTemplates;
|
||||
use crate::helper::mail_queue::queue::MailQueue;
|
||||
use std::sync::Arc;
|
||||
use crate::helper::sitebuilder::model::general::{Footer, Header, Stylesheet};
|
||||
use crate::database::controller::password_resets::{validate_token, change_password_with_token, validate_password};
|
||||
|
||||
#[post("/", data = "<login_form>")]
|
||||
pub fn welcome_post(
|
||||
|
@ -56,3 +62,113 @@ pub fn welcome_post(
|
|||
|
||||
Err(Template::render("module_welcome", &get_context(alert)))
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, FromForm)]
|
||||
pub struct PasswordResetForm{
|
||||
pub(crate) email: String,
|
||||
}
|
||||
|
||||
#[post("/password_reset", data = "<password_reset_form>")]
|
||||
pub fn password_reset_post(
|
||||
password_reset_form: Form<PasswordResetForm>,
|
||||
settings: State<Settings>,
|
||||
mt: State<MailTemplates>,
|
||||
mq: State<Arc<MailQueue>>,
|
||||
) -> Template {
|
||||
let mut alert : Option<Alert> = None;
|
||||
|
||||
match request_password_reset(&settings, &mt, mq, password_reset_form.email.clone()){
|
||||
Ok(_) => {
|
||||
alert = Some(Alert::new(
|
||||
AlertClass::Success,
|
||||
"Falls ein Benutzer mit der angegebenen Email existiert wurde ein Link zum Zurücksetzen des Passwortes per Email verschickt!".to_string()))
|
||||
}
|
||||
Err(_) => {
|
||||
alert = Some(Alert::new(
|
||||
AlertClass::Danger,
|
||||
"Das Passwort konnte nicht zurückgesetzt werden. Bitte versuchen Sie es später erneut.".to_string()))
|
||||
|
||||
}
|
||||
}
|
||||
Template::render("module_welcome", &get_context(alert))
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct PasswordResetPage{
|
||||
header: Header,
|
||||
footer: Footer,
|
||||
logo_path: String,
|
||||
alert: Option<Alert>,
|
||||
}
|
||||
|
||||
#[get("/password_reset?<token>")]
|
||||
pub fn password_change_get(
|
||||
settings: State<Settings>,
|
||||
token: String,
|
||||
) -> Result<Template, Redirect> {
|
||||
match validate_token(&settings, token){
|
||||
Ok(_) => (),
|
||||
Err(_) => {
|
||||
return Err(Redirect::to("/?error=password_reset_token_invalid"))
|
||||
}
|
||||
}
|
||||
let header = Header {
|
||||
html_language: "de".to_string(),
|
||||
site_title: "einsatz.online".to_string(),
|
||||
stylesheets: vec![Stylesheet {
|
||||
path: "/css/errms.css".to_string(),
|
||||
}],
|
||||
};
|
||||
let footer = Footer { scripts: vec![] };
|
||||
let render = PasswordResetPage{
|
||||
header,
|
||||
footer,
|
||||
logo_path: "/img/logo.jpg".to_string(),
|
||||
alert: None
|
||||
};
|
||||
|
||||
Ok(Template::render("password_reset", &render))
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, FromForm)]
|
||||
pub struct PasswordChangeForm{
|
||||
pub(crate) password: String,
|
||||
}
|
||||
|
||||
#[post("/password_reset?1<token>", data = "<password_change_form>")]
|
||||
pub fn password_change_post(
|
||||
settings: State<Settings>,
|
||||
password_change_form: Form<PasswordChangeForm>,
|
||||
token: String,
|
||||
) -> Result<Redirect, Template> {
|
||||
let mut alert = None;
|
||||
let password_change_form = password_change_form.into_inner();
|
||||
if !validate_password(password_change_form.password.clone()){
|
||||
alert = Some(Alert::new(AlertClass::Danger, "Das Passwort muss mindestens 10 Zeichen lang sein!".to_string()));
|
||||
}else {
|
||||
match change_password_with_token(&settings, token, password_change_form.password) {
|
||||
Ok(_) => {
|
||||
return Ok(Redirect::to("/?error=password_reset_success"))
|
||||
},
|
||||
Err(_) => {
|
||||
alert = Some(Alert::new(AlertClass::Danger, "Es ist ein interner Fehler aufgetreten, das Passwort konnte nicht geändert werden.".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
let header = Header {
|
||||
html_language: "de".to_string(),
|
||||
site_title: "einsatz.online".to_string(),
|
||||
stylesheets: vec![Stylesheet {
|
||||
path: "/css/errms.css".to_string(),
|
||||
}],
|
||||
};
|
||||
let footer = Footer { scripts: vec![] };
|
||||
let render = PasswordResetPage{
|
||||
header,
|
||||
footer,
|
||||
logo_path: "/img/logo.jpg".to_string(),
|
||||
alert,
|
||||
};
|
||||
|
||||
Err(Template::render("password_reset", &render))
|
||||
}
|
Loading…
Reference in New Issue