Skip to content

Commit

Permalink
feat(API): add direct email update endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
jakeaturner committed Oct 20, 2024
1 parent ffebb9b commit b8f033f
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
32 changes: 32 additions & 0 deletions server/controllers/UserController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,38 @@ export class UserController {
return true;
}

/**
* Directly updates a User's email address without verification or validation.
* Intended for use by API actors with elevated permissions only.
*
* @param req - Incoming API request.
* @param res - Outgoing API response.
* @returns The fulfilled API response.
*/
public async updateUserEmailDirect(req: Request, res: Response): Promise<Response> {
const { uuid } = req.params as UserUUIDParams;
const { email } = req.body as CreateUserEmailChangeRequestBody;

const foundUser = await User.findOne({ where: { uuid } });
if (!foundUser) {
return errors.notFound(res);
}

const existingUser = await User.findOne({ where: { email } });
if (existingUser) {
return errors.badRequest(res, 'Email already in use.');
}

await foundUser.update({ email });

return res.send({
data: {
central_identity_id: foundUser.uuid,
email,
},
});
}

/**
* Creates a new EmailVerification opportunity for a user to change their email address.
*
Expand Down
9 changes: 9 additions & 0 deletions server/routes/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ usersRouter.route('/:uuid/avatar').post(
catchInternal((req, res) => controller.updateUserAvatar(req, res)),
);

usersRouter.route('/:uuid/email-change-direct').post(
verifyAPIAuthentication,
ensureActorIsAPIUser,
ensureAPIUserHasPermission(['users:write']),
validate(UserValidator.uuidParamSchema, 'params'),
validate(UserValidator.updateUserEmailDirectSchema, 'body'),
catchInternal((req, res) => controller.updateUserEmailDirect(req, res)),
);

usersRouter.route('/:uuid/email-change').post(
verifyAPIAuthentication,
ensureUserResourcePermission(true),
Expand Down
75 changes: 75 additions & 0 deletions server/swagger/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,81 @@
}
}
}
},
"/users/{uuid}/email-change-direct": {
"post": {
"summary": "Change a user's email directly without validation or verification. Intended for API actors with sufficent permissions.",
"operationId": "updateUserEmailDirect",
"tags": [
"users"
],
"parameters": [
{
"in": "path",
"name": "uuid",
"schema": {
"type": "string"
},
"required": true,
"description": "User UUID"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"uuid": {
"type": "string"
},
"email": {
"type": "string"
}
}
}
}
},
"400": {
"description": "Bad Request: Request is malformed or email is already in use",
"content": {
"application/json": {
"schema": {
"message": {
"type": "string"
}
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"message": {
"type": "string"
}
}
}
}
}
}
}
}
},
"components": {
Expand Down
4 changes: 4 additions & 0 deletions server/validators/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export const updateUserEmailSchema = joi.object({
email: joi.string().email().required(),
});

export const updateUserEmailDirectSchema = joi.object({
email: joi.string().email().required(),
});

export const updateUserOrganizationAdminRoleSchema = joi.object({
admin_role: joi.string().valid(...Object.keys(UserOrganizationAdminRoleEnum)).required(),
});
Expand Down

0 comments on commit b8f033f

Please sign in to comment.