Skip to content

Commit d9b7589

Browse files
Merge pull request #46 from Sachintechjoomla/Issue#254011
Issue#254011 Feat: Update > LC update participant address
2 parents e0438da + 607b05d commit d9b7589

File tree

3 files changed

+296
-0
lines changed

3 files changed

+296
-0
lines changed

controllers/v1/programUsers.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,53 @@ module.exports = class ProgramUsers extends Abstract {
181181
}
182182
})
183183
}
184+
185+
/**
186+
* Update entity location/profile information
187+
* Validates that logged-in user has participant assigned before updating
188+
* @method
189+
* @name updateEntityLocation
190+
* @param {Object} req - request object
191+
* @param {String} req.body.userId - participant's userId to update
192+
* @param {String} req.body.entityId - participant's entityId (optional)
193+
* @param {Object} req.body.updateData - profile data to update (province, site, address, etc.)
194+
* @returns {Object} response with status and updated user data
195+
*/
196+
async updateEntityLocation(req) {
197+
return new Promise(async (resolve, reject) => {
198+
try {
199+
const { userId, entityId, updateData } = req.body
200+
201+
if (!userId) {
202+
return reject({
203+
status: HTTP_STATUS_CODE.bad_request.status,
204+
message: 'userId is required',
205+
})
206+
}
207+
208+
if (!updateData) {
209+
return reject({
210+
status: HTTP_STATUS_CODE.bad_request.status,
211+
message: 'updateData is required',
212+
})
213+
}
214+
215+
const result = await programUsersHelper.updateEntityLocation(
216+
{
217+
userId,
218+
entityId,
219+
updateData,
220+
},
221+
req.userDetails
222+
)
223+
224+
return resolve(result)
225+
} catch (error) {
226+
return reject({
227+
status: HTTP_STATUS_CODE.internal_server_error.status,
228+
message: error.message || 'Internal server error',
229+
})
230+
}
231+
})
232+
}
184233
}

generics/services/users.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,8 +640,87 @@ const accountSearch = function (
640640
})
641641
}
642642

643+
/**
644+
* Update user profile
645+
* @method
646+
* @name updateProfile
647+
* @param {String} userId - user id to update
648+
* @param {Object} updateData - user profile data to update (address, province, site, etc.)
649+
* @param {String} userToken - logged in user token
650+
* @param {String} tenantCode - tenant code
651+
* @param {String} organizationId - organization id (required for org-admin endpoint)
652+
* @returns {Promise} A promise that resolves with the updated user data or rejects with an error.
653+
*/
654+
const updateProfile = function (userId, updateData, userToken, tenantCode, organizationId) {
655+
return new Promise(async (resolve, reject) => {
656+
try {
657+
// Use org-admin/updateUser endpoint to update participant profile
658+
// This endpoint supports both role updates and profile updates (address, province, site, etc.)
659+
const url = interfaceServiceUrl + process.env.USER_SERVICE_BASE_URL + '/v1/org-admin/updateUser/' + userId
660+
661+
// Include organization_id in the body (required by org-admin endpoint)
662+
const bodyData = {
663+
...updateData,
664+
organization_id: organizationId,
665+
}
666+
667+
const options = {
668+
headers: {
669+
'Content-Type': 'application/json',
670+
internal_access_token: process.env.INTERNAL_ACCESS_TOKEN,
671+
'x-auth-token': userToken,
672+
tenantId: tenantCode,
673+
},
674+
json: bodyData,
675+
}
676+
677+
// Use PATCH method for org-admin updateUser endpoint (as per working curl)
678+
// request library supports patch method, but if not available, use method option
679+
if (request.patch) {
680+
request.patch(url, options, updateCallback)
681+
} else {
682+
// Fallback: use request with method option
683+
options.method = 'PATCH'
684+
request(url, options, updateCallback)
685+
}
686+
let result = {
687+
success: true,
688+
}
689+
690+
function updateCallback(err, data) {
691+
if (err) {
692+
result.success = false
693+
result.error = err
694+
} else {
695+
let response = typeof data.body === 'string' ? JSON.parse(data.body) : data.body
696+
if (response.responseCode === HTTP_STATUS_CODE['ok'].code) {
697+
result['data'] = response.result
698+
} else {
699+
result.success = false
700+
result.message = response.message
701+
result.responseCode = response.responseCode
702+
}
703+
}
704+
return resolve(result)
705+
}
706+
setTimeout(function () {
707+
return resolve(
708+
(result = {
709+
success: false,
710+
message: 'Request timeout',
711+
})
712+
)
713+
}, CONSTANTS.common.SERVER_TIME_OUT)
714+
} catch (error) {
715+
console.log('error', error)
716+
return reject(error)
717+
}
718+
})
719+
}
720+
643721
module.exports = {
644722
profile: profile,
723+
updateProfile: updateProfile,
645724
// locationSearch : locationSearch,
646725
// getParentEntities : getParentEntities,
647726
// profileReadPrivate: profileReadPrivate,

module/programUsers/helper.js

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,4 +714,172 @@ module.exports = class ProgramUsersHelper {
714714
}
715715
}
716716
}
717+
718+
/**
719+
* Check if logged-in user has the participant assigned in programUsers
720+
* @method
721+
* @name checkParticipantAssigned
722+
* @param {String} loggedInUserId - logged in user's userId
723+
* @param {String} participantUserId - participant's userId to check
724+
* @param {String} participantEntityId - participant's entityId to check
725+
* @param {String} tenantId - tenant ID
726+
* @returns {Promise<Object>} result with success status and programUsers document if found
727+
*/
728+
static async checkParticipantAssigned(loggedInUserId, participantUserId, participantEntityId, tenantId) {
729+
try {
730+
// Find programUsers document where logged-in user is the userId and has the participant in entities
731+
const query = {
732+
userId: loggedInUserId.toString(),
733+
tenantId: tenantId,
734+
entities: {
735+
$elemMatch: {
736+
$or: [
737+
{ userId: participantUserId.toString() },
738+
{ userId: participantEntityId.toString() },
739+
{ entityId: participantEntityId.toString() },
740+
{ externalId: participantEntityId.toString() },
741+
],
742+
},
743+
},
744+
}
745+
746+
const programUserDoc = await programUsersQueries.programUsersDocument(query, [
747+
'_id',
748+
'userId',
749+
'entities',
750+
'programId',
751+
'programExternalId',
752+
])
753+
754+
if (!programUserDoc || programUserDoc.length === 0) {
755+
return {
756+
success: false,
757+
message: 'Participant not assigned to logged-in user',
758+
}
759+
}
760+
761+
// Find the specific entity
762+
const doc = programUserDoc[0]
763+
const entity = doc.entities?.find(
764+
(e) =>
765+
e.userId == participantUserId ||
766+
e.userId == participantEntityId ||
767+
e.entityId == participantEntityId ||
768+
e.externalId == participantEntityId
769+
)
770+
771+
if (!entity) {
772+
return {
773+
success: false,
774+
message: 'Participant entity not found in programUsers',
775+
}
776+
}
777+
778+
return {
779+
success: true,
780+
programUserDoc: doc,
781+
entity: entity,
782+
}
783+
} catch (error) {
784+
console.error('Error checking participant assignment:', error)
785+
return {
786+
success: false,
787+
message: error.message || 'Error checking participant assignment',
788+
}
789+
}
790+
}
791+
792+
/**
793+
* Update entity location/profile information
794+
* Similar to user/update but validates that logged-in user has participant assigned
795+
* @method
796+
* @name updateEntityLocation
797+
* @param {Object} data - request body data
798+
* @param {String} data.userId - participant's userId to update
799+
* @param {String} data.entityId - participant's entityId (optional, can use userId)
800+
* @param {Object} data.updateData - profile data to update (province, site, address, etc.)
801+
* @param {Object} userDetails - logged in user details
802+
* @returns {Object} result with status and updated user data
803+
*/
804+
static async updateEntityLocation(data, userDetails) {
805+
try {
806+
const { userId, entityId, updateData } = data
807+
const loggedInUserId = userDetails.userInformation?.userId
808+
const tenantId = userDetails.userInformation?.tenantId
809+
const userToken = userDetails.userToken
810+
811+
// Validate required fields
812+
if (!userId) {
813+
return {
814+
success: false,
815+
status: HTTP_STATUS_CODE.bad_request.status,
816+
message: 'userId is required',
817+
}
818+
}
819+
820+
if (!updateData || typeof updateData !== 'object' || Object.keys(updateData).length === 0) {
821+
return {
822+
success: false,
823+
status: HTTP_STATUS_CODE.bad_request.status,
824+
message: 'updateData is required and must be a non-empty object',
825+
}
826+
}
827+
828+
// Use entityId if provided, otherwise use userId
829+
const participantIdentifier = entityId || userId
830+
831+
// Check if logged-in user has this participant assigned
832+
const assignmentCheck = await this.checkParticipantAssigned(
833+
loggedInUserId,
834+
userId,
835+
participantIdentifier,
836+
tenantId
837+
)
838+
839+
if (!assignmentCheck.success) {
840+
return {
841+
success: false,
842+
status: HTTP_STATUS_CODE.forbidden.status,
843+
message: assignmentCheck.message || 'You do not have permission to update this participant',
844+
}
845+
}
846+
847+
// Get tenant code and organization ID from userDetails
848+
const tenantCode =
849+
userDetails.userInformation?.tenantCode || userDetails.userInformation?.tenantId || tenantId
850+
const organizationId = userDetails.userInformation?.organizationId
851+
852+
// Call user service to update the participant's profile using org-admin endpoint
853+
const updateResult = await userService.updateProfile(
854+
userId,
855+
updateData,
856+
userToken,
857+
tenantCode,
858+
organizationId
859+
)
860+
861+
if (!updateResult.success) {
862+
return {
863+
success: false,
864+
status: HTTP_STATUS_CODE.bad_request.status,
865+
message: updateResult.message || 'Failed to update participant profile',
866+
error: updateResult.error,
867+
}
868+
}
869+
870+
return {
871+
success: true,
872+
status: HTTP_STATUS_CODE.ok.status,
873+
message: 'Participant profile updated successfully',
874+
result: updateResult.data,
875+
}
876+
} catch (error) {
877+
console.error('Error updating participant location:', error)
878+
return {
879+
success: false,
880+
status: HTTP_STATUS_CODE.internal_server_error.status,
881+
message: error.message || 'Internal server error',
882+
}
883+
}
884+
}
717885
}

0 commit comments

Comments
 (0)