diff --git a/packages/server/src/Interface.ts b/packages/server/src/Interface.ts index 0a334153b1a..f1c603043cb 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 340ff27b251..677d689311c 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 324907d0b2c..e4159bf3fa8 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 b000c9ea3fb..d1d7cccbab7 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 f8a10c33f21..6b1a554caa9 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 78cb4348c5e..6c6dea22a34 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 d6c7531181f..0479a20de0d 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 9d19373b436..1ac4f439575 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 4cde7615804..b38213aa0b7 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 1f151c37c73..5f864a85c5e 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 b066df0c8a8..ae2a869283a 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 c0926266085..ba5fadeee38 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/marketplaces/index.ts b/packages/server/src/controllers/marketplaces/index.ts index 5d19d40e6cd..1984f3ad938 100644 --- a/packages/server/src/controllers/marketplaces/index.ts +++ b/packages/server/src/controllers/marketplaces/index.ts @@ -47,6 +47,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 b7f79b642c8..d467f3157e4 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/variables/index.ts b/packages/server/src/controllers/variables/index.ts index 42b58603ecc..3f8455410bf 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 e7c1d84e55d..4778962a14f 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 28843213928..1d9eabbe8f1 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 0ff726afea2..d3561aa0017 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 2c43158c487..5cff59f49ea 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 e45719e69d4..ed99cebd3c6 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 8dd604d3d01..8acd5f2bb15 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 01babca474b..9a94fde52fa 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 85128ae0173..4f23a05e3c7 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 8e7f6f9b962..a14e0c9059a 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 87885cf8a3f..eac53f6392a 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 3a0dcbc898a..2e35b64a685 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 6a8006dd67e..33105c0f6ed 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 d7ddfc393d6..5dd4384e043 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 d20edcf9449..dc29f97a654 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 8cb0f594a36..e1d79d9124b 100644 --- a/packages/server/src/enterprise/middleware/passport/index.ts +++ b/packages/server/src/enterprise/middleware/passport/index.ts @@ -174,7 +174,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 583d4ad604c..d0856c4bc9e 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 f990de5a85f..e216c6977ee 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 245f1e4711e..1d0983c6761 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 1e1d4a3da81..f4f0ca7a52f 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -279,8 +279,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/chatflows/index.ts b/packages/server/src/routes/chatflows/index.ts index 774f0928dcb..5da9c4ed1d6 100644 --- a/packages/server/src/routes/chatflows/index.ts +++ b/packages/server/src/routes/chatflows/index.ts @@ -4,20 +4,40 @@ import { checkAnyPermission, checkPermission } from '../../enterprise/rbac/Permi 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'], checkPermission('chatflows:delete,agentflows:delete'), chatflowsController.deleteChatflow) // CHECK FOR CHANGE -router.get('/has-changed/:id/:lastUpdatedDateTime', chatflowsController.checkIfChatflowHasChanged) +router.get( + '/has-changed/:id/:lastUpdatedDateTime', + checkPermission('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 a8b6036333a..5e009c92774 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 72dfc4a008a..0151124b9ca 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 4ff25b5467c..579ff1c6759 100644 --- a/packages/server/src/services/chatflows/index.ts +++ b/packages/server/src/services/chatflows/index.ts @@ -238,11 +238,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 89219cabe26..e07c32da3af 100644 --- a/packages/server/src/services/credentials/index.ts +++ b/packages/server/src/services/credentials/index.ts @@ -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 = [] @@ -124,7 +124,7 @@ 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({ @@ -165,11 +165,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 +178,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 351919e6b23..4042e420f40 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 05520523de4..0ee1cad2015 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 4b2d7d81da1..3f2a42081d7 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 9195ac26f7c..fe0aae71b73 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 3cfbcc6f399..bd3d7e23a30 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 8873f9824da..7e2d8f461d7 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 8ce05499f2c..7755e86f39e 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 6f7f9c6b654..c7a3b26a18c 100644 --- a/packages/server/src/services/marketplaces/index.ts +++ b/packages/server/src/services/marketplaces/index.ts @@ -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/variables/index.ts b/packages/server/src/services/variables/index.ts index fb1f10a48ae..5b427e95488 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 16b9acfe78b..f0151d57a95 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 00000000000..6c3864fd8f7 --- /dev/null +++ b/packages/ui/src/routes/DefaultRedirect.jsx @@ -0,0 +1,71 @@ +import { Navigate } from 'react-router-dom' +import { useAuth } from '@/hooks/useAuth' +import { useSelector } from 'react-redux' +import { useConfig } from '@/store/context/ConfigContext' + +/** + * 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) + + // Define the order of routes to check (based on the menu order in dashboard.js) + const routesToCheck = [ + { path: '/chatflows', permission: 'chatflows:view' }, + { path: '/agentflows', permission: 'agentflows:view' }, + { path: '/executions', permission: 'executions:view' }, + { path: '/assistants', permission: 'assistants:view' }, + { path: '/marketplaces', permission: 'templates:marketplace,templates:custom' }, + { path: '/tools', permission: 'tools:view' }, + { path: '/credentials', permission: 'credentials:view' }, + { path: '/variables', permission: 'variables:view' }, + { path: '/apikey', permission: 'apikeys:view' }, + { path: '/document-stores', permission: 'documentStores:view' }, + // Evaluation routes (with display flags) + { path: '/datasets', permission: 'datasets:view', display: 'feat:datasets' }, + { path: '/evaluators', permission: 'evaluators:view', display: 'feat:evaluators' }, + { path: '/evaluations', permission: 'evaluations:view', display: 'feat:evaluations' }, + // Management routes (with display flags) + { path: '/sso-config', permission: 'sso:manage', display: 'feat:sso-config' }, + { path: '/roles', permission: 'roles:manage', display: 'feat:roles' }, + { path: '/users', permission: 'users:manage', display: 'feat:users' }, + { path: '/workspaces', permission: 'workspace:view', display: 'feat:workspaces' }, + { path: '/login-activity', permission: 'loginActivity:view', display: 'feat:login-activity' }, + // Other routes + { path: '/logs', permission: 'logs:view', display: 'feat:logs' }, + { path: '/account', display: 'feat:account' } + ] + + // For open source, redirect to chatflows (no permission checks) + if (isOpenSource) { + return + } + + // For global admins, redirect to chatflows (they have access to everything) + if (isGlobal) { + return + } + + // Check each route in order and redirect to the first accessible one + for (const route of routesToCheck) { + const { path, 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, redirect to this route + if (hasRequiredPermission && hasRequiredDisplay) { + return + } + } + + // If no accessible routes found, redirect to unauthorized + // 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 ce7caa0423d..d816e922d5a 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'))) @@ -78,11 +79,7 @@ const MainRoutes = { children: [ { path: '/', - element: ( - - - - ) + element: }, { path: '/chatflows', diff --git a/packages/ui/src/views/auth/register.jsx b/packages/ui/src/views/auth/register.jsx index 7ac0cc9793d..30c18b12e1f 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 e5206208593..1e0a7d3cf46 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 8ac0d35d5a3..9476aa64644 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 a53682e2dfa..72886d11486 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) }