From fdc41646d18e6e34c9258b632857529c19a50233 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 5 Jan 2023 15:59:45 -0500 Subject: [PATCH] feat: api v3 route to add email to user, optionally bypassing validation email, closes #11009 --- public/openapi/write/users/uid/emails.yaml | 51 ++++++++++++++++++++++ src/controllers/write/users.js | 18 ++++++++ src/routes/write/users.js | 1 + 3 files changed, 70 insertions(+) diff --git a/public/openapi/write/users/uid/emails.yaml b/public/openapi/write/users/uid/emails.yaml index 8bd00809c0..c6b67acf9e 100644 --- a/public/openapi/write/users/uid/emails.yaml +++ b/public/openapi/write/users/uid/emails.yaml @@ -16,6 +16,57 @@ get: 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 +post: + tags: + - users + summary: add email to user + description: | + This operation adds an email to the user account, optionally bypassing the confirmation step if requested. + + **Note**: The confirmation bypass can only be called by super administrators or users with the `admin:users` privilege. + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the account to add the email + example: 1 + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + email: + type: string + description: A single email address + example: test@example.org + skipConfirmation: + type: boolean + description: If truthy, will automatically confirm the user's email. + example: 1 + required: + - email + responses: + '200': + description: email successfully added to user account content: application/json: schema: diff --git a/src/controllers/write/users.js b/src/controllers/write/users.js index 56d547aaaf..9e400c5ce9 100644 --- a/src/controllers/write/users.js +++ b/src/controllers/write/users.js @@ -253,6 +253,24 @@ Users.getInviteGroups = async function (req, res) { return helpers.formatApiResponse(200, res, userInviteGroups.map(group => group.displayName)); }; +Users.addEmail = async (req, res) => { + const canManageUsers = await privileges.admin.can('admin:users', req.uid); + const skipConfirmation = canManageUsers && req.body.skipConfirmation; + + if (skipConfirmation) { + await user.setUserField(req.params.uid, 'email', req.body.email); + await user.email.confirmByUid(req.params.uid); + } else { + await api.users.update(req, { + uid: req.params.uid, + email: req.body.email, + }); + } + + const emails = await db.getSortedSetRangeByScore('email:uid', 0, 500, req.params.uid, req.params.uid); + helpers.formatApiResponse(200, res, { emails }); +}; + Users.listEmails = async (req, res) => { const [isPrivileged, { showemail }] = await Promise.all([ user.isPrivileged(req.uid), diff --git a/src/routes/write/users.js b/src/routes/write/users.js index 980eccc8a2..23d8d75ddd 100644 --- a/src/routes/write/users.js +++ b/src/routes/write/users.js @@ -48,6 +48,7 @@ function authenticatedRoutes() { 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, 'post', '/:uid/emails', [...middlewares, middleware.assert.user], controllers.write.users.addEmail); 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);