@intlayer/backend 5.7.2 → 5.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/controllers/ai.controller.cjs.map +1 -1
- package/dist/cjs/controllers/dictionary.controller.cjs +39 -20
- package/dist/cjs/controllers/dictionary.controller.cjs.map +1 -1
- package/dist/cjs/controllers/newsletter.controller.cjs.map +1 -1
- package/dist/cjs/controllers/organization.controller.cjs +51 -19
- package/dist/cjs/controllers/organization.controller.cjs.map +1 -1
- package/dist/cjs/controllers/project.controller.cjs +42 -12
- package/dist/cjs/controllers/project.controller.cjs.map +1 -1
- package/dist/cjs/controllers/projectAccessKey.controller.cjs +21 -3
- package/dist/cjs/controllers/projectAccessKey.controller.cjs.map +1 -1
- package/dist/cjs/controllers/search.controller.cjs.map +1 -1
- package/dist/cjs/controllers/stripe.controller.cjs.map +1 -1
- package/dist/cjs/controllers/tag.controller.cjs +48 -17
- package/dist/cjs/controllers/tag.controller.cjs.map +1 -1
- package/dist/cjs/controllers/user.controller.cjs +7 -1
- package/dist/cjs/controllers/user.controller.cjs.map +1 -1
- package/dist/cjs/middlewares/sessionAuth.middleware.cjs.map +1 -1
- package/dist/cjs/routes/ai.routes.cjs.map +1 -1
- package/dist/cjs/routes/dictionary.routes.cjs.map +1 -1
- package/dist/cjs/routes/eventListener.routes.cjs.map +1 -1
- package/dist/cjs/routes/newsletter.routes.cjs.map +1 -1
- package/dist/cjs/routes/organization.routes.cjs.map +1 -1
- package/dist/cjs/routes/project.routes.cjs +3 -12
- package/dist/cjs/routes/project.routes.cjs.map +1 -1
- package/dist/cjs/routes/search.routes.cjs.map +1 -1
- package/dist/cjs/routes/stripe.routes.cjs.map +1 -1
- package/dist/cjs/routes/tags.routes.cjs.map +1 -1
- package/dist/cjs/routes/user.routes.cjs.map +1 -1
- package/dist/cjs/schemas/tag.schema.cjs +5 -0
- package/dist/cjs/schemas/tag.schema.cjs.map +1 -1
- package/dist/cjs/services/dictionary.service.cjs +0 -8
- package/dist/cjs/services/dictionary.service.cjs.map +1 -1
- package/dist/cjs/services/organization.service.cjs +0 -9
- package/dist/cjs/services/organization.service.cjs.map +1 -1
- package/dist/cjs/types/tag.types.cjs.map +1 -1
- package/dist/cjs/utils/auth/getAuth.cjs +1 -0
- package/dist/cjs/utils/auth/getAuth.cjs.map +1 -1
- package/dist/cjs/utils/permissions.cjs +100 -22
- package/dist/cjs/utils/permissions.cjs.map +1 -1
- package/dist/esm/controllers/ai.controller.mjs.map +1 -1
- package/dist/esm/controllers/dictionary.controller.mjs +39 -20
- package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
- package/dist/esm/controllers/newsletter.controller.mjs.map +1 -1
- package/dist/esm/controllers/organization.controller.mjs +51 -19
- package/dist/esm/controllers/organization.controller.mjs.map +1 -1
- package/dist/esm/controllers/project.controller.mjs +42 -12
- package/dist/esm/controllers/project.controller.mjs.map +1 -1
- package/dist/esm/controllers/projectAccessKey.controller.mjs +21 -3
- package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
- package/dist/esm/controllers/search.controller.mjs.map +1 -1
- package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
- package/dist/esm/controllers/tag.controller.mjs +48 -17
- package/dist/esm/controllers/tag.controller.mjs.map +1 -1
- package/dist/esm/controllers/user.controller.mjs +7 -1
- package/dist/esm/controllers/user.controller.mjs.map +1 -1
- package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
- package/dist/esm/routes/ai.routes.mjs.map +1 -1
- package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
- package/dist/esm/routes/eventListener.routes.mjs.map +1 -1
- package/dist/esm/routes/newsletter.routes.mjs.map +1 -1
- package/dist/esm/routes/organization.routes.mjs.map +1 -1
- package/dist/esm/routes/project.routes.mjs +3 -12
- package/dist/esm/routes/project.routes.mjs.map +1 -1
- package/dist/esm/routes/search.routes.mjs.map +1 -1
- package/dist/esm/routes/stripe.routes.mjs.map +1 -1
- package/dist/esm/routes/tags.routes.mjs.map +1 -1
- package/dist/esm/routes/user.routes.mjs.map +1 -1
- package/dist/esm/schemas/tag.schema.mjs +5 -0
- package/dist/esm/schemas/tag.schema.mjs.map +1 -1
- package/dist/esm/services/dictionary.service.mjs +0 -7
- package/dist/esm/services/dictionary.service.mjs.map +1 -1
- package/dist/esm/services/organization.service.mjs +0 -9
- package/dist/esm/services/organization.service.mjs.map +1 -1
- package/dist/esm/utils/auth/getAuth.mjs +1 -0
- package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
- package/dist/esm/utils/permissions.mjs +100 -22
- package/dist/esm/utils/permissions.mjs.map +1 -1
- package/dist/types/controllers/ai.controller.d.ts +10 -9
- package/dist/types/controllers/ai.controller.d.ts.map +1 -1
- package/dist/types/controllers/dictionary.controller.d.ts +9 -8
- package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
- package/dist/types/controllers/newsletter.controller.d.ts +5 -4
- package/dist/types/controllers/newsletter.controller.d.ts.map +1 -1
- package/dist/types/controllers/organization.controller.d.ts +11 -10
- package/dist/types/controllers/organization.controller.d.ts.map +1 -1
- package/dist/types/controllers/project.controller.d.ts +10 -9
- package/dist/types/controllers/project.controller.d.ts.map +1 -1
- package/dist/types/controllers/projectAccessKey.controller.d.ts +5 -4
- package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
- package/dist/types/controllers/search.controller.d.ts.map +1 -1
- package/dist/types/controllers/stripe.controller.d.ts +5 -4
- package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
- package/dist/types/controllers/tag.controller.d.ts +6 -5
- package/dist/types/controllers/tag.controller.d.ts.map +1 -1
- package/dist/types/controllers/user.controller.d.ts +9 -8
- package/dist/types/controllers/user.controller.d.ts.map +1 -1
- package/dist/types/middlewares/sessionAuth.middleware.d.ts +2 -0
- package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
- package/dist/types/schemas/tag.schema.d.ts.map +1 -1
- package/dist/types/services/dictionary.service.d.ts +0 -1
- package/dist/types/services/dictionary.service.d.ts.map +1 -1
- package/dist/types/services/organization.service.d.ts.map +1 -1
- package/dist/types/types/tag.types.d.ts +2 -0
- package/dist/types/types/tag.types.d.ts.map +1 -1
- package/dist/types/utils/auth/getAuth.d.ts.map +1 -1
- package/dist/types/utils/permissions.d.ts +67 -26
- package/dist/types/utils/permissions.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/controllers/ai.controller.ts"],"sourcesContent":["import { DiscussionModel } from '@/models/discussion.model';\nimport type { Dictionary } from '@/types/dictionary.types';\nimport type { Tag } from '@/types/tag.types';\nimport { type KeyPath } from '@intlayer/core';\nimport { getDictionariesByTags } from '@services/dictionary.service';\nimport * as tagService from '@services/tag.service';\nimport { getTagsByKeys } from '@services/tag.service';\nimport {\n AIConfig,\n getAIConfig,\n type AIOptions,\n type ChatCompletionRequestMessage,\n} from '@utils/AI/aiSdk';\nimport * as askDocQuestionUtil from '@utils/AI/askDocQuestion/askDocQuestion';\nimport * as auditContentDeclarationUtil from '@utils/AI/auditDictionary';\nimport * as auditContentDeclarationFieldUtil from '@utils/AI/auditDictionaryField';\nimport * as auditContentDeclarationMetadataUtil from '@utils/AI/auditDictionaryMetadata';\nimport * as auditTagUtil from '@utils/AI/auditTag';\nimport * as autocompleteUtil from '@utils/AI/autocomplete';\nimport * as customQueryUtil from '@utils/AI/customQuery';\nimport * as translateJSONUtil from '@utils/AI/translateJSON';\nimport { ErrorHandler, type AppError } from '@utils/errors';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport type { Locales } from 'intlayer';\n\ntype ReplaceAIConfigByOptions<T> = Omit<T, 'aiConfig'> & {\n aiOptions?: AIOptions;\n};\n\nexport type CustomQueryBody =\n ReplaceAIConfigByOptions<customQueryUtil.CustomQueryOptions>;\nexport type CustomQueryResult =\n ResponseData<customQueryUtil.CustomQueryResultData>;\n\nexport const customQuery = async (\n req: Request<AuditContentDeclarationBody>,\n res: Response<CustomQueryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { aiOptions, tagsKeys, ...rest } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: customQueryUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n const auditResponse = await customQueryUtil.customQuery({\n ...rest,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'QUERY_FAILED');\n return;\n }\n\n const responseData = formatResponse<customQueryUtil.CustomQueryResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type TranslateJSONBody = Omit<\n ReplaceAIConfigByOptions<translateJSONUtil.TranslateJSONOptions>,\n 'tags'\n> & {\n tagsKeys?: string[];\n};\nexport type TranslateJSONResult =\n ResponseData<translateJSONUtil.TranslateJSONResultData>;\n\nexport const translateJSON = async (\n req: Request<AuditContentDeclarationBody>,\n res: Response<TranslateJSONResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { aiOptions, tagsKeys, ...rest } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: translateJSONUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let tags: Tag[] = [];\n\n if (project?.organizationId) {\n tags = await getTagsByKeys(tagsKeys, project.organizationId);\n }\n\n const auditResponse = await translateJSONUtil.translateJSON({\n ...rest,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n tags,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<translateJSONUtil.TranslateJSONResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditContentDeclarationBody = {\n aiOptions?: AIOptions;\n locales: Locales[];\n defaultLocale: Locales;\n fileContent: string;\n filePath?: string;\n tagsKeys?: string[];\n};\nexport type AuditContentDeclarationResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditContentDeclaration = async (\n req: Request<AuditContentDeclarationBody>,\n res: Response<AuditContentDeclarationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { fileContent, filePath, aiOptions, locales, defaultLocale, tagsKeys } =\n req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditContentDeclarationUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let tags: Tag[] = [];\n\n if (project?.organizationId) {\n tags = await getTagsByKeys(tagsKeys, project.organizationId);\n }\n\n const auditResponse = await auditContentDeclarationUtil.auditDictionary({\n fileContent,\n filePath,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n locales,\n defaultLocale,\n tags,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditContentDeclarationFieldBody = {\n aiOptions?: AIOptions;\n locales: Locales[];\n fileContent: string;\n filePath?: string;\n tagsKeys?: string[];\n keyPath: KeyPath[];\n};\nexport type AuditContentDeclarationFieldResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditContentDeclarationField = async (\n req: Request<AuditContentDeclarationFieldBody>,\n res: Response<AuditContentDeclarationFieldResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { fileContent, aiOptions, locales, tagsKeys, keyPath } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditContentDeclarationFieldUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let tags: Tag[] = [];\n\n if (project?.organizationId) {\n tags = await getTagsByKeys(tagsKeys, project.organizationId);\n }\n\n const auditResponse =\n await auditContentDeclarationFieldUtil.auditDictionaryField({\n fileContent,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n locales,\n tags,\n keyPath,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditContentDeclarationMetadataBody = {\n aiOptions?: AIOptions;\n fileContent: string;\n};\nexport type AuditContentDeclarationMetadataResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditContentDeclarationMetadata = async (\n req: Request<AuditContentDeclarationMetadataBody>,\n res: Response<AuditContentDeclarationMetadataResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization } = res.locals;\n const { fileContent, aiOptions } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditContentDeclarationMetadataUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n const tags: Tag[] = await tagService.findTags(\n {\n organizationId: organization?.id,\n },\n 0,\n 1000\n );\n\n const auditResponse =\n await auditContentDeclarationMetadataUtil.auditDictionaryMetadata({\n fileContent,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n tags,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditTagBody = {\n aiOptions?: AIOptions;\n tag: Tag;\n};\nexport type AuditTagResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditTag = async (\n req: Request<undefined, undefined, AuditTagBody>,\n res: Response<AuditTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { aiOptions, tag } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditTagUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let dictionaries: Dictionary[] = [];\n if (project?.organizationId) {\n dictionaries = await getDictionariesByTags([tag.key], project.id);\n }\n\n const auditResponse = await auditTagUtil.auditTag({\n aiConfig,\n dictionaries,\n tag,\n applicationContext: aiOptions?.applicationContext,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AskDocQuestionBody = {\n messages: ChatCompletionRequestMessage[];\n discutionId: string;\n};\nexport type AskDocQuestionResult =\n ResponseData<askDocQuestionUtil.AskDocQuestionResult>;\n\nexport const askDocQuestion = async (\n req: Request<undefined, undefined, AskDocQuestionBody>,\n res: Response<AskDocQuestionResult>\n) => {\n const { messages, discutionId } = req.body;\n const { user, project, organization } = res.locals;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: {},\n defaultOptions: askDocQuestionUtil.aiDefaultOptions,\n accessType: ['public'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n // 1. Prepare SSE headers and flush them NOW\n res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');\n res.setHeader('Cache-Control', 'no-cache, no-transform');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no'); // disable nginx buffering\n res.flushHeaders?.();\n res.write(': connected\\n\\n'); // initial comment keeps some browsers happy\n res.flush?.();\n\n // 2. Kick off the upstream stream WITHOUT awaiting it\n askDocQuestionUtil\n .askDocQuestion(messages, aiConfig, {\n onMessage: (chunk) => {\n res.write(`data: ${JSON.stringify({ chunk })}\\n\\n`);\n res.flush?.();\n },\n })\n .then(async (fullResponse) => {\n const lastUserMessageContent = messages.findLast(\n (msg) => msg.role === 'user'\n )?.content;\n const lastUserMessageNbWords = lastUserMessageContent\n ? lastUserMessageContent.split(' ').length\n : 0;\n if (lastUserMessageNbWords > 2) {\n // If the last user message is less than 3 words, don't persist the discussion\n // Example: \"Hello\", \"Hi\", \"Hey\", \"test\", etc.\n\n // 3. Persist discussion while the client already has all chunks\n await DiscussionModel.findOneAndUpdate(\n { discutionId },\n {\n $set: {\n discutionId,\n userId: user?.id,\n projectId: project?.id,\n organizationId: organization?.id,\n messages: [\n ...messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n timestamp: msg.timestamp,\n })),\n {\n role: 'assistant',\n content: fullResponse.response,\n relatedFiles: fullResponse.relatedFiles,\n timestamp: new Date(),\n },\n ],\n },\n },\n { upsert: true, new: true }\n );\n }\n\n // 4. Tell the client we're done and close the stream\n res.write(\n `data: ${JSON.stringify({ done: true, response: fullResponse })}\\n\\n`\n );\n res.end();\n })\n .catch((err) => {\n // propagate error as an SSE event so the client knows why it closed\n res.write(\n `event: error\\ndata: ${JSON.stringify({ message: err.message })}\\n\\n`\n );\n res.end();\n });\n};\n\nexport type AutocompleteBody = {\n text: string;\n aiOptions?: AIOptions;\n contextBefore?: string;\n currentLine?: string;\n contextAfter?: string;\n};\n\nexport type AutocompleteResponse = ResponseData<{\n autocompletion: string;\n}>;\n\nexport const autocomplete = async (\n req: Request<undefined, undefined, AutocompleteBody>,\n res: Response<AutocompleteResponse>\n) => {\n try {\n const { text, aiOptions, contextBefore, currentLine, contextAfter } =\n req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: autocompleteUtil.aiDefaultOptions,\n accessType: ['public'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n const response = (await autocompleteUtil.autocomplete({\n text,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n contextBefore,\n currentLine,\n contextAfter,\n })) ?? {\n autocompletion: '',\n tokenUsed: 0,\n };\n\n const responseData =\n formatResponse<autocompleteUtil.AutocompleteFileResultData>({\n data: response,\n });\n\n res.json(responseData);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/controllers/ai.controller.ts"],"sourcesContent":["import { DiscussionModel } from '@/models/discussion.model';\nimport type { Dictionary } from '@/types/dictionary.types';\nimport type { Tag } from '@/types/tag.types';\nimport { type KeyPath } from '@intlayer/core';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport { getDictionariesByTags } from '@services/dictionary.service';\nimport * as tagService from '@services/tag.service';\nimport { getTagsByKeys } from '@services/tag.service';\nimport {\n AIConfig,\n getAIConfig,\n type AIOptions,\n type ChatCompletionRequestMessage,\n} from '@utils/AI/aiSdk';\nimport * as askDocQuestionUtil from '@utils/AI/askDocQuestion/askDocQuestion';\nimport * as auditContentDeclarationUtil from '@utils/AI/auditDictionary';\nimport * as auditContentDeclarationFieldUtil from '@utils/AI/auditDictionaryField';\nimport * as auditContentDeclarationMetadataUtil from '@utils/AI/auditDictionaryMetadata';\nimport * as auditTagUtil from '@utils/AI/auditTag';\nimport * as autocompleteUtil from '@utils/AI/autocomplete';\nimport * as customQueryUtil from '@utils/AI/customQuery';\nimport * as translateJSONUtil from '@utils/AI/translateJSON';\nimport { ErrorHandler, type AppError } from '@utils/errors';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport type { Locales } from 'intlayer';\n\ntype ReplaceAIConfigByOptions<T> = Omit<T, 'aiConfig'> & {\n aiOptions?: AIOptions;\n};\n\nexport type CustomQueryBody =\n ReplaceAIConfigByOptions<customQueryUtil.CustomQueryOptions>;\nexport type CustomQueryResult =\n ResponseData<customQueryUtil.CustomQueryResultData>;\n\nexport const customQuery = async (\n req: Request<AuditContentDeclarationBody>,\n res: ResponseWithSession<CustomQueryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { aiOptions, tagsKeys, ...rest } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: customQueryUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n const auditResponse = await customQueryUtil.customQuery({\n ...rest,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'QUERY_FAILED');\n return;\n }\n\n const responseData = formatResponse<customQueryUtil.CustomQueryResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type TranslateJSONBody = Omit<\n ReplaceAIConfigByOptions<translateJSONUtil.TranslateJSONOptions>,\n 'tags'\n> & {\n tagsKeys?: string[];\n};\nexport type TranslateJSONResult =\n ResponseData<translateJSONUtil.TranslateJSONResultData>;\n\nexport const translateJSON = async (\n req: Request<AuditContentDeclarationBody>,\n res: ResponseWithSession<TranslateJSONResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { aiOptions, tagsKeys, ...rest } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: translateJSONUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let tags: Tag[] = [];\n\n if (project?.organizationId) {\n tags = await getTagsByKeys(tagsKeys, project.organizationId);\n }\n\n const auditResponse = await translateJSONUtil.translateJSON({\n ...rest,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n tags,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<translateJSONUtil.TranslateJSONResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditContentDeclarationBody = {\n aiOptions?: AIOptions;\n locales: Locales[];\n defaultLocale: Locales;\n fileContent: string;\n filePath?: string;\n tagsKeys?: string[];\n};\nexport type AuditContentDeclarationResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditContentDeclaration = async (\n req: Request<AuditContentDeclarationBody>,\n res: ResponseWithSession<AuditContentDeclarationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { fileContent, filePath, aiOptions, locales, defaultLocale, tagsKeys } =\n req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditContentDeclarationUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let tags: Tag[] = [];\n\n if (project?.organizationId) {\n tags = await getTagsByKeys(tagsKeys, project.organizationId);\n }\n\n const auditResponse = await auditContentDeclarationUtil.auditDictionary({\n fileContent,\n filePath,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n locales,\n defaultLocale,\n tags,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditContentDeclarationFieldBody = {\n aiOptions?: AIOptions;\n locales: Locales[];\n fileContent: string;\n filePath?: string;\n tagsKeys?: string[];\n keyPath: KeyPath[];\n};\nexport type AuditContentDeclarationFieldResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditContentDeclarationField = async (\n req: Request<AuditContentDeclarationFieldBody>,\n res: ResponseWithSession<AuditContentDeclarationFieldResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { fileContent, aiOptions, locales, tagsKeys, keyPath } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditContentDeclarationFieldUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let tags: Tag[] = [];\n\n if (project?.organizationId) {\n tags = await getTagsByKeys(tagsKeys, project.organizationId);\n }\n\n const auditResponse =\n await auditContentDeclarationFieldUtil.auditDictionaryField({\n fileContent,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n locales,\n tags,\n keyPath,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditContentDeclarationMetadataBody = {\n aiOptions?: AIOptions;\n fileContent: string;\n};\nexport type AuditContentDeclarationMetadataResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditContentDeclarationMetadata = async (\n req: Request<AuditContentDeclarationMetadataBody>,\n res: ResponseWithSession<AuditContentDeclarationMetadataResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization } = res.locals;\n const { fileContent, aiOptions } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditContentDeclarationMetadataUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n const tags: Tag[] = await tagService.findTags(\n {\n organizationId: organization?.id,\n },\n 0,\n 1000\n );\n\n const auditResponse =\n await auditContentDeclarationMetadataUtil.auditDictionaryMetadata({\n fileContent,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n tags,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AuditTagBody = {\n aiOptions?: AIOptions;\n tag: Tag;\n};\nexport type AuditTagResult =\n ResponseData<auditContentDeclarationUtil.AuditFileResultData>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const auditTag = async (\n req: Request<undefined, undefined, AuditTagBody>,\n res: ResponseWithSession<AuditTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project } = res.locals;\n const { aiOptions, tag } = req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: auditTagUtil.aiDefaultOptions,\n accessType: ['registered_user', 'apiKey'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n try {\n let dictionaries: Dictionary[] = [];\n if (project?.organizationId) {\n dictionaries = await getDictionariesByTags([tag.key], project.id);\n }\n\n const auditResponse = await auditTagUtil.auditTag({\n aiConfig,\n dictionaries,\n tag,\n applicationContext: aiOptions?.applicationContext,\n });\n\n if (!auditResponse) {\n ErrorHandler.handleGenericErrorResponse(res, 'AUDIT_FAILED');\n return;\n }\n\n const responseData =\n formatResponse<auditContentDeclarationUtil.AuditFileResultData>({\n data: auditResponse,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AskDocQuestionBody = {\n messages: ChatCompletionRequestMessage[];\n discutionId: string;\n};\nexport type AskDocQuestionResult =\n ResponseData<askDocQuestionUtil.AskDocQuestionResult>;\n\nexport const askDocQuestion = async (\n req: Request<undefined, undefined, AskDocQuestionBody>,\n res: ResponseWithSession<AskDocQuestionResult>\n) => {\n const { messages, discutionId } = req.body;\n const { user, project, organization } = res.locals;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: {},\n defaultOptions: askDocQuestionUtil.aiDefaultOptions,\n accessType: ['public'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n // 1. Prepare SSE headers and flush them NOW\n res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');\n res.setHeader('Cache-Control', 'no-cache, no-transform');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no'); // disable nginx buffering\n res.flushHeaders?.();\n res.write(': connected\\n\\n'); // initial comment keeps some browsers happy\n res.flush?.();\n\n // 2. Kick off the upstream stream WITHOUT awaiting it\n askDocQuestionUtil\n .askDocQuestion(messages, aiConfig, {\n onMessage: (chunk) => {\n res.write(`data: ${JSON.stringify({ chunk })}\\n\\n`);\n res.flush?.();\n },\n })\n .then(async (fullResponse) => {\n const lastUserMessageContent = messages.findLast(\n (msg) => msg.role === 'user'\n )?.content;\n const lastUserMessageNbWords = lastUserMessageContent\n ? lastUserMessageContent.split(' ').length\n : 0;\n if (lastUserMessageNbWords > 2) {\n // If the last user message is less than 3 words, don't persist the discussion\n // Example: \"Hello\", \"Hi\", \"Hey\", \"test\", etc.\n\n // 3. Persist discussion while the client already has all chunks\n await DiscussionModel.findOneAndUpdate(\n { discutionId },\n {\n $set: {\n discutionId,\n userId: user?.id,\n projectId: project?.id,\n organizationId: organization?.id,\n messages: [\n ...messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n timestamp: msg.timestamp,\n })),\n {\n role: 'assistant',\n content: fullResponse.response,\n relatedFiles: fullResponse.relatedFiles,\n timestamp: new Date(),\n },\n ],\n },\n },\n { upsert: true, new: true }\n );\n }\n\n // 4. Tell the client we're done and close the stream\n res.write(\n `data: ${JSON.stringify({ done: true, response: fullResponse })}\\n\\n`\n );\n res.end();\n })\n .catch((err) => {\n // propagate error as an SSE event so the client knows why it closed\n res.write(\n `event: error\\ndata: ${JSON.stringify({ message: err.message })}\\n\\n`\n );\n res.end();\n });\n};\n\nexport type AutocompleteBody = {\n text: string;\n aiOptions?: AIOptions;\n contextBefore?: string;\n currentLine?: string;\n contextAfter?: string;\n};\n\nexport type AutocompleteResponse = ResponseData<{\n autocompletion: string;\n}>;\n\nexport const autocomplete = async (\n req: Request<undefined, undefined, AutocompleteBody>,\n res: ResponseWithSession<AutocompleteResponse>\n) => {\n try {\n const { text, aiOptions, contextBefore, currentLine, contextAfter } =\n req.body;\n\n let aiConfig: AIConfig;\n try {\n aiConfig = await getAIConfig(res, {\n userOptions: aiOptions,\n defaultOptions: autocompleteUtil.aiDefaultOptions,\n accessType: ['public'],\n });\n } catch (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'AI_ACCESS_DENIED');\n return;\n }\n\n const response = (await autocompleteUtil.autocomplete({\n text,\n aiConfig,\n applicationContext: aiOptions?.applicationContext,\n contextBefore,\n currentLine,\n contextAfter,\n })) ?? {\n autocompletion: '',\n tokenUsed: 0,\n };\n\n const responseData =\n formatResponse<autocompleteUtil.AutocompleteFileResultData>({\n data: response,\n });\n\n res.json(responseData);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
|
|
@@ -58,10 +58,6 @@ const getDictionaries = async (req, res, _next) => {
|
|
|
58
58
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
-
if (!(0, import_permissions.hasPermission)(roles, "dictionary:read")(res.locals)) {
|
|
62
|
-
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
61
|
try {
|
|
66
62
|
const dictionaries = await dictionaryService.findDictionaries(
|
|
67
63
|
{
|
|
@@ -71,6 +67,16 @@ const getDictionaries = async (req, res, _next) => {
|
|
|
71
67
|
skip,
|
|
72
68
|
pageSize
|
|
73
69
|
);
|
|
70
|
+
if (!(0, import_permissions.hasPermission)(
|
|
71
|
+
roles,
|
|
72
|
+
"dictionary:read"
|
|
73
|
+
)({
|
|
74
|
+
...res.locals,
|
|
75
|
+
targetDictionaries: dictionaries
|
|
76
|
+
})) {
|
|
77
|
+
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
74
80
|
const totalItems = await dictionaryService.countDictionaries(filters);
|
|
75
81
|
const dictionariesAPI = dictionaries.map(
|
|
76
82
|
(el) => (0, import_dictionary.mapDictionaryToAPI)(el, project.id)
|
|
@@ -95,14 +101,21 @@ const getDictionariesKeys = async (_req, res, _next) => {
|
|
|
95
101
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
96
102
|
return;
|
|
97
103
|
}
|
|
98
|
-
if (!(0, import_permissions.hasPermission)(roles, "dictionary:read")(res.locals)) {
|
|
99
|
-
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
104
|
try {
|
|
103
|
-
const
|
|
104
|
-
project.id
|
|
105
|
-
);
|
|
105
|
+
const dictionaries = await dictionaryService.findDictionaries({
|
|
106
|
+
projectIds: project.id
|
|
107
|
+
});
|
|
108
|
+
if (!(0, import_permissions.hasPermission)(
|
|
109
|
+
roles,
|
|
110
|
+
"dictionary:read"
|
|
111
|
+
)({
|
|
112
|
+
...res.locals,
|
|
113
|
+
targetDictionaries: dictionaries
|
|
114
|
+
})) {
|
|
115
|
+
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const dictionariesKeys = dictionaries.map((dictionary) => dictionary.key);
|
|
106
119
|
const responseData = (0, import_responseData.formatResponse)({
|
|
107
120
|
data: dictionariesKeys
|
|
108
121
|
});
|
|
@@ -125,15 +138,21 @@ const getDictionaryByKey = async (req, res, _next) => {
|
|
|
125
138
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
126
139
|
return;
|
|
127
140
|
}
|
|
128
|
-
if (!(0, import_permissions.hasPermission)(roles, "dictionary:read")(res.locals)) {
|
|
129
|
-
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
141
|
try {
|
|
133
142
|
const dictionary = await dictionaryService.getDictionaryByKey(
|
|
134
143
|
dictionaryKey,
|
|
135
144
|
project.id
|
|
136
145
|
);
|
|
146
|
+
if (!(0, import_permissions.hasPermission)(
|
|
147
|
+
roles,
|
|
148
|
+
"dictionary:read"
|
|
149
|
+
)({
|
|
150
|
+
...res.locals,
|
|
151
|
+
targetDictionaries: [dictionary]
|
|
152
|
+
})) {
|
|
153
|
+
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
137
156
|
if (!dictionary.projectIds.map(String).includes(String(project.id))) {
|
|
138
157
|
import_errors.ErrorHandler.handleGenericErrorResponse(
|
|
139
158
|
res,
|
|
@@ -171,10 +190,6 @@ const addDictionary = async (req, res, _next) => {
|
|
|
171
190
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "DICTIONARY_PROJECT_MISMATCH");
|
|
172
191
|
return;
|
|
173
192
|
}
|
|
174
|
-
if (!(0, import_permissions.hasPermission)(roles, "dictionary:write")(res.locals)) {
|
|
175
|
-
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
193
|
const dictionary = {
|
|
179
194
|
key: dictionaryData.key,
|
|
180
195
|
title: dictionaryData.title,
|
|
@@ -188,6 +203,10 @@ const addDictionary = async (req, res, _next) => {
|
|
|
188
203
|
},
|
|
189
204
|
projectIds: dictionaryData.projectIds ?? [String(project.id)]
|
|
190
205
|
};
|
|
206
|
+
if (!(0, import_permissions.hasPermission)(roles, "dictionary:write")(res.locals)) {
|
|
207
|
+
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
191
210
|
try {
|
|
192
211
|
const newDictionary = await dictionaryService.createDictionary(dictionary);
|
|
193
212
|
const apiResult = (0, import_dictionary.mapDictionaryToAPI)(newDictionary, project.id);
|
|
@@ -435,7 +454,7 @@ const deleteDictionary = async (req, res, _next) => {
|
|
|
435
454
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
436
455
|
return;
|
|
437
456
|
}
|
|
438
|
-
if (!(0, import_permissions.hasPermission)(roles, "dictionary:admin")()) {
|
|
457
|
+
if (!(0, import_permissions.hasPermission)(roles, "dictionary:admin")(res.locals)) {
|
|
439
458
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
440
459
|
return;
|
|
441
460
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/controllers/dictionary.controller.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionaryAPI,\n DictionaryCreationData,\n DictionaryData,\n VersionedContent,\n} from '@/types/dictionary.types';\nimport * as eventListener from '@controllers/eventListener.controller';\nimport type {\n ContentNode,\n Dictionary as LocalDictionary,\n} from '@intlayer/core';\nimport { logger } from '@logger';\nimport * as dictionaryService from '@services/dictionary.service';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport {\n type DictionaryFiltersParams,\n getDictionaryFiltersAndPagination,\n} from '@utils/filtersAndPagination/getDictionaryFiltersAndPagination';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport { mapDictionaryToAPI } from '@utils/mapper/dictionary';\nimport { hasPermission } from '@utils/permissions';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport { t } from 'express-intlayer';\n\nexport type GetDictionariesParams =\n FiltersAndPagination<DictionaryFiltersParams>;\nexport type GetDictionariesResult = PaginatedResponse<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaries = async (\n req: Request<GetDictionariesParams>,\n res: Response<GetDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getDictionaryFiltersAndPagination(req);\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:read')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const dictionaries = await dictionaryService.findDictionaries(\n {\n ...filters,\n projectIds: project.id,\n },\n skip,\n pageSize\n );\n const totalItems = await dictionaryService.countDictionaries(filters);\n\n const dictionariesAPI = dictionaries.map((el) =>\n mapDictionaryToAPI(el, project.id)\n );\n\n const responseData = formatPaginatedResponse<DictionaryAPI>({\n data: dictionariesAPI,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionariesKeysResult = ResponseData<string[]>;\n\n/**\n * Retrieves a list of dictionaries keys based on filters and pagination.\n */\nexport const getDictionariesKeys = async (\n _req: Request,\n res: Response<GetDictionariesKeysResult>,\n _next: NextFunction\n) => {\n const { project, roles } = res.locals;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:read')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const dictionariesKeys = await dictionaryService.getDictionariesKeys(\n project.id\n );\n\n const responseData = formatResponse<string[]>({\n data: dictionariesKeys,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionaryParams = { dictionaryKey: string };\nexport type GetDictionaryQuery = { version?: string };\nexport type GetDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaryByKey = async (\n req: Request<GetDictionaryParams, any, any, GetDictionaryQuery>,\n res: Response<GetDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, roles } = res.locals;\n const { dictionaryKey } = req.params;\n const version = req.query.version;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:read')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n dictionaryKey,\n project.id\n );\n\n if (!dictionary.projectIds.map(String).includes(String(project.id))) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const apiResult = mapDictionaryToAPI(dictionary, project.id, version);\n\n const responseData = formatResponse<DictionaryAPI>({\n data: apiResult,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddDictionaryBody = { dictionary: DictionaryCreationData };\nexport type AddDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Adds a new dictionary to the database.\n */\nexport const addDictionary = async (\n req: Request<any, any, AddDictionaryBody>,\n res: Response<AddDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, roles } = res.locals;\n const dictionaryData = req.body.dictionary;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project.id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:write')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const dictionary: DictionaryData = {\n key: dictionaryData.key,\n title: dictionaryData.title,\n description: dictionaryData.description,\n content: new Map([\n ['v1', { content: dictionaryData.content ?? ({} as ContentNode) }],\n ]),\n creatorId: user.id,\n filePath: {\n [String(project.id)]: dictionaryData.filePath ?? '',\n },\n projectIds: dictionaryData.projectIds ?? [String(project.id)],\n };\n\n try {\n const newDictionary = await dictionaryService.createDictionary(dictionary);\n\n const apiResult = mapDictionaryToAPI(newDictionary, project.id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary created successfully',\n fr: 'Dictionnaire créé avec succès',\n es: 'Diccionario creado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been created successfully',\n fr: 'Votre dictionnaire a été créé avec succès',\n es: 'Su diccionario ha sido creado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: mapDictionaryToAPI(newDictionary, project.id),\n status: 'ADDED',\n },\n ]);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type PushDictionariesBody = {\n dictionaries: LocalDictionary[];\n};\ntype PushDictionariesResultData = {\n newDictionaries: string[];\n updatedDictionaries: string[];\n error: { dictionaryId: string; message: string }[];\n};\nexport type PushDictionariesResult = ResponseData<PushDictionariesResultData>;\n\n/**\n * Check each dictionaries, add the new ones and update the existing ones.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response containing the created dictionary.\n */\nexport const pushDictionaries = async (\n req: Request<any, any, PushDictionariesBody>,\n res: Response<PushDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, roles } = res.locals;\n const dictionaryData = req.body.dictionaries;\n const dictionariesKeys = dictionaryData.map((dictionary) => dictionary.key);\n\n if (\n typeof dictionaryData === 'object' &&\n Array.isArray(dictionaryData) &&\n dictionaryData.length === 0\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARIES_NOT_PROVIDED');\n return;\n } else if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:write')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const { existingDictionariesKey, newDictionariesKey } =\n await dictionaryService.getExistingDictionaryKey(\n dictionariesKeys,\n project.id\n );\n\n const existingDictionaries = dictionaryData.filter((dictionary) =>\n existingDictionariesKey.includes(dictionary.key)\n );\n const newDictionaries = dictionaryData.filter((dictionary) =>\n newDictionariesKey.includes(dictionary.key)\n );\n\n const newDictionariesResult: DictionaryAPI[] = [];\n const updatedDictionariesResult: DictionaryAPI[] = [];\n const errorResult: PushDictionariesResultData['error'] = [];\n\n for (const dictionaryDataEl of newDictionaries) {\n const dictionary: DictionaryData = {\n title: dictionaryDataEl.title,\n description: dictionaryDataEl.description,\n projectIds: [String(project.id)],\n creatorId: user.id,\n content: new Map([\n ['v1', { content: dictionaryDataEl.content ?? ({} as ContentNode) }],\n ]),\n filePath: {\n [String(project.id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const newDictionary =\n await dictionaryService.createDictionary(dictionary);\n newDictionariesResult.push(\n mapDictionaryToAPI(newDictionary, project.id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n\n if (existingDictionariesKey.length >= 0) {\n const existingDictionariesDB =\n await dictionaryService.getDictionariesByKeys(\n existingDictionariesKey,\n project.id\n );\n\n for (const dictionaryDataEl of existingDictionaries) {\n const existingDictionaryDB = existingDictionariesDB.find(\n (dictionaryDB) => dictionaryDB.key === dictionaryDataEl.key\n )!;\n\n const versionList = [...(existingDictionaryDB.content.keys() ?? [])];\n const lastVersion = versionList[versionList.length - 1];\n\n const lastContent =\n (existingDictionaryDB.content.get(lastVersion)\n ?.content as DictionaryAPI['content']) ?? null;\n\n const isSameContent =\n JSON.stringify(lastContent) ===\n JSON.stringify(dictionaryDataEl.content);\n\n let newContent: VersionedContent = existingDictionaryDB.content;\n\n if (!isSameContent) {\n const newContentVersion =\n dictionaryService.incrementVersion(existingDictionaryDB);\n\n existingDictionaryDB.content.set(newContentVersion, {\n content: dictionaryDataEl.content ?? ({} as ContentNode),\n });\n\n newContent = existingDictionaryDB.content;\n }\n\n const dictionary: DictionaryData = {\n ...ensureMongoDocumentToObject(existingDictionaryDB),\n ...dictionaryDataEl,\n content: newContent,\n projectIds: [String(project.id)],\n creatorId: user.id,\n filePath: {\n [String(project.id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const updatedDictionary =\n await dictionaryService.updateDictionaryByKey(\n dictionaryDataEl.key,\n dictionary,\n project.id\n );\n updatedDictionariesResult.push(\n mapDictionaryToAPI(updatedDictionary, project.id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n }\n\n const result: PushDictionariesResultData = {\n newDictionaries: newDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n updatedDictionaries: updatedDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n error: errorResult,\n };\n\n const responseData = formatResponse<PushDictionariesResultData>({\n message: t({\n en: 'Dictionaries updated successfully',\n fr: 'Dictionnaires mis à jour avec succès',\n es: 'Diccionarios actualizados con éxito',\n }),\n description: t({\n en: 'Your dictionaries have been updated successfully',\n fr: 'Vos dictionnaires ont été mis à jour avec succès',\n es: 'Sus diccionarios han sido actualizados con éxito',\n }),\n data: result,\n });\n\n eventListener.sendDictionaryUpdate([\n ...newDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'ADDED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ...updatedDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'UPDATED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateDictionaryParam = { dictionaryId: string };\nexport type UpdateDictionaryBody = Partial<Dictionary>;\nexport type UpdateDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Updates an existing dictionary in the database.\n */\nexport const updateDictionary = async (\n req: Request<UpdateDictionaryParam, any, UpdateDictionaryBody>,\n res: Response<UpdateDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { dictionaryId } = req.params;\n const { project, roles } = res.locals;\n const dictionaryData = req.body;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project.id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n if (typeof dictionaryId === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:write')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const updatedDictionary = await dictionaryService.updateDictionaryById(\n dictionaryId,\n dictionaryData\n );\n\n const apiResult = mapDictionaryToAPI(updatedDictionary, project.id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary updated successfully',\n fr: 'Dictionnaire mis à jour avec succès',\n es: 'Diccionario actualizado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been updated successfully',\n fr: 'Votre dictionnaire a été mis à jour avec succès',\n es: 'Su diccionario ha sido actualizado con éxito',\n }),\n data: apiResult,\n });\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'UPDATED',\n },\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteDictionaryParam = { dictionaryId: string };\nexport type DeleteDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Deletes a dictionary from the database by its ID.\n */\nexport const deleteDictionary = async (\n req: Request<DeleteDictionaryParam>,\n res: Response<DeleteDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, roles } = res.locals;\n const { dictionaryId } = req.params as Partial<DeleteDictionaryParam>;\n\n if (!dictionaryId) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:admin')()) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const dictionaryToDelete =\n await dictionaryService.getDictionaryById(dictionaryId);\n\n if (!dictionaryToDelete.projectIds.includes(project.id)) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const deletedDictionary =\n await dictionaryService.deleteDictionaryById(dictionaryId);\n\n if (!deletedDictionary) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_NOT_FOUND', {\n dictionaryId,\n });\n return;\n }\n\n logger.info(`Dictionary deleted: ${String(deletedDictionary.id)}`);\n\n const apiResult = mapDictionaryToAPI(deletedDictionary, project.id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary deleted successfully',\n fr: 'Dictionnaire supprimé avec succès',\n es: 'Diccionario eliminado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been deleted successfully',\n fr: 'Votre dictionnaire a été supprimé avec succès',\n es: 'Su diccionario ha sido eliminado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'DELETED',\n },\n ]);\n\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/controllers/dictionary.controller.ts"],"sourcesContent":["import type {\n Dictionary,\n DictionaryAPI,\n DictionaryCreationData,\n DictionaryData,\n VersionedContent,\n} from '@/types/dictionary.types';\nimport * as eventListener from '@controllers/eventListener.controller';\nimport type {\n ContentNode,\n Dictionary as LocalDictionary,\n} from '@intlayer/core';\nimport { logger } from '@logger';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport * as dictionaryService from '@services/dictionary.service';\nimport { ensureMongoDocumentToObject } from '@utils/ensureMongoDocumentToObject';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport {\n type DictionaryFiltersParams,\n getDictionaryFiltersAndPagination,\n} from '@utils/filtersAndPagination/getDictionaryFiltersAndPagination';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport { mapDictionaryToAPI } from '@utils/mapper/dictionary';\nimport { hasPermission } from '@utils/permissions';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\n\nexport type GetDictionariesParams =\n FiltersAndPagination<DictionaryFiltersParams>;\nexport type GetDictionariesResult = PaginatedResponse<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaries = async (\n req: Request<GetDictionariesParams>,\n res: ResponseWithSession<GetDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getDictionaryFiltersAndPagination(req);\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const dictionaries = await dictionaryService.findDictionaries(\n {\n ...filters,\n projectIds: project.id,\n },\n skip,\n pageSize\n );\n\n if (\n !hasPermission(\n roles,\n 'dictionary:read'\n )({\n ...res.locals,\n targetDictionaries: dictionaries,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const totalItems = await dictionaryService.countDictionaries(filters);\n\n const dictionariesAPI = dictionaries.map((el) =>\n mapDictionaryToAPI(el, project.id)\n );\n\n const responseData = formatPaginatedResponse<DictionaryAPI>({\n data: dictionariesAPI,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionariesKeysResult = ResponseData<string[]>;\n\n/**\n * Retrieves a list of dictionaries keys based on filters and pagination.\n */\nexport const getDictionariesKeys = async (\n _req: Request,\n res: ResponseWithSession<GetDictionariesKeysResult>,\n _next: NextFunction\n) => {\n const { project, roles } = res.locals;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n try {\n const dictionaries = await dictionaryService.findDictionaries({\n projectIds: project.id,\n });\n\n if (\n !hasPermission(\n roles,\n 'dictionary:read'\n )({\n ...res.locals,\n targetDictionaries: dictionaries,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const dictionariesKeys = dictionaries.map((dictionary) => dictionary.key);\n\n const responseData = formatResponse<string[]>({\n data: dictionariesKeys,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetDictionaryParams = { dictionaryKey: string };\nexport type GetDictionaryQuery = { version?: string };\nexport type GetDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaryByKey = async (\n req: Request<GetDictionaryParams, any, any, GetDictionaryQuery>,\n res: ResponseWithSession<GetDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, roles } = res.locals;\n const { dictionaryKey } = req.params;\n const version = req.query.version;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const dictionary = await dictionaryService.getDictionaryByKey(\n dictionaryKey,\n project.id\n );\n\n if (\n !hasPermission(\n roles,\n 'dictionary:read'\n )({\n ...res.locals,\n targetDictionaries: [dictionary],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n if (!dictionary.projectIds.map(String).includes(String(project.id))) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const apiResult = mapDictionaryToAPI(dictionary, project.id, version);\n\n const responseData = formatResponse<DictionaryAPI>({\n data: apiResult,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddDictionaryBody = { dictionary: DictionaryCreationData };\nexport type AddDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Adds a new dictionary to the database.\n */\nexport const addDictionary = async (\n req: Request<any, any, AddDictionaryBody>,\n res: ResponseWithSession<AddDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, roles } = res.locals;\n const dictionaryData = req.body.dictionary;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project.id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n const dictionary: DictionaryData = {\n key: dictionaryData.key,\n title: dictionaryData.title,\n description: dictionaryData.description,\n content: new Map([\n ['v1', { content: dictionaryData.content ?? ({} as ContentNode) }],\n ]),\n creatorId: user.id,\n filePath: {\n [String(project.id)]: dictionaryData.filePath ?? '',\n },\n projectIds: dictionaryData.projectIds ?? [String(project.id)],\n };\n\n if (!hasPermission(roles, 'dictionary:write')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const newDictionary = await dictionaryService.createDictionary(dictionary);\n\n const apiResult = mapDictionaryToAPI(newDictionary, project.id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary created successfully',\n fr: 'Dictionnaire créé avec succès',\n es: 'Diccionario creado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been created successfully',\n fr: 'Votre dictionnaire a été créé avec succès',\n es: 'Su diccionario ha sido creado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: mapDictionaryToAPI(newDictionary, project.id),\n status: 'ADDED',\n },\n ]);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type PushDictionariesBody = {\n dictionaries: LocalDictionary[];\n};\ntype PushDictionariesResultData = {\n newDictionaries: string[];\n updatedDictionaries: string[];\n error: { dictionaryId: string; message: string }[];\n};\nexport type PushDictionariesResult = ResponseData<PushDictionariesResultData>;\n\n/**\n * Check each dictionaries, add the new ones and update the existing ones.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response containing the created dictionary.\n */\nexport const pushDictionaries = async (\n req: Request<any, any, PushDictionariesBody>,\n res: ResponseWithSession<PushDictionariesResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, user, roles } = res.locals;\n const dictionaryData = req.body.dictionaries;\n const dictionariesKeys = dictionaryData.map((dictionary) => dictionary.key);\n\n if (\n typeof dictionaryData === 'object' &&\n Array.isArray(dictionaryData) &&\n dictionaryData.length === 0\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARIES_NOT_PROVIDED');\n return;\n } else if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:write')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const { existingDictionariesKey, newDictionariesKey } =\n await dictionaryService.getExistingDictionaryKey(\n dictionariesKeys,\n project.id\n );\n\n const existingDictionaries = dictionaryData.filter((dictionary) =>\n existingDictionariesKey.includes(dictionary.key)\n );\n const newDictionaries = dictionaryData.filter((dictionary) =>\n newDictionariesKey.includes(dictionary.key)\n );\n\n const newDictionariesResult: DictionaryAPI[] = [];\n const updatedDictionariesResult: DictionaryAPI[] = [];\n const errorResult: PushDictionariesResultData['error'] = [];\n\n for (const dictionaryDataEl of newDictionaries) {\n const dictionary: DictionaryData = {\n title: dictionaryDataEl.title,\n description: dictionaryDataEl.description,\n projectIds: [String(project.id)],\n creatorId: user.id,\n content: new Map([\n ['v1', { content: dictionaryDataEl.content ?? ({} as ContentNode) }],\n ]),\n filePath: {\n [String(project.id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const newDictionary =\n await dictionaryService.createDictionary(dictionary);\n newDictionariesResult.push(\n mapDictionaryToAPI(newDictionary, project.id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n\n if (existingDictionariesKey.length >= 0) {\n const existingDictionariesDB =\n await dictionaryService.getDictionariesByKeys(\n existingDictionariesKey,\n project.id\n );\n\n for (const dictionaryDataEl of existingDictionaries) {\n const existingDictionaryDB = existingDictionariesDB.find(\n (dictionaryDB) => dictionaryDB.key === dictionaryDataEl.key\n )!;\n\n const versionList = [...(existingDictionaryDB.content.keys() ?? [])];\n const lastVersion = versionList[versionList.length - 1];\n\n const lastContent =\n (existingDictionaryDB.content.get(lastVersion)\n ?.content as DictionaryAPI['content']) ?? null;\n\n const isSameContent =\n JSON.stringify(lastContent) ===\n JSON.stringify(dictionaryDataEl.content);\n\n let newContent: VersionedContent = existingDictionaryDB.content;\n\n if (!isSameContent) {\n const newContentVersion =\n dictionaryService.incrementVersion(existingDictionaryDB);\n\n existingDictionaryDB.content.set(newContentVersion, {\n content: dictionaryDataEl.content ?? ({} as ContentNode),\n });\n\n newContent = existingDictionaryDB.content;\n }\n\n const dictionary: DictionaryData = {\n ...ensureMongoDocumentToObject(existingDictionaryDB),\n ...dictionaryDataEl,\n content: newContent,\n projectIds: [String(project.id)],\n creatorId: user.id,\n filePath: {\n [String(project.id)]: dictionaryDataEl.filePath ?? '',\n },\n key: dictionaryDataEl.key,\n };\n\n try {\n const updatedDictionary =\n await dictionaryService.updateDictionaryByKey(\n dictionaryDataEl.key,\n dictionary,\n project.id\n );\n updatedDictionariesResult.push(\n mapDictionaryToAPI(updatedDictionary, project.id)\n );\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n }\n }\n\n const result: PushDictionariesResultData = {\n newDictionaries: newDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n updatedDictionaries: updatedDictionariesResult.map(\n (dictionary) => dictionary.key\n ),\n error: errorResult,\n };\n\n const responseData = formatResponse<PushDictionariesResultData>({\n message: t({\n en: 'Dictionaries updated successfully',\n fr: 'Dictionnaires mis à jour avec succès',\n es: 'Diccionarios actualizados con éxito',\n }),\n description: t({\n en: 'Your dictionaries have been updated successfully',\n fr: 'Vos dictionnaires ont été mis à jour avec succès',\n es: 'Sus diccionarios han sido actualizados con éxito',\n }),\n data: result,\n });\n\n eventListener.sendDictionaryUpdate([\n ...newDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'ADDED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ...updatedDictionariesResult.map(\n (dictionary) =>\n ({\n dictionary,\n status: 'UPDATED',\n }) as eventListener.SendDictionaryUpdateArg\n ),\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateDictionaryParam = { dictionaryId: string };\nexport type UpdateDictionaryBody = Partial<Dictionary>;\nexport type UpdateDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Updates an existing dictionary in the database.\n */\nexport const updateDictionary = async (\n req: Request<UpdateDictionaryParam, any, UpdateDictionaryBody>,\n res: ResponseWithSession<UpdateDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { dictionaryId } = req.params;\n const { project, roles } = res.locals;\n const dictionaryData = req.body;\n\n if (!dictionaryData) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_DATA_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!dictionaryData.projectIds?.includes(String(project.id))) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_PROJECT_MISMATCH');\n return;\n }\n\n if (typeof dictionaryId === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:write')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const updatedDictionary = await dictionaryService.updateDictionaryById(\n dictionaryId,\n dictionaryData\n );\n\n const apiResult = mapDictionaryToAPI(updatedDictionary, project.id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary updated successfully',\n fr: 'Dictionnaire mis à jour avec succès',\n es: 'Diccionario actualizado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been updated successfully',\n fr: 'Votre dictionnaire a été mis à jour avec succès',\n es: 'Su diccionario ha sido actualizado con éxito',\n }),\n data: apiResult,\n });\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'UPDATED',\n },\n ]);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteDictionaryParam = { dictionaryId: string };\nexport type DeleteDictionaryResult = ResponseData<DictionaryAPI>;\n\n/**\n * Deletes a dictionary from the database by its ID.\n */\nexport const deleteDictionary = async (\n req: Request<DeleteDictionaryParam>,\n res: ResponseWithSession<DeleteDictionaryResult>,\n _next: NextFunction\n): Promise<void> => {\n const { project, roles } = res.locals;\n const { dictionaryId } = req.params as Partial<DeleteDictionaryParam>;\n\n if (!dictionaryId) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_ID_NOT_FOUND');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'dictionary:admin')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const dictionaryToDelete =\n await dictionaryService.getDictionaryById(dictionaryId);\n\n if (!dictionaryToDelete.projectIds.includes(project.id)) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n return;\n }\n\n const deletedDictionary =\n await dictionaryService.deleteDictionaryById(dictionaryId);\n\n if (!deletedDictionary) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_NOT_FOUND', {\n dictionaryId,\n });\n return;\n }\n\n logger.info(`Dictionary deleted: ${String(deletedDictionary.id)}`);\n\n const apiResult = mapDictionaryToAPI(deletedDictionary, project.id);\n\n const responseData = formatResponse<DictionaryAPI>({\n message: t({\n en: 'Dictionary deleted successfully',\n fr: 'Dictionnaire supprimé avec succès',\n es: 'Diccionario eliminado con éxito',\n }),\n description: t({\n en: 'Your dictionary has been deleted successfully',\n fr: 'Votre dictionnaire a été supprimé avec succès',\n es: 'Su diccionario ha sido eliminado con éxito',\n }),\n data: apiResult,\n });\n\n res.json(responseData);\n\n eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'DELETED',\n },\n ]);\n\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/controllers/newsletter.controller.ts"],"sourcesContent":["import type { EmailsList, UserAPI } from '@/types/user.types';\nimport { logger } from '@logger';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { hasPermission } from '@utils/permissions';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport { t } from 'express-intlayer';\nimport { ObjectId } from 'mongodb';\n\nexport type NewsletterSubscriptionBody = {\n email: string;\n emailList: EmailsList | EmailsList[];\n};\nexport type NewsletterSubscriptionResult = ResponseData<UserAPI>;\n\n/**\n * Subscribes a user to the newsletter.\n * If the user doesn't exist, creates a new user.\n * If the user exists, updates their newsletter subscription to true.\n */\nexport const subscribeToNewsletter = async (\n req: Request<any, any, NewsletterSubscriptionBody>,\n res: Response<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const { roles } = res.locals;\n const { email, emailList } = req.body;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, true])\n ) as Record<EmailsList, boolean>;\n\n try {\n // Check if user exists\n let user = await userService.getUserByEmail(email);\n\n if (!user) {\n user = await userService.createUser({\n email,\n emailsList: emailsListObject,\n });\n\n logger.info(`New user created and subscribed to newsletter: ${email}`);\n } else {\n if (\n !hasPermission(\n roles,\n 'user:write'\n )({\n ...res.locals,\n targetUserIds: [user.id],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n // Update existing user's newsletter subscription\n user = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User subscribed to newsletter: ${email}`);\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully subscribed to newsletter',\n fr: 'Abonnement à la newsletter réussi',\n es: 'Suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully subscribed to our newsletter',\n fr: 'Vous avez été abonné avec succès à notre newsletter',\n es: 'Te has suscrito exitosamente a nuestro boletín',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type NewsletterUnsubscriptionBody = {\n userId: string;\n emailList: EmailsList | EmailsList[];\n};\n\n/**\n * Unsubscribes a user from the newsletter.\n * Only works if the user exists.\n */\nexport const unsubscribeFromNewsletter = async (\n req: Request<any, any, NewsletterUnsubscriptionBody>,\n res: Response<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId, emailList } = req.body;\n const { roles } = res.locals;\n\n if (!userId) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:write'\n )({\n ...res.locals,\n targetUserIds: [new ObjectId(userId)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n // Check if user exists\n const user = await userService.getUserById(userId);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, false])\n ) as Record<EmailsList, boolean>;\n\n // Update user's newsletter subscription to false\n const updatedUser = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User unsubscribed from newsletter: ${updatedUser.email}`);\n\n const formattedUser = mapUserToAPI(updatedUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully unsubscribed from newsletter',\n fr: 'Désabonnement de la newsletter réussi',\n es: 'Cancelación de suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully unsubscribed from our newsletter',\n fr: 'Vous avez été désabonné avec succès de notre newsletter',\n es: 'Te has desuscrito exitosamente de nuestro boletín',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\n/**\n * Gets the newsletter subscription status for a user.\n */\nexport const getNewsletterStatus = async (\n _req: Request<{ email: string }>,\n res: Response<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const email = res.locals.user?.email;\n const { roles } = res.locals;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:read'\n )({\n ...res.locals,\n targetUserIds: [user.id],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Newsletter subscription status retrieved',\n fr: \"Statut d'abonnement à la newsletter récupéré\",\n es: 'Estado de suscripción al boletín obtenido',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/controllers/newsletter.controller.ts"],"sourcesContent":["import type { EmailsList, UserAPI } from '@/types/user.types';\nimport { logger } from '@logger';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { hasPermission } from '@utils/permissions';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport { ObjectId } from 'mongodb';\n\nexport type NewsletterSubscriptionBody = {\n email: string;\n emailList: EmailsList | EmailsList[];\n};\nexport type NewsletterSubscriptionResult = ResponseData<UserAPI>;\n\n/**\n * Subscribes a user to the newsletter.\n * If the user doesn't exist, creates a new user.\n * If the user exists, updates their newsletter subscription to true.\n */\nexport const subscribeToNewsletter = async (\n req: Request<any, any, NewsletterSubscriptionBody>,\n res: ResponseWithSession<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const { roles } = res.locals;\n const { email, emailList } = req.body;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, true])\n ) as Record<EmailsList, boolean>;\n\n try {\n // Check if user exists\n let user = await userService.getUserByEmail(email);\n\n if (!user) {\n user = await userService.createUser({\n email,\n emailsList: emailsListObject,\n });\n\n logger.info(`New user created and subscribed to newsletter: ${email}`);\n } else {\n if (\n !hasPermission(\n roles,\n 'user:write'\n )({\n ...res.locals,\n targetUserIds: [user.id],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n // Update existing user's newsletter subscription\n user = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User subscribed to newsletter: ${email}`);\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully subscribed to newsletter',\n fr: 'Abonnement à la newsletter réussi',\n es: 'Suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully subscribed to our newsletter',\n fr: 'Vous avez été abonné avec succès à notre newsletter',\n es: 'Te has suscrito exitosamente a nuestro boletín',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type NewsletterUnsubscriptionBody = {\n userId: string;\n emailList: EmailsList | EmailsList[];\n};\n\n/**\n * Unsubscribes a user from the newsletter.\n * Only works if the user exists.\n */\nexport const unsubscribeFromNewsletter = async (\n req: Request<any, any, NewsletterUnsubscriptionBody>,\n res: ResponseWithSession<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId, emailList } = req.body;\n const { roles } = res.locals;\n\n if (!userId) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:write'\n )({\n ...res.locals,\n targetUserIds: [new ObjectId(userId)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n // Check if user exists\n const user = await userService.getUserById(userId);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, false])\n ) as Record<EmailsList, boolean>;\n\n // Update user's newsletter subscription to false\n const updatedUser = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User unsubscribed from newsletter: ${updatedUser.email}`);\n\n const formattedUser = mapUserToAPI(updatedUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully unsubscribed from newsletter',\n fr: 'Désabonnement de la newsletter réussi',\n es: 'Cancelación de suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully unsubscribed from our newsletter',\n fr: 'Vous avez été désabonné avec succès de notre newsletter',\n es: 'Te has desuscrito exitosamente de nuestro boletín',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\n/**\n * Gets the newsletter subscription status for a user.\n */\nexport const getNewsletterStatus = async (\n _req: Request<{ email: string }>,\n res: ResponseWithSession<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const email = res.locals.user?.email;\n const { roles } = res.locals;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:read'\n )({\n ...res.locals,\n targetUserIds: [user.id],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Newsletter subscription status retrieved',\n fr: \"Statut d'abonnement à la newsletter récupéré\",\n es: 'Estado de suscripción al boletín obtenido',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAAuB;AAEvB,kBAA6B;AAC7B,oBAA4C;AAC5C,kBAA6B;AAC7B,yBAA8B;AAC9B,0BAAkD;AAElD,8BAAkB;AAClB,qBAAyB;AAalB,MAAM,wBAAwB,OACnC,KACA,KACA,UACkB;AAClB,QAAM,EAAE,MAAM,IAAI,IAAI;AACtB,QAAM,EAAE,OAAO,UAAU,IAAI,IAAI;AAEjC,MAAI,CAAC,OAAO;AACV,+BAAa,2BAA2B,KAAK,qBAAqB;AAClE;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,QAAQ,SAAS,IAAI,YAAY,CAAC,SAAS;AAGpE,QAAM,mBAAmB,OAAO;AAAA,IAC9B,WAAW,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC;AAAA,EACvC;AAEA,MAAI;AAEF,QAAI,OAAO,MAAM,YAAY,eAAe,KAAK;AAEjD,QAAI,CAAC,MAAM;AACT,aAAO,MAAM,YAAY,WAAW;AAAA,QAClC;AAAA,QACA,YAAY;AAAA,MACd,CAAC;AAED,2BAAO,KAAK,kDAAkD,KAAK,EAAE;AAAA,IACvE,OAAO;AACL,UACE,KAAC;AAAA,QACC;AAAA,QACA;AAAA,MACF,EAAE;AAAA,QACA,GAAG,IAAI;AAAA,QACP,eAAe,CAAC,KAAK,EAAE;AAAA,MACzB,CAAC,GACD;AACA,mCAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,MACF;AAGA,aAAO,MAAM,YAAY,eAAe,KAAK,IAAI;AAAA,QAC/C,YAAY,EAAE,GAAG,KAAK,YAAY,GAAG,iBAAiB;AAAA,MACxD,CAAC;AAED,2BAAO,KAAK,kCAAkC,KAAK,EAAE;AAAA,IACvD;AAEA,UAAM,oBAAgB,0BAAa,IAAI;AAEvC,UAAM,mBAAe,oCAAwB;AAAA,MAC3C,aAAS,2BAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,iBAAa,2BAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM;AAAA,IACR,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,+BAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAWO,MAAM,4BAA4B,OACvC,KACA,KACA,UACkB;AAClB,QAAM,EAAE,QAAQ,UAAU,IAAI,IAAI;AAClC,QAAM,EAAE,MAAM,IAAI,IAAI;AAEtB,MAAI,CAAC,QAAQ;AACX,+BAAa,2BAA2B,KAAK,qBAAqB;AAClE;AAAA,EACF;AAEA,MACE,KAAC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EAAE;AAAA,IACA,GAAG,IAAI;AAAA,IACP,eAAe,CAAC,IAAI,wBAAS,MAAM,CAAC;AAAA,EACtC,CAAC,GACD;AACA,+BAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,OAAO,MAAM,YAAY,YAAY,MAAM;AAEjD,QAAI,CAAC,MAAM;AACT,iCAAa,2BAA2B,KAAK,gBAAgB;AAC7D;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,QAAQ,SAAS,IAAI,YAAY,CAAC,SAAS;AAGpE,UAAM,mBAAmB,OAAO;AAAA,MAC9B,WAAW,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;AAAA,IACxC;AAGA,UAAM,cAAc,MAAM,YAAY,eAAe,KAAK,IAAI;AAAA,MAC5D,YAAY,EAAE,GAAG,KAAK,YAAY,GAAG,iBAAiB;AAAA,IACxD,CAAC;AAED,yBAAO,KAAK,sCAAsC,YAAY,KAAK,EAAE;AAErE,UAAM,oBAAgB,0BAAa,WAAW;AAE9C,UAAM,mBAAe,oCAAwB;AAAA,MAC3C,aAAS,2BAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,iBAAa,2BAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM;AAAA,IACR,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,+BAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAKO,MAAM,sBAAsB,OACjC,MACA,KACA,UACkB;AAClB,QAAM,QAAQ,IAAI,OAAO,MAAM;AAC/B,QAAM,EAAE,MAAM,IAAI,IAAI;AAEtB,MAAI,CAAC,OAAO;AACV,+BAAa,2BAA2B,KAAK,qBAAqB;AAClE;AAAA,EACF;AAEA,MAAI;AACF,UAAM,OAAO,MAAM,YAAY,eAAe,KAAK;AAEnD,QAAI,CAAC,MAAM;AACT,iCAAa,2BAA2B,KAAK,gBAAgB;AAC7D;AAAA,IACF;AAEA,QACE,KAAC;AAAA,MACC;AAAA,MACA;AAAA,IACF,EAAE;AAAA,MACA,GAAG,IAAI;AAAA,MACP,eAAe,CAAC,KAAK,EAAE;AAAA,IACzB,CAAC,GACD;AACA,iCAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,IACF;AAEA,UAAM,oBAAgB,0BAAa,IAAI;AAEvC,UAAM,mBAAe,oCAAwB;AAAA,MAC3C,aAAS,2BAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM;AAAA,IACR,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,+BAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;","names":[]}
|
|
@@ -60,10 +60,6 @@ const getOrganizations = async (req, res, _next) => {
|
|
|
60
60
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
-
if (!(0, import_permissions.hasPermission)(roles, "organization:read")()) {
|
|
64
|
-
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
63
|
const restrictedFilter = {
|
|
68
64
|
...filters,
|
|
69
65
|
membersIds: { $in: [...filters?.membersIds ?? [], String(user.id)] }
|
|
@@ -74,6 +70,16 @@ const getOrganizations = async (req, res, _next) => {
|
|
|
74
70
|
skip,
|
|
75
71
|
pageSize
|
|
76
72
|
);
|
|
73
|
+
if (!(0, import_permissions.hasPermission)(
|
|
74
|
+
roles,
|
|
75
|
+
"organization:read"
|
|
76
|
+
)({
|
|
77
|
+
...res.locals,
|
|
78
|
+
targetOrganizations: organizations
|
|
79
|
+
})) {
|
|
80
|
+
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
77
83
|
const totalItems = await organizationService.countOrganizations(filters);
|
|
78
84
|
const responseData = (0, import_responseData.formatPaginatedResponse)({
|
|
79
85
|
data: (0, import_organization.mapOrganizationsToAPI)(organizations),
|
|
@@ -96,12 +102,18 @@ const getOrganization = async (req, res, _next) => {
|
|
|
96
102
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_ID_NOT_FOUND");
|
|
97
103
|
return;
|
|
98
104
|
}
|
|
99
|
-
if (!(0, import_permissions.hasPermission)(roles, "organization:read")()) {
|
|
100
|
-
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
105
|
try {
|
|
104
106
|
const organization = await organizationService.getOrganizationById(organizationId);
|
|
107
|
+
if (!(0, import_permissions.hasPermission)(
|
|
108
|
+
roles,
|
|
109
|
+
"organization:read"
|
|
110
|
+
)({
|
|
111
|
+
...res.locals,
|
|
112
|
+
targetOrganizations: [organization]
|
|
113
|
+
})) {
|
|
114
|
+
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
105
117
|
const responseData = (0, import_responseData.formatResponse)({
|
|
106
118
|
data: (0, import_organization.mapOrganizationToAPI)(organization)
|
|
107
119
|
});
|
|
@@ -123,10 +135,6 @@ const addOrganization = async (req, res, _next) => {
|
|
|
123
135
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
124
136
|
return;
|
|
125
137
|
}
|
|
126
|
-
if (!(0, import_permissions.hasPermission)(roles, "organization:write")()) {
|
|
127
|
-
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
138
|
try {
|
|
131
139
|
const newOrganization = await organizationService.createOrganization(
|
|
132
140
|
organization,
|
|
@@ -163,7 +171,13 @@ const updateOrganization = async (req, res, _next) => {
|
|
|
163
171
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
|
|
164
172
|
return;
|
|
165
173
|
}
|
|
166
|
-
if (!(0, import_permissions.hasPermission)(
|
|
174
|
+
if (!(0, import_permissions.hasPermission)(
|
|
175
|
+
roles,
|
|
176
|
+
"organization:write"
|
|
177
|
+
)({
|
|
178
|
+
...res.locals,
|
|
179
|
+
targetOrganizations: [organization]
|
|
180
|
+
})) {
|
|
167
181
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
168
182
|
return;
|
|
169
183
|
}
|
|
@@ -209,7 +223,13 @@ const addOrganizationMember = async (req, res, _next) => {
|
|
|
209
223
|
});
|
|
210
224
|
return;
|
|
211
225
|
}
|
|
212
|
-
if (!(0, import_permissions.hasPermission)(
|
|
226
|
+
if (!(0, import_permissions.hasPermission)(
|
|
227
|
+
roles,
|
|
228
|
+
"organization:admin"
|
|
229
|
+
)({
|
|
230
|
+
...res.locals,
|
|
231
|
+
targetOrganizations: [organization]
|
|
232
|
+
})) {
|
|
213
233
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
214
234
|
return;
|
|
215
235
|
}
|
|
@@ -288,7 +308,13 @@ const updateOrganizationMembers = async (req, res, _next) => {
|
|
|
288
308
|
);
|
|
289
309
|
return;
|
|
290
310
|
}
|
|
291
|
-
if (!(0, import_permissions.hasPermission)(
|
|
311
|
+
if (!(0, import_permissions.hasPermission)(
|
|
312
|
+
roles,
|
|
313
|
+
"organization:admin"
|
|
314
|
+
)({
|
|
315
|
+
...res.locals,
|
|
316
|
+
targetOrganizations: [organization]
|
|
317
|
+
})) {
|
|
292
318
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
293
319
|
return;
|
|
294
320
|
}
|
|
@@ -355,7 +381,13 @@ const deleteOrganization = async (_req, res, _next) => {
|
|
|
355
381
|
});
|
|
356
382
|
return;
|
|
357
383
|
}
|
|
358
|
-
if (!(0, import_permissions.hasPermission)(
|
|
384
|
+
if (!(0, import_permissions.hasPermission)(
|
|
385
|
+
roles,
|
|
386
|
+
"organization:admin"
|
|
387
|
+
)({
|
|
388
|
+
...res.locals,
|
|
389
|
+
targetOrganizations: [organization]
|
|
390
|
+
})) {
|
|
359
391
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
360
392
|
return;
|
|
361
393
|
}
|
|
@@ -398,7 +430,7 @@ const selectOrganization = async (req, res, _next) => {
|
|
|
398
430
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_ID_NOT_FOUND");
|
|
399
431
|
return;
|
|
400
432
|
}
|
|
401
|
-
if (
|
|
433
|
+
if (typeof session === "undefined") {
|
|
402
434
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
|
|
403
435
|
return;
|
|
404
436
|
}
|
|
@@ -434,9 +466,9 @@ const selectOrganization = async (req, res, _next) => {
|
|
|
434
466
|
}
|
|
435
467
|
};
|
|
436
468
|
const unselectOrganization = async (_req, res, _next) => {
|
|
437
|
-
const { session
|
|
469
|
+
const { session } = res.locals;
|
|
438
470
|
try {
|
|
439
|
-
if (
|
|
471
|
+
if (typeof session === "undefined") {
|
|
440
472
|
import_errors.ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
|
|
441
473
|
return;
|
|
442
474
|
}
|