first commit
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import Path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import UserGetter from '../../../../app/src/Features/User/UserGetter.js'
|
||||
import UserRegistrationHandler from '../../../../app/src/Features/User/UserRegistrationHandler.js'
|
||||
import ErrorController from '../../../../app/src/Features/Errors/ErrorController.js'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
|
||||
const __dirname = Path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
function registerNewUser(req, res, next) {
|
||||
res.render(Path.resolve(__dirname, '../views/user/register'))
|
||||
}
|
||||
|
||||
async function register(req, res, next) {
|
||||
const { email } = req.body
|
||||
if (email == null || email === '') {
|
||||
return res.sendStatus(422) // Unprocessable Entity
|
||||
}
|
||||
const { user, setNewPasswordUrl } =
|
||||
await UserRegistrationHandler.promises.registerNewUserAndSendActivationEmail(
|
||||
email
|
||||
)
|
||||
res.json({
|
||||
email: user.email,
|
||||
setNewPasswordUrl,
|
||||
})
|
||||
}
|
||||
|
||||
async function activateAccountPage(req, res, next) {
|
||||
// An 'activation' is actually just a password reset on an account that
|
||||
// was set with a random password originally.
|
||||
if (req.query.user_id == null || req.query.token == null) {
|
||||
return ErrorController.notFound(req, res)
|
||||
}
|
||||
|
||||
if (typeof req.query.user_id !== 'string') {
|
||||
return ErrorController.forbidden(req, res)
|
||||
}
|
||||
|
||||
const user = await UserGetter.promises.getUser(req.query.user_id, {
|
||||
email: 1,
|
||||
loginCount: 1,
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
return ErrorController.notFound(req, res)
|
||||
}
|
||||
|
||||
if (user.loginCount > 0) {
|
||||
// Already seen this user, so account must be activated.
|
||||
// This lets users keep clicking the 'activate' link in their email
|
||||
// as a way to log in which, if I know our users, they will.
|
||||
return res.redirect(`/login`)
|
||||
}
|
||||
|
||||
req.session.doLoginAfterPasswordReset = true
|
||||
|
||||
res.render(Path.resolve(__dirname, '../views/user/activate'), {
|
||||
title: 'activate_account',
|
||||
email: user.email,
|
||||
token: req.query.token,
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
registerNewUser,
|
||||
register: expressify(register),
|
||||
activateAccountPage: expressify(activateAccountPage),
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
import logger from '@overleaf/logger'
|
||||
import UserActivateController from './UserActivateController.mjs'
|
||||
import AuthenticationController from '../../../../app/src/Features/Authentication/AuthenticationController.js'
|
||||
import AuthorizationMiddleware from '../../../../app/src/Features/Authorization/AuthorizationMiddleware.js'
|
||||
|
||||
export default {
|
||||
apply(webRouter) {
|
||||
logger.debug({}, 'Init UserActivate router')
|
||||
|
||||
webRouter.get(
|
||||
'/admin/user',
|
||||
AuthorizationMiddleware.ensureUserIsSiteAdmin,
|
||||
(req, res) => res.redirect('/admin/register')
|
||||
)
|
||||
|
||||
webRouter.get('/user/activate', UserActivateController.activateAccountPage)
|
||||
AuthenticationController.addEndpointToLoginWhitelist('/user/activate')
|
||||
|
||||
webRouter.get(
|
||||
'/admin/register',
|
||||
AuthorizationMiddleware.ensureUserIsSiteAdmin,
|
||||
UserActivateController.registerNewUser
|
||||
)
|
||||
webRouter.post(
|
||||
'/admin/register',
|
||||
AuthorizationMiddleware.ensureUserIsSiteAdmin,
|
||||
UserActivateController.register
|
||||
)
|
||||
},
|
||||
}
|
1
services/web/modules/user-activate/app/src/tsconfig.json
Normal file
1
services/web/modules/user-activate/app/src/tsconfig.json
Normal file
@@ -0,0 +1 @@
|
||||
{ "extends": "../../../../tsconfig.backend.json" }
|
@@ -0,0 +1,72 @@
|
||||
extends ../../../../../app/views/layout-website-redesign-bootstrap-5
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
div.col-lg-6.col-xl-4.m-auto
|
||||
.notification-list
|
||||
.notification.notification-type-success(aria-live="off" role="alert")
|
||||
.notification-content-and-cta
|
||||
.notification-icon
|
||||
span.material-symbols(aria-hidden="true")
|
||||
| check_circle
|
||||
.notification-content
|
||||
p
|
||||
| #{translate("nearly_activated")}
|
||||
|
||||
h1.h3 #{translate("please_set_a_password")}
|
||||
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="activationForm",
|
||||
action="/user/password/set",
|
||||
method="POST",
|
||||
)
|
||||
+formMessages()
|
||||
|
||||
+customFormMessage('token-expired', 'danger')
|
||||
| #{translate("activation_token_expired")}
|
||||
|
||||
+customFormMessage('invalid-password', 'danger')
|
||||
| #{translate('invalid_password')}
|
||||
|
||||
input(name='_csrf', type='hidden', value=csrfToken)
|
||||
input(
|
||||
type="hidden",
|
||||
name="passwordResetToken",
|
||||
value=token
|
||||
)
|
||||
|
||||
.form-group
|
||||
label(for='emailField') #{translate("email")}
|
||||
input.form-control#emailField(
|
||||
aria-label="email",
|
||||
type='email',
|
||||
name='email',
|
||||
placeholder="email@example.com",
|
||||
autocomplete="username"
|
||||
value=email
|
||||
required,
|
||||
disabled
|
||||
)
|
||||
.form-group
|
||||
label(for='passwordField') #{translate("password")}
|
||||
input.form-control#passwordField(
|
||||
type='password',
|
||||
name='password',
|
||||
placeholder="********",
|
||||
autocomplete="new-password",
|
||||
autofocus,
|
||||
required,
|
||||
minlength=settings.passwordStrengthOptions.length.min
|
||||
)
|
||||
.actions
|
||||
button.btn.btn-primary(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight
|
||||
aria-label=translate('activate')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate('activate')}
|
||||
span(hidden data-ol-inflight="pending")
|
||||
| #{translate('activating')}…
|
@@ -0,0 +1,13 @@
|
||||
extends ../../../../../app/views/layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'modules/user-activate/pages/user-activate-page'
|
||||
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
.content.content-alt#main-content
|
||||
.container
|
||||
#user-activate-register-container
|
Reference in New Issue
Block a user