User Email and email validation API (#10160)

* feat: wip user emails api

* fix: allow admins with manage-users access to email confirmation api as well

* fix: wrong route path

* docs: openapi spec
isekai-main
Julian Lam 3 years ago committed by GitHub
parent 868bff302c
commit d098e26f82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -78,6 +78,12 @@ paths:
$ref: 'write/users/uid/invites.yaml'
/users/{uid}/invites/groups:
$ref: 'write/users/uid/invites/groups.yaml'
/users/{uid}/emails:
$ref: 'write/users/uid/emails.yaml'
/users/{uid}/emails/{email}:
$ref: 'write/users/uid/emails/email.yaml'
/users/{uid}/emails/{email}/confirm:
$ref: 'write/users/uid/emails/email/confirm.yaml'
/groups/:
$ref: 'write/groups.yaml'
/groups/{slug}:

@ -0,0 +1,33 @@
get:
tags:
- users
summary: get user emails
description: |
This operation lists all emails associated with the user.
This route is accessible to all users if the target user has elected to show their email publicly. Otherwise, it is only accessible to privileged users, or if the calling user is the same as the target user.
parameters:
- in: path
required: true
name: uid
schema:
type: number
description: A valid user id
example: 1
responses:
'200':
description: user emails successfully listed
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../components/schemas/Status.yaml#/Status
response:
type: object
properties:
emails:
type: array
items:
type: string
description: An email address

@ -0,0 +1,25 @@
get:
tags:
- users
summary: get user's email data
description: |
This operation lists the data associated with a single email.
This route is accessible to all users if the target user has elected to show their email publicly. Otherwise, it is only accessible to privileged users, or if the calling user is the same as the target user.
parameters:
- in: path
required: true
name: uid
schema:
type: number
description: A valid user id
example: 1
- in: path
required: true
name: email
schema:
type: string
description: A valid email address
example: test@example.org
responses:
'204':
description: user's email data successfully retrieved

@ -0,0 +1,34 @@
post:
tags:
- users
summary: validate a user's email address
description: |
Marks the passed-in user's email as confirmed.
This route is only accessible to administrators with the `admin:users` privilege (or superadmins)
parameters:
- in: path
required: true
name: uid
schema:
type: number
description: A valid user id
example: 1
- in: path
required: true
name: email
schema:
type: string
description: A valid email address
example: test@example.org
responses:
'200':
description: successfully confirmed a user email
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../../../components/schemas/Status.yaml#/Status
response:
type: object

@ -233,3 +233,51 @@ Users.getInviteGroups = async function (req, res) {
const userInviteGroups = await groups.getUserInviteGroups(req.params.uid);
return helpers.formatApiResponse(200, res, userInviteGroups);
};
Users.listEmails = async (req, res) => {
const [isPrivileged, { showemail }] = await Promise.all([
user.isPrivileged(req.uid),
user.getSettings(req.params.uid),
]);
const isSelf = req.uid === parseInt(req.params.uid, 10);
if (isSelf || isPrivileged || showemail) {
const emails = await db.getSortedSetRangeByScore('email:uid', 0, 500, req.params.uid, req.params.uid);
helpers.formatApiResponse(200, res, { emails });
} else {
helpers.formatApiResponse(204, res);
}
};
Users.getEmail = async (req, res) => {
const [isPrivileged, { showemail }, exists] = await Promise.all([
user.isPrivileged(req.uid),
user.getSettings(req.params.uid),
db.isSortedSetMember('email:uid', req.params.email.toLowerCase()),
]);
const isSelf = req.uid === parseInt(req.params.uid, 10);
if (exists && (isSelf || isPrivileged || showemail)) {
helpers.formatApiResponse(204, res);
} else {
helpers.formatApiResponse(404, res);
}
};
Users.confirmEmail = async (req, res) => {
const [exists, canManage] = await Promise.all([
db.isSortedSetMember('email:uid', req.params.email.toLowerCase()),
privileges.admin.can('admin:users', req.uid),
]);
if (!canManage) {
helpers.notAllowed(req, res);
}
if (exists) {
await user.email.confirmByUid(req.params.uid);
helpers.formatApiResponse(200, res);
} else {
helpers.formatApiResponse(404, res);
}
};

@ -44,6 +44,10 @@ function authenticatedRoutes() {
setupApiRoute(router, 'post', '/:uid/invites', middlewares, controllers.write.users.invite);
setupApiRoute(router, 'get', '/:uid/invites/groups', [...middlewares, middleware.assert.user], controllers.write.users.getInviteGroups);
setupApiRoute(router, 'get', '/:uid/emails', [...middlewares, middleware.assert.user], controllers.write.users.listEmails);
setupApiRoute(router, 'get', '/:uid/emails/:email', [...middlewares, middleware.assert.user], controllers.write.users.getEmail);
setupApiRoute(router, 'post', '/:uid/emails/:email/confirm', [...middlewares, middleware.assert.user], controllers.write.users.confirmEmail);
// Shorthand route to access user routes by userslug
router.all('/+bySlug/:userslug*?', [], controllers.write.users.redirectBySlug);
}

Loading…
Cancel
Save