register form fields

This commit is contained in:
Priec
2026-06-19 11:14:47 +02:00
parent 11762728c9
commit e70743996b
2 changed files with 51 additions and 10 deletions

View File

@@ -22,6 +22,10 @@
{% if error == "exists" %} {% if error == "exists" %}
{{ ui::alert_danger(message=t(key="register-error-exists", lang=lang | default(value='sk')), extra="mt-3") }} {{ ui::alert_danger(message=t(key="register-error-exists", lang=lang | default(value='sk')), extra="mt-3") }}
{% elif error == "mismatch" %}
{{ ui::alert_danger(message=t(key="set-password-mismatch", lang=lang | default(value='sk')), extra="mt-3") }}
{% elif error == "weak" %}
{{ ui::alert_danger(message=t(key="set-password-weak", lang=lang | default(value='sk')), extra="mt-3") }}
{% elif error %} {% elif error %}
{{ ui::alert_danger(message=t(key="register-error-invalid", lang=lang | default(value='sk')), extra="mt-3") }} {{ ui::alert_danger(message=t(key="register-error-invalid", lang=lang | default(value='sk')), extra="mt-3") }}
{% endif %} {% endif %}
@@ -42,20 +46,12 @@
<span class="text-xs text-on-surface/60 dark:text-on-surface-dark/60">{{ t(key="account-type-locked", lang=lang | default(value='sk')) }}</span> <span class="text-xs text-on-surface/60 dark:text-on-surface-dark/60">{{ t(key="account-type-locked", lang=lang | default(value='sk')) }}</span>
</div> </div>
<div class="flex flex-col gap-1">
<label for="name"
class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">
{{ t(key="register-name", lang=lang | default(value='sk')) }}
</label>
{{ ui::input(name="name", id="name", required=true, autocomplete="name", attrs="autofocus") }}
</div>
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<label for="email" <label for="email"
class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong"> class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">
{{ t(key="login-email", lang=lang | default(value='sk')) }} {{ t(key="login-email", lang=lang | default(value='sk')) }}
</label> </label>
{{ ui::input(name="email", id="email", type="email", required=true, autocomplete="email") }} {{ ui::input(name="email", id="email", type="email", required=true, autocomplete="email", attrs="autofocus") }}
</div> </div>
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
@@ -66,6 +62,14 @@
{{ ui::input(name="password", id="password", type="password", required=true, autocomplete="new-password") }} {{ ui::input(name="password", id="password", type="password", required=true, autocomplete="new-password") }}
</div> </div>
<div class="flex flex-col gap-1">
<label for="password_confirm"
class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">
{{ t(key="set-password-confirm", lang=lang | default(value='sk')) }}
</label>
{{ ui::input(name="password_confirm", id="password_confirm", type="password", required=true, autocomplete="new-password") }}
</div>
{{ ui::button(label=t(key="register-submit", lang=lang | default(value='sk')), type="submit", extra="mt-1 w-full") }} {{ ui::button(label=t(key="register-submit", lang=lang | default(value='sk')), type="submit", extra="mt-1 w-full") }}
</form> </form>

View File

@@ -106,13 +106,50 @@ async fn register_page(
register_view(&v, &jar, None) register_view(&v, &jar, None)
} }
/// Registration form. The name is no longer collected from the user — it is
/// derived from the email — and the password is entered twice to guard against
/// typos.
#[derive(Debug, serde::Deserialize)]
struct RegisterForm {
email: String,
password: String,
password_confirm: String,
#[serde(default)]
account_type: Option<String>,
}
/// Derive a display name from an email address (its local part), falling back to
/// the full address when the local part is too short for the name validator.
fn name_from_email(email: &str) -> String {
let local = email.split('@').next().unwrap_or("").trim();
if local.chars().count() >= 2 {
local.to_string()
} else {
email.trim().to_string()
}
}
#[debug_handler] #[debug_handler]
async fn register( async fn register(
jar: CookieJar, jar: CookieJar,
ViewEngine(v): ViewEngine<TeraView>, ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>, State(ctx): State<AppContext>,
Form(params): Form<RegisterParams>, Form(form): Form<RegisterForm>,
) -> Result<Response> { ) -> Result<Response> {
if form.password != form.password_confirm {
return register_view(&v, &jar, Some("mismatch"));
}
if form.password.len() < 8 {
return register_view(&v, &jar, Some("weak"));
}
let params = RegisterParams {
name: name_from_email(&form.email),
email: form.email,
password: form.password,
account_type: form.account_type,
};
let user = match users::Model::create_with_password(&ctx.db, &params).await { let user = match users::Model::create_with_password(&ctx.db, &params).await {
Ok(user) => user, Ok(user) => user,
Err(ModelError::EntityAlreadyExists {}) => { Err(ModelError::EntityAlreadyExists {}) => {