refactor: login-related page templates structure (#6769)

#### What type of PR is this?

/area core
/kind improvement
/milestone 2.20.x

#### What this PR does / why we need it:

Fixes https://github.com/halo-dev/halo/issues/6760

重构登录、注册、找回密码、两步验证等模板的结构,提供更好的复用性,现在主题可以这样复用模板:

login.html

```html
<form th:replace="~{gateway_modules/form_fragments::login}"></form>
```

signup.html

```html
<form th:replace="~{gateway_modules/form_fragments::signup}"></form>
```

challenges/two-factor/totp.html

```html
<form th:replace="~{gateway_modules/form_fragments::totp}"></form>
```

#### Special notes for your reviewer:

需要测试各个页面是否功能正常

#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/6771/head^2
Ryan Wang 2024-10-07 17:28:51 +08:00 committed by GitHub
parent 04e195f034
commit 709884212a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 466 additions and 502 deletions

View File

@ -8,35 +8,7 @@
<div th:replace="~{gateway_modules/common_fragments::haloLogo}"></div>
<div class="halo-form-wrapper">
<h1 class="form-title" th:text="#{title}"></h1>
<form
class="halo-form"
th:action="@{/challenges/two-factor/totp}"
name="two-factor-form"
id="two-factor-form"
method="post"
>
<div class="alert alert-error" role="alert" th:if="${param.error.size() > 0}">
<strong th:text="#{messages.invalidError}"></strong>
</div>
<div class="form-item">
<label for="code" th:text="#{form.code.label}"></label>
<div class="form-input">
<input
type="text"
inputmode="numeric"
id="code"
name="code"
autocomplete="one-time-code"
pattern="\d{6}"
autofocus
required
/>
</div>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.submit}"></button>
</div>
</form>
<form th:replace="~{gateway_modules/form_fragments::totp}"></form>
</div>
</div>
</th:block>

View File

@ -1,4 +1 @@
title=两步验证
messages.invalidError=错误的验证码
form.code.label=验证码
form.submit=验证

View File

@ -1,4 +1 @@
title=Two-Factor Authentication
messages.invalidError=Invalid TOTP code
form.code.label=TOTP Code
form.submit=Verify

View File

@ -1,4 +1 @@
title=Autenticación en Dos Pasos
messages.invalidError=Código de verificación incorrecto
form.code.label=Código de Verificación
form.submit=Verificar

View File

@ -1,4 +1 @@
title=兩步驗證
messages.invalidError=錯誤的驗證碼
form.code.label=驗證碼
form.submit=驗證

View File

@ -1,7 +1,9 @@
<th:block th:fragment="basicStaticResources">
<link rel="stylesheet" href="/webjars/normalize.css/8.0.1/normalize.css" />
<link rel="stylesheet" th:href="|/styles/main.css?v=${site.version}|" />
<th:block th:replace="~{gateway_modules/common_fragments::basicStyleResources}"></th:block>
<th:block th:replace="~{gateway_modules/common_fragments::basicScriptResources}"></th:block>
</th:block>
<th:block th:fragment="basicScriptResources">
<script th:inline="javascript">
const i18nResources = {
sendVerificationCodeSuccess: `[(#{js.sendVerificationCode.success})]`,
@ -12,6 +14,11 @@
<script src="/js/main.js"></script>
</th:block>
<th:block th:fragment="basicStyleResources">
<link rel="stylesheet" href="/webjars/normalize.css/8.0.1/normalize.css" />
<link rel="stylesheet" th:href="|/styles/main.css?v=${site.version}|" />
</th:block>
<div th:remove="tag" th:fragment="languageSwitcher">
<style>
.language-switcher {
@ -111,4 +118,4 @@
</li>
</ul>
</th:block>
</div>
</div>

View File

@ -0,0 +1,291 @@
<form
th:fragment="login"
class="halo-form"
name="login-form"
id="login-form"
th:action="${authProvider.spec.authenticationUrl}"
th:method="${authProvider.spec.method}"
>
<div class="alert alert-error" role="alert" th:if="${param.error.size() > 0}" th:with="error = ${param.error[0]}">
<strong th:if="${error == 'invalid-credential'}">
<span th:text="#{form.login.error.invalidCredential}"></span>
</strong>
<strong th:if="${error == 'rate-limit-exceeded'}">
<span th:text="#{form.login.error.rateLimitExceeded}"></span>
</strong>
</div>
<div class="alert" role="alert" th:if="${param.logout.size() > 0}">
<strong th:text="#{form.login.messages.logoutSuccess}"></strong>
</div>
<div class="alert" role="alert" th:if="${param.signup.size() > 0}">
<strong th:text="#{form.login.messages.signupSuccess}"></strong>
</div>
<div class="alert" role="alert" th:if="${param.oauth2_bind.size() > 0}">
<strong th:text="#{form.login.messages.oauth2Bind}"></strong>
</div>
<div th:replace="~{__${fragmentTemplateName}__::form}"></div>
<div th:if="${authProvider.spec.rememberMeSupport}" class="form-item-compact">
<input type="checkbox" id="remember-me" name="remember-me" value="true" />
<label for="remember-me" th:text="#{form.login.rememberMe.label}"></label>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.login.submit}"></button>
</div>
</form>
<form
th:fragment="signup"
class="halo-form"
name="signup-form"
id="signup-form"
th:action="@{/signup}"
th:object="${form}"
method="post"
>
<div class="alert alert-error" role="alert" th:if="${error == 'invalid-email-code'}">
<strong>
<span th:text="#{form.signup.error.invalidEmailCode}"></span>
</strong>
</div>
<div class="alert alert-error" role="alert" th:if="${error == 'rate-limit-exceeded'}">
<strong>
<span th:text="#{form.signup.error.rateLimitExceeded}"></span>
</strong>
</div>
<div class="alert alert-error" role="alert" th:if="${error == 'duplicate-name'}">
<strong>
<span th:text="#{form.signup.error.duplicateName}"></span>
</strong>
</div>
<div class="form-item-group">
<div class="form-item">
<label for="username" th:text="#{form.signup.username.label}"></label>
<div class="form-input">
<input
type="text"
id="username"
name="username"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
autofocus
required
th:field="*{username}"
/>
</div>
<p class="alert alert-error" th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></p>
</div>
<div class="form-item">
<label for="displayName" th:text="#{form.signup.displayName.label}"></label>
<div class="form-input">
<input
type="text"
id="displayName"
name="displayName"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
required
th:field="*{displayName}"
/>
</div>
<p class="alert alert-error" th:if="${#fields.hasErrors('displayName')}" th:errors="*{displayName}"></p>
</div>
</div>
<div class="form-item-group">
<div class="form-item">
<label for="email" th:text="#{form.signup.email.label}"></label>
<div class="form-input">
<input
type="email"
id="email"
name="email"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
required
th:field="*{email}"
/>
</div>
<p class="alert alert-error" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p>
</div>
<div class="form-item" th:if="${globalInfo.mustVerifyEmailOnRegistration}">
<label for="emailCode" th:text="#{form.signup.emailCode.label}"></label>
<div class="form-input-group">
<div class="form-input">
<input type="text" inputmode="numeric" pattern="\d*" id="emailCode" name="emailCode" required />
</div>
<button id="emailCodeSendButton" type="button" th:text="#{form.signup.emailCode.sendButton}"></button>
</div>
<p class="alert alert-error" th:if="${#fields.hasErrors('emailCode')}" th:errors="*{emailCode}"></p>
</div>
</div>
<div class="form-item">
<label for="password" th:text="#{form.signup.password.label}"></label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'password', name = 'password', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
<p class="alert alert-error" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></p>
</div>
<div class="form-item">
<label for="confirmPassword" th:text="#{form.signup.confirmPassword.label}"></label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'confirmPassword', name = 'confirmPassword', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
<p class="alert alert-error" th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}"></p>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.signup.submit}"></button>
</div>
<script th:inline="javascript">
document.addEventListener("DOMContentLoaded", function () {
function sendRequest() {
return new Promise((resolve, reject) => {
const email = document.getElementById("email").value;
if (!email) {
throw new Error(/*[[#{form.signup.emailCode.send.emptyValidation}]]*/);
}
fetch("/signup/send-email-code", {
method: "POST",
body: JSON.stringify({ email: email }),
headers: {
"Content-Type": "application/json",
[[${_csrf.headerName}]]: [[${_csrf.token}]],
},
})
.then((response) => {
if (response.ok) {
resolve(response);
}
reject(response);
})
.catch((e) => {
reject(e);
});
});
}
const emailCodeSendButton = document.getElementById("emailCodeSendButton");
sendVerificationCode(emailCodeSendButton, sendRequest);
var password = document.getElementById("password"),
confirm_password = document.getElementById("confirmPassword");
function validatePassword() {
if (password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
} else {
confirm_password.setCustomValidity("");
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
});
</script>
</form>
<form
th:fragment="totp"
class="halo-form"
th:action="@{/challenges/two-factor/totp}"
name="two-factor-form"
id="two-factor-form"
method="post"
>
<div class="alert alert-error" role="alert" th:if="${param.error.size() > 0}">
<strong th:text="#{form.totp.messages.invalidError}"></strong>
</div>
<div class="form-item">
<label for="code" th:text="#{form.totp.code.label}"></label>
<div class="form-input">
<input
type="text"
inputmode="numeric"
id="code"
name="code"
autocomplete="one-time-code"
pattern="\d{6}"
autofocus
required
/>
</div>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.totp.submit}"></button>
</div>
</form>
<form th:fragment="logout" class="halo-form" id="logout-form" name="logout-form" th:action="@{/logout}" method="post">
<div class="form-item">
<button type="submit" th:text="#{form.logout.submit}"></button>
</div>
</form>
<form
th:fragment="passwordResetLink"
class="halo-form"
th:action="@{/password-reset/{resetToken}(resetToken=${resetToken})}"
method="post"
>
<p style="color: red" role="alert" th:if="${error}" th:text="${error}"></p>
<div class="form-item">
<label for="password" th:text="#{form.passwordResetLink.password.label}">Password</label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'password', name = 'password', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
</div>
<div class="form-item">
<label for="confirmPassword" th:text="#{form.passwordResetLink.confirmPassword.label}">Confirm Password</label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'confirmPassword', name = 'confirmPassword', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
</div>
<div class="form-item">
<div class="alert" th:text="#{form.passwordResetLink.password.tips}"></div>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.passwordResetLink.submit}"></button>
</div>
</form>
<th:block th:fragment="passwordReset">
<form th:if="${sent}" method="get" action="/login" class="halo-form">
<div class="form-item">
<div class="alert" th:text="#{form.passwordReset.message.success}"></div>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.passwordReset.sent.submit}"></button>
</div>
</form>
<form th:unless="${sent}" class="halo-form" th:action="@{/password-reset}" method="post">
<div class="alert alert-error" th:if="${error}">
<strong th:text="${error}"></strong>
</div>
<div class="form-item">
<label for="email" th:text="#{form.passwordReset.email.label}"></label>
<div class="form-input">
<input type="email" id="email" name="email" autofocus required />
</div>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.passwordReset.submit}"></button>
</div>
</form>
</th:block>

View File

@ -0,0 +1,36 @@
form.login.messages.logoutSuccess=登出成功。
form.login.messages.signupSuccess=恭喜!注册成功,请立即登录。
form.login.messages.oauth2Bind=当前登录未绑定账号,请尝试通过其他方式登录,登录成功后会自动绑定账号。
form.login.error.invalidCredential=无效的凭证。
form.login.error.rateLimitExceeded=请求过于频繁,请稍后再试。
form.login.rememberMe.label=保持登录会话
form.login.submit=登录
form.signup.username.label=用户名
form.signup.displayName.label=名称
form.signup.email.label=电子邮箱
form.signup.emailCode.label=邮箱验证码
form.signup.emailCode.sendButton=发送
form.signup.emailCode.send.emptyValidation=请先输入邮箱地址
form.signup.password.label=密码
form.signup.confirmPassword.label=确认密码
form.signup.submit=注册
form.signup.error.invalidEmailCode=无效的邮箱验证码
form.signup.error.duplicateName=用户名已经被注册
form.signup.error.rateLimitExceeded=请求过于频繁,请稍后再试
form.totp.messages.invalidError=错误的验证码
form.totp.code.label=验证码
form.totp.submit=验证
form.logout.submit=退出登录
form.passwordResetLink.password.label=密码
form.passwordResetLink.confirmPassword.label=确认密码
form.passwordResetLink.password.tips=密码必须至少包含 8 个字符,并且至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符。
form.passwordResetLink.submit=修改密码
form.passwordReset.email.label=电子邮箱
form.passwordReset.submit=提交
form.passwordReset.sent.submit=返回到登录页面
form.passwordReset.message.success=检查您的电子邮件中是否有重置密码的链接。如果几分钟内没有出现,请检查您的垃圾邮件文件夹。

View File

@ -0,0 +1,36 @@
form.login.messages.logoutSuccess=Logout successfully.
form.login.messages.signupSuccess=Congratulations! Sign up successfully, please login now.
form.login.messages.oauth2Bind=The current login is not bound to an account. Please try to log in through other methods. After successful login, the account will be automatically bound.
form.login.error.invalidCredential=Invalid credentials.
form.login.error.rateLimitExceeded=Too many requests, please try again later.
form.login.rememberMe.label=Remember me
form.login.submit=Login
form.signup.username.label=Username
form.signup.displayName.label=Display Name
form.signup.email.label=Email
form.signup.emailCode.label=Email Verification Code
form.signup.emailCode.sendButton=Send
form.signup.emailCode.send.emptyValidation=Please enter your email address first
form.signup.password.label=Password
form.signup.confirmPassword.label=Confirm Password
form.signup.submit=Sign Up
form.signup.error.invalidEmailCode=Invalid Email Verification Code
form.signup.error.duplicateName=Username is already taken
form.signup.error.rateLimitExceeded=Too many requests, please try again later
form.totp.messages.invalidError=Invalid TOTP code
form.totp.code.label=TOTP Code
form.totp.submit=Verify
form.logout.submit=Logout
form.passwordResetLink.password.label=Password
form.passwordResetLink.confirmPassword.label=Confirm Password
form.passwordResetLink.password.tips=Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character.
form.passwordResetLink.submit=Change password
form.passwordReset.email.label=Email
form.passwordReset.submit=Submit
form.passwordReset.sent.submit=Return to login
form.passwordReset.message.success=Check your email for a link to reset your password. If it doesnt appear within a few minutes, check your spam folder.

View File

@ -0,0 +1,36 @@
form.login.messages.logoutSuccess=Cierre de sesión exitoso.
form.login.messages.signupSuccess=¡Felicidades! Registro exitoso, por favor inicie sesión de inmediato.
form.login.messages.oauth2Bind=El inicio de sesión actual no está vinculado a una cuenta. Intente iniciar sesión a través de otros métodos. Después de un inicio de sesión exitoso, la cuenta se vinculará automáticamente.
form.login.error.invalidCredential=Credenciales inválidas.
form.login.error.rateLimitExceeded=Demasiadas solicitudes, por favor intente nuevamente más tarde.
form.login.rememberMe.label=Mantener sesión iniciada
form.login.submit=Iniciar sesión
form.signup.username.label=Nombre de Usuario
form.signup.displayName.label=Nombre
form.signup.email.label=Correo Electrónico
form.signup.emailCode.label=Código de Verificación
form.signup.emailCode.sendButton=Enviar
form.signup.emailCode.send.emptyValidation=Por favor, introduce tu dirección de correo electrónico primero
form.signup.password.label=Contraseña
form.signup.confirmPassword.label=Confirmar Contraseña
form.signup.submit=Registrarse
form.signup.error.invalidEmailCode=Código de verificación del correo inválido
form.signup.error.duplicateName=El nombre de usuario ya está registrado
form.signup.error.rateLimitExceeded=Demasiadas solicitudes, por favor intente nuevamente más tarde
form.totp.messages.invalidError=Código de verificación incorrecto
form.totp.code.label=Código de Verificación
form.totp.submit=Verificar
form.logout.submit=Cerrar Sesión
form.passwordResetLink.password.label=Contraseña
form.passwordResetLink.confirmPassword.label=Confirmar Contraseña
form.passwordResetLink.password.tips=La contraseña debe tener al menos 8 caracteres e incluir al menos una letra mayúscula, una letra minúscula, un número y un carácter especial.
form.passwordResetLink.submit=Cambiar Contraseña
form.passwordReset.email.label=Correo Electrónico
form.passwordReset.submit=Enviar
form.passwordReset.sent.submit=Volver a la Página de Inicio de Sesión
form.passwordReset.message.success=Revisa tu correo electrónico para ver el enlace de restablecimiento de contraseña. Si no aparece en unos minutos, revisa tu carpeta de spam.

View File

@ -0,0 +1,36 @@
form.login.messages.logoutSuccess=登出成功。
form.login.messages.signupSuccess=恭喜!註冊成功,請立即登入。
form.login.messages.oauth2Bind=當前登入未綁定至帳戶。請嘗試通過其他方法登入。成功登入後,帳戶將自動綁定。
form.login.error.invalidCredential=無效的憑證。
form.login.error.rateLimitExceeded=請求過於頻繁,請稍後再試。
form.login.form.rememberMe.label=保持登入會話
form.login.form.submit=登入
form.signup.username.label=使用者名稱
form.signup.displayName.label=名稱
form.signup.email.label=電子郵件
form.signup.emailCode.label=郵箱驗證碼
form.signup.emailCode.sendButton=發送
form.signup.emailCode.send.emptyValidation=請先輸入電子郵件地址
form.signup.password.label=密碼
form.signup.confirmPassword.label=確認密碼
form.signup.submit=註冊
form.signup.error.invalidEmailCode=無效的郵箱驗證碼
form.signup.error.duplicateName=使用者名稱已經被註冊
form.signup.error.rateLimitExceeded=請求過於頻繁,請稍後再試
form.totp.messages.invalidError=錯誤的驗證碼
form.totp.code.label=驗證碼
form.totp.submit=驗證
form.logout.submit=退出登入
form.passwordResetLink.password.label=密碼
form.passwordResetLink.confirmPassword.label=確認密碼
form.passwordResetLink.password.tips=密碼必須至少包含 8 個字元,並且至少包含一個大寫字母、一個小寫字母、一個數字和一個特殊字元。
form.passwordResetLink.submit=修改密碼
form.passwordReset.email.label=電子郵件
form.passwordReset.submit=提交
form.passwordReset.sent.submit=返回到登入頁面
form.passwordReset.message.success=檢查您的電子郵件中是否有重置密碼的連結。如果幾分鐘內沒有出現,請檢查您的垃圾郵件資料夾。

View File

@ -1,42 +1,4 @@
<!-- Those fragments are only for login template-->
<form
th:fragment="form"
class="halo-form"
name="login-form"
id="login-form"
th:action="${authProvider.spec.authenticationUrl}"
th:method="${authProvider.spec.method}"
>
<div class="alert alert-error" role="alert" th:if="${param.error.size() > 0}" th:with="error = ${param.error[0]}">
<strong th:if="${error == 'invalid-credential'}">
<span th:text="#{error.invalid-credential}"></span>
</strong>
<strong th:if="${error == 'rate-limit-exceeded'}">
<span th:text="#{error.rate-limit-exceeded}"></span>
</strong>
</div>
<div class="alert" role="alert" th:if="${param.logout.size() > 0}">
<strong th:text="#{messages.logoutSuccess}"></strong>
</div>
<div class="alert" role="alert" th:if="${param.signup.size() > 0}">
<strong th:text="#{messages.signupSuccess}"></strong>
</div>
<div class="alert" role="alert" th:if="${param.oauth2_bind.size() > 0}">
<strong th:text="#{messages.oauth2_bind}"></strong>
</div>
<div th:replace="~{__${fragmentTemplateName}__::form}"></div>
<div th:if="${authProvider.spec.rememberMeSupport}" class="form-item-compact">
<input type="checkbox" id="remember-me" name="remember-me" value="true" />
<label for="remember-me" th:text="#{form.rememberMe.label}"></label>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.submit}"></button>
</div>
</form>
<div th:remove="tag" th:fragment="formAuthProviders">
<th:block th:unless="${#lists.isEmpty(formAuthProviders)}">
<div class="divider-wrapper">
@ -95,4 +57,4 @@
<span th:text="#{returnToSite}"></span>
</a>
</div>
</div>
</div>

View File

@ -1,13 +1,3 @@
messages.loginError=无效的凭证。
messages.logoutSuccess=登出成功。
messages.signupSuccess=恭喜!注册成功,请立即登录。
messages.oauth2_bind=当前登录未绑定账号,请尝试通过其他方式登录,登录成功后会自动绑定账号。
error.invalid-credential=无效的凭证。
error.rate-limit-exceeded=请求过于频繁,请稍后再试。
form.rememberMe.label=保持登录会话
form.submit=登录
otherLogin.label=其他登录方式
signup.description=没有账号?
signup.link=立即注册

View File

@ -1,13 +1,3 @@
messages.loginError=Invalid credentials.
messages.logoutSuccess=Logout successfully.
messages.oauth2_bind=The current login is not bound to an account. Please try to log in through other methods. After successful login, the account will be automatically bound.
messages.signupSuccess=Congratulations! Sign up successfully, please login now.
error.invalid-credential=Invalid credentials.
error.rate-limit-exceeded=Too many requests, please try again later.
form.rememberMe.label=Remember me
form.submit=Login
otherLogin.label=Other Login
signup.description=Don't have an account?
signup.link=Sign up

View File

@ -1,13 +1,4 @@
messages.loginError=Credenciales inválidas.
messages.logoutSuccess=Cierre de sesión exitoso.
messages.signupSuccess=¡Felicidades! Registro exitoso, por favor inicie sesión de inmediato.
error.invalid-credential=Credenciales inválidas.
error.rate-limit-exceeded=Demasiadas solicitudes, por favor intente nuevamente más tarde.
form.rememberMe.label=Mantener sesión iniciada
form.submit=Iniciar sesión
otherLogin.label=Otras formas de inicio de sesión
signup.description=¿No tienes una cuenta?
signup.link=Regístrate ahora
returnToSite=Volver al sitio
returnToSite=Volver al sitio

View File

@ -1,13 +1,5 @@
messages.loginError=無效的憑證。
messages.logoutSuccess=登出成功。
messages.signupSuccess=恭喜!註冊成功,請立即登入。
error.invalid-credential=無效的憑證。
error.rate-limit-exceeded=請求過於頻繁,請稍後再試。
form.rememberMe.label=保持登入會話
form.submit=登入
otherLogin.label=其他登入方式
signup.description=沒有帳號?
signup.link=立即註冊
returnToSite=返回網站
returnToSite=返回網站

View File

@ -8,7 +8,7 @@
<div th:replace="~{gateway_modules/common_fragments::haloLogo}"></div>
<div class="halo-form-wrapper">
<form th:replace="~{gateway_modules/login_fragments::form}"></form>
<form th:replace="~{gateway_modules/form_fragments::login}"></form>
<div th:replace="~{gateway_modules/login_fragments::formAuthProviders}"></div>
<div th:replace="~{gateway_modules/common_fragments::socialAuthProviders}"></div>
</div>
@ -17,4 +17,4 @@
<div th:replace="~{gateway_modules/common_fragments::languageSwitcher}"></div>
</div>
</th:block>
</html>
</html>

View File

@ -1,37 +0,0 @@
<div th:remove="tag" th:fragment="form">
<div class="form-item">
<label for="email"> Email </label>
<div class="form-input">
<input
type="email"
id="email"
name="email"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
required
autofocus
/>
</div>
</div>
<div class="form-item">
<label for="code"> Code </label>
<div class="form-input-group">
<div class="form-input">
<input
type="text"
id="code"
name="code"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
required
/>
</div>
<button type="button">Send</button>
</div>
</div>
</div>

View File

@ -7,12 +7,8 @@
<div class="gateway-wrapper">
<div class="halo-form-wrapper">
<h1 class="form-title" th:text="#{form.title}"></h1>
<form class="halo-form" id="logout-form" name="logout-form" th:action="@{/logout}" method="post">
<div class="form-item">
<button type="submit" th:text="#{form.submit}"></button>
</div>
</form>
<form th:replace="~{gateway_modules/form_fragments::logout}"></form>
</div>
</div>
</th:block>
</html>
</html>

View File

@ -1,3 +1,2 @@
title=退出登录
form.title=确定要退出登录吗?
form.submit=退出登录
form.title=确定要退出登录吗?

View File

@ -1,3 +1,2 @@
title=Logout
form.title=Are you sure want to log out?
form.submit=Logout
form.title=Are you sure want to log out?

View File

@ -1,3 +1,2 @@
title=Cerrar Sesión
form.title=¿Estás seguro de que deseas cerrar sesión?
form.submit=Cerrar Sesión
form.title=¿Estás seguro de que deseas cerrar sesión?

View File

@ -1,3 +1,2 @@
title=退出登入
form.title=確定要退出登入嗎?
form.submit=退出登入
form.title=確定要退出登入嗎?

View File

@ -8,33 +8,8 @@
<div th:replace="~{gateway_modules/common_fragments::haloLogo}"></div>
<div class="halo-form-wrapper">
<h1 class="form-title" th:text="#{title(${username})}"></h1>
<p style="color: red" role="alert" th:if="${error}" th:text="${error}"></p>
<form
class="halo-form"
th:action="@{/password-reset/{resetToken}(resetToken=${resetToken})}"
method="post"
>
<div class="form-item">
<label for="password" th:text="#{form.password.label}">Password</label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'password', name = 'password', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
</div>
<div class="form-item">
<label for="confirmPassword" th:text="#{form.confirmPassword.label}">Confirm Password</label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'confirmPassword', name = 'confirmPassword', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
</div>
<div class="form-item">
<p th:text="#{form.password.tips}"></p>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.submit}">Change password</button>
</div>
</form>
<form th:replace="~{gateway_modules/form_fragments::passwordResetLink}"></form>
</div>
<div th:replace="~{gateway_modules/common_fragments::languageSwitcher}"></div>
</div>
</th:block>

View File

@ -1,5 +1 @@
title=为 {0} 修改密码
form.password.label=密码
form.confirmPassword.label=确认密码
form.password.tips=密码必须至少包含 8 个字符,并且至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符。
form.submit=修改密码

View File

@ -1,5 +1 @@
title=Change password for @{0}
form.password.label=Password
form.confirmPassword.label=Confirm Password
form.password.tips=Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character.
form.submit=Change password

View File

@ -1,5 +1 @@
title=Cambiar Contraseña para {0}
form.password.label=Contraseña
form.confirmPassword.label=Confirmar Contraseña
form.password.tips=La contraseña debe tener al menos 8 caracteres e incluir al menos una letra mayúscula, una letra minúscula, un número y un carácter especial.
form.submit=Cambiar Contraseña

View File

@ -1,5 +1 @@
title=為 {0} 修改密碼
form.password.label=密碼
form.confirmPassword.label=確認密碼
form.password.tips=密碼必須至少包含 8 個字元,並且至少包含一個大寫字母、一個小寫字母、一個數字和一個特殊字元。
form.submit=修改密碼

View File

@ -8,28 +8,7 @@
<div th:replace="~{gateway_modules/common_fragments::haloLogo}"></div>
<div class="halo-form-wrapper">
<h1 class="form-title" th:text="${sent} ? #{sent.title} : #{title}"></h1>
<div class="alert alert-error" th:if="${error}">
<strong th:text="${error}"></strong>
</div>
<form th:if="${sent}" method="get" action="/login" class="halo-form">
<div class="form-item">
<div class="alert" th:text="#{sent.form.message}"></div>
</div>
<div class="form-item">
<button type="submit" th:text="#{sent.form.submit}"></button>
</div>
</form>
<form th:unless="${sent}" class="halo-form" th:action="@{/password-reset}" method="post">
<div class="form-item">
<label for="email" th:text="#{form.email.label}"></label>
<div class="form-input">
<input type="email" id="email" name="email" autofocus required />
</div>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.submit}"></button>
</div>
</form>
<form th:replace="~{gateway_modules/form_fragments::passwordReset}"></form>
</div>
<div th:replace="~{gateway_modules/common_fragments::languageSwitcher}"></div>

View File

@ -1,6 +1,2 @@
title=重置密码
form.email.label=电子邮箱
form.submit=提交
sent.form.submit=返回到登录页面
sent.form.message=检查您的电子邮件中是否有重置密码的链接。如果几分钟内没有出现,请检查您的垃圾邮件文件夹。
sent.title=已发送重置密码的邮件

View File

@ -1,6 +1,2 @@
title=Reset password
form.email.label=Email
form.submit=Submit
sent.form.submit=Return to login
sent.form.message=Check your email for a link to reset your password. If it doesnt appear within a few minutes, check your spam folder.
sent.title=Password reset email has been sent

View File

@ -1,6 +1,2 @@
title=Restablecer Contraseña
form.email.label=Correo Electrónico
form.submit=Enviar
sent.form.submit=Volver a la Página de Inicio de Sesión
sent.form.message=Revisa tu correo electrónico para ver el enlace de restablecimiento de contraseña. Si no aparece en unos minutos, revisa tu carpeta de spam.
sent.title=Correo de Restablecimiento de Contraseña Enviado
sent.title=Correo de Restablecimiento de Contraseña Enviado

View File

@ -1,6 +1,2 @@
title=重置密碼
form.email.label=電子郵件
form.submit=提交
sent.form.submit=返回到登入頁面
sent.form.message=檢查您的電子郵件中是否有重置密碼的連結。如果幾分鐘內沒有出現,請檢查您的垃圾郵件資料夾。
sent.title=已發送重置密碼的郵件
sent.title=已發送重置密碼的郵件

View File

@ -15,198 +15,10 @@
<div th:replace="~{gateway_modules/common_fragments::haloLogo}"></div>
<div class="halo-form-wrapper">
<h1 class="form-title" th:text="#{title}"></h1>
<p class="alert alert=erro" role="alert" th:if="${error == 'invalid-email-code'}">
<span th:text="#{error.invalid-email-code}">Invalid email code</span>
</p>
<p class="alert alert=erro" role="alert" th:if="${error == 'rate-limit-exceeded'}">
<span th:text="#{error.rate-limit-exceeded}">Rate limit exceeded</span>
</p>
<p class="alert alert=erro" role="alert" th:if="${error == 'duplicate-name'}">
<span th:text="#{error.duplicate-name}">Duplicate name</span>
</p>
<form
class="halo-form"
name="signup-form"
id="signup-form"
th:action="@{/signup}"
th:object="${form}"
method="post"
>
<div class="form-item-group">
<div class="form-item">
<label for="username" th:text="#{form.username.label}"></label>
<div class="form-input">
<input
type="text"
id="username"
name="username"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
autofocus
required
th:field="*{username}"
/>
</div>
<p
class="alert alert-error"
th:if="${#fields.hasErrors('username')}"
th:errors="*{username}"
></p>
</div>
<div class="form-item">
<label for="displayName" th:text="#{form.displayName.label}"></label>
<div class="form-input">
<input
type="text"
id="displayName"
name="displayName"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
required
th:field="*{displayName}"
/>
</div>
<p
class="alert alert-error"
th:if="${#fields.hasErrors('displayName')}"
th:errors="*{displayName}"
></p>
</div>
</div>
<div class="form-item-group">
<div class="form-item">
<label for="email" th:text="#{form.email.label}"></label>
<div class="form-input">
<input
type="email"
id="email"
name="email"
autocomplete="off"
spellcheck="false"
autocorrect="off"
autocapitalize="off"
required
th:field="*{email}"
/>
</div>
<p class="alert alert-error" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p>
</div>
<div class="form-item" th:if="${globalInfo.mustVerifyEmailOnRegistration}">
<label for="emailCode" th:text="#{form.emailCode.label}"></label>
<div class="form-input-group">
<div class="form-input">
<input
type="text"
inputmode="numeric"
pattern="\d*"
id="emailCode"
name="emailCode"
required
/>
</div>
<button
id="emailCodeSendButton"
type="button"
th:text="#{form.emailCode.sendButton}"
></button>
</div>
<p
class="alert alert-error"
th:if="${#fields.hasErrors('emailCode')}"
th:errors="*{emailCode}"
></p>
</div>
</div>
<div class="form-item">
<label for="password" th:text="#{form.password.label}"></label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'password', name = 'password', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
<p
class="alert alert-error"
th:if="${#fields.hasErrors('password')}"
th:errors="*{password}"
></p>
</div>
<div class="form-item">
<label for="confirmPassword" th:text="#{form.confirmPassword.label}"></label>
<th:block
th:replace="~{gateway_modules/input_fragments :: password(id = 'confirmPassword', name = 'confirmPassword', required = 'true', minlength = 6, enableToggle = true)}"
></th:block>
<p
class="alert alert-error"
th:if="${#fields.hasErrors('confirmPassword')}"
th:errors="*{confirmPassword}"
></p>
</div>
<div class="form-item">
<button type="submit" th:text="#{form.submit}"></button>
</div>
</form>
<form th:replace="~{gateway_modules/form_fragments::signup}"></form>
<div th:replace="~{gateway_modules/common_fragments::socialAuthProviders}"></div>
</div>
<div th:replace="~{gateway_modules/common_fragments::languageSwitcher}"></div>
</div>
<script th:inline="javascript">
document.addEventListener("DOMContentLoaded", function () {
function sendRequest() {
return new Promise((resolve, reject) => {
const email = document.getElementById("email").value;
if (!email) {
throw new Error(/*[[#{form.emailCode.send.emptyValidation}]]*/);
}
fetch("/signup/send-email-code", {
method: "POST",
body: JSON.stringify({ email: email }),
headers: {
"Content-Type": "application/json",
[[${_csrf.headerName}]]: [[${_csrf.token}]],
},
})
.then((response) => {
if (response.ok) {
resolve(response);
}
reject(response);
})
.catch((e) => {
reject(e);
});
});
}
const emailCodeSendButton = document.getElementById("emailCodeSendButton");
sendVerificationCode(emailCodeSendButton, sendRequest);
var password = document.getElementById("password"),
confirm_password = document.getElementById("confirmPassword");
function validatePassword() {
if (password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
} else {
confirm_password.setCustomValidity("");
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
});
</script>
</th:block>
</html>

View File

@ -1,14 +1 @@
title=注册
form.username.label=用户名
form.displayName.label=名称
form.email.label=电子邮箱
form.emailCode.label=邮箱验证码
form.emailCode.sendButton=发送
form.emailCode.send.emptyValidation=请先输入邮箱地址
form.password.label=密码
form.confirmPassword.label=确认密码
form.submit=注册
error.invalid-email-code=无效的邮箱验证码
error.duplicate-name=用户名已经被注册
error.rate-limit-exceeded=请求过于频繁,请稍后再试
title=注册

View File

@ -1,14 +1 @@
title=Sign Up
form.username.label=Username
form.displayName.label=Display Name
form.email.label=Email
form.emailCode.label=Email Verification Code
form.emailCode.sendButton=Send
form.emailCode.send.emptyValidation=Please enter your email address first
form.password.label=Password
form.confirmPassword.label=Confirm Password
form.submit=Sign Up
error.invalid-email-code=Invalid Email Verification Code
error.duplicate-name=Username is already taken
error.rate-limit-exceeded=Too many requests, please try again later
title=Sign Up

View File

@ -1,14 +1 @@
title=Registrarse
form.username.label=Nombre de Usuario
form.displayName.label=Nombre
form.email.label=Correo Electrónico
form.emailCode.label=Código de Verificación
form.emailCode.sendButton=Enviar
form.emailCode.send.emptyValidation=Por favor, introduce tu dirección de correo electrónico primero
form.password.label=Contraseña
form.confirmPassword.label=Confirmar Contraseña
form.submit=Registrarse
error.invalid-email-code=Código de verificación del correo inválido
error.duplicate-name=El nombre de usuario ya está registrado
error.rate-limit-exceeded=Demasiadas solicitudes, por favor intente nuevamente más tarde
title=Registrarse

View File

@ -1,14 +1 @@
title=註冊
form.username.label=使用者名稱
form.displayName.label=名稱
form.email.label=電子郵件
form.emailCode.label=郵箱驗證碼
form.emailCode.sendButton=發送
form.emailCode.send.emptyValidation=請先輸入電子郵件地址
form.password.label=密碼
form.confirmPassword.label=確認密碼
form.submit=註冊
error.invalid-email-code=無效的郵箱驗證碼
error.duplicate-name=使用者名稱已經被註冊
error.rate-limit-exceeded=請求過於頻繁,請稍後再試
title=註冊