Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions src/controllers/v1/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,28 @@ module.exports = class Admin {
}

/**
* Deactivate Org
* @method
* @name deactivateOrg
* @param {String} req.params.id - org Id.
* @returns {JSON} - deactivated org response
* Deactivate an organization by its ID.
*
* Validates that the requesting user has admin access before deactivating
* the specified organization and all associated users.
*
* @async
* @method deactivateOrg
* @param {Object} req - Express request object.
* @param {string} req.params.id - The unique identifier (ID or code) of the organization to deactivate.
* @param {Object} req.decodedToken - Decoded JWT token of the authenticated user.
* @param {string[]} req.decodedToken.roles - Roles assigned to the logged-in user.
* @param {number} req.decodedToken.id - ID of the logged-in user.
* @param {Object} req.headers - HTTP request headers.
* @param {string} req.headers.tenant-id - Tenant code associated with the request.
* @returns {Promise<Object>} Response object from `adminService.deactivateOrg`,
* containing status, message, and deactivated user count.
*
* @throws {Object} Failure response if:
* - The user is not an admin.
* - The organization cannot be deactivated.
*/

async deactivateOrg(req) {
try {
if (!utilsHelper.validateRoleAccess(req.decodedToken.roles, common.ADMIN_ROLE)) {
Expand All @@ -136,7 +152,11 @@ module.exports = class Admin {
})
}

const result = await adminService.deactivateOrg(req.params.id, req.decodedToken.id)
const result = await adminService.deactivateOrg(
req.params.id,
req.headers?.['tenant-id'],
req.decodedToken.id
)
return result
} catch (error) {
return error
Expand Down
76 changes: 45 additions & 31 deletions src/services/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -568,70 +568,84 @@ module.exports = class AdminHelper {
}

/**
* Deactivate Organization
* @method
* @name deactivateOrg
* @param {Number} id - org id
* @param {Object} loggedInUserId - logged in user id
* @returns {JSON} - Deactivated user count
* Deactivate an organization and all its associated users.
*
* This method:
* 1. Updates the organization's status to inactive.
* 2. Deactivates all users belonging to the organization.
* 3. Ends all active sessions for the deactivated users.
* 4. Broadcasts an event to end any upcoming sessions.
*
* @async
* @function deactivateOrg
* @param {string} organizationCode - The unique code identifying the organization.
* @param {string} tenantCode - The tenant code to which the organization belongs.
* @param {number} loggedInUserId - The ID of the user performing the deactivation.
* @returns {Promise<Object>} Success or failure response object containing:
* - {number} result.deactivated_users - The number of users deactivated.
*
* @throws {Error} Will throw an error if the organization status update fails or if a database error occurs.
*/
static async deactivateOrg(id, loggedInUserId) {

static async deactivateOrg(organizationCode, tenantCode, loggedInUserId) {
try {
//deactivate org
let rowsAffected = await organizationQueries.update(
// 1. Deactivate org
const orgRowsAffected = await organizationQueries.update(
{
id,
code: organizationCode,
tenant_code: tenantCode,
},
{
status: common.INACTIVE_STATUS,
updated_by: loggedInUserId,
}
)

if (rowsAffected == 0) {
if (orgRowsAffected === 0) {
return responses.failureResponse({
message: 'STATUS_UPDATE_FAILED',
statusCode: httpStatusCode.bad_request,
responseCode: 'CLIENT_ERROR',
})
}

//deactivate all users in org
const [modifiedCount] = await userQueries.updateUser(
// 2. Deactivate all users in the org using the same helper as deactivateUser
const [userRowsAffected, updatedUsers] = await userQueries.deactivateUserInOrg(
{
organization_id: id,
tenant_code: tenantCode,
},
organizationCode,
tenantCode,
{
status: common.INACTIVE_STATUS,
updated_by: loggedInUserId,
}
)

const users = await userQueries.findAll(
{
organization_id: id,
},
{
attributes: ['id'],
}
true // so we can get the user IDs
)

const userIds = _.map(users, 'id')
eventBroadcaster('deactivateUpcomingSession', {
requestBody: {
user_ids: userIds,
},
})
// 3. Broadcast & remove sessions if users were found
if (userRowsAffected > 0) {
const userIds = updatedUsers.map((u) => u.id)

// End all active sessions for those users
await userHelper.removeAllUserSessions(userIds, tenantCode)

// Broadcast to end upcoming sessions
eventBroadcaster('deactivateUpcomingSession', {
requestBody: { user_ids: userIds },
})
}

// 4. Return success
return responses.successResponse({
statusCode: httpStatusCode.ok,
message: 'ORG_DEACTIVATED',
result: {
deactivated_users: modifiedCount,
deactivated_users: userRowsAffected,
},
})
} catch (error) {
console.log(error)
console.error('Error in deactivateOrg:', error)
throw error
}
}
Expand Down