New Feature: Ability to change role for a workspace user. (#4616)

* New Feature: Ability to change role for a workspace user.

* reverting some of the changes in workspace-user.service.ts and minor code cleanup in the ui components.

* chore: refactor updateWorkspaceUser function queryRunner handling

---------

Co-authored-by: chungyau97 <chungyau97@gmail.com>
This commit is contained in:
Vinod Kiran
2025-06-19 23:07:29 +05:30
committed by GitHub
parent a107aa7a77
commit 9a60b7b223
6 changed files with 280 additions and 57 deletions
@@ -1,10 +1,11 @@
import { Request, Response, NextFunction } from 'express'
import { NextFunction, Request, Response } from 'express'
import { StatusCodes } from 'http-status-codes'
import { WorkspaceUserService } from '../services/workspace-user.service'
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
import { WorkspaceUser } from '../database/entities/workspace-user.entity'
import { QueryRunner } from 'typeorm'
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
import { GeneralErrorMessage } from '../../utils/constants'
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
import { WorkspaceUser } from '../database/entities/workspace-user.entity'
import { WorkspaceUserService } from '../services/workspace-user.service'
export class WorkspaceUserController {
public async create(req: Request, res: Response, next: NextFunction) {
@@ -57,12 +58,18 @@ export class WorkspaceUserController {
}
public async update(req: Request, res: Response, next: NextFunction) {
let queryRunner: QueryRunner | undefined
try {
queryRunner = getRunningExpressApp().AppDataSource.createQueryRunner()
await queryRunner.connect()
const workspaceUserService = new WorkspaceUserService()
const workspaceUser = await workspaceUserService.updateWorkspaceUser(req.body)
const workspaceUser = await workspaceUserService.updateWorkspaceUser(req.body, queryRunner)
return res.status(StatusCodes.OK).json(workspaceUser)
} catch (error) {
if (queryRunner && queryRunner.isTransactionActive) await queryRunner.rollbackTransaction()
next(error)
} finally {
if (queryRunner && !queryRunner.isReleased) await queryRunner.release()
}
}
@@ -1,26 +1,26 @@
import { HttpStatusCode } from 'axios'
import { RedisStore } from 'connect-redis'
import express, { NextFunction, Request, Response } from 'express'
import session from 'express-session'
import { StatusCodes } from 'http-status-codes'
import jwt, { JwtPayload, sign } from 'jsonwebtoken'
import passport from 'passport'
import { VerifiedCallback } from 'passport-jwt'
import express, { NextFunction, Request, Response } from 'express'
import { ErrorMessage, IAssignedWorkspace, LoggedInUser } from '../../Interface.Enterprise'
import { decryptToken, encryptToken, generateSafeCopy } from '../../utils/tempTokenUtils'
import jwt, { JwtPayload, sign } from 'jsonwebtoken'
import { getAuthStrategy } from './AuthStrategy'
import { IdentityManager } from '../../../IdentityManager'
import { HttpStatusCode } from 'axios'
import { getRunningExpressApp } from '../../../utils/getRunningExpressApp'
import session from 'express-session'
import { OrganizationService } from '../../services/organization.service'
import { AccountService } from '../../services/account.service'
import { WorkspaceUser, WorkspaceUserStatus } from '../../database/entities/workspace-user.entity'
import { RoleErrorMessage, RoleService } from '../../services/role.service'
import { GeneralRole } from '../../database/entities/role.entity'
import { RedisStore } from 'connect-redis'
import { WorkspaceUserService } from '../../services/workspace-user.service'
import { OrganizationUserErrorMessage, OrganizationUserService } from '../../services/organization-user.service'
import { InternalFlowiseError } from '../../../errors/internalFlowiseError'
import { StatusCodes } from 'http-status-codes'
import { OrganizationUserStatus } from '../../database/entities/organization-user.entity'
import { IdentityManager } from '../../../IdentityManager'
import { Platform } from '../../../Interface'
import { getRunningExpressApp } from '../../../utils/getRunningExpressApp'
import { OrganizationUserStatus } from '../../database/entities/organization-user.entity'
import { GeneralRole } from '../../database/entities/role.entity'
import { WorkspaceUser, WorkspaceUserStatus } from '../../database/entities/workspace-user.entity'
import { ErrorMessage, IAssignedWorkspace, LoggedInUser } from '../../Interface.Enterprise'
import { AccountService } from '../../services/account.service'
import { OrganizationUserErrorMessage, OrganizationUserService } from '../../services/organization-user.service'
import { OrganizationService } from '../../services/organization.service'
import { RoleErrorMessage, RoleService } from '../../services/role.service'
import { WorkspaceUserService } from '../../services/workspace-user.service'
import { decryptToken, encryptToken, generateSafeCopy } from '../../utils/tempTokenUtils'
import { getAuthStrategy } from './AuthStrategy'
import { initializeDBClientAndStore, initializeRedisClientAndStore } from './SessionPersistance'
const localStrategy = require('passport-local').Strategy
@@ -123,7 +123,7 @@ export const initializeJwtCookieMiddleware = async (app: express.Application, id
if (!organizationUser)
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, OrganizationUserErrorMessage.ORGANIZATION_USER_NOT_FOUND)
organizationUser.status = OrganizationUserStatus.ACTIVE
await workspaceUserService.updateWorkspaceUser(workspaceUser)
await workspaceUserService.updateWorkspaceUser(workspaceUser, queryRunner)
await organizationUserService.updateOrganizationUser(organizationUser)
const workspaceUsers = await workspaceUserService.readWorkspaceUserByUserId(organizationUser.userId, queryRunner)
@@ -327,19 +327,22 @@ export class WorkspaceUserService {
return newWorkspace
}
public async updateWorkspaceUser(newWorkspaserUser: Partial<WorkspaceUser>) {
const queryRunner = this.dataSource.createQueryRunner()
await queryRunner.connect()
public async updateWorkspaceUser(newWorkspaserUser: Partial<WorkspaceUser>, queryRunner: QueryRunner) {
const { workspaceUser } = await this.readWorkspaceUserByWorkspaceIdUserId(
newWorkspaserUser.workspaceId,
newWorkspaserUser.userId,
queryRunner
)
if (!workspaceUser) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, WorkspaceUserErrorMessage.WORKSPACE_USER_NOT_FOUND)
if (newWorkspaserUser.roleId) {
if (newWorkspaserUser.roleId && workspaceUser.role) {
const role = await this.roleService.readRoleById(newWorkspaserUser.roleId, queryRunner)
if (!role) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, RoleErrorMessage.ROLE_NOT_FOUND)
// check if the role is from the same organization
if (role.organizationId !== workspaceUser.role.organizationId) {
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, RoleErrorMessage.ROLE_NOT_FOUND)
}
// delete role, the new role will be created again, with the new roleId (newWorkspaserUser.roleId)
if (workspaceUser.role) delete workspaceUser.role
}
const updatedBy = await this.userService.readUserById(newWorkspaserUser.updatedBy, queryRunner)
if (!updatedBy) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, UserErrorMessage.USER_NOT_FOUND)
@@ -348,16 +351,7 @@ export class WorkspaceUserService {
newWorkspaserUser.createdBy = workspaceUser.createdBy
let updataWorkspaceUser = queryRunner.manager.merge(WorkspaceUser, workspaceUser, newWorkspaserUser)
try {
await queryRunner.startTransaction()
updataWorkspaceUser = await this.saveWorkspaceUser(updataWorkspaceUser, queryRunner)
await queryRunner.commitTransaction()
} catch (error) {
await queryRunner.rollbackTransaction()
throw error
} finally {
await queryRunner.release()
}
updataWorkspaceUser = await this.saveWorkspaceUser(updataWorkspaceUser, queryRunner)
return updataWorkspaceUser
}