Merge pull request #22609 from overleaf/mf-migrate-aux-password-pages-to-bs5
[web] Migrate reset password page to bootstrap 5 and website redesign GitOrigin-RevId: 613865379d094b305c6dc78f74dc70341214f4ed
This commit is contained in:
@@ -8,6 +8,7 @@ import UserSessionsManager from '../User/UserSessionsManager.js'
|
||||
import OError from '@overleaf/o-error'
|
||||
import EmailsHelper from '../Helpers/EmailHelper.js'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
import SplitTestHandler from '../SplitTests/SplitTestHandler.js'
|
||||
|
||||
async function setNewUserPassword(req, res, next) {
|
||||
let user
|
||||
@@ -191,19 +192,29 @@ async function renderSetPasswordForm(req, res, next) {
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
renderRequestResetForm(req, res) {
|
||||
const errorQuery = req.query.error
|
||||
let error = null
|
||||
if (errorQuery === 'token_expired') {
|
||||
error = 'password_reset_token_expired'
|
||||
}
|
||||
res.render('user/passwordReset', {
|
||||
title: 'reset_password',
|
||||
error,
|
||||
})
|
||||
},
|
||||
async function renderRequestResetForm(req, res) {
|
||||
const errorQuery = req.query.error
|
||||
let error = null
|
||||
if (errorQuery === 'token_expired') {
|
||||
error = 'password_reset_token_expired'
|
||||
}
|
||||
const { variant } = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'auth-pages-bs5'
|
||||
)
|
||||
|
||||
const template =
|
||||
variant === 'enabled' ? 'user/passwordReset-bs5' : 'user/passwordReset'
|
||||
|
||||
res.render(template, {
|
||||
title: 'reset_password',
|
||||
error,
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
renderRequestResetForm: expressify(renderRequestResetForm),
|
||||
requestReset: expressify(requestReset),
|
||||
renderSetPasswordForm: expressify(renderSetPasswordForm),
|
||||
setNewUserPassword: expressify(setNewUserPassword),
|
||||
|
||||
@@ -5,6 +5,10 @@ mixin notificationIcon(type)
|
||||
span.material-symbols(aria-hidden="true") info
|
||||
else if type === 'success'
|
||||
span.material-symbols(aria-hidden="true") check_circle
|
||||
else if type === 'error'
|
||||
span.material-symbols(aria-hidden="true") error
|
||||
else if type === 'warning'
|
||||
span.material-symbols(aria-hidden="true") warning
|
||||
|
||||
|
||||
mixin notification(options)
|
||||
@@ -24,7 +28,7 @@ mixin notification(options)
|
||||
if title
|
||||
p
|
||||
b #{title}
|
||||
| #{content}
|
||||
| !{content}
|
||||
//- TODO: handle action
|
||||
//- if action
|
||||
//- .notification-cta
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
extends ../layout-website-redesign-bootstrap-5
|
||||
include ../_mixins/recaptcha
|
||||
include ../_mixins/notification
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
|
||||
block content
|
||||
- var showCaptcha = settings.recaptcha && settings.recaptcha.siteKey && !(settings.recaptcha.disabled && settings.recaptcha.disabled.passwordReset)
|
||||
|
||||
if showCaptcha
|
||||
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render=explicit")
|
||||
div(
|
||||
id="recaptcha"
|
||||
class="g-recaptcha"
|
||||
data-sitekey=settings.recaptcha.siteKey
|
||||
data-size="invisible"
|
||||
data-badge="inline"
|
||||
)
|
||||
|
||||
main#main-content(data-ol-captcha-retry-trigger-area="")
|
||||
a.auth-aux-logo(href="/")
|
||||
img(src=buildImgPath("ol-brand/overleaf-o-dark.svg") alt=settings.appName)
|
||||
.auth-aux-container
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="passwordResetForm"
|
||||
action="/user/password/reset"
|
||||
method="POST"
|
||||
captcha=(showCaptcha ? '' : false)
|
||||
captcha-action-name=(showCaptcha ? "passwordReset" : false)
|
||||
)
|
||||
if error === 'password_reset_token_expired'
|
||||
h1.h3.mb-3.mt-0 #{translate("sorry_your_token_expired")}
|
||||
p #{translate('please_request_a_new_password_reset_email_and_follow_the_link')}.
|
||||
else
|
||||
h1.h3.mb-3.mt-0(data-ol-not-sent) #{translate("password_reset_sentence_case")}
|
||||
h1.h3.mb-3.mt-0(hidden data-ol-sent) #{translate("check_your_email")}
|
||||
p.mb-3.pb-3(data-ol-not-sent) #{translate("enter_your_email_address_below_and_we_will_send_you_a_link_to_reset_your_password")}.
|
||||
|
||||
div(data-ol-not-sent)
|
||||
+formMessages()
|
||||
if error && error !== 'password_reset_token_expired'
|
||||
+notification({ariaLive: 'assertive', type: 'error', className: 'mb-3', content: translate(error)})
|
||||
|
||||
div(data-ol-custom-form-message="no-password-allowed-due-to-sso" hidden)
|
||||
+notification({ariaLive: 'polite', type: 'error', className: 'mb-3', content: translate("you_cant_reset_password_due_to_sso", {}, [{name: 'a', attrs: {href: '/sso-login'}}])})
|
||||
input(type="hidden" name="_csrf" value=csrfToken)
|
||||
.form-group.mb-3
|
||||
label.form-label(for='email') #{translate("email")}
|
||||
input.form-control#email(
|
||||
aria-label="email"
|
||||
type='email'
|
||||
name='email'
|
||||
required
|
||||
autocomplete="username"
|
||||
autofocus
|
||||
)
|
||||
.actions
|
||||
button.btn.btn-primary.w-100.mb-3(
|
||||
type='submit'
|
||||
data-ol-disabled-inflight
|
||||
aria-label=translate('reset_password_sentence_case')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate("reset_password_sentence_case")}
|
||||
span(hidden data-ol-inflight="pending")
|
||||
| #{translate("requesting_password_reset")}…
|
||||
a.btn.btn-ghost.w-100.mb-3(href="/login") #{translate("back_to_log_in")}
|
||||
div(hidden data-ol-sent)
|
||||
p.mb-4 #{translate('password_reset_email_sent')}
|
||||
a.btn.btn-primary.w-100.mb-3(href="/login") #{translate('back_to_log_in')}
|
||||
|
||||
if showCaptcha
|
||||
+recaptchaConditions
|
||||
@@ -37,6 +37,7 @@
|
||||
@import 'group-settings';
|
||||
@import 'templates-v2';
|
||||
@import 'homepage';
|
||||
@import 'auth';
|
||||
@import 'login-register';
|
||||
@import 'login';
|
||||
@import 'register';
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
.auth-aux-logo {
|
||||
position: absolute;
|
||||
top: var(--spacing-06);
|
||||
left: var(--spacing-06);
|
||||
|
||||
img {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-aux-container {
|
||||
padding-top: calc($header-height + $spacing-11);
|
||||
max-width: 320px;
|
||||
min-height: 100vh;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
.recaptcha-branding {
|
||||
@include body-xs;
|
||||
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
@@ -1485,6 +1485,7 @@
|
||||
"password_managed_externally": "Password settings are managed externally",
|
||||
"password_reset": "Password Reset",
|
||||
"password_reset_email_sent": "You have been sent an email to complete your password reset.",
|
||||
"password_reset_sentence_case": "Password reset",
|
||||
"password_reset_token_expired": "Your password reset token has expired. Please request a new password reset email and follow the link there.",
|
||||
"password_too_long_please_reset": "Maximum password length exceeded. Please reset your password.",
|
||||
"password_updated": "Password updated",
|
||||
@@ -1761,6 +1762,7 @@
|
||||
"resending_confirmation_email": "Resending confirmation email",
|
||||
"reset_password": "Reset Password",
|
||||
"reset_password_link": "Click this link to reset your password",
|
||||
"reset_password_sentence_case": "Reset password",
|
||||
"reset_your_password": "Reset your password",
|
||||
"resize": "Resize",
|
||||
"resolve": "Resolve",
|
||||
|
||||
@@ -60,6 +60,11 @@ describe('PasswordResetController', function () {
|
||||
removeReconfirmFlag: sinon.stub().resolves(),
|
||||
},
|
||||
}
|
||||
this.SplitTestHandler = {
|
||||
promises: {
|
||||
getAssignment: sinon.stub().resolves('default'),
|
||||
},
|
||||
}
|
||||
this.PasswordResetController = await esmock.strict(MODULE_PATH, {
|
||||
'@overleaf/settings': this.settings,
|
||||
'../../../../app/src/Features/PasswordReset/PasswordResetHandler':
|
||||
@@ -81,6 +86,8 @@ describe('PasswordResetController', function () {
|
||||
'../../../../app/src/Features/User/UserSessionsManager':
|
||||
this.UserSessionsManager,
|
||||
'../../../../app/src/Features/User/UserUpdater': this.UserUpdater,
|
||||
'../../../../app/src/Features/SplitTests/SplitTestHandler':
|
||||
this.SplitTestHandler,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user