diff --git a/packages/server/src/Interface.ts b/packages/server/src/Interface.ts index 0a334153b..f1c603043 100644 --- a/packages/server/src/Interface.ts +++ b/packages/server/src/Interface.ts @@ -70,7 +70,7 @@ export interface IChatFlow { apiConfig?: string category?: string type?: ChatflowType - workspaceId?: string + workspaceId: string } export interface IChatMessage { @@ -115,7 +115,7 @@ export interface ITool { func?: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface IAssistant { @@ -125,7 +125,7 @@ export interface IAssistant { iconSrc?: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface ICredential { @@ -135,7 +135,7 @@ export interface ICredential { encryptedData: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface IVariable { @@ -145,7 +145,7 @@ export interface IVariable { type: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface ILead { @@ -177,7 +177,7 @@ export interface IExecution { createdDate: Date updatedDate: Date stoppedDate: Date - workspaceId?: string + workspaceId: string } export interface IComponentNodes { @@ -333,7 +333,7 @@ export interface ICredentialReqBody { name: string credentialName: string plainDataObj: ICredentialDataDecrypted - workspaceId?: string + workspaceId: string } // Decrypted credential object sent back to client @@ -352,7 +352,7 @@ export interface IApiKey { apiKey: string apiSecret: string updatedDate: Date - workspaceId?: string + workspaceId: string } export interface ICustomTemplate { @@ -366,7 +366,7 @@ export interface ICustomTemplate { badge?: string framework?: string usecases?: string - workspaceId?: string + workspaceId: string } export interface IFlowConfig { diff --git a/packages/server/src/controllers/apikey/index.ts b/packages/server/src/controllers/apikey/index.ts index 340ff27b2..677d68931 100644 --- a/packages/server/src/controllers/apikey/index.ts +++ b/packages/server/src/controllers/apikey/index.ts @@ -9,6 +9,9 @@ const getAllApiKeys = async (req: Request, res: Response, next: NextFunction) => try { const autoCreateNewKey = true const { page, limit } = getPageAndLimitParams(req) + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.getAllApiKeys(req.user?.activeWorkspaceId, autoCreateNewKey, page, limit) return res.json(apiResponse) } catch (error) { @@ -21,6 +24,9 @@ const createApiKey = async (req: Request, res: Response, next: NextFunction) => if (typeof req.body === 'undefined' || !req.body.keyName) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.createApiKey - keyName not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.createApiKey(req.body.keyName, req.user?.activeWorkspaceId) return res.json(apiResponse) } catch (error) { @@ -37,6 +43,9 @@ const updateApiKey = async (req: Request, res: Response, next: NextFunction) => if (typeof req.body === 'undefined' || !req.body.keyName) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.updateApiKey - keyName not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.updateApiKey(req.params.id, req.body.keyName, req.user?.activeWorkspaceId) return res.json(apiResponse) } catch (error) { @@ -50,6 +59,9 @@ const importKeys = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.body === 'undefined' || !req.body.jsonFile) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.importKeys - body not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } req.body.workspaceId = req.user?.activeWorkspaceId const apiResponse = await apikeyService.importKeys(req.body) return res.json(apiResponse) @@ -64,6 +76,9 @@ const deleteApiKey = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.deleteApiKey - id not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.deleteApiKey(req.params.id, req.user?.activeWorkspaceId) return res.json(apiResponse) } catch (error) { diff --git a/packages/server/src/controllers/assistants/index.ts b/packages/server/src/controllers/assistants/index.ts index 324907d0b..e4159bf3f 100644 --- a/packages/server/src/controllers/assistants/index.ts +++ b/packages/server/src/controllers/assistants/index.ts @@ -52,7 +52,14 @@ const deleteAssistant = async (req: Request, res: Response, next: NextFunction) `Error: assistantsController.deleteAssistant - id not provided!` ) } - const apiResponse = await assistantsService.deleteAssistant(req.params.id, req.query.isDeleteBoth) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.deleteAssistant - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.deleteAssistant(req.params.id, req.query.isDeleteBoth, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -62,7 +69,14 @@ const deleteAssistant = async (req: Request, res: Response, next: NextFunction) const getAllAssistants = async (req: Request, res: Response, next: NextFunction) => { try { const type = req.query.type as AssistantType - const apiResponse = await assistantsService.getAllAssistants(type, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.getAllAssistants - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.getAllAssistants(workspaceId, type) return res.json(apiResponse) } catch (error) { next(error) @@ -77,7 +91,14 @@ const getAssistantById = async (req: Request, res: Response, next: NextFunction) `Error: assistantsController.getAssistantById - id not provided!` ) } - const apiResponse = await assistantsService.getAssistantById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.getAssistantById - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.getAssistantById(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -98,7 +119,14 @@ const updateAssistant = async (req: Request, res: Response, next: NextFunction) `Error: assistantsController.updateAssistant - body not provided!` ) } - const apiResponse = await assistantsService.updateAssistant(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.updateAssistant - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.updateAssistant(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -116,7 +144,14 @@ const getChatModels = async (req: Request, res: Response, next: NextFunction) => const getDocumentStores = async (req: Request, res: Response, next: NextFunction) => { try { - const apiResponse = await assistantsService.getDocumentStores(req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.getDocumentStores - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.getDocumentStores(workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/chat-messages/index.ts b/packages/server/src/controllers/chat-messages/index.ts index b000c9ea3..d1d7cccba 100644 --- a/packages/server/src/controllers/chat-messages/index.ts +++ b/packages/server/src/controllers/chat-messages/index.ts @@ -166,7 +166,7 @@ const removeAllChatMessages = async (req: Request, res: Response, next: NextFunc ) } const chatflowid = req.params.id - const chatflow = await chatflowsService.getChatflowById(req.params.id) + const chatflow = await chatflowsService.getChatflowById(req.params.id, workspaceId) if (!chatflow) { return res.status(404).send(`Chatflow ${req.params.id} not found`) } diff --git a/packages/server/src/controllers/chatflows/index.ts b/packages/server/src/controllers/chatflows/index.ts index f8a10c33f..6b1a554ca 100644 --- a/packages/server/src/controllers/chatflows/index.ts +++ b/packages/server/src/controllers/chatflows/index.ts @@ -110,7 +110,14 @@ const getChatflowById = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: chatflowsController.getChatflowById - id not provided!`) } - const apiResponse = await chatflowsService.getChatflowById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: chatflowsController.getChatflowById - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await chatflowsService.getChatflowById(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -165,7 +172,14 @@ const updateChatflow = async (req: Request, res: Response, next: NextFunction) = if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: chatflowsController.updateChatflow - id not provided!`) } - const chatflow = await chatflowsService.getChatflowById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: chatflowsController.saveChatflow - workspace ${workspaceId} not found!` + ) + } + const chatflow = await chatflowsService.getChatflowById(req.params.id, workspaceId) if (!chatflow) { return res.status(404).send(`Chatflow ${req.params.id} not found`) } @@ -176,13 +190,6 @@ const updateChatflow = async (req: Request, res: Response, next: NextFunction) = `Error: chatflowsController.saveChatflow - organization ${orgId} not found!` ) } - const workspaceId = req.user?.activeWorkspaceId - if (!workspaceId) { - throw new InternalFlowiseError( - StatusCodes.NOT_FOUND, - `Error: chatflowsController.saveChatflow - workspace ${workspaceId} not found!` - ) - } const subscriptionId = req.user?.activeOrganizationSubscriptionId || '' const body = req.body const updateChatFlow = new ChatFlow() diff --git a/packages/server/src/controllers/credentials/index.ts b/packages/server/src/controllers/credentials/index.ts index 78cb4348c..6c6dea22a 100644 --- a/packages/server/src/controllers/credentials/index.ts +++ b/packages/server/src/controllers/credentials/index.ts @@ -28,7 +28,14 @@ const deleteCredentials = async (req: Request, res: Response, next: NextFunction `Error: credentialsController.deleteCredentials - id not provided!` ) } - const apiResponse = await credentialsService.deleteCredentials(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.deleteCredentials - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.deleteCredentials(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -37,7 +44,14 @@ const deleteCredentials = async (req: Request, res: Response, next: NextFunction const getAllCredentials = async (req: Request, res: Response, next: NextFunction) => { try { - const apiResponse = await credentialsService.getAllCredentials(req.query.credentialName, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.getAllCredentials - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.getAllCredentials(req.query.credentialName, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -52,7 +66,14 @@ const getCredentialById = async (req: Request, res: Response, next: NextFunction `Error: credentialsController.getCredentialById - id not provided!` ) } - const apiResponse = await credentialsService.getCredentialById(req.params.id, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.getCredentialById - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.getCredentialById(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -73,7 +94,14 @@ const updateCredential = async (req: Request, res: Response, next: NextFunction) `Error: credentialsController.updateCredential - body not provided!` ) } - const apiResponse = await credentialsService.updateCredential(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.updateCredential - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.updateCredential(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/dataset/index.ts b/packages/server/src/controllers/dataset/index.ts index d6c753118..0479a20de 100644 --- a/packages/server/src/controllers/dataset/index.ts +++ b/packages/server/src/controllers/dataset/index.ts @@ -7,7 +7,14 @@ import { getPageAndLimitParams } from '../../utils/pagination' const getAllDatasets = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await datasetService.getAllDatasets(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.getAllDatasets - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.getAllDatasets(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -20,7 +27,14 @@ const getDataset = async (req: Request, res: Response, next: NextFunction) => { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.getDataset - id not provided!`) } const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await datasetService.getDataset(req.params.id, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.getDataset - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.getDataset(req.params.id, workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -33,7 +47,14 @@ const createDataset = async (req: Request, res: Response, next: NextFunction) => throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.createDataset - body not provided!`) } const body = req.body - body.workspaceId = req.user?.activeWorkspaceId + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.createDataset - workspace ${workspaceId} not found!` + ) + } + body.workspaceId = workspaceId const apiResponse = await datasetService.createDataset(body) return res.json(apiResponse) } catch (error) { @@ -49,7 +70,14 @@ const updateDataset = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.updateDataset - id not provided!`) } - const apiResponse = await datasetService.updateDataset(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.updateDataset - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.updateDataset(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -61,7 +89,14 @@ const deleteDataset = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.deleteDataset - id not provided!`) } - const apiResponse = await datasetService.deleteDataset(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.deleteDataset - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.deleteDataset(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -76,6 +111,14 @@ const addDatasetRow = async (req: Request, res: Response, next: NextFunction) => if (!req.body.datasetId) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.addDatasetRow - datasetId not provided!`) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.addDatasetRow - workspace ${workspaceId} not found!` + ) + } + req.body.workspaceId = workspaceId const apiResponse = await datasetService.addDatasetRow(req.body) return res.json(apiResponse) } catch (error) { @@ -91,6 +134,14 @@ const updateDatasetRow = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.updateDatasetRow - id not provided!`) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.updateDatasetRow - workspace ${workspaceId} not found!` + ) + } + req.body.workspaceId = workspaceId const apiResponse = await datasetService.updateDatasetRow(req.params.id, req.body) return res.json(apiResponse) } catch (error) { @@ -103,7 +154,14 @@ const deleteDatasetRow = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.deleteDatasetRow - id not provided!`) } - const apiResponse = await datasetService.deleteDatasetRow(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.deleteDatasetRow - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.deleteDatasetRow(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -113,7 +171,14 @@ const deleteDatasetRow = async (req: Request, res: Response, next: NextFunction) const patchDeleteRows = async (req: Request, res: Response, next: NextFunction) => { try { const ids = req.body.ids ?? [] - const apiResponse = await datasetService.patchDeleteRows(ids) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.patchDeleteRows - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.patchDeleteRows(ids, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -125,8 +190,14 @@ const reorderDatasetRow = async (req: Request, res: Response, next: NextFunction if (!req.body) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.reorderDatasetRow - body not provided!`) } - - const apiResponse = await datasetService.reorderDatasetRow(req.body.datasetId, req.body.rows) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.reorderDatasetRow - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.reorderDatasetRow(req.body.datasetId, req.body.rows, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/documentstore/index.ts b/packages/server/src/controllers/documentstore/index.ts index 9d19373b4..1ac4f4395 100644 --- a/packages/server/src/controllers/documentstore/index.ts +++ b/packages/server/src/controllers/documentstore/index.ts @@ -27,7 +27,12 @@ const createDocumentStore = async (req: Request, res: Response, next: NextFuncti const body = req.body body.workspaceId = req.user?.activeWorkspaceId - + if (!body.workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.createDocumentStore - workspaceId not provided!` + ) + } const docStore = DocumentStoreDTO.toEntity(body) const apiResponse = await documentStoreService.createDocumentStore(docStore, orgId) return res.json(apiResponse) @@ -40,7 +45,14 @@ const getAllDocumentStores = async (req: Request, res: Response, next: NextFunct try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse: any = await documentStoreService.getAllDocumentStores(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.getAllDocumentStores - workspaceId not provided!` + ) + } + const apiResponse: any = await documentStoreService.getAllDocumentStores(workspaceId, page, limit) if (apiResponse?.total >= 0) { return res.json({ total: apiResponse.total, @@ -102,9 +114,16 @@ const getDocumentStoreById = async (req: Request, res: Response, next: NextFunct `Error: documentStoreController.getDocumentStoreById - id not provided!` ) } - const apiResponse = await documentStoreService.getDocumentStoreById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.getDocumentStoreById - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.getDocumentStoreById(req.params.id, workspaceId) if (apiResponse && apiResponse.whereUsed) { - apiResponse.whereUsed = JSON.stringify(await documentStoreService.getUsedChatflowNames(apiResponse)) + apiResponse.whereUsed = JSON.stringify(await documentStoreService.getUsedChatflowNames(apiResponse, workspaceId)) } return res.json(DocumentStoreDTO.fromEntity(apiResponse)) } catch (error) { @@ -126,12 +145,20 @@ const getDocumentStoreFileChunks = async (req: Request, res: Response, next: Nex `Error: documentStoreController.getDocumentStoreFileChunks - fileId not provided!` ) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.getDocumentStoreFileChunks - workspaceId not provided!` + ) + } const appDataSource = getRunningExpressApp().AppDataSource const page = req.params.pageNo ? parseInt(req.params.pageNo) : 1 const apiResponse = await documentStoreService.getDocumentStoreFileChunks( appDataSource, req.params.storeId, req.params.fileId, + workspaceId, page ) return res.json(apiResponse) @@ -160,10 +187,18 @@ const deleteDocumentStoreFileChunk = async (req: Request, res: Response, next: N `Error: documentStoreController.deleteDocumentStoreFileChunk - chunkId not provided!` ) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.deleteDocumentStoreFileChunk - workspaceId not provided!` + ) + } const apiResponse = await documentStoreService.deleteDocumentStoreFileChunk( req.params.storeId, req.params.loaderId, - req.params.chunkId + req.params.chunkId, + workspaceId ) return res.json(apiResponse) } catch (error) { @@ -198,12 +233,20 @@ const editDocumentStoreFileChunk = async (req: Request, res: Response, next: Nex `Error: documentStoreController.editDocumentStoreFileChunk - body not provided!` ) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.editDocumentStoreFileChunk - workspaceId not provided!` + ) + } const apiResponse = await documentStoreService.editDocumentStoreFileChunk( req.params.storeId, req.params.loaderId, req.params.chunkId, body.pageContent, - body.metadata + body.metadata, + workspaceId ) return res.json(apiResponse) } catch (error) { @@ -221,7 +264,14 @@ const saveProcessingLoader = async (req: Request, res: Response, next: NextFunct ) } const body = req.body - const apiResponse = await documentStoreService.saveProcessingLoader(appServer.AppDataSource, body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.saveProcessingLoader - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.saveProcessingLoader(appServer.AppDataSource, body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -289,7 +339,14 @@ const updateDocumentStore = async (req: Request, res: Response, next: NextFuncti `Error: documentStoreController.updateDocumentStore - body not provided!` ) } - const store = await documentStoreService.getDocumentStoreById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.updateDocumentStore - workspaceId not provided!` + ) + } + const store = await documentStoreService.getDocumentStoreById(req.params.id, workspaceId) if (!store) { throw new InternalFlowiseError( StatusCodes.NOT_FOUND, @@ -449,7 +506,14 @@ const deleteVectorStoreFromStore = async (req: Request, res: Response, next: Nex `Error: documentStoreController.deleteVectorStoreFromStore - storeId not provided!` ) } - const apiResponse = await documentStoreService.deleteVectorStoreFromStore(req.params.storeId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.deleteVectorStoreFromStore - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.deleteVectorStoreFromStore(req.params.storeId, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -463,7 +527,14 @@ const saveVectorStoreConfig = async (req: Request, res: Response, next: NextFunc } const body = req.body const appDataSource = getRunningExpressApp().AppDataSource - const apiResponse = await documentStoreService.saveVectorStoreConfig(appDataSource, body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.saveVectorStoreConfig - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.saveVectorStoreConfig(appDataSource, body, true, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -476,7 +547,14 @@ const updateVectorStoreConfigOnly = async (req: Request, res: Response, next: Ne throw new Error('Error: documentStoreController.updateVectorStoreConfigOnly - body not provided!') } const body = req.body - const apiResponse = await documentStoreService.updateVectorStoreConfigOnly(body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.updateVectorStoreConfigOnly - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.updateVectorStoreConfigOnly(body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/evaluations/index.ts b/packages/server/src/controllers/evaluations/index.ts index 4cde76158..b38213aa0 100644 --- a/packages/server/src/controllers/evaluations/index.ts +++ b/packages/server/src/controllers/evaluations/index.ts @@ -31,7 +31,7 @@ const createEvaluation = async (req: Request, res: Response, next: NextFunction) const httpProtocol = req.get('x-forwarded-proto') || req.get('X-Forwarded-Proto') || req.protocol const baseURL = `${httpProtocol}://${req.get('host')}` - const apiResponse = await evaluationsService.createEvaluation(body, baseURL, orgId) + const apiResponse = await evaluationsService.createEvaluation(body, baseURL, orgId, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -47,9 +47,16 @@ const runAgain = async (req: Request, res: Response, next: NextFunction) => { if (!orgId) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Error: evaluationsService.runAgain - organization ${orgId} not found!`) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.runAgain - workspace ${workspaceId} not found!` + ) + } const httpProtocol = req.get('x-forwarded-proto') || req.get('X-Forwarded-Proto') || req.protocol const baseURL = `${httpProtocol}://${req.get('host')}` - const apiResponse = await evaluationsService.runAgain(req.params.id, baseURL, orgId) + const apiResponse = await evaluationsService.runAgain(req.params.id, baseURL, orgId, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -61,7 +68,14 @@ const getEvaluation = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.getEvaluation - id not provided!`) } - const apiResponse = await evaluationsService.getEvaluation(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.getEvaluation - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.getEvaluation(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -73,7 +87,14 @@ const deleteEvaluation = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.deleteEvaluation - id not provided!`) } - const apiResponse = await evaluationsService.deleteEvaluation(req.params.id, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.deleteEvaluation - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.deleteEvaluation(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -83,7 +104,14 @@ const deleteEvaluation = async (req: Request, res: Response, next: NextFunction) const getAllEvaluations = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await evaluationsService.getAllEvaluations(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.getAllEvaluations - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.getAllEvaluations(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -95,7 +123,14 @@ const isOutdated = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.isOutdated - id not provided!`) } - const apiResponse = await evaluationsService.isOutdated(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.isOutdated - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.isOutdated(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -107,7 +142,14 @@ const getVersions = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.getVersions - id not provided!`) } - const apiResponse = await evaluationsService.getVersions(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.getVersions - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.getVersions(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -118,7 +160,14 @@ const patchDeleteEvaluations = async (req: Request, res: Response, next: NextFun try { const ids = req.body.ids ?? [] const isDeleteAllVersion = req.body.isDeleteAllVersion ?? false - const apiResponse = await evaluationsService.patchDeleteEvaluations(ids, isDeleteAllVersion, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.patchDeleteEvaluations - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.patchDeleteEvaluations(ids, workspaceId, isDeleteAllVersion) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/evaluators/index.ts b/packages/server/src/controllers/evaluators/index.ts index 1f151c37c..5f864a85c 100644 --- a/packages/server/src/controllers/evaluators/index.ts +++ b/packages/server/src/controllers/evaluators/index.ts @@ -7,7 +7,14 @@ import { getPageAndLimitParams } from '../../utils/pagination' const getAllEvaluators = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await evaluatorService.getAllEvaluators(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.getAllEvaluators - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.getAllEvaluators(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -19,7 +26,14 @@ const getEvaluator = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluatorService.getEvaluator - id not provided!`) } - const apiResponse = await evaluatorService.getEvaluator(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.getEvaluator - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.getEvaluator(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -48,7 +62,14 @@ const updateEvaluator = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluatorService.updateEvaluator - id not provided!`) } - const apiResponse = await evaluatorService.updateEvaluator(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.updateEvaluator - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.updateEvaluator(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -60,7 +81,14 @@ const deleteEvaluator = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluatorService.deleteEvaluator - id not provided!`) } - const apiResponse = await evaluatorService.deleteEvaluator(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.deleteEvaluator - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.deleteEvaluator(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/export-import/index.ts b/packages/server/src/controllers/export-import/index.ts index b066df0c8..ae2a86928 100644 --- a/packages/server/src/controllers/export-import/index.ts +++ b/packages/server/src/controllers/export-import/index.ts @@ -5,10 +5,14 @@ import exportImportService from '../../services/export-import' const exportData = async (req: Request, res: Response, next: NextFunction) => { try { - const apiResponse = await exportImportService.exportData( - exportImportService.convertExportInput(req.body), - req.user?.activeWorkspaceId - ) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: exportImportController.exportData - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await exportImportService.exportData(exportImportService.convertExportInput(req.body), workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/flow-configs/index.ts b/packages/server/src/controllers/flow-configs/index.ts index c09262660..ba5fadeee 100644 --- a/packages/server/src/controllers/flow-configs/index.ts +++ b/packages/server/src/controllers/flow-configs/index.ts @@ -11,7 +11,14 @@ const getSingleFlowConfig = async (req: Request, res: Response, next: NextFuncti `Error: flowConfigsController.getSingleFlowConfig - id not provided!` ) } - const apiResponse = await flowConfigsService.getSingleFlowConfig(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: flowConfigsController.getSingleFlowConfig - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await flowConfigsService.getSingleFlowConfig(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/internal-predictions/index.ts b/packages/server/src/controllers/internal-predictions/index.ts index 5e53a1d65..b5614faf2 100644 --- a/packages/server/src/controllers/internal-predictions/index.ts +++ b/packages/server/src/controllers/internal-predictions/index.ts @@ -1,12 +1,22 @@ -import { Request, Response, NextFunction } from 'express' -import { utilBuildChatflow } from '../../utils/buildChatflow' -import { getRunningExpressApp } from '../../utils/getRunningExpressApp' +import { NextFunction, Request, Response } from 'express' +import { StatusCodes } from 'http-status-codes' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { getErrorMessage } from '../../errors/utils' import { MODE } from '../../Interface' +import chatflowService from '../../services/chatflows' +import { utilBuildChatflow } from '../../utils/buildChatflow' +import { getRunningExpressApp } from '../../utils/getRunningExpressApp' // Send input message and get prediction result (Internal) const createInternalPrediction = async (req: Request, res: Response, next: NextFunction) => { try { + const workspaceId = req.user?.activeWorkspaceId + + const chatflow = await chatflowService.getChatflowById(req.params.id, workspaceId) + if (!chatflow) { + throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${req.params.id} not found`) + } + if (req.body.streaming || req.body.streaming === 'true') { createAndStreamInternalPrediction(req, res, next) return diff --git a/packages/server/src/controllers/marketplaces/index.ts b/packages/server/src/controllers/marketplaces/index.ts index 5d19d40e6..552336855 100644 --- a/packages/server/src/controllers/marketplaces/index.ts +++ b/packages/server/src/controllers/marketplaces/index.ts @@ -1,7 +1,7 @@ -import { Request, Response, NextFunction } from 'express' -import marketplacesService from '../../services/marketplaces' -import { InternalFlowiseError } from '../../errors/internalFlowiseError' +import { NextFunction, Request, Response } from 'express' import { StatusCodes } from 'http-status-codes' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' +import marketplacesService from '../../services/marketplaces' // Get all templates for marketplaces const getAllTemplates = async (req: Request, res: Response, next: NextFunction) => { @@ -21,7 +21,14 @@ const deleteCustomTemplate = async (req: Request, res: Response, next: NextFunct `Error: marketplacesService.deleteCustomTemplate - id not provided!` ) } - const apiResponse = await marketplacesService.deleteCustomTemplate(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: marketplacesController.deleteCustomTemplate - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await marketplacesService.deleteCustomTemplate(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -47,6 +54,12 @@ const saveCustomTemplate = async (req: Request, res: Response, next: NextFunctio } const body = req.body body.workspaceId = req.user?.activeWorkspaceId + if (!body.workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: marketplacesController.saveCustomTemplate - workspace ${body.workspaceId} not found!` + ) + } const apiResponse = await marketplacesService.saveCustomTemplate(body) return res.json(apiResponse) } catch (error) { diff --git a/packages/server/src/controllers/predictions/index.ts b/packages/server/src/controllers/predictions/index.ts index b7f79b642..d467f3157 100644 --- a/packages/server/src/controllers/predictions/index.ts +++ b/packages/server/src/controllers/predictions/index.ts @@ -25,7 +25,9 @@ const createPrediction = async (req: Request, res: Response, next: NextFunction) `Error: predictionsController.createPrediction - body not provided!` ) } - const chatflow = await chatflowsService.getChatflowById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + + const chatflow = await chatflowsService.getChatflowById(req.params.id, workspaceId) if (!chatflow) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${req.params.id} not found`) } diff --git a/packages/server/src/controllers/text-to-speech/index.ts b/packages/server/src/controllers/text-to-speech/index.ts index 6cfa3f5ef..af92713a8 100644 --- a/packages/server/src/controllers/text-to-speech/index.ts +++ b/packages/server/src/controllers/text-to-speech/index.ts @@ -1,11 +1,11 @@ -import { Request, Response, NextFunction } from 'express' +import { NextFunction, Request, Response } from 'express' +import { convertTextToSpeechStream } from 'flowise-components' +import { StatusCodes } from 'http-status-codes' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' import chatflowsService from '../../services/chatflows' import textToSpeechService from '../../services/text-to-speech' -import { InternalFlowiseError } from '../../errors/internalFlowiseError' -import { StatusCodes } from 'http-status-codes' -import { getRunningExpressApp } from '../../utils/getRunningExpressApp' -import { convertTextToSpeechStream } from 'flowise-components' import { databaseEntities } from '../../utils' +import { getRunningExpressApp } from '../../utils/getRunningExpressApp' const generateTextToSpeech = async (req: Request, res: Response) => { try { @@ -30,8 +30,15 @@ const generateTextToSpeech = async (req: Request, res: Response) => { let provider: string, credentialId: string, voice: string, model: string if (chatflowId) { + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: textToSpeechController.generateTextToSpeech - workspace ${workspaceId} not found!` + ) + } // Get TTS config from chatflow - const chatflow = await chatflowsService.getChatflowById(chatflowId) + const chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId) const ttsConfig = JSON.parse(chatflow.textToSpeech) // Find the provider with status: true diff --git a/packages/server/src/controllers/tools/index.ts b/packages/server/src/controllers/tools/index.ts index 8b5772a4f..301d9420e 100644 --- a/packages/server/src/controllers/tools/index.ts +++ b/packages/server/src/controllers/tools/index.ts @@ -1,7 +1,7 @@ import { NextFunction, Request, Response } from 'express' -import toolsService from '../../services/tools' -import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { StatusCodes } from 'http-status-codes' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' +import toolsService from '../../services/tools' import { getPageAndLimitParams } from '../../utils/pagination' const createTool = async (req: Request, res: Response, next: NextFunction) => { @@ -32,7 +32,11 @@ const deleteTool = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: toolsController.deleteTool - id not provided!`) } - const apiResponse = await toolsService.deleteTool(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Error: toolsController.deleteTool - workspace ${workspaceId} not found!`) + } + const apiResponse = await toolsService.deleteTool(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -54,7 +58,14 @@ const getToolById = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: toolsController.getToolById - id not provided!`) } - const apiResponse = await toolsService.getToolById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: toolsController.getToolById - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await toolsService.getToolById(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -69,7 +80,11 @@ const updateTool = async (req: Request, res: Response, next: NextFunction) => { if (!req.body) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: toolsController.deleteTool - body not provided!`) } - const apiResponse = await toolsService.updateTool(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Error: toolsController.updateTool - workspace ${workspaceId} not found!`) + } + const apiResponse = await toolsService.updateTool(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/variables/index.ts b/packages/server/src/controllers/variables/index.ts index 42b58603e..3f8455410 100644 --- a/packages/server/src/controllers/variables/index.ts +++ b/packages/server/src/controllers/variables/index.ts @@ -37,7 +37,14 @@ const deleteVariable = async (req: Request, res: Response, next: NextFunction) = if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, 'Error: variablesController.deleteVariable - id not provided!') } - const apiResponse = await variablesService.deleteVariable(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: variablesController.deleteVariable - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await variablesService.deleteVariable(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -47,7 +54,14 @@ const deleteVariable = async (req: Request, res: Response, next: NextFunction) = const getAllVariables = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await variablesService.getAllVariables(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: variablesController.getAllVariables - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await variablesService.getAllVariables(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -65,7 +79,14 @@ const updateVariable = async (req: Request, res: Response, next: NextFunction) = 'Error: variablesController.updateVariable - body not provided!' ) } - const variable = await variablesService.getVariableById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: variablesController.updateVariable - workspace ${workspaceId} not found!` + ) + } + const variable = await variablesService.getVariableById(req.params.id, workspaceId) if (!variable) { return res.status(404).send(`Variable ${req.params.id} not found in the database`) } diff --git a/packages/server/src/database/entities/ApiKey.ts b/packages/server/src/database/entities/ApiKey.ts index e7c1d84e5..4778962a1 100644 --- a/packages/server/src/database/entities/ApiKey.ts +++ b/packages/server/src/database/entities/ApiKey.ts @@ -19,6 +19,6 @@ export class ApiKey implements IApiKey { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Assistant.ts b/packages/server/src/database/entities/Assistant.ts index 288432139..1d9eabbe8 100644 --- a/packages/server/src/database/entities/Assistant.ts +++ b/packages/server/src/database/entities/Assistant.ts @@ -27,6 +27,6 @@ export class Assistant implements IAssistant { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/ChatFlow.ts b/packages/server/src/database/entities/ChatFlow.ts index 0ff726afe..d3561aa00 100644 --- a/packages/server/src/database/entities/ChatFlow.ts +++ b/packages/server/src/database/entities/ChatFlow.ts @@ -61,6 +61,6 @@ export class ChatFlow implements IChatFlow { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Credential.ts b/packages/server/src/database/entities/Credential.ts index 2c43158c4..5cff59f49 100644 --- a/packages/server/src/database/entities/Credential.ts +++ b/packages/server/src/database/entities/Credential.ts @@ -24,6 +24,6 @@ export class Credential implements ICredential { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/CustomTemplate.ts b/packages/server/src/database/entities/CustomTemplate.ts index e45719e69..ed99cebd3 100644 --- a/packages/server/src/database/entities/CustomTemplate.ts +++ b/packages/server/src/database/entities/CustomTemplate.ts @@ -27,7 +27,7 @@ export class CustomTemplate implements ICustomTemplate { @Column({ nullable: true, type: 'text' }) type?: string - @Column({ nullable: true, type: 'text' }) + @Column({ nullable: false, type: 'text' }) workspaceId: string @Column({ type: 'timestamp' }) diff --git a/packages/server/src/database/entities/Dataset.ts b/packages/server/src/database/entities/Dataset.ts index 8dd604d3d..8acd5f2bb 100644 --- a/packages/server/src/database/entities/Dataset.ts +++ b/packages/server/src/database/entities/Dataset.ts @@ -19,6 +19,6 @@ export class Dataset implements IDataset { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/DocumentStore.ts b/packages/server/src/database/entities/DocumentStore.ts index 01babca47..9a94fde52 100644 --- a/packages/server/src/database/entities/DocumentStore.ts +++ b/packages/server/src/database/entities/DocumentStore.ts @@ -38,6 +38,6 @@ export class DocumentStore implements IDocumentStore { @Column({ nullable: true, type: 'text' }) recordManagerConfig: string | null - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Evaluation.ts b/packages/server/src/database/entities/Evaluation.ts index 85128ae01..4f23a05e3 100644 --- a/packages/server/src/database/entities/Evaluation.ts +++ b/packages/server/src/database/entities/Evaluation.ts @@ -36,6 +36,6 @@ export class Evaluation implements IEvaluation { @UpdateDateColumn() runDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Evaluator.ts b/packages/server/src/database/entities/Evaluator.ts index 8e7f6f9b9..a14e0c905 100644 --- a/packages/server/src/database/entities/Evaluator.ts +++ b/packages/server/src/database/entities/Evaluator.ts @@ -23,6 +23,6 @@ export class Evaluator implements IEvaluator { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Execution.ts b/packages/server/src/database/entities/Execution.ts index 87885cf8a..eac53f639 100644 --- a/packages/server/src/database/entities/Execution.ts +++ b/packages/server/src/database/entities/Execution.ts @@ -42,6 +42,6 @@ export class Execution implements IExecution { @JoinColumn({ name: 'agentflowId' }) agentflow: ChatFlow - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Tool.ts b/packages/server/src/database/entities/Tool.ts index 3a0dcbc89..2e35b64a6 100644 --- a/packages/server/src/database/entities/Tool.ts +++ b/packages/server/src/database/entities/Tool.ts @@ -33,6 +33,6 @@ export class Tool implements ITool { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Variable.ts b/packages/server/src/database/entities/Variable.ts index 6a8006dd6..33105c0f6 100644 --- a/packages/server/src/database/entities/Variable.ts +++ b/packages/server/src/database/entities/Variable.ts @@ -24,6 +24,6 @@ export class Variable implements IVariable { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/enterprise/Interface.Enterprise.ts b/packages/server/src/enterprise/Interface.Enterprise.ts index d7ddfc393..5dd4384e0 100644 --- a/packages/server/src/enterprise/Interface.Enterprise.ts +++ b/packages/server/src/enterprise/Interface.Enterprise.ts @@ -17,7 +17,6 @@ export class IUser { role: string lastLogin: Date activeWorkspaceId: string - isApiKeyValidated?: boolean loginMode?: string activeOrganizationId?: string } @@ -73,7 +72,6 @@ export type LoggedInUser = { activeWorkspaceId: string activeWorkspace: string assignedWorkspaces: IAssignedWorkspace[] - isApiKeyValidated: boolean permissions?: string[] features?: Record ssoRefreshToken?: string diff --git a/packages/server/src/enterprise/controllers/workspace.controller.ts b/packages/server/src/enterprise/controllers/workspace.controller.ts index d20edcf94..dc29f97a6 100644 --- a/packages/server/src/enterprise/controllers/workspace.controller.ts +++ b/packages/server/src/enterprise/controllers/workspace.controller.ts @@ -129,7 +129,6 @@ export class WorkspaceController { activeWorkspaceId: workspace.id, activeWorkspace: workspace.name, assignedWorkspaces, - isApiKeyValidated: true, isSSO: req.user.ssoProvider ? true : false, permissions: [...JSON.parse(role.permissions)], features, diff --git a/packages/server/src/enterprise/middleware/passport/index.ts b/packages/server/src/enterprise/middleware/passport/index.ts index 43abf56de..dc7658030 100644 --- a/packages/server/src/enterprise/middleware/passport/index.ts +++ b/packages/server/src/enterprise/middleware/passport/index.ts @@ -179,7 +179,6 @@ export const initializeJwtCookieMiddleware = async (app: express.Application, id activeWorkspaceId: workspaceUser.workspaceId, activeWorkspace: workspaceUser.workspace.name, assignedWorkspaces, - isApiKeyValidated: true, permissions: [...JSON.parse(role.permissions)], features } diff --git a/packages/server/src/enterprise/rbac/PermissionCheck.ts b/packages/server/src/enterprise/rbac/PermissionCheck.ts index 583d4ad60..d0856c4bc 100644 --- a/packages/server/src/enterprise/rbac/PermissionCheck.ts +++ b/packages/server/src/enterprise/rbac/PermissionCheck.ts @@ -7,7 +7,7 @@ export const checkPermission = (permission: string) => { const user = req.user // if the user is not logged in, return forbidden if (user) { - if (user.isApiKeyValidated || user.isOrganizationAdmin) { + if (user.isOrganizationAdmin) { return next() } const permissions = user.permissions @@ -26,7 +26,7 @@ export const checkAnyPermission = (permissionsString: string) => { const user = req.user // if the user is not logged in, return forbidden if (user) { - if (user.isApiKeyValidated || user.isOrganizationAdmin) { + if (user.isOrganizationAdmin) { return next() } const permissions = user.permissions diff --git a/packages/server/src/enterprise/sso/SSOBase.ts b/packages/server/src/enterprise/sso/SSOBase.ts index f990de5a8..e216c6977 100644 --- a/packages/server/src/enterprise/sso/SSOBase.ts +++ b/packages/server/src/enterprise/sso/SSOBase.ts @@ -132,7 +132,6 @@ abstract class SSOBase { activeWorkspaceId: workspaceUser.workspaceId, activeWorkspace: workspaceUser.workspace.name, assignedWorkspaces, - isApiKeyValidated: true, ssoToken: accessToken as string, ssoRefreshToken: refreshToken, ssoProvider: ssoProviderName, diff --git a/packages/server/src/enterprise/utils/ControllerServiceUtils.ts b/packages/server/src/enterprise/utils/ControllerServiceUtils.ts index 245f1e471..1d0983c67 100644 --- a/packages/server/src/enterprise/utils/ControllerServiceUtils.ts +++ b/packages/server/src/enterprise/utils/ControllerServiceUtils.ts @@ -1,11 +1,19 @@ import { Equal } from 'typeorm' import { Request } from 'express' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' +import { StatusCodes } from 'http-status-codes' export const getWorkspaceSearchOptions = (workspaceId?: string) => { - return workspaceId ? { workspaceId: Equal(workspaceId) } : {} + if (!workspaceId) { + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, `Workspace ID is required`) + } + return { workspaceId: Equal(workspaceId) } } export const getWorkspaceSearchOptionsFromReq = (req: Request) => { const workspaceId = req.user?.activeWorkspaceId - return workspaceId ? { workspaceId: Equal(workspaceId) } : {} + if (!workspaceId) { + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, `Workspace ID is required`) + } + return { workspaceId: Equal(workspaceId) } } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index e418984df..258be4cbd 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -280,8 +280,7 @@ export class App { activeOrganizationProductId: productId, isOrganizationAdmin: true, activeWorkspaceId: apiKeyWorkSpaceId!, - activeWorkspace: workspace.name, - isApiKeyValidated: true + activeWorkspace: workspace.name } next() } diff --git a/packages/server/src/routes/chat-messages/index.ts b/packages/server/src/routes/chat-messages/index.ts index ca90abcf7..efea8da9c 100644 --- a/packages/server/src/routes/chat-messages/index.ts +++ b/packages/server/src/routes/chat-messages/index.ts @@ -3,7 +3,8 @@ import chatMessageController from '../../controllers/chat-messages' const router = express.Router() // CREATE -router.post(['/', '/:id'], chatMessageController.createChatMessage) +// NOTE: Unused route +// router.post(['/', '/:id'], chatMessageController.createChatMessage) // READ router.get(['/', '/:id'], chatMessageController.getAllChatMessages) diff --git a/packages/server/src/routes/chatflows/index.ts b/packages/server/src/routes/chatflows/index.ts index 774f0928d..5d2ec2609 100644 --- a/packages/server/src/routes/chatflows/index.ts +++ b/packages/server/src/routes/chatflows/index.ts @@ -1,23 +1,43 @@ import express from 'express' import chatflowsController from '../../controllers/chatflows' -import { checkAnyPermission, checkPermission } from '../../enterprise/rbac/PermissionCheck' +import { checkAnyPermission } from '../../enterprise/rbac/PermissionCheck' const router = express.Router() // CREATE -router.post('/', checkAnyPermission('chatflows:create,chatflows:update'), chatflowsController.saveChatflow) +router.post( + '/', + checkAnyPermission('chatflows:create,chatflows:update,agentflows:create,agentflows:update'), + chatflowsController.saveChatflow +) // READ -router.get('/', checkAnyPermission('chatflows:view,chatflows:update'), chatflowsController.getAllChatflows) -router.get(['/', '/:id'], checkAnyPermission('chatflows:view,chatflows:update,chatflows:delete'), chatflowsController.getChatflowById) +router.get( + '/', + checkAnyPermission('chatflows:view,chatflows:update,agentflows:view,agentflows:update'), + chatflowsController.getAllChatflows +) +router.get( + ['/', '/:id'], + checkAnyPermission('chatflows:view,chatflows:update,chatflows:delete,agentflows:view,agentflows:update,agentflows:delete'), + chatflowsController.getChatflowById +) router.get(['/apikey/', '/apikey/:apikey'], chatflowsController.getChatflowByApiKey) // UPDATE -router.put(['/', '/:id'], checkAnyPermission('chatflows:create,chatflows:update'), chatflowsController.updateChatflow) +router.put( + ['/', '/:id'], + checkAnyPermission('chatflows:create,chatflows:update,agentflows:create,agentflows:update'), + chatflowsController.updateChatflow +) // DELETE -router.delete(['/', '/:id'], checkPermission('chatflows:delete'), chatflowsController.deleteChatflow) +router.delete(['/', '/:id'], checkAnyPermission('chatflows:delete,agentflows:delete'), chatflowsController.deleteChatflow) // CHECK FOR CHANGE -router.get('/has-changed/:id/:lastUpdatedDateTime', chatflowsController.checkIfChatflowHasChanged) +router.get( + '/has-changed/:id/:lastUpdatedDateTime', + checkAnyPermission('chatflows:update,agentflows:update'), + chatflowsController.checkIfChatflowHasChanged +) export default router diff --git a/packages/server/src/services/apikey/index.ts b/packages/server/src/services/apikey/index.ts index a8b603633..5e009c927 100644 --- a/packages/server/src/services/apikey/index.ts +++ b/packages/server/src/services/apikey/index.ts @@ -9,14 +9,14 @@ import { Not, IsNull } from 'typeorm' import { getWorkspaceSearchOptions } from '../../enterprise/utils/ControllerServiceUtils' import { v4 as uuidv4 } from 'uuid' -const getAllApiKeysFromDB = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllApiKeysFromDB = async (workspaceId: string, page: number = -1, limit: number = -1) => { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(ApiKey).createQueryBuilder('api_key').orderBy('api_key.updatedDate', 'DESC') if (page > 0 && limit > 0) { queryBuilder.skip((page - 1) * limit) queryBuilder.take(limit) } - if (workspaceId) queryBuilder.andWhere('api_key.workspaceId = :workspaceId', { workspaceId }) + queryBuilder.andWhere('api_key.workspaceId = :workspaceId', { workspaceId }) const [data, total] = await queryBuilder.getManyAndCount() const keysWithChatflows = await addChatflowsCount(data) @@ -27,7 +27,7 @@ const getAllApiKeysFromDB = async (workspaceId?: string, page: number = -1, limi } } -const getAllApiKeys = async (workspaceId?: string, autoCreateNewKey?: boolean, page: number = -1, limit: number = -1) => { +const getAllApiKeys = async (workspaceId: string, autoCreateNewKey?: boolean, page: number = -1, limit: number = -1) => { try { let keys = await getAllApiKeysFromDB(workspaceId, page, limit) const isEmpty = keys?.total === 0 || (Array.isArray(keys) && keys?.length === 0) @@ -71,7 +71,7 @@ const getApiKeyById = async (apiKeyId: string) => { } } -const createApiKey = async (keyName: string, workspaceId?: string) => { +const createApiKey = async (keyName: string, workspaceId: string) => { try { const apiKey = generateAPIKey() const apiSecret = generateSecretHash(apiKey) @@ -91,11 +91,12 @@ const createApiKey = async (keyName: string, workspaceId?: string) => { } // Update api key -const updateApiKey = async (id: string, keyName: string, workspaceId?: string) => { +const updateApiKey = async (id: string, keyName: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const currentKey = await appServer.AppDataSource.getRepository(ApiKey).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!currentKey) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `ApiKey ${currentKey} not found`) @@ -108,7 +109,7 @@ const updateApiKey = async (id: string, keyName: string, workspaceId?: string) = } } -const deleteApiKey = async (id: string, workspaceId?: string) => { +const deleteApiKey = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(ApiKey).delete({ id, workspaceId }) diff --git a/packages/server/src/services/assistants/index.ts b/packages/server/src/services/assistants/index.ts index 72dfc4a00..0151124b9 100644 --- a/packages/server/src/services/assistants/index.ts +++ b/packages/server/src/services/assistants/index.ts @@ -160,11 +160,12 @@ const createAssistant = async (requestBody: any, orgId: string): Promise => { +const deleteAssistant = async (assistantId: string, isDeleteBoth: any, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: assistantId + id: assistantId, + workspaceId: workspaceId }) if (!assistant) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Assistant ${assistantId} not found`) @@ -225,7 +226,7 @@ async function getAssistantsCountByOrganization(type: AssistantType, organizatio } } -const getAllAssistants = async (type?: AssistantType, workspaceId?: string): Promise => { +const getAllAssistants = async (workspaceId: string, type?: AssistantType): Promise => { try { const appServer = getRunningExpressApp() if (type) { @@ -245,7 +246,7 @@ const getAllAssistants = async (type?: AssistantType, workspaceId?: string): Pro } } -const getAllAssistantsCount = async (type?: AssistantType, workspaceId?: string): Promise => { +const getAllAssistantsCount = async (workspaceId: string, type?: AssistantType): Promise => { try { const appServer = getRunningExpressApp() if (type) { @@ -265,11 +266,12 @@ const getAllAssistantsCount = async (type?: AssistantType, workspaceId?: string) } } -const getAssistantById = async (assistantId: string): Promise => { +const getAssistantById = async (assistantId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: assistantId + id: assistantId, + workspaceId: workspaceId }) if (!dbResponse) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Assistant ${assistantId} not found`) @@ -283,11 +285,12 @@ const getAssistantById = async (assistantId: string): Promise => { } } -const updateAssistant = async (assistantId: string, requestBody: any): Promise => { +const updateAssistant = async (assistantId: string, requestBody: any, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: assistantId + id: assistantId, + workspaceId: workspaceId }) if (!assistant) { @@ -461,7 +464,7 @@ const getChatModels = async (): Promise => { } } -const getDocumentStores = async (activeWorkspaceId?: string): Promise => { +const getDocumentStores = async (activeWorkspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const stores = await appServer.AppDataSource.getRepository(DocumentStore).findBy(getWorkspaceSearchOptions(activeWorkspaceId)) diff --git a/packages/server/src/services/chatflows/index.ts b/packages/server/src/services/chatflows/index.ts index 88e543356..17456bc13 100644 --- a/packages/server/src/services/chatflows/index.ts +++ b/packages/server/src/services/chatflows/index.ts @@ -106,6 +106,8 @@ const deleteChatflow = async (chatflowId: string, orgId: string, workspaceId: st try { const appServer = getRunningExpressApp() + await getChatflowById(chatflowId, workspaceId) + const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).delete({ id: chatflowId }) // Update document store usage @@ -238,11 +240,14 @@ const getChatflowByApiKey = async (apiKeyId: string, keyonly?: unknown): Promise } } -const getChatflowById = async (chatflowId: string): Promise => { +const getChatflowById = async (chatflowId: string, workspaceId?: string): Promise => { try { const appServer = getRunningExpressApp() - const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ - id: chatflowId + const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).findOne({ + where: { + id: chatflowId, + ...(workspaceId ? { workspaceId } : {}) + } }) if (!dbResponse) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${chatflowId} not found in the database!`) diff --git a/packages/server/src/services/credentials/index.ts b/packages/server/src/services/credentials/index.ts index 4a511b793..9f1f318ad 100644 --- a/packages/server/src/services/credentials/index.ts +++ b/packages/server/src/services/credentials/index.ts @@ -1,14 +1,14 @@ -import { omit } from 'lodash' import { StatusCodes } from 'http-status-codes' -import { getRunningExpressApp } from '../../utils/getRunningExpressApp' -import { Credential } from '../../database/entities/Credential' -import { transformToCredentialEntity, decryptCredentialData } from '../../utils' +import { omit } from 'lodash' import { ICredentialReturnResponse } from '../../Interface' -import { InternalFlowiseError } from '../../errors/internalFlowiseError' -import { getErrorMessage } from '../../errors/utils' -import { getWorkspaceSearchOptions } from '../../enterprise/utils/ControllerServiceUtils' +import { Credential } from '../../database/entities/Credential' import { WorkspaceShared } from '../../enterprise/database/entities/EnterpriseEntities' import { WorkspaceService } from '../../enterprise/services/workspace.service' +import { getWorkspaceSearchOptions } from '../../enterprise/utils/ControllerServiceUtils' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' +import { getErrorMessage } from '../../errors/utils' +import { decryptCredentialData, transformToCredentialEntity } from '../../utils' +import { getRunningExpressApp } from '../../utils/getRunningExpressApp' const createCredential = async (requestBody: any) => { try { @@ -31,10 +31,10 @@ const createCredential = async (requestBody: any) => { } // Delete all credentials from chatflowid -const deleteCredentials = async (credentialId: string): Promise => { +const deleteCredentials = async (credentialId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() - const dbResponse = await appServer.AppDataSource.getRepository(Credential).delete({ id: credentialId }) + const dbResponse = await appServer.AppDataSource.getRepository(Credential).delete({ id: credentialId, workspaceId: workspaceId }) if (!dbResponse) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${credentialId} not found`) } @@ -47,7 +47,7 @@ const deleteCredentials = async (credentialId: string): Promise => { } } -const getAllCredentials = async (paramCredentialName: any, workspaceId?: string) => { +const getAllCredentials = async (paramCredentialName: any, workspaceId: string) => { try { const appServer = getRunningExpressApp() let dbResponse: any[] = [] @@ -124,11 +124,12 @@ const getAllCredentials = async (paramCredentialName: any, workspaceId?: string) } } -const getCredentialById = async (credentialId: string, workspaceId?: string): Promise => { +const getCredentialById = async (credentialId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({ - id: credentialId + id: credentialId, + workspaceId: workspaceId }) if (!credential) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${credentialId} not found`) @@ -165,11 +166,12 @@ const getCredentialById = async (credentialId: string, workspaceId?: string): Pr } } -const updateCredential = async (credentialId: string, requestBody: any): Promise => { +const updateCredential = async (credentialId: string, requestBody: any, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({ - id: credentialId + id: credentialId, + workspaceId: workspaceId }) if (!credential) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${credentialId} not found`) @@ -177,6 +179,7 @@ const updateCredential = async (credentialId: string, requestBody: any): Promise const decryptedCredentialData = await decryptCredentialData(credential.encryptedData) requestBody.plainDataObj = { ...decryptedCredentialData, ...requestBody.plainDataObj } const updateCredential = await transformToCredentialEntity(requestBody) + updateCredential.workspaceId = workspaceId await appServer.AppDataSource.getRepository(Credential).merge(credential, updateCredential) const dbResponse = await appServer.AppDataSource.getRepository(Credential).save(credential) return dbResponse diff --git a/packages/server/src/services/dataset/index.ts b/packages/server/src/services/dataset/index.ts index 351919e6b..4042e420f 100644 --- a/packages/server/src/services/dataset/index.ts +++ b/packages/server/src/services/dataset/index.ts @@ -9,7 +9,7 @@ import { In } from 'typeorm' import csv from 'csv-parser' -const getAllDatasets = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllDatasets = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(Dataset).createQueryBuilder('ds').orderBy('ds.updatedDate', 'DESC') @@ -43,11 +43,12 @@ const getAllDatasets = async (workspaceId?: string, page: number = -1, limit: nu } } -const getDataset = async (id: string, page: number = -1, limit: number = -1) => { +const getDataset = async (id: string, workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) const queryBuilder = appServer.AppDataSource.getRepository(DatasetRow).createQueryBuilder('dsr').orderBy('dsr.sequenceNo', 'ASC') queryBuilder.andWhere('dsr.datasetId = :datasetId', { datasetId: id }) @@ -88,7 +89,7 @@ const getDataset = async (id: string, page: number = -1, limit: number = -1) => } } -const reorderDatasetRow = async (datasetId: string, rows: any[]) => { +const reorderDatasetRow = async (datasetId: string, rows: any[], workspaceId: string) => { try { const appServer = getRunningExpressApp() await appServer.AppDataSource.transaction(async (entityManager) => { @@ -102,7 +103,7 @@ const reorderDatasetRow = async (datasetId: string, rows: any[]) => { item.sequenceNo = row.sequenceNo await entityManager.getRepository(DatasetRow).save(item) } - await changeUpdateOnDataset(datasetId, entityManager) + await changeUpdateOnDataset(datasetId, workspaceId, entityManager) }) return { message: 'Dataset row reordered successfully' } } catch (error) { @@ -211,11 +212,12 @@ const createDataset = async (body: any) => { } // Update dataset -const updateDataset = async (id: string, body: any) => { +const updateDataset = async (id: string, body: any, workspaceId: string) => { try { const appServer = getRunningExpressApp() const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!dataset) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Dataset ${id} not found`) @@ -230,10 +232,10 @@ const updateDataset = async (id: string, body: any) => { } // Delete dataset via id -const deleteDataset = async (id: string) => { +const deleteDataset = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() - const result = await appServer.AppDataSource.getRepository(Dataset).delete({ id: id }) + const result = await appServer.AppDataSource.getRepository(Dataset).delete({ id: id, workspaceId: workspaceId }) // delete all rows for this dataset await appServer.AppDataSource.getRepository(DatasetRow).delete({ datasetId: id }) @@ -250,7 +252,7 @@ const addDatasetRow = async (body: any) => { const appServer = getRunningExpressApp() if (body.csvFile) { await _csvToDatasetRows(body.datasetId, body.csvFile, body.firstRowHeaders) - await changeUpdateOnDataset(body.datasetId) + await changeUpdateOnDataset(body.datasetId, body.workspaceId) return { message: 'Dataset rows added successfully' } } else { // get the max value first @@ -272,7 +274,7 @@ const addDatasetRow = async (body: any) => { newDs.sequenceNo = sequenceNo === 0 ? sequenceNo : sequenceNo + 1 const row = appServer.AppDataSource.getRepository(DatasetRow).create(newDs) const result = await appServer.AppDataSource.getRepository(DatasetRow).save(row) - await changeUpdateOnDataset(body.datasetId) + await changeUpdateOnDataset(body.datasetId, body.workspaceId) return result } } catch (error) { @@ -283,10 +285,11 @@ const addDatasetRow = async (body: any) => { } } -const changeUpdateOnDataset = async (id: string, entityManager?: any) => { +const changeUpdateOnDataset = async (id: string, workspaceId: string, entityManager?: any) => { const appServer = getRunningExpressApp() const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!dataset) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Dataset ${id} not found`) @@ -311,7 +314,7 @@ const updateDatasetRow = async (id: string, body: any) => { Object.assign(updateItem, body) appServer.AppDataSource.getRepository(DatasetRow).merge(item, updateItem) const result = await appServer.AppDataSource.getRepository(DatasetRow).save(item) - await changeUpdateOnDataset(body.datasetId) + await changeUpdateOnDataset(body.datasetId, body.workspaceId) return result } catch (error) { throw new InternalFlowiseError( @@ -322,7 +325,7 @@ const updateDatasetRow = async (id: string, body: any) => { } // Delete dataset row via id -const deleteDatasetRow = async (id: string) => { +const deleteDatasetRow = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() return await appServer.AppDataSource.transaction(async (entityManager) => { @@ -332,7 +335,7 @@ const deleteDatasetRow = async (id: string) => { if (!item) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Dataset Row ${id} not found`) const result = await entityManager.getRepository(DatasetRow).delete({ id: id }) - await changeUpdateOnDataset(item.datasetId, entityManager) + await changeUpdateOnDataset(item.datasetId, workspaceId, entityManager) return result }) } catch (error) { @@ -344,7 +347,7 @@ const deleteDatasetRow = async (id: string) => { } // Delete dataset rows via ids -const patchDeleteRows = async (ids: string[] = []) => { +const patchDeleteRows = async (ids: string[] = [], workspaceId: string) => { try { const appServer = getRunningExpressApp() const datasetItemsToBeDeleted = await appServer.AppDataSource.getRepository(DatasetRow).find({ @@ -356,7 +359,7 @@ const patchDeleteRows = async (ids: string[] = []) => { const datasetIds = [...new Set(datasetItemsToBeDeleted.map((item) => item.datasetId))] for (const datasetId of datasetIds) { - await changeUpdateOnDataset(datasetId) + await changeUpdateOnDataset(datasetId, workspaceId) } return dbResponse } catch (error) { diff --git a/packages/server/src/services/documentstore/index.ts b/packages/server/src/services/documentstore/index.ts index 05520523d..0ee1cad20 100644 --- a/packages/server/src/services/documentstore/index.ts +++ b/packages/server/src/services/documentstore/index.ts @@ -77,7 +77,7 @@ const createDocumentStore = async (newDocumentStore: DocumentStore, orgId: strin } } -const getAllDocumentStores = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllDocumentStores = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(DocumentStore) @@ -88,7 +88,7 @@ const getAllDocumentStores = async (workspaceId?: string, page: number = -1, lim queryBuilder.skip((page - 1) * limit) queryBuilder.take(limit) } - if (workspaceId) queryBuilder.andWhere('doc_store.workspaceId = :workspaceId', { workspaceId }) + queryBuilder.andWhere('doc_store.workspaceId = :workspaceId', { workspaceId }) const [data, total] = await queryBuilder.getManyAndCount() @@ -172,11 +172,12 @@ const deleteLoaderFromDocumentStore = async ( } } -const getDocumentStoreById = async (storeId: string) => { +const getDocumentStoreById = async (storeId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -193,7 +194,7 @@ const getDocumentStoreById = async (storeId: string) => { } } -const getUsedChatflowNames = async (entity: DocumentStore) => { +const getUsedChatflowNames = async (entity: DocumentStore, workspaceId: string) => { try { const appServer = getRunningExpressApp() if (entity.whereUsed) { @@ -201,7 +202,7 @@ const getUsedChatflowNames = async (entity: DocumentStore) => { const updatedWhereUsed: IDocumentStoreWhereUsed[] = [] for (let i = 0; i < whereUsed.length; i++) { const associatedChatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOne({ - where: { id: whereUsed[i] }, + where: { id: whereUsed[i], workspaceId: workspaceId }, select: ['id', 'name'] }) if (associatedChatflow) { @@ -223,10 +224,17 @@ const getUsedChatflowNames = async (entity: DocumentStore) => { } // Get chunks for a specific loader or store -const getDocumentStoreFileChunks = async (appDataSource: DataSource, storeId: string, docId: string, pageNo: number = 1) => { +const getDocumentStoreFileChunks = async ( + appDataSource: DataSource, + storeId: string, + docId: string, + workspaceId: string, + pageNo: number = 1 +) => { try { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -307,24 +315,20 @@ const deleteDocumentStore = async (storeId: string, orgId: string, workspaceId: try { const appServer = getRunningExpressApp() - // delete all the chunks associated with the store - await appServer.AppDataSource.getRepository(DocumentStoreFileChunk).delete({ - storeId: storeId - }) - // now delete the files associated with the store const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) } - if (workspaceId) { - if (entity?.workspaceId !== workspaceId) { - throw new Error('Unauthorized access') - } - } + // delete all the chunks associated with the store + await appServer.AppDataSource.getRepository(DocumentStoreFileChunk).delete({ + storeId: storeId + }) + // now delete the files associated with the store try { const { totalSize } = await removeFilesFromStorage(orgId, DOCUMENT_STORE_BASE_FOLDER, entity.id) await updateStorageUsage(orgId, workspaceId, totalSize, usageCacheManager) @@ -351,11 +355,12 @@ const deleteDocumentStore = async (storeId: string, orgId: string, workspaceId: } } -const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chunkId: string) => { +const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chunkId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) @@ -377,7 +382,7 @@ const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chun found.totalChars -= tbdChunk.pageContent.length entity.loaders = JSON.stringify(loaders) await appServer.AppDataSource.getRepository(DocumentStore).save(entity) - return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId) + return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId, workspaceId) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, @@ -386,13 +391,14 @@ const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chun } } -const deleteVectorStoreFromStore = async (storeId: string) => { +const deleteVectorStoreFromStore = async (storeId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const componentNodes = appServer.nodesPool.componentNodes const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) @@ -465,11 +471,19 @@ const deleteVectorStoreFromStore = async (storeId: string) => { } } -const editDocumentStoreFileChunk = async (storeId: string, docId: string, chunkId: string, content: string, metadata: ICommonObject) => { +const editDocumentStoreFileChunk = async ( + storeId: string, + docId: string, + chunkId: string, + content: string, + metadata: ICommonObject, + workspaceId: string +) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) @@ -493,7 +507,7 @@ const editDocumentStoreFileChunk = async (storeId: string, docId: string, chunkI await appServer.AppDataSource.getRepository(DocumentStoreFileChunk).save(editChunk) entity.loaders = JSON.stringify(loaders) await appServer.AppDataSource.getRepository(DocumentStore).save(entity) - return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId) + return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId, workspaceId) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, @@ -718,10 +732,15 @@ export const previewChunks = async ({ appDataSource, componentNodes, data, orgId } } -const saveProcessingLoader = async (appDataSource: DataSource, data: IDocumentStoreLoaderForPreview): Promise => { +const saveProcessingLoader = async ( + appDataSource: DataSource, + data: IDocumentStoreLoaderForPreview, + workspaceId: string +): Promise => { try { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -809,7 +828,8 @@ export const processLoader = async ({ usageCacheManager }: IExecuteProcessLoader) => { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -817,11 +837,6 @@ export const processLoader = async ({ `Error: documentStoreServices.processLoader - Document store ${data.storeId} not found` ) } - if (workspaceId) { - if (entity?.workspaceId !== workspaceId) { - throw new Error('Unauthorized access') - } - } await _saveChunksToStorage( appDataSource, componentNodes, @@ -833,7 +848,7 @@ export const processLoader = async ({ subscriptionId, usageCacheManager ) - return getDocumentStoreFileChunks(appDataSource, data.storeId as string, docLoaderId) + return getDocumentStoreFileChunks(appDataSource, data.storeId as string, docLoaderId, workspaceId) } const processLoaderMiddleware = async ( @@ -1114,11 +1129,12 @@ const updateDocumentStoreUsage = async (chatId: string, storeId: string | undefi } } -const updateVectorStoreConfigOnly = async (data: ICommonObject) => { +const updateVectorStoreConfigOnly = async (data: ICommonObject, workspaceId: string) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${data.storeId} not found`) @@ -1141,10 +1157,11 @@ const updateVectorStoreConfigOnly = async (data: ICommonObject) => { ) } } -const saveVectorStoreConfig = async (appDataSource: DataSource, data: ICommonObject, isStrictSave = true) => { +const saveVectorStoreConfig = async (appDataSource: DataSource, data: ICommonObject, isStrictSave = true, workspaceId: string) => { try { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${data.storeId} not found`) @@ -1210,14 +1227,23 @@ export const insertIntoVectorStore = async ({ telemetry, data, isStrictSave, - orgId + orgId, + workspaceId }: IExecuteVectorStoreInsert) => { try { - const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave) + const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave, workspaceId) entity.status = DocumentStoreStatus.UPSERTING await appDataSource.getRepository(DocumentStore).save(entity) - const indexResult = await _insertIntoVectorStoreWorkerThread(appDataSource, componentNodes, telemetry, data, isStrictSave, orgId) + const indexResult = await _insertIntoVectorStoreWorkerThread( + appDataSource, + componentNodes, + telemetry, + data, + isStrictSave, + orgId, + workspaceId + ) return indexResult } catch (error) { throw new InternalFlowiseError( @@ -1283,10 +1309,11 @@ const _insertIntoVectorStoreWorkerThread = async ( telemetry: Telemetry, data: ICommonObject, isStrictSave = true, - orgId: string + orgId: string, + workspaceId: string ) => { try { - const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave) + const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave, workspaceId) let upsertHistory: Record = {} const chatflowid = data.storeId // fake chatflowid because this is not tied to any chatflow @@ -1858,7 +1885,7 @@ const upsertDocStore = async ( } try { - const newLoader = await saveProcessingLoader(appDataSource, processData) + const newLoader = await saveProcessingLoader(appDataSource, processData, workspaceId) const result = await processLoader({ appDataSource, componentNodes, diff --git a/packages/server/src/services/evaluations/EvaluatorRunner.ts b/packages/server/src/services/evaluations/EvaluatorRunner.ts index 4b2d7d81d..3f2a42081 100644 --- a/packages/server/src/services/evaluations/EvaluatorRunner.ts +++ b/packages/server/src/services/evaluations/EvaluatorRunner.ts @@ -14,7 +14,8 @@ export const runAdditionalEvaluators = async ( metricsArray: ICommonObject[], actualOutputArray: string[], errorArray: string[], - selectedEvaluators: string[] + selectedEvaluators: string[], + workspaceId: string ) => { const evaluationResults: any[] = [] const evaluatorDict: any = {} @@ -27,7 +28,7 @@ export const runAdditionalEvaluators = async ( const evaluatorId = selectedEvaluators[i] let evaluator = evaluatorDict[evaluatorId] if (!evaluator) { - evaluator = await evaluatorsService.getEvaluator(evaluatorId) + evaluator = await evaluatorsService.getEvaluator(evaluatorId, workspaceId) evaluatorDict[evaluatorId] = evaluator } diff --git a/packages/server/src/services/evaluations/index.ts b/packages/server/src/services/evaluations/index.ts index 9195ac26f..fe0aae71b 100644 --- a/packages/server/src/services/evaluations/index.ts +++ b/packages/server/src/services/evaluations/index.ts @@ -21,11 +21,12 @@ import evaluatorsService from '../evaluator' import { LLMEvaluationRunner } from './LLMEvaluationRunner' import { Assistant } from '../../database/entities/Assistant' -const runAgain = async (id: string, baseURL: string, orgId: string) => { +const runAgain = async (id: string, baseURL: string, orgId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const additionalConfig = evaluation.additionalConfig ? JSON.parse(evaluation.additionalConfig) : {} @@ -55,13 +56,13 @@ const runAgain = async (id: string, baseURL: string, orgId: string) => { } } data.version = true - return await createEvaluation(data, baseURL, orgId) + return await createEvaluation(data, baseURL, orgId, workspaceId) } catch (error) { throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error: EvalsService.runAgain - ${getErrorMessage(error)}`) } } -const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: string) => { +const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const newEval = new Evaluation() @@ -97,7 +98,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str ) const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: body.datasetId + id: body.datasetId, + workspaceId: workspaceId }) if (!dataset) throw new Error(`Dataset ${body.datasetId} not found`) @@ -124,7 +126,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str for (let i = 0; i < chatflowIds.length; i++) { const chatflowId = chatflowIds[i] const cFlow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ - id: chatflowId + id: chatflowId, + workspaceId: workspaceId }) if (cFlow && cFlow.apikeyid) { const apikeyObj = await appServer.AppDataSource.getRepository(ApiKey).findOneBy({ @@ -243,7 +246,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str metricsArray, actualOutputArray, errorArray, - body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] + body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [], + workspaceId ) newRun.evaluators = JSON.stringify(results) @@ -257,7 +261,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str const llmEvaluatorMap: { evaluatorId: string; evaluator: any }[] = [] for (let i = 0; i < resultRow.LLMEvaluators.length; i++) { const evaluatorId = resultRow.LLMEvaluators[i] - const evaluator = await evaluatorsService.getEvaluator(evaluatorId) + const evaluator = await evaluatorsService.getEvaluator(evaluatorId, workspaceId) llmEvaluatorMap.push({ evaluatorId: evaluatorId, evaluator: evaluator @@ -338,7 +342,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str } } -const getAllEvaluations = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllEvaluations = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() @@ -421,7 +425,7 @@ const getAllEvaluations = async (workspaceId?: string, page: number = -1, limit: } // Delete evaluation and all rows via id -const deleteEvaluation = async (id: string, activeWorkspaceId?: string) => { +const deleteEvaluation = async (id: string, activeWorkspaceId: string) => { try { const appServer = getRunningExpressApp() await appServer.AppDataSource.getRepository(Evaluation).delete({ id: id }) @@ -437,11 +441,12 @@ const deleteEvaluation = async (id: string, activeWorkspaceId?: string) => { } // check for outdated evaluations -const isOutdated = async (id: string) => { +const isOutdated = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const evaluationRunDate = evaluation.runDate.getTime() @@ -456,7 +461,8 @@ const isOutdated = async (id: string) => { // check if the evaluation is outdated by extracting the runTime and then check with the dataset last updated time as well // as the chatflows last updated time. If the evaluation is outdated, then return true else return false const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: evaluation.datasetId + id: evaluation.datasetId, + workspaceId: workspaceId }) if (dataset) { const datasetLastUpdated = dataset.updatedDate.getTime() @@ -483,7 +489,8 @@ const isOutdated = async (id: string) => { } } const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ - id: chatflowIds[i] + id: chatflowIds[i], + workspaceId: workspaceId }) if (!chatflow) { returnObj.errors.push({ @@ -511,7 +518,8 @@ const isOutdated = async (id: string) => { continue } const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: chatflowIds[i] + id: chatflowIds[i], + workspaceId: workspaceId }) if (!assistant) { returnObj.errors.push({ @@ -540,11 +548,12 @@ const isOutdated = async (id: string) => { } } -const getEvaluation = async (id: string) => { +const getEvaluation = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const versionCount = await appServer.AppDataSource.getRepository(Evaluation).countBy({ @@ -553,7 +562,7 @@ const getEvaluation = async (id: string) => { const items = await appServer.AppDataSource.getRepository(EvaluationRun).find({ where: { evaluationId: id } }) - const versions = (await getVersions(id)).versions + const versions = (await getVersions(id, workspaceId)).versions const versionNo = versions.findIndex((version) => version.id === id) + 1 return { ...evaluation, @@ -566,11 +575,12 @@ const getEvaluation = async (id: string) => { } } -const getVersions = async (id: string) => { +const getVersions = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const versions = await appServer.AppDataSource.getRepository(Evaluation).find({ @@ -597,12 +607,13 @@ const getVersions = async (id: string) => { } } -const patchDeleteEvaluations = async (ids: string[] = [], isDeleteAllVersion?: boolean, activeWorkspaceId?: string) => { +const patchDeleteEvaluations = async (ids: string[] = [], activeWorkspaceId: string, isDeleteAllVersion?: boolean) => { try { const appServer = getRunningExpressApp() const evalsToBeDeleted = await appServer.AppDataSource.getRepository(Evaluation).find({ where: { - id: In(ids) + id: In(ids), + workspaceId: activeWorkspaceId } }) await appServer.AppDataSource.getRepository(Evaluation).delete(ids) diff --git a/packages/server/src/services/evaluator/index.ts b/packages/server/src/services/evaluator/index.ts index 3cfbcc6f3..bd3d7e23a 100644 --- a/packages/server/src/services/evaluator/index.ts +++ b/packages/server/src/services/evaluator/index.ts @@ -5,11 +5,11 @@ import { getErrorMessage } from '../../errors/utils' import { Evaluator } from '../../database/entities/Evaluator' import { EvaluatorDTO } from '../../Interface.Evaluation' -const getAllEvaluators = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllEvaluators = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(Evaluator).createQueryBuilder('ev').orderBy('ev.updatedDate', 'DESC') - if (workspaceId) queryBuilder.andWhere('ev.workspaceId = :workspaceId', { workspaceId }) + queryBuilder.andWhere('ev.workspaceId = :workspaceId', { workspaceId }) if (page > 0 && limit > 0) { queryBuilder.skip((page - 1) * limit) queryBuilder.take(limit) @@ -31,11 +31,12 @@ const getAllEvaluators = async (workspaceId?: string, page: number = -1, limit: } } -const getEvaluator = async (id: string) => { +const getEvaluator = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluator = await appServer.AppDataSource.getRepository(Evaluator).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluator) throw new Error(`Evaluator ${id} not found`) return EvaluatorDTO.fromEntity(evaluator) @@ -65,11 +66,12 @@ const createEvaluator = async (body: any) => { } // Update Evaluator -const updateEvaluator = async (id: string, body: any) => { +const updateEvaluator = async (id: string, body: any, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluator = await appServer.AppDataSource.getRepository(Evaluator).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluator) throw new Error(`Evaluator ${id} not found`) @@ -88,10 +90,10 @@ const updateEvaluator = async (id: string, body: any) => { } // Delete Evaluator via id -const deleteEvaluator = async (id: string) => { +const deleteEvaluator = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() - return await appServer.AppDataSource.getRepository(Evaluator).delete({ id: id }) + return await appServer.AppDataSource.getRepository(Evaluator).delete({ id: id, workspaceId: workspaceId }) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, diff --git a/packages/server/src/services/export-import/index.ts b/packages/server/src/services/export-import/index.ts index 8873f9824..7e2d8f461 100644 --- a/packages/server/src/services/export-import/index.ts +++ b/packages/server/src/services/export-import/index.ts @@ -90,7 +90,7 @@ const convertExportInput = (body: any): ExportInput => { } const FileDefaultName = 'ExportData.json' -const exportData = async (exportInput: ExportInput, activeWorkspaceId?: string): Promise<{ FileDefaultName: string } & ExportData> => { +const exportData = async (exportInput: ExportInput, activeWorkspaceId: string): Promise<{ FileDefaultName: string } & ExportData> => { try { let AgentFlow: ChatFlow[] | { data: ChatFlow[]; total: number } = exportInput.agentflow === true ? await chatflowService.getAllChatflows('MULTIAGENT', activeWorkspaceId) : [] @@ -101,17 +101,17 @@ const exportData = async (exportInput: ExportInput, activeWorkspaceId?: string): AgentFlowV2 = 'data' in AgentFlowV2 ? AgentFlowV2.data : AgentFlowV2 let AssistantCustom: Assistant[] = - exportInput.assistantCustom === true ? await assistantService.getAllAssistants('CUSTOM', activeWorkspaceId) : [] + exportInput.assistantCustom === true ? await assistantService.getAllAssistants(activeWorkspaceId, 'CUSTOM') : [] let AssistantFlow: ChatFlow[] | { data: ChatFlow[]; total: number } = exportInput.assistantCustom === true ? await chatflowService.getAllChatflows('ASSISTANT', activeWorkspaceId) : [] AssistantFlow = 'data' in AssistantFlow ? AssistantFlow.data : AssistantFlow let AssistantOpenAI: Assistant[] = - exportInput.assistantOpenAI === true ? await assistantService.getAllAssistants('OPENAI', activeWorkspaceId) : [] + exportInput.assistantOpenAI === true ? await assistantService.getAllAssistants(activeWorkspaceId, 'OPENAI') : [] let AssistantAzure: Assistant[] = - exportInput.assistantAzure === true ? await assistantService.getAllAssistants('AZURE', activeWorkspaceId) : [] + exportInput.assistantAzure === true ? await assistantService.getAllAssistants(activeWorkspaceId, 'AZURE') : [] let ChatFlow: ChatFlow[] | { data: ChatFlow[]; total: number } = exportInput.chatflow === true ? await chatflowService.getAllChatflows('CHATFLOW', activeWorkspaceId) : [] diff --git a/packages/server/src/services/flow-configs/index.ts b/packages/server/src/services/flow-configs/index.ts index 8ce05499f..7755e86f3 100644 --- a/packages/server/src/services/flow-configs/index.ts +++ b/packages/server/src/services/flow-configs/index.ts @@ -6,10 +6,10 @@ import chatflowsService from '../chatflows' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { getErrorMessage } from '../../errors/utils' -const getSingleFlowConfig = async (chatflowId: string): Promise => { +const getSingleFlowConfig = async (chatflowId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() - const chatflow = await chatflowsService.getChatflowById(chatflowId) + const chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId) if (!chatflow) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${chatflowId} not found in the database!`) } diff --git a/packages/server/src/services/marketplaces/index.ts b/packages/server/src/services/marketplaces/index.ts index 6f7f9c6b6..ef50ad687 100644 --- a/packages/server/src/services/marketplaces/index.ts +++ b/packages/server/src/services/marketplaces/index.ts @@ -1,16 +1,16 @@ -import path from 'path' import * as fs from 'fs' import { StatusCodes } from 'http-status-codes' +import path from 'path' +import { DeleteResult } from 'typeorm' +import { v4 as uuidv4 } from 'uuid' +import { CustomTemplate } from '../../database/entities/CustomTemplate' +import { WorkspaceService } from '../../enterprise/services/workspace.service' +import { getWorkspaceSearchOptions } from '../../enterprise/utils/ControllerServiceUtils' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { getErrorMessage } from '../../errors/utils' import { IReactFlowEdge, IReactFlowNode } from '../../Interface' import { getRunningExpressApp } from '../../utils/getRunningExpressApp' -import { DeleteResult } from 'typeorm' -import { CustomTemplate } from '../../database/entities/CustomTemplate' -import { v4 as uuidv4 } from 'uuid' import chatflowsService from '../chatflows' -import { getWorkspaceSearchOptions } from '../../enterprise/utils/ControllerServiceUtils' -import { WorkspaceService } from '../../enterprise/services/workspace.service' type ITemplate = { badge: string @@ -138,10 +138,10 @@ const getAllTemplates = async () => { } } -const deleteCustomTemplate = async (templateId: string): Promise => { +const deleteCustomTemplate = async (templateId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() - return await appServer.AppDataSource.getRepository(CustomTemplate).delete({ id: templateId }) + return await appServer.AppDataSource.getRepository(CustomTemplate).delete({ id: templateId, workspaceId: workspaceId }) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, @@ -211,7 +211,7 @@ const saveCustomTemplate = async (body: any): Promise => { Object.assign(customTemplate, body) if (body.chatflowId) { - const chatflow = await chatflowsService.getChatflowById(body.chatflowId) + const chatflow = await chatflowsService.getChatflowById(body.chatflowId, body.workspaceId) const flowData = JSON.parse(chatflow.flowData) const { framework, exportJson } = _generateExportFlowData(flowData) flowDataStr = JSON.stringify(exportJson) diff --git a/packages/server/src/services/tools/index.ts b/packages/server/src/services/tools/index.ts index e31a0f461..57f7e06ed 100644 --- a/packages/server/src/services/tools/index.ts +++ b/packages/server/src/services/tools/index.ts @@ -1,12 +1,12 @@ import { StatusCodes } from 'http-status-codes' -import { Tool } from '../../database/entities/Tool' -import { getAppVersion } from '../../utils' -import { InternalFlowiseError } from '../../errors/internalFlowiseError' -import { getErrorMessage } from '../../errors/utils' -import { getRunningExpressApp } from '../../utils/getRunningExpressApp' -import { FLOWISE_METRIC_COUNTERS, FLOWISE_COUNTER_STATUS } from '../../Interface.Metrics' import { QueryRunner } from 'typeorm' import { validate } from 'uuid' +import { Tool } from '../../database/entities/Tool' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' +import { getErrorMessage } from '../../errors/utils' +import { FLOWISE_COUNTER_STATUS, FLOWISE_METRIC_COUNTERS } from '../../Interface.Metrics' +import { getAppVersion } from '../../utils' +import { getRunningExpressApp } from '../../utils/getRunningExpressApp' const createTool = async (requestBody: any, orgId: string): Promise => { try { @@ -31,11 +31,12 @@ const createTool = async (requestBody: any, orgId: string): Promise => { } } -const deleteTool = async (toolId: string): Promise => { +const deleteTool = async (toolId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(Tool).delete({ - id: toolId + id: toolId, + workspaceId: workspaceId }) return dbResponse } catch (error) { @@ -65,11 +66,12 @@ const getAllTools = async (workspaceId?: string, page: number = -1, limit: numbe } } -const getToolById = async (toolId: string): Promise => { +const getToolById = async (toolId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(Tool).findOneBy({ - id: toolId + id: toolId, + workspaceId: workspaceId }) if (!dbResponse) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Tool ${toolId} not found`) @@ -80,11 +82,12 @@ const getToolById = async (toolId: string): Promise => { } } -const updateTool = async (toolId: string, toolBody: any): Promise => { +const updateTool = async (toolId: string, toolBody: any, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const tool = await appServer.AppDataSource.getRepository(Tool).findOneBy({ - id: toolId + id: toolId, + workspaceId: workspaceId }) if (!tool) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Tool ${toolId} not found`) diff --git a/packages/server/src/services/variables/index.ts b/packages/server/src/services/variables/index.ts index fb1f10a48..5b427e954 100644 --- a/packages/server/src/services/variables/index.ts +++ b/packages/server/src/services/variables/index.ts @@ -32,10 +32,10 @@ const createVariable = async (newVariable: Variable, orgId: string) => { } } -const deleteVariable = async (variableId: string): Promise => { +const deleteVariable = async (variableId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() - const dbResponse = await appServer.AppDataSource.getRepository(Variable).delete({ id: variableId }) + const dbResponse = await appServer.AppDataSource.getRepository(Variable).delete({ id: variableId, workspaceId: workspaceId }) return dbResponse } catch (error) { throw new InternalFlowiseError( @@ -45,7 +45,7 @@ const deleteVariable = async (variableId: string): Promise => { } } -const getAllVariables = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllVariables = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(Variable) @@ -77,11 +77,12 @@ const getAllVariables = async (workspaceId?: string, page: number = -1, limit: n } } -const getVariableById = async (variableId: string) => { +const getVariableById = async (variableId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(Variable).findOneBy({ - id: variableId + id: variableId, + workspaceId: workspaceId }) if (appServer.identityManager.getPlatformType() === Platform.CLOUD && dbResponse?.type === 'runtime') { diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 16b9acfe7..f0151d57a 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -834,7 +834,8 @@ export const getGlobalVariable = async ( value: overrideConfig.vars[propertyName], id: '', updatedDate: new Date(), - createdDate: new Date() + createdDate: new Date(), + workspaceId: '' }) } } diff --git a/packages/ui/src/routes/DefaultRedirect.jsx b/packages/ui/src/routes/DefaultRedirect.jsx new file mode 100644 index 000000000..6af3d1069 --- /dev/null +++ b/packages/ui/src/routes/DefaultRedirect.jsx @@ -0,0 +1,100 @@ +import { useAuth } from '@/hooks/useAuth' +import { useConfig } from '@/store/context/ConfigContext' +import { useSelector } from 'react-redux' + +// Import all view components +import Account from '@/views/account' +import Executions from '@/views/agentexecutions' +import Agentflows from '@/views/agentflows' +import APIKey from '@/views/apikey' +import Assistants from '@/views/assistants' +import Login from '@/views/auth/login' +import LoginActivityPage from '@/views/auth/loginActivity' +import SSOConfig from '@/views/auth/ssoConfig' +import Unauthorized from '@/views/auth/unauthorized' +import Chatflows from '@/views/chatflows' +import Credentials from '@/views/credentials' +import EvalDatasets from '@/views/datasets' +import Documents from '@/views/docstore' +import EvalEvaluation from '@/views/evaluations/index' +import Evaluators from '@/views/evaluators' +import Marketplaces from '@/views/marketplaces' +import RolesPage from '@/views/roles' +import Logs from '@/views/serverlogs' +import Tools from '@/views/tools' +import UsersPage from '@/views/users' +import Variables from '@/views/variables' +import Workspaces from '@/views/workspace' + +/** + * Component that redirects users to the first accessible page based on their permissions + * This prevents 403 errors when users don't have access to the default chatflows page + */ +export const DefaultRedirect = () => { + const { hasPermission, hasDisplay } = useAuth() + const { isOpenSource } = useConfig() + const isGlobal = useSelector((state) => state.auth.isGlobal) + const isAuthenticated = useSelector((state) => state.auth.isAuthenticated) + + // Define the order of routes to check (based on the menu order in dashboard.js) + const routesToCheck = [ + { component: Chatflows, permission: 'chatflows:view' }, + { component: Agentflows, permission: 'agentflows:view' }, + { component: Executions, permission: 'executions:view' }, + { component: Assistants, permission: 'assistants:view' }, + { component: Marketplaces, permission: 'templates:marketplace,templates:custom' }, + { component: Tools, permission: 'tools:view' }, + { component: Credentials, permission: 'credentials:view' }, + { component: Variables, permission: 'variables:view' }, + { component: APIKey, permission: 'apikeys:view' }, + { component: Documents, permission: 'documentStores:view' }, + // Evaluation routes (with display flags) + { component: EvalDatasets, permission: 'datasets:view', display: 'feat:datasets' }, + { component: Evaluators, permission: 'evaluators:view', display: 'feat:evaluators' }, + { component: EvalEvaluation, permission: 'evaluations:view', display: 'feat:evaluations' }, + // Management routes (with display flags) + { component: SSOConfig, permission: 'sso:manage', display: 'feat:sso-config' }, + { component: RolesPage, permission: 'roles:manage', display: 'feat:roles' }, + { component: UsersPage, permission: 'users:manage', display: 'feat:users' }, + { component: Workspaces, permission: 'workspace:view', display: 'feat:workspaces' }, + { component: LoginActivityPage, permission: 'loginActivity:view', display: 'feat:login-activity' }, + // Other routes + { component: Logs, permission: 'logs:view', display: 'feat:logs' }, + { component: Account, display: 'feat:account' } + ] + + // If user is not authenticated, show login page + if (!isAuthenticated) { + return + } + + // For open source, show chatflows (no permission checks) + if (isOpenSource) { + return + } + + // For global admins, show chatflows (they have access to everything) + if (isGlobal) { + return + } + + // Check each route in order and return the first accessible component + for (const route of routesToCheck) { + const { component: Component, permission, display } = route + + // Check permission if specified + const hasRequiredPermission = !permission || hasPermission(permission) + + // Check display flag if specified + const hasRequiredDisplay = !display || hasDisplay(display) + + // If user has both required permission and display access, return this component + if (hasRequiredPermission && hasRequiredDisplay) { + return + } + } + + // If no accessible routes found, show unauthorized page + // This should rarely happen as most users should have at least one permission + return +} diff --git a/packages/ui/src/routes/MainRoutes.jsx b/packages/ui/src/routes/MainRoutes.jsx index 06774535e..544433db6 100644 --- a/packages/ui/src/routes/MainRoutes.jsx +++ b/packages/ui/src/routes/MainRoutes.jsx @@ -5,6 +5,7 @@ import MainLayout from '@/layout/MainLayout' import Loadable from '@/ui-component/loading/Loadable' import { RequireAuth } from '@/routes/RequireAuth' +import { DefaultRedirect } from '@/routes/DefaultRedirect' // chatflows routing const Chatflows = Loadable(lazy(() => import('@/views/chatflows'))) @@ -77,11 +78,7 @@ const MainRoutes = { children: [ { path: '/', - element: ( - - - - ) + element: }, { path: '/chatflows', diff --git a/packages/ui/src/routes/RequireAuth.jsx b/packages/ui/src/routes/RequireAuth.jsx index d9694d674..b02c1ef7a 100644 --- a/packages/ui/src/routes/RequireAuth.jsx +++ b/packages/ui/src/routes/RequireAuth.jsx @@ -1,9 +1,9 @@ -import { Navigate } from 'react-router' -import PropTypes from 'prop-types' -import { useLocation } from 'react-router-dom' -import { useConfig } from '@/store/context/ConfigContext' import { useAuth } from '@/hooks/useAuth' +import { useConfig } from '@/store/context/ConfigContext' +import PropTypes from 'prop-types' import { useSelector } from 'react-redux' +import { Navigate } from 'react-router' +import { useLocation } from 'react-router-dom' /** * Checks if a feature flag is enabled @@ -29,13 +29,18 @@ const checkFeatureFlag = (features, display, children) => { export const RequireAuth = ({ permission, display, children }) => { const location = useLocation() - const { isCloud, isOpenSource, isEnterpriseLicensed } = useConfig() + const { isCloud, isOpenSource, isEnterpriseLicensed, loading } = useConfig() const { hasPermission } = useAuth() const isGlobal = useSelector((state) => state.auth.isGlobal) const currentUser = useSelector((state) => state.auth.user) const features = useSelector((state) => state.auth.features) const permissions = useSelector((state) => state.auth.permissions) + // Step 0: Wait for config to load + if (loading) { + return null + } + // Step 1: Authentication Check // Redirect to login if user is not authenticated if (!currentUser) { @@ -50,29 +55,36 @@ export const RequireAuth = ({ permission, display, children }) => { // Cloud & Enterprise: Check both permissions and feature flags if (isCloud || isEnterpriseLicensed) { - // Allow access to basic features (no display property) - if (!display) return children + // Routes with display property - check feature flags + if (display) { + // Check if user has any permissions + if (permissions.length === 0) { + return + } - // Check if user has any permissions - if (permissions.length === 0) { - return + // Organization admins bypass permission checks + if (isGlobal) { + return checkFeatureFlag(features, display, children) + } + + // Check user permissions and feature flags + if (!permission || hasPermission(permission)) { + return checkFeatureFlag(features, display, children) + } + + return } - // Organization admins bypass permission checks - if (isGlobal) { - return checkFeatureFlag(features, display, children) + // Standard routes: check permissions (global admins bypass) + if (permission && !hasPermission(permission) && !isGlobal) { + return } - // Check user permissions and feature flags - if (!permission || hasPermission(permission)) { - return checkFeatureFlag(features, display, children) - } - - return + return children } - // Fallback: Allow access if none of the above conditions match - return children + // Fallback: If none of the platform types match, deny access + return } RequireAuth.propTypes = { diff --git a/packages/ui/src/views/auth/register.jsx b/packages/ui/src/views/auth/register.jsx index 7ac0cc979..30c18b12e 100644 --- a/packages/ui/src/views/auth/register.jsx +++ b/packages/ui/src/views/auth/register.jsx @@ -201,7 +201,7 @@ const RegisterPage = () => { useEffect(() => { if (ssoLoginApi.data) { store.dispatch(loginSuccess(ssoLoginApi.data)) - navigate(location.state?.path || '/chatflows') + navigate(location.state?.path || '/') } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/packages/ui/src/views/auth/signIn.jsx b/packages/ui/src/views/auth/signIn.jsx index e52062085..1e0a7d3cf 100644 --- a/packages/ui/src/views/auth/signIn.jsx +++ b/packages/ui/src/views/auth/signIn.jsx @@ -112,7 +112,7 @@ const SignInPage = () => { if (loginApi.data) { setLoading(false) store.dispatch(loginSuccess(loginApi.data)) - navigate(location.state?.path || '/chatflows') + navigate(location.state?.path || '/') //navigate(0) } @@ -122,7 +122,7 @@ const SignInPage = () => { useEffect(() => { if (ssoLoginApi.data) { store.dispatch(loginSuccess(ssoLoginApi.data)) - navigate(location.state?.path || '/chatflows') + navigate(location.state?.path || '/') } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/packages/ui/src/views/auth/ssoSuccess.jsx b/packages/ui/src/views/auth/ssoSuccess.jsx index 8ac0d35d5..9476aa646 100644 --- a/packages/ui/src/views/auth/ssoSuccess.jsx +++ b/packages/ui/src/views/auth/ssoSuccess.jsx @@ -19,7 +19,7 @@ const SSOSuccess = () => { if (user) { if (user.status === 200) { store.dispatch(loginSuccess(user.data)) - navigate('/chatflows') + navigate('/') } else { navigate('/login') } diff --git a/packages/ui/src/views/organization/index.jsx b/packages/ui/src/views/organization/index.jsx index a53682e2d..72886d114 100644 --- a/packages/ui/src/views/organization/index.jsx +++ b/packages/ui/src/views/organization/index.jsx @@ -225,7 +225,7 @@ const OrganizationSetupPage = () => { setLoading(false) store.dispatch(loginSuccess(loginApi.data)) localStorage.setItem('username', loginApi.data.name) - navigate(location.state?.path || '/chatflows') + navigate(location.state?.path || '/') //navigate(0) }