2025-05-10 02:09:06 +02:00
/ * !
* Copyright ( c ) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License : https : //github.com/plankanban/planka/blob/master/LICENSE.md
* /
2025-09-08 16:20:27 +02:00
/ * *
* @ swagger
2025-09-08 18:25:26 +02:00
* /users/ { id } / email :
2025-09-08 16:20:27 +02:00
* patch :
* summary : Update user email
* description : Updates a user 's email address. Users must provide current password when updating their own email. Admins can update any user' s email without a password .
* tags :
* - Users
* parameters :
* - in : path
* name : id
* required : true
* description : ID of the user whose email to update
* schema :
* type : string
* example : 1357158568008091264
* requestBody :
* required : true
* content :
* application / json :
* schema :
* type : object
* required :
* - email
* properties :
* email :
* type : string
* format : email
* maxLength : 256
* description : Email address for login and notifications
* example : john . doe @ example . com
* currentPassword :
* type : string
* maxLength : 256
* description : Current password ( required when updating own email )
* example : SecurePassword123 !
* responses :
* 200 :
* description : Email updated successfully
* content :
* application / json :
* schema :
* type : object
* required :
* - item
* properties :
* item :
* $ref : '#/components/schemas/User'
* 400 :
* $ref : '#/components/responses/ValidationError'
* 401 :
* $ref : '#/components/responses/Unauthorized'
* 403 :
* $ref : '#/components/responses/Forbidden'
* 404 :
* $ref : '#/components/responses/NotFound'
* 409 :
* $ref : '#/components/responses/Conflict'
* /
2019-10-18 08:06:34 +05:00
const bcrypt = require ( 'bcrypt' ) ;
2025-05-10 02:09:06 +02:00
const { idInput } = require ( '../../../utils/inputs' ) ;
2019-10-18 08:06:34 +05:00
const Errors = {
2023-10-17 19:18:19 +02:00
NOT _ENOUGH _RIGHTS : {
notEnoughRights : 'Not enough rights' ,
} ,
2020-04-03 00:35:25 +05:00
INVALID _CURRENT _PASSWORD : {
invalidCurrentPassword : 'Invalid current password' ,
2019-10-18 08:06:34 +05:00
} ,
2025-05-10 02:09:06 +02:00
USER _NOT _FOUND : {
userNotFound : 'User not found' ,
} ,
2020-04-03 00:35:25 +05:00
EMAIL _ALREADY _IN _USE : {
emailAlreadyInUse : 'Email already in use' ,
2019-11-05 18:01:42 +05:00
} ,
2019-10-18 08:06:34 +05:00
} ;
module . exports = {
inputs : {
id : {
2025-05-10 02:09:06 +02:00
... idInput ,
2019-11-05 18:01:42 +05:00
required : true ,
2019-10-18 08:06:34 +05:00
} ,
email : {
type : 'string' ,
2025-05-10 02:09:06 +02:00
maxLength : 256 ,
2019-10-18 08:06:34 +05:00
isEmail : true ,
2019-11-05 18:01:42 +05:00
required : true ,
2019-10-18 08:06:34 +05:00
} ,
currentPassword : {
type : 'string' ,
2019-11-05 18:01:42 +05:00
isNotEmptyString : true ,
2025-05-10 02:09:06 +02:00
maxLength : 256 ,
2019-11-05 18:01:42 +05:00
} ,
2019-10-18 08:06:34 +05:00
} ,
exits : {
2023-10-17 19:18:19 +02:00
notEnoughRights : {
responseType : 'forbidden' ,
} ,
2020-04-03 00:35:25 +05:00
invalidCurrentPassword : {
2019-11-05 18:01:42 +05:00
responseType : 'forbidden' ,
2019-10-18 08:06:34 +05:00
} ,
2025-05-10 02:09:06 +02:00
userNotFound : {
responseType : 'notFound' ,
} ,
2020-04-03 00:35:25 +05:00
emailAlreadyInUse : {
2019-11-05 18:01:42 +05:00
responseType : 'conflict' ,
} ,
2019-10-18 08:06:34 +05:00
} ,
2021-06-24 01:05:22 +05:00
async fn ( inputs ) {
2019-10-18 08:06:34 +05:00
const { currentUser } = this . req ;
if ( inputs . id === currentUser . id ) {
if ( ! inputs . currentPassword ) {
2020-04-03 00:35:25 +05:00
throw Errors . INVALID _CURRENT _PASSWORD ;
2019-10-18 08:06:34 +05:00
}
2025-05-10 02:09:06 +02:00
} else if ( currentUser . role !== User . Roles . ADMIN ) {
2019-10-18 08:06:34 +05:00
throw Errors . USER _NOT _FOUND ; // Forbidden
}
2025-05-10 02:09:06 +02:00
let user = await User . qm . getOneById ( inputs . id ) ;
2019-10-18 08:06:34 +05:00
if ( ! user ) {
throw Errors . USER _NOT _FOUND ;
}
2025-05-10 02:09:06 +02:00
if ( user . email === sails . config . custom . defaultAdminEmail || user . isSsoUser ) {
2023-10-17 19:18:19 +02:00
throw Errors . NOT _ENOUGH _RIGHTS ;
2023-09-12 01:12:38 +02:00
}
2025-05-10 02:09:06 +02:00
if ( inputs . id === currentUser . id ) {
const isCurrentPasswordValid = await bcrypt . compare ( inputs . currentPassword , user . password ) ;
if ( ! isCurrentPasswordValid ) {
throw Errors . INVALID _CURRENT _PASSWORD ;
}
2019-10-18 08:06:34 +05:00
}
const values = _ . pick ( inputs , [ 'email' ] ) ;
2022-12-26 21:10:50 +01:00
user = await sails . helpers . users . updateOne
. with ( {
values ,
record : user ,
2024-06-12 00:51:36 +02:00
actorUser : currentUser ,
2022-12-26 21:10:50 +01:00
request : this . req ,
} )
2020-04-03 00:35:25 +05:00
. intercept ( 'emailAlreadyInUse' , ( ) => Errors . EMAIL _ALREADY _IN _USE ) ;
2019-10-18 08:06:34 +05:00
if ( ! user ) {
throw Errors . USER _NOT _FOUND ;
}
2021-06-24 01:05:22 +05:00
return {
2025-05-10 02:09:06 +02:00
item : sails . helpers . users . presentOne ( user , currentUser ) ,
2021-06-24 01:05:22 +05:00
} ;
2019-11-05 18:01:42 +05:00
} ,
2019-10-18 08:06:34 +05:00
} ;