account type is permanent and password registration is now working at checkout
Some checks failed
CI / Check Style (push) Has been cancelled
CI / Run Clippy (push) Has been cancelled
CI / Run Tests (push) Has been cancelled

This commit is contained in:
Priec
2026-06-18 22:10:17 +02:00
parent 46cc2459bd
commit f3daa27ce7
24 changed files with 483 additions and 103 deletions

View File

@@ -185,6 +185,71 @@ fn verified_view(v: &TeraView, jar: &CookieJar, ok: bool) -> Result<Response> {
)
}
/// Set-password form for accounts created during checkout (and any account that
/// has a valid reset token). Reuses the password-reset token machinery.
#[derive(Debug, serde::Deserialize)]
struct SetPasswordForm {
token: String,
password: String,
password_confirm: String,
}
fn set_password_view(
v: &TeraView,
jar: &CookieJar,
token: &str,
valid: bool,
error: Option<&str>,
) -> Result<Response> {
format::view(
v,
"auth/set_password.html",
json!({
"token": token,
"valid": valid,
"error": error,
"logged_in_admin": false,
"lang": current_lang(jar),
}),
)
}
#[debug_handler]
async fn set_password_page(
jar: CookieJar,
ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>,
Path(token): Path<String>,
) -> Result<Response> {
let valid = users::Model::find_by_reset_token(&ctx.db, &token).await.is_ok();
set_password_view(&v, &jar, &token, valid, None)
}
#[debug_handler]
async fn set_password(
jar: CookieJar,
ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>,
Form(form): Form<SetPasswordForm>,
) -> Result<Response> {
let Ok(user) = users::Model::find_by_reset_token(&ctx.db, &form.token).await else {
return set_password_view(&v, &jar, &form.token, false, None);
};
if form.password != form.password_confirm {
return set_password_view(&v, &jar, &form.token, true, Some("mismatch"));
}
if form.password.len() < 8 {
return set_password_view(&v, &jar, &form.token, true, Some("weak"));
}
// Setting the password through an emailed link also proves email ownership,
// so the account is marked verified here.
let user = user.into_active_model().reset_password(&ctx.db, &form.password).await?;
if user.email_verified_at.is_none() {
user.into_active_model().verified(&ctx.db).await?;
}
format::redirect("/login")
}
#[debug_handler]
async fn logout() -> Result<Response> {
format::render()
@@ -211,6 +276,8 @@ pub fn routes() -> Routes {
.add("/register", get(register_page))
.add("/register", post(register))
.add("/verify/{token}", get(verify))
.add("/set-password/{token}", get(set_password_page))
.add("/set-password", post(set_password))
.add("/logout", post(logout))
.add("/admin", get(admin_entry))
}