@intlayer/backend 7.5.9 → 7.5.11
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/README.md +9 -2
- package/dist/assets/utils/AI/askDocQuestion/PROMPT.md +1 -1
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/cli/ci.json +3080 -0
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/cli/list_projects.json +1 -0
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_fastify.json +9 -0
- package/dist/esm/controllers/ai.controller.mjs +95 -128
- package/dist/esm/controllers/ai.controller.mjs.map +1 -1
- package/dist/esm/controllers/bitbucket.controller.mjs +77 -0
- package/dist/esm/controllers/bitbucket.controller.mjs.map +1 -0
- package/dist/esm/controllers/dictionary.controller.mjs +106 -198
- package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
- package/dist/esm/controllers/eventListener.controller.mjs +13 -19
- package/dist/esm/controllers/eventListener.controller.mjs.map +1 -1
- package/dist/esm/controllers/github.controller.mjs +77 -0
- package/dist/esm/controllers/github.controller.mjs.map +1 -0
- package/dist/esm/controllers/gitlab.controller.mjs +77 -0
- package/dist/esm/controllers/gitlab.controller.mjs.map +1 -0
- package/dist/esm/controllers/newsletter.controller.mjs +30 -60
- package/dist/esm/controllers/newsletter.controller.mjs.map +1 -1
- package/dist/esm/controllers/oAuth2.controller.mjs +11 -8
- package/dist/esm/controllers/oAuth2.controller.mjs.map +1 -1
- package/dist/esm/controllers/organization.controller.mjs +100 -225
- package/dist/esm/controllers/organization.controller.mjs.map +1 -1
- package/dist/esm/controllers/project.controller.mjs +194 -204
- package/dist/esm/controllers/project.controller.mjs.map +1 -1
- package/dist/esm/controllers/projectAccessKey.controller.mjs +38 -71
- package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
- package/dist/esm/controllers/search.controller.mjs +3 -3
- package/dist/esm/controllers/search.controller.mjs.map +1 -1
- package/dist/esm/controllers/stripe.controller.mjs +34 -67
- package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
- package/dist/esm/controllers/tag.controller.mjs +51 -113
- package/dist/esm/controllers/tag.controller.mjs.map +1 -1
- package/dist/esm/controllers/user.controller.mjs +64 -113
- package/dist/esm/controllers/user.controller.mjs.map +1 -1
- package/dist/esm/export.mjs +4 -1
- package/dist/esm/index.mjs +105 -41
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/middlewares/oAuth2.middleware.mjs +19 -14
- package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
- package/dist/esm/middlewares/sessionAuth.middleware.mjs +6 -7
- package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
- package/dist/esm/routes/ai.routes.mjs +19 -15
- package/dist/esm/routes/ai.routes.mjs.map +1 -1
- package/dist/esm/routes/bitbucket.routes.mjs +43 -0
- package/dist/esm/routes/bitbucket.routes.mjs.map +1 -0
- package/dist/esm/routes/dictionary.routes.mjs +10 -10
- package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
- package/dist/esm/routes/eventListener.routes.mjs +3 -3
- package/dist/esm/routes/eventListener.routes.mjs.map +1 -1
- package/dist/esm/routes/github.routes.mjs +43 -0
- package/dist/esm/routes/github.routes.mjs.map +1 -0
- package/dist/esm/routes/gitlab.routes.mjs +43 -0
- package/dist/esm/routes/gitlab.routes.mjs.map +1 -0
- package/dist/esm/routes/newsletter.routes.mjs +5 -5
- package/dist/esm/routes/newsletter.routes.mjs.map +1 -1
- package/dist/esm/routes/organization.routes.mjs +11 -11
- package/dist/esm/routes/organization.routes.mjs.map +1 -1
- package/dist/esm/routes/project.routes.mjs +38 -14
- package/dist/esm/routes/project.routes.mjs.map +1 -1
- package/dist/esm/routes/search.routes.mjs +3 -3
- package/dist/esm/routes/search.routes.mjs.map +1 -1
- package/dist/esm/routes/stripe.routes.mjs +5 -5
- package/dist/esm/routes/stripe.routes.mjs.map +1 -1
- package/dist/esm/routes/tags.routes.mjs +6 -6
- package/dist/esm/routes/tags.routes.mjs.map +1 -1
- package/dist/esm/routes/user.routes.mjs +9 -9
- package/dist/esm/routes/user.routes.mjs.map +1 -1
- package/dist/esm/schemas/project.schema.mjs +70 -1
- package/dist/esm/schemas/project.schema.mjs.map +1 -1
- package/dist/esm/services/bitbucket.service.mjs +173 -0
- package/dist/esm/services/bitbucket.service.mjs.map +1 -0
- package/dist/esm/services/ci.service.mjs +134 -0
- package/dist/esm/services/ci.service.mjs.map +1 -0
- package/dist/esm/services/email.service.mjs +1 -1
- package/dist/esm/services/email.service.mjs.map +1 -1
- package/dist/esm/services/github.service.mjs +218 -0
- package/dist/esm/services/github.service.mjs.map +1 -0
- package/dist/esm/services/gitlab.service.mjs +217 -0
- package/dist/esm/services/gitlab.service.mjs.map +1 -0
- package/dist/esm/services/oAuth2.service.mjs +1 -1
- package/dist/esm/services/subscription.service.mjs +1 -1
- package/dist/esm/services/subscription.service.mjs.map +1 -1
- package/dist/esm/services/webhook.service.mjs +164 -0
- package/dist/esm/services/webhook.service.mjs.map +1 -0
- package/dist/esm/utils/auth/getAuth.mjs +28 -16
- package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
- package/dist/esm/utils/cors.mjs +15 -5
- package/dist/esm/utils/cors.mjs.map +1 -1
- package/dist/esm/utils/errors/ErrorHandler.mjs +32 -4
- package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
- package/dist/esm/utils/errors/ErrorsClass.mjs +1 -1
- package/dist/esm/utils/errors/ErrorsClass.mjs.map +1 -1
- package/dist/esm/utils/errors/errorCodes.mjs +234 -0
- package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs +1 -1
- package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs +1 -1
- package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/mapper/project.mjs +28 -1
- package/dist/esm/utils/mapper/project.mjs.map +1 -1
- package/dist/esm/utils/mongoDB/connectDB.mjs +1 -1
- package/dist/esm/utils/rateLimiter.mjs +40 -30
- package/dist/esm/utils/rateLimiter.mjs.map +1 -1
- package/dist/esm/webhooks/stripe.webhook.mjs +2 -2
- package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -1
- package/dist/types/controllers/ai.controller.d.ts +29 -12
- package/dist/types/controllers/ai.controller.d.ts.map +1 -1
- package/dist/types/controllers/bitbucket.controller.d.ts +62 -0
- package/dist/types/controllers/bitbucket.controller.d.ts.map +1 -0
- package/dist/types/controllers/dictionary.controller.d.ts +23 -13
- package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
- package/dist/types/controllers/eventListener.controller.d.ts +4 -2
- package/dist/types/controllers/eventListener.controller.d.ts.map +1 -1
- package/dist/types/controllers/github.controller.d.ts +63 -0
- package/dist/types/controllers/github.controller.d.ts.map +1 -0
- package/dist/types/controllers/gitlab.controller.d.ts +67 -0
- package/dist/types/controllers/gitlab.controller.d.ts.map +1 -0
- package/dist/types/controllers/newsletter.controller.d.ts +8 -7
- package/dist/types/controllers/newsletter.controller.d.ts.map +1 -1
- package/dist/types/controllers/oAuth2.controller.d.ts +4 -2
- package/dist/types/controllers/oAuth2.controller.d.ts.map +1 -1
- package/dist/types/controllers/organization.controller.d.ts +28 -12
- package/dist/types/controllers/organization.controller.d.ts.map +1 -1
- package/dist/types/controllers/project.controller.d.ts +60 -17
- package/dist/types/controllers/project.controller.d.ts.map +1 -1
- package/dist/types/controllers/projectAccessKey.controller.d.ts +10 -5
- package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
- package/dist/types/controllers/search.controller.d.ts +4 -2
- package/dist/types/controllers/search.controller.d.ts.map +1 -1
- package/dist/types/controllers/stripe.controller.d.ts +11 -12
- package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
- package/dist/types/controllers/tag.controller.d.ts +14 -9
- package/dist/types/controllers/tag.controller.d.ts.map +1 -1
- package/dist/types/controllers/user.controller.d.ts +22 -9
- package/dist/types/controllers/user.controller.d.ts.map +1 -1
- package/dist/types/emails/InviteUserEmail.d.ts +4 -4
- package/dist/types/emails/MagicLinkEmail.d.ts +4 -4
- package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +4 -4
- package/dist/types/emails/OAuthTokenCreatedEmail.d.ts.map +1 -1
- package/dist/types/emails/PasswordChangeConfirmation.d.ts +4 -4
- package/dist/types/emails/ResetUserPassword.d.ts +4 -4
- package/dist/types/emails/ResetUserPassword.d.ts.map +1 -1
- package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -4
- package/dist/types/emails/ValidateUserEmail.d.ts +4 -4
- package/dist/types/emails/Welcome.d.ts +4 -4
- package/dist/types/export.d.ts +11 -5
- package/dist/types/middlewares/oAuth2.middleware.d.ts +9 -4
- package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
- package/dist/types/middlewares/sessionAuth.middleware.d.ts +13 -3
- package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
- package/dist/types/models/discussion.model.d.ts +3 -3
- package/dist/types/models/oAuth2.model.d.ts +3 -3
- package/dist/types/routes/ai.routes.d.ts +2 -2
- package/dist/types/routes/ai.routes.d.ts.map +1 -1
- package/dist/types/routes/bitbucket.routes.d.ts +35 -0
- package/dist/types/routes/bitbucket.routes.d.ts.map +1 -0
- package/dist/types/routes/dictionary.routes.d.ts +2 -2
- package/dist/types/routes/dictionary.routes.d.ts.map +1 -1
- package/dist/types/routes/eventListener.routes.d.ts +2 -2
- package/dist/types/routes/eventListener.routes.d.ts.map +1 -1
- package/dist/types/routes/github.routes.d.ts +35 -0
- package/dist/types/routes/github.routes.d.ts.map +1 -0
- package/dist/types/routes/gitlab.routes.d.ts +35 -0
- package/dist/types/routes/gitlab.routes.d.ts.map +1 -0
- package/dist/types/routes/newsletter.routes.d.ts +2 -2
- package/dist/types/routes/newsletter.routes.d.ts.map +1 -1
- package/dist/types/routes/organization.routes.d.ts +2 -2
- package/dist/types/routes/organization.routes.d.ts.map +1 -1
- package/dist/types/routes/project.routes.d.ts +22 -2
- package/dist/types/routes/project.routes.d.ts.map +1 -1
- package/dist/types/routes/search.routes.d.ts +2 -2
- package/dist/types/routes/search.routes.d.ts.map +1 -1
- package/dist/types/routes/stripe.routes.d.ts +2 -2
- package/dist/types/routes/stripe.routes.d.ts.map +1 -1
- package/dist/types/routes/tags.routes.d.ts +2 -2
- package/dist/types/routes/tags.routes.d.ts.map +1 -1
- package/dist/types/routes/user.routes.d.ts +2 -2
- package/dist/types/routes/user.routes.d.ts.map +1 -1
- package/dist/types/schemas/dictionary.schema.d.ts +6 -6
- package/dist/types/schemas/discussion.schema.d.ts +6 -6
- package/dist/types/schemas/oAuth2.schema.d.ts +5 -5
- package/dist/types/schemas/oAuth2.schema.d.ts.map +1 -1
- package/dist/types/schemas/plans.schema.d.ts +6 -6
- package/dist/types/schemas/project.schema.d.ts +6 -6
- package/dist/types/schemas/project.schema.d.ts.map +1 -1
- package/dist/types/schemas/session.schema.d.ts +6 -6
- package/dist/types/schemas/tag.schema.d.ts +6 -6
- package/dist/types/schemas/user.schema.d.ts +6 -6
- package/dist/types/schemas/user.schema.d.ts.map +1 -1
- package/dist/types/services/bitbucket.service.d.ts +71 -0
- package/dist/types/services/bitbucket.service.d.ts.map +1 -0
- package/dist/types/services/ci.service.d.ts +27 -0
- package/dist/types/services/ci.service.d.ts.map +1 -0
- package/dist/types/services/github.service.d.ts +40 -0
- package/dist/types/services/github.service.d.ts.map +1 -0
- package/dist/types/services/gitlab.service.d.ts +58 -0
- package/dist/types/services/gitlab.service.d.ts.map +1 -0
- package/dist/types/services/webhook.service.d.ts +19 -0
- package/dist/types/services/webhook.service.d.ts.map +1 -0
- package/dist/types/types/project.types.d.ts +46 -5
- package/dist/types/types/project.types.d.ts.map +1 -1
- package/dist/types/types/session.types.d.ts +1 -1
- package/dist/types/types/user.types.d.ts +1 -1
- package/dist/types/utils/AI/auditTag/index.d.ts +1 -1
- package/dist/types/utils/auth/getAuth.d.ts.map +1 -1
- package/dist/types/utils/cors.d.ts +2 -2
- package/dist/types/utils/errors/ErrorHandler.d.ts +31 -3
- package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
- package/dist/types/utils/errors/ErrorsClass.d.ts +1 -1
- package/dist/types/utils/errors/errorCodes.d.ts +234 -0
- package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts +8 -4
- package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts +6 -3
- package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts +6 -2
- package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +8 -4
- package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts +6 -2
- package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +8 -4
- package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts +6 -2
- package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/mapper/project.d.ts.map +1 -1
- package/dist/types/utils/permissions.d.ts +1 -1
- package/dist/types/utils/rateLimiter.d.ts +4 -2
- package/dist/types/utils/rateLimiter.d.ts.map +1 -1
- package/package.json +24 -28
- package/dist/esm/middlewares/request.middleware.mjs +0 -17
- package/dist/esm/middlewares/request.middleware.mjs.map +0 -1
- package/dist/types/middlewares/request.middleware.d.ts +0 -7
- package/dist/types/middlewares/request.middleware.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitbucket.controller.mjs","names":["bitbucketService.getAuthorizationUrl","bitbucketService.exchangeCodeForToken","accessToken: string | undefined","bitbucketService.getUserRepositories","bitbucketService.checkIntlayerConfig","bitbucketService.getRepositoryFileContents"],"sources":["../../../src/controllers/bitbucket.controller.ts"],"sourcesContent":["import * as bitbucketService from '@services/bitbucket.service';\nimport { getBitbucketTokenFromUser } from '@services/bitbucket.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\n\nexport type BitbucketGetAuthUrlQuerystring = {\n redirectUri: string;\n};\n\nexport type BitbucketGetAuthUrlResult = ResponseData<{\n authUrl: string;\n}>;\n\nexport const getAuthUrl = async (\n request: FastifyRequest<{ Querystring: BitbucketGetAuthUrlQuerystring }>,\n reply: FastifyReply\n): Promise<void> => {\n const { redirectUri } = request.query;\n\n if (!redirectUri) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'BITBUCKET_REDIRECT_URI_MISSING'\n );\n }\n\n try {\n const authUrl = bitbucketService.getAuthorizationUrl(redirectUri);\n const responseData = formatResponse<{ authUrl: string }>({\n data: { authUrl },\n });\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type BitbucketAuthCallbackBody = {\n code: string;\n};\n\nexport type BitbucketAuthCallbackResult = ResponseData<{\n token: string;\n}>;\n\nexport const authCallback = async (\n request: FastifyRequest<{ Body: BitbucketAuthCallbackBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { code } = request.body;\n\n if (!code) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'BITBUCKET_CODE_MISSING'\n );\n }\n\n try {\n const token = await bitbucketService.exchangeCodeForToken(code);\n const responseData = formatResponse<{ token: string }>({\n data: { token },\n });\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type BitbucketListReposQuerystring = {\n token?: string;\n};\n\nexport type BitbucketListReposResult = ResponseData<\n bitbucketService.BitbucketRepository[]\n>;\n\nexport const listRepos = async (\n request: FastifyRequest<{ Querystring: BitbucketListReposQuerystring }>,\n reply: FastifyReply\n): Promise<void> => {\n const { token } = request.query;\n const userId = request.locals?.user?.id;\n\n try {\n let accessToken: string | undefined = token;\n\n if (!accessToken && userId) {\n accessToken =\n (await getBitbucketTokenFromUser(String(userId))) ?? undefined;\n }\n\n if (!accessToken) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'BITBUCKET_TOKEN_MISSING'\n );\n }\n\n const repos = await bitbucketService.getUserRepositories(accessToken);\n const responseData = formatResponse<bitbucketService.BitbucketRepository[]>(\n {\n data: repos,\n }\n );\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type BitbucketCheckConfigBody = {\n token?: string;\n workspace: string;\n repoSlug: string;\n branch?: string;\n};\n\nexport type BitbucketCheckConfigResult = ResponseData<{\n hasConfig: boolean;\n configPaths: string[];\n}>;\n\n/**\n * Check if intlayer.config.ts (or candidates) exists in a Bitbucket repository\n */\nexport const checkConfig = async (\n request: FastifyRequest<{ Body: BitbucketCheckConfigBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { token, workspace, repoSlug, branch = 'main' } = request.body;\n const userId = request.locals?.user?.id;\n\n try {\n let accessToken: string | undefined = token;\n\n if (!accessToken && userId) {\n accessToken =\n (await getBitbucketTokenFromUser(String(userId))) ?? undefined;\n }\n\n if (!accessToken || !workspace || !repoSlug) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'BITBUCKET_CHECK_CONFIG_MISSING_PARAMS'\n );\n }\n\n const configPaths = await bitbucketService.checkIntlayerConfig(\n accessToken,\n workspace,\n repoSlug,\n branch\n );\n\n const responseData = formatResponse<{\n hasConfig: boolean;\n configPaths: string[];\n }>({\n data: {\n hasConfig: configPaths.length > 0,\n configPaths: configPaths,\n },\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type BitbucketGetConfigFileBody = {\n token?: string;\n workspace: string;\n repoSlug: string;\n branch?: string;\n path?: string;\n};\n\nexport type BitbucketGetConfigFileResult = ResponseData<{\n content: string;\n}>;\n\nexport const getConfigFile = async (\n request: FastifyRequest<{ Body: BitbucketGetConfigFileBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const {\n token,\n workspace,\n repoSlug,\n branch = 'main',\n path = 'intlayer.config.ts',\n } = request.body;\n const userId = request.locals?.user?.id;\n\n try {\n let accessToken: string | undefined = token;\n\n if (!accessToken && userId) {\n accessToken =\n (await getBitbucketTokenFromUser(String(userId))) ?? undefined;\n }\n\n if (!accessToken || !workspace || !repoSlug) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'BITBUCKET_GET_CONFIG_FILE_MISSING_PARAMS'\n );\n }\n\n const content = await bitbucketService.getRepositoryFileContents(\n accessToken,\n workspace,\n repoSlug,\n path,\n branch\n );\n\n if (!content) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'BITBUCKET_CONFIG_FILE_NOT_FOUND'\n );\n }\n\n const responseData = formatResponse<{ content: string }>({\n data: { content },\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n"],"mappings":";;;;;AAcA,MAAa,aAAa,OACxB,SACA,UACkB;CAClB,MAAM,EAAE,gBAAgB,QAAQ;AAEhC,KAAI,CAAC,YACH,QAAO,aAAa,2BAClB,OACA,iCACD;AAGH,KAAI;EAEF,MAAM,eAAe,eAAoC,EACvD,MAAM,EAAE,SAFMA,oBAAqC,YAAY,EAE9C,EAClB,CAAC;AACF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;AAYxE,MAAa,eAAe,OAC1B,SACA,UACkB;CAClB,MAAM,EAAE,SAAS,QAAQ;AAEzB,KAAI,CAAC,KACH,QAAO,aAAa,2BAClB,OACA,yBACD;AAGH,KAAI;EAEF,MAAM,eAAe,eAAkC,EACrD,MAAM,EAAE,OAFI,MAAMC,qBAAsC,KAAK,EAE9C,EAChB,CAAC;AACF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;AAYxE,MAAa,YAAY,OACvB,SACA,UACkB;CAClB,MAAM,EAAE,UAAU,QAAQ;CAC1B,MAAM,SAAS,QAAQ,QAAQ,MAAM;AAErC,KAAI;EACF,IAAIC,cAAkC;AAEtC,MAAI,CAAC,eAAe,OAClB,eACG,MAAM,0BAA0B,OAAO,OAAO,CAAC,IAAK;AAGzD,MAAI,CAAC,YACH,QAAO,aAAa,2BAClB,OACA,0BACD;EAIH,MAAM,eAAe,eACnB,EACE,MAHU,MAAMC,oBAAqC,YAAY,EAIlE,CACF;AACD,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;;;;AAmBxE,MAAa,cAAc,OACzB,SACA,UACkB;CAClB,MAAM,EAAE,OAAO,WAAW,UAAU,SAAS,WAAW,QAAQ;CAChE,MAAM,SAAS,QAAQ,QAAQ,MAAM;AAErC,KAAI;EACF,IAAID,cAAkC;AAEtC,MAAI,CAAC,eAAe,OAClB,eACG,MAAM,0BAA0B,OAAO,OAAO,CAAC,IAAK;AAGzD,MAAI,CAAC,eAAe,CAAC,aAAa,CAAC,SACjC,QAAO,aAAa,2BAClB,OACA,wCACD;EAGH,MAAM,cAAc,MAAME,oBACxB,aACA,WACA,UACA,OACD;EAED,MAAM,eAAe,eAGlB,EACD,MAAM;GACJ,WAAW,YAAY,SAAS;GACnB;GACd,EACF,CAAC;AAEF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;AAgBxE,MAAa,gBAAgB,OAC3B,SACA,UACkB;CAClB,MAAM,EACJ,OACA,WACA,UACA,SAAS,QACT,OAAO,yBACL,QAAQ;CACZ,MAAM,SAAS,QAAQ,QAAQ,MAAM;AAErC,KAAI;EACF,IAAIF,cAAkC;AAEtC,MAAI,CAAC,eAAe,OAClB,eACG,MAAM,0BAA0B,OAAO,OAAO,CAAC,IAAK;AAGzD,MAAI,CAAC,eAAe,CAAC,aAAa,CAAC,SACjC,QAAO,aAAa,2BAClB,OACA,2CACD;EAGH,MAAM,UAAU,MAAMG,0BACpB,aACA,WACA,UACA,MACA,OACD;AAED,MAAI,CAAC,QACH,QAAO,aAAa,2BAClB,OACA,kCACD;EAGH,MAAM,eAAe,eAAoC,EACvD,MAAM,EAAE,SAAS,EAClB,CAAC;AAEF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB"}
|
|
@@ -2,12 +2,14 @@ import { ensureMongoDocumentToObject } from "../utils/ensureMongoDocumentToObjec
|
|
|
2
2
|
import { logger } from "../logger/index.mjs";
|
|
3
3
|
import { formatPaginatedResponse, formatResponse } from "../utils/responseData.mjs";
|
|
4
4
|
import { ErrorHandler } from "../utils/errors/ErrorHandler.mjs";
|
|
5
|
+
import { getProjectById } from "../services/project.service.mjs";
|
|
5
6
|
import { countDictionaries, createDictionary, deleteDictionaryById, findDictionaries, getDictionaryById, getDictionaryByKey as getDictionaryByKey$1, incrementVersion, updateDictionaryById, updateDictionaryByKey } from "../services/dictionary.service.mjs";
|
|
6
7
|
import { sendDictionaryUpdate } from "./eventListener.controller.mjs";
|
|
8
|
+
import { triggerAll } from "../services/webhook.service.mjs";
|
|
7
9
|
import { getDictionaryFiltersAndPagination } from "../utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs";
|
|
8
10
|
import { mapDictionaryToAPI } from "../utils/mapper/dictionary.mjs";
|
|
9
11
|
import { hasPermission } from "../utils/permissions.mjs";
|
|
10
|
-
import { t } from "
|
|
12
|
+
import { t } from "fastify-intlayer";
|
|
11
13
|
import { isDeepStrictEqual } from "node:util";
|
|
12
14
|
|
|
13
15
|
//#region src/controllers/dictionary.controller.ts
|
|
@@ -23,29 +25,20 @@ const removeMetadata = (obj) => {
|
|
|
23
25
|
/**
|
|
24
26
|
* Retrieves a list of dictionaries based on filters and pagination.
|
|
25
27
|
*/
|
|
26
|
-
const getDictionaries = async (
|
|
27
|
-
const { user, project, roles } =
|
|
28
|
-
const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getDictionaryFiltersAndPagination(
|
|
29
|
-
if (!project)
|
|
30
|
-
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (!user) {
|
|
34
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
28
|
+
const getDictionaries = async (request, reply) => {
|
|
29
|
+
const { user, project, roles } = request.locals || {};
|
|
30
|
+
const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getDictionaryFiltersAndPagination(request);
|
|
31
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
32
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
37
33
|
try {
|
|
38
34
|
const dictionaries = await findDictionaries({
|
|
39
35
|
...filters,
|
|
40
36
|
projectIds: project.id
|
|
41
37
|
}, skip, pageSize, sortOptions);
|
|
42
|
-
if (!hasPermission(roles, "dictionary:read")({
|
|
43
|
-
...
|
|
38
|
+
if (!hasPermission(roles || [], "dictionary:read")({
|
|
39
|
+
...request.locals,
|
|
44
40
|
targetDictionaries: dictionaries
|
|
45
|
-
}))
|
|
46
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
41
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
49
42
|
const totalItems = await countDictionaries(filters);
|
|
50
43
|
const responseData = formatPaginatedResponse({
|
|
51
44
|
data: dictionaries.map((el) => mapDictionaryToAPI(el)),
|
|
@@ -54,129 +47,84 @@ const getDictionaries = async (req, res, _next) => {
|
|
|
54
47
|
totalPages: getNumberOfPages(totalItems),
|
|
55
48
|
totalItems
|
|
56
49
|
});
|
|
57
|
-
|
|
58
|
-
return;
|
|
50
|
+
return reply.send(responseData);
|
|
59
51
|
} catch (error) {
|
|
60
|
-
ErrorHandler.handleAppErrorResponse(
|
|
61
|
-
return;
|
|
52
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
62
53
|
}
|
|
63
54
|
};
|
|
64
55
|
/**
|
|
65
56
|
* Retrieves a list of dictionaries keys based on filters and pagination.
|
|
66
57
|
*/
|
|
67
|
-
const getDictionariesKeys = async (
|
|
68
|
-
const { project, roles } =
|
|
69
|
-
if (!project)
|
|
70
|
-
ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
58
|
+
const getDictionariesKeys = async (_request, reply) => {
|
|
59
|
+
const { project, roles } = _request.locals || {};
|
|
60
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
73
61
|
try {
|
|
74
62
|
const dictionaries = await findDictionaries({ projectIds: project.id });
|
|
75
|
-
if (!hasPermission(roles, "dictionary:read")({
|
|
76
|
-
...
|
|
63
|
+
if (!hasPermission(roles || [], "dictionary:read")({
|
|
64
|
+
..._request.locals,
|
|
77
65
|
targetDictionaries: dictionaries
|
|
78
|
-
}))
|
|
79
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
66
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
82
67
|
const responseData = formatResponse({ data: dictionaries.map((dictionary) => dictionary.key) });
|
|
83
|
-
|
|
84
|
-
return;
|
|
68
|
+
return reply.send(responseData);
|
|
85
69
|
} catch (error) {
|
|
86
|
-
ErrorHandler.handleAppErrorResponse(
|
|
87
|
-
return;
|
|
70
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
88
71
|
}
|
|
89
72
|
};
|
|
90
73
|
/**
|
|
91
74
|
* Retrieves a list of dictionaries keys based on filters and pagination.
|
|
92
75
|
*/
|
|
93
|
-
const getDictionariesUpdateTimestamp = async (
|
|
94
|
-
const { project, roles } =
|
|
95
|
-
if (!project)
|
|
96
|
-
ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
76
|
+
const getDictionariesUpdateTimestamp = async (_request, reply) => {
|
|
77
|
+
const { project, roles } = _request.locals || {};
|
|
78
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
99
79
|
try {
|
|
100
80
|
const dictionaries = await findDictionaries({ projectIds: project.id });
|
|
101
|
-
if (!hasPermission(roles, "dictionary:read")({
|
|
102
|
-
...
|
|
81
|
+
if (!hasPermission(roles || [], "dictionary:read")({
|
|
82
|
+
..._request.locals,
|
|
103
83
|
targetDictionaries: dictionaries
|
|
104
|
-
}))
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
updatedAt: new Date(dictionary.updatedAt).getTime()
|
|
113
|
-
}
|
|
114
|
-
}), {}) });
|
|
115
|
-
res.json(responseData);
|
|
116
|
-
return;
|
|
84
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
85
|
+
const dictionariesUpdateTimestamp = {};
|
|
86
|
+
for (const dictionary of dictionaries) dictionariesUpdateTimestamp[dictionary.id] = {
|
|
87
|
+
key: dictionary.key,
|
|
88
|
+
updatedAt: new Date(dictionary.updatedAt).getTime()
|
|
89
|
+
};
|
|
90
|
+
const responseData = formatResponse({ data: dictionariesUpdateTimestamp });
|
|
91
|
+
return reply.send(responseData);
|
|
117
92
|
} catch (error) {
|
|
118
|
-
ErrorHandler.handleAppErrorResponse(
|
|
119
|
-
return;
|
|
93
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
120
94
|
}
|
|
121
95
|
};
|
|
122
96
|
/**
|
|
123
97
|
* Retrieves a list of dictionaries based on filters and pagination.
|
|
124
98
|
*/
|
|
125
|
-
const getDictionaryByKey = async (
|
|
126
|
-
const { project, user, roles } =
|
|
127
|
-
const { dictionaryKey } =
|
|
128
|
-
const version =
|
|
129
|
-
if (!project)
|
|
130
|
-
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (!user) {
|
|
134
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
99
|
+
const getDictionaryByKey = async (request, reply) => {
|
|
100
|
+
const { project, user, roles } = request.locals || {};
|
|
101
|
+
const { dictionaryKey } = request.params;
|
|
102
|
+
const version = request.query.version;
|
|
103
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
104
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
137
105
|
try {
|
|
138
106
|
const dictionary = await getDictionaryByKey$1(dictionaryKey, project.id);
|
|
139
|
-
if (!hasPermission(roles, "dictionary:read")({
|
|
140
|
-
...
|
|
107
|
+
if (!hasPermission(roles || [], "dictionary:read")({
|
|
108
|
+
...request.locals,
|
|
141
109
|
targetDictionaries: [dictionary]
|
|
142
|
-
}))
|
|
143
|
-
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
if (!dictionary.projectIds.map(String).includes(String(project.id))) {
|
|
147
|
-
ErrorHandler.handleGenericErrorResponse(res, "DICTIONARY_PROJECT_MISMATCH");
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
110
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
111
|
+
if (!dictionary.projectIds.map(String).includes(String(project.id))) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_PROJECT_MISMATCH");
|
|
150
112
|
const responseData = formatResponse({ data: mapDictionaryToAPI(dictionary, version) });
|
|
151
|
-
|
|
152
|
-
return;
|
|
113
|
+
return reply.send(responseData);
|
|
153
114
|
} catch (error) {
|
|
154
|
-
ErrorHandler.handleAppErrorResponse(
|
|
155
|
-
return;
|
|
115
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
156
116
|
}
|
|
157
117
|
};
|
|
158
118
|
/**
|
|
159
119
|
* Adds a new dictionary to the database.
|
|
160
120
|
*/
|
|
161
|
-
const addDictionary = async (
|
|
162
|
-
const { project, user, roles } =
|
|
163
|
-
const dictionaryData =
|
|
164
|
-
if (!dictionaryData)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (!project) {
|
|
169
|
-
ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (!user) {
|
|
173
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
if (!dictionaryData.projectIds?.includes(String(project.id))) {
|
|
177
|
-
ErrorHandler.handleGenericErrorResponse(res, "DICTIONARY_PROJECT_MISMATCH");
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
121
|
+
const addDictionary = async (request, reply) => {
|
|
122
|
+
const { project, user, roles } = request.locals || {};
|
|
123
|
+
const dictionaryData = request.body.dictionary;
|
|
124
|
+
if (!dictionaryData) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_DATA_NOT_FOUND");
|
|
125
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
126
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
127
|
+
if (!dictionaryData.projectIds?.includes(String(project.id))) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_PROJECT_MISMATCH");
|
|
180
128
|
const dictionary = {
|
|
181
129
|
key: dictionaryData.key,
|
|
182
130
|
title: dictionaryData.title,
|
|
@@ -185,10 +133,7 @@ const addDictionary = async (req, res, _next) => {
|
|
|
185
133
|
creatorId: user.id,
|
|
186
134
|
projectIds: dictionaryData.projectIds ?? [String(project.id)]
|
|
187
135
|
};
|
|
188
|
-
if (!hasPermission(roles, "dictionary:write")(
|
|
189
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
136
|
+
if (!hasPermission(roles || [], "dictionary:write")(request.locals)) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
192
137
|
try {
|
|
193
138
|
const newDictionary = await createDictionary(dictionary);
|
|
194
139
|
const apiResult = mapDictionaryToAPI(newDictionary);
|
|
@@ -205,46 +150,33 @@ const addDictionary = async (req, res, _next) => {
|
|
|
205
150
|
}),
|
|
206
151
|
data: apiResult
|
|
207
152
|
});
|
|
208
|
-
res.json(responseData);
|
|
209
153
|
sendDictionaryUpdate([{
|
|
210
154
|
dictionary: mapDictionaryToAPI(newDictionary),
|
|
211
155
|
status: "ADDED"
|
|
212
156
|
}]);
|
|
213
|
-
|
|
157
|
+
if (project) try {
|
|
158
|
+
const fullProject = await getProjectById(project.id);
|
|
159
|
+
await triggerAll(fullProject);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
logger.error("Failed to trigger CI builds after dictionary creation", error);
|
|
162
|
+
}
|
|
163
|
+
return reply.send(responseData);
|
|
214
164
|
} catch (error) {
|
|
215
|
-
ErrorHandler.handleAppErrorResponse(
|
|
216
|
-
return;
|
|
165
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
217
166
|
}
|
|
218
167
|
};
|
|
219
168
|
/**
|
|
220
169
|
* Check each dictionaries, add the new ones and update the existing ones.
|
|
221
|
-
* @param req - Express request object.
|
|
222
|
-
* @param res - Express response object.
|
|
223
|
-
* @returns Response containing the created dictionary.
|
|
224
170
|
*/
|
|
225
|
-
const pushDictionaries = async (
|
|
226
|
-
const { project, user, roles } =
|
|
227
|
-
let dictionaryData =
|
|
171
|
+
const pushDictionaries = async (request, reply) => {
|
|
172
|
+
const { project, user, roles } = request.locals || {};
|
|
173
|
+
let dictionaryData = request.body.dictionaries;
|
|
228
174
|
if (dictionaryData && !Array.isArray(dictionaryData) && typeof dictionaryData === "object" && "dictionaries" in dictionaryData && Array.isArray(dictionaryData.dictionaries)) dictionaryData = dictionaryData.dictionaries;
|
|
229
|
-
if (typeof dictionaryData === "object" && Array.isArray(dictionaryData) && dictionaryData.length === 0)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
if (!project) {
|
|
237
|
-
ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
if (!user) {
|
|
241
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (!hasPermission(roles, "dictionary:write")(res.locals)) {
|
|
245
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
175
|
+
if (typeof dictionaryData === "object" && Array.isArray(dictionaryData) && dictionaryData.length === 0) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARIES_NOT_PROVIDED");
|
|
176
|
+
else if (!dictionaryData) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_DATA_NOT_FOUND");
|
|
177
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
178
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
179
|
+
if (!hasPermission(roles || [], "dictionary:write")(request.locals)) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
248
180
|
try {
|
|
249
181
|
const existingDictionaries = dictionaryData.filter((dictionary) => dictionary.id !== void 0);
|
|
250
182
|
const newDictionaries = dictionaryData.filter((dictionary) => dictionary.id === void 0);
|
|
@@ -336,40 +268,29 @@ const pushDictionaries = async (req, res, _next) => {
|
|
|
336
268
|
dictionary,
|
|
337
269
|
status: "UPDATED"
|
|
338
270
|
}))]);
|
|
339
|
-
|
|
340
|
-
|
|
271
|
+
if (project && (newDictionariesResult.length > 0 || updatedDictionariesResult.length > 0)) try {
|
|
272
|
+
const fullProject = await getProjectById(project.id);
|
|
273
|
+
await triggerAll(fullProject);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
logger.error("Failed to trigger CI builds after dictionary push", error);
|
|
276
|
+
}
|
|
277
|
+
return reply.send(responseData);
|
|
341
278
|
} catch (error) {
|
|
342
|
-
ErrorHandler.handleAppErrorResponse(
|
|
343
|
-
return;
|
|
279
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
344
280
|
}
|
|
345
281
|
};
|
|
346
282
|
/**
|
|
347
283
|
* Updates an existing dictionary in the database.
|
|
348
284
|
*/
|
|
349
|
-
const updateDictionary = async (
|
|
350
|
-
const { dictionaryId } =
|
|
351
|
-
const { project, roles } =
|
|
352
|
-
const dictionaryData =
|
|
353
|
-
if (!dictionaryData)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (!
|
|
358
|
-
ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
if (!dictionaryData.projectIds?.includes(String(project.id))) {
|
|
362
|
-
ErrorHandler.handleGenericErrorResponse(res, "DICTIONARY_PROJECT_MISMATCH");
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
if (typeof dictionaryId === "undefined") {
|
|
366
|
-
ErrorHandler.handleGenericErrorResponse(res, "DICTIONARY_ID_NOT_FOUND");
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
if (!hasPermission(roles, "dictionary:write")(res.locals)) {
|
|
370
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
285
|
+
const updateDictionary = async (request, reply) => {
|
|
286
|
+
const { dictionaryId } = request.params;
|
|
287
|
+
const { project, roles } = request.locals || {};
|
|
288
|
+
const dictionaryData = request.body;
|
|
289
|
+
if (!dictionaryData) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_DATA_NOT_FOUND");
|
|
290
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
291
|
+
if (!dictionaryData.projectIds?.includes(String(project.id))) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_PROJECT_MISMATCH");
|
|
292
|
+
if (typeof dictionaryId === "undefined") return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_ID_NOT_FOUND");
|
|
293
|
+
if (!hasPermission(roles || [], "dictionary:write")(request.locals)) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
373
294
|
try {
|
|
374
295
|
const apiResult = mapDictionaryToAPI(await updateDictionaryById(dictionaryId, dictionaryData));
|
|
375
296
|
const responseData = formatResponse({
|
|
@@ -389,41 +310,30 @@ const updateDictionary = async (req, res, _next) => {
|
|
|
389
310
|
dictionary: apiResult,
|
|
390
311
|
status: "UPDATED"
|
|
391
312
|
}]);
|
|
392
|
-
|
|
393
|
-
|
|
313
|
+
if (project) try {
|
|
314
|
+
const fullProject = await getProjectById(project.id);
|
|
315
|
+
await triggerAll(fullProject);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
logger.error("Failed to trigger CI builds after dictionary update", error);
|
|
318
|
+
}
|
|
319
|
+
return reply.send(responseData);
|
|
394
320
|
} catch (error) {
|
|
395
|
-
ErrorHandler.handleAppErrorResponse(
|
|
396
|
-
return;
|
|
321
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
397
322
|
}
|
|
398
323
|
};
|
|
399
324
|
/**
|
|
400
325
|
* Deletes a dictionary from the database by its ID.
|
|
401
326
|
*/
|
|
402
|
-
const deleteDictionary = async (
|
|
403
|
-
const { project, roles } =
|
|
404
|
-
const { dictionaryId } =
|
|
405
|
-
if (!dictionaryId)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
if (!project) {
|
|
410
|
-
ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
if (!hasPermission(roles, "dictionary:admin")(res.locals)) {
|
|
414
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
327
|
+
const deleteDictionary = async (request, reply) => {
|
|
328
|
+
const { project, roles } = request.locals || {};
|
|
329
|
+
const { dictionaryId } = request.params;
|
|
330
|
+
if (!dictionaryId) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_ID_NOT_FOUND");
|
|
331
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
332
|
+
if (!hasPermission(roles || [], "dictionary:admin")(request.locals)) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
417
333
|
try {
|
|
418
|
-
if (!(await getDictionaryById(dictionaryId)).projectIds.includes(project.id))
|
|
419
|
-
ErrorHandler.handleGenericErrorResponse(res, "DICTIONARY_PROJECT_MISMATCH");
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
334
|
+
if (!(await getDictionaryById(dictionaryId)).projectIds.includes(project.id)) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_PROJECT_MISMATCH");
|
|
422
335
|
const deletedDictionary = await deleteDictionaryById(dictionaryId);
|
|
423
|
-
if (!deletedDictionary) {
|
|
424
|
-
ErrorHandler.handleGenericErrorResponse(res, "DICTIONARY_NOT_FOUND", { dictionaryId });
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
336
|
+
if (!deletedDictionary) return ErrorHandler.handleGenericErrorResponse(reply, "DICTIONARY_NOT_FOUND", { dictionaryId });
|
|
427
337
|
logger.info(`Dictionary deleted: ${String(deletedDictionary.id)}`);
|
|
428
338
|
const apiResult = mapDictionaryToAPI(deletedDictionary);
|
|
429
339
|
const responseData = formatResponse({
|
|
@@ -439,15 +349,13 @@ const deleteDictionary = async (req, res, _next) => {
|
|
|
439
349
|
}),
|
|
440
350
|
data: apiResult
|
|
441
351
|
});
|
|
442
|
-
res.json(responseData);
|
|
443
352
|
sendDictionaryUpdate([{
|
|
444
353
|
dictionary: apiResult,
|
|
445
354
|
status: "DELETED"
|
|
446
355
|
}]);
|
|
447
|
-
return;
|
|
356
|
+
return reply.send(responseData);
|
|
448
357
|
} catch (error) {
|
|
449
|
-
ErrorHandler.handleAppErrorResponse(
|
|
450
|
-
return;
|
|
358
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
451
359
|
}
|
|
452
360
|
};
|
|
453
361
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dictionary.controller.mjs","names":["clone: T","dictionaryService.findDictionaries","dictionaryService.countDictionaries","dictionaryService.getDictionaryByKey","dictionary: DictionaryData","dictionaryService.createDictionary","newDictionariesResult: PushDictionariesResultData['newDictionaries']","updatedDictionariesResult: PushDictionariesResultData['updatedDictionaries']","errorResult: PushDictionariesResultData['error']","dictionaryService.getDictionaryById","newContent: VersionedContent","dictionaryService.incrementVersion","dictionaryService.updateDictionaryByKey","result: PushDictionariesResultData","dictionaryService.updateDictionaryById","dictionaryService.deleteDictionaryById"],"sources":["../../../src/controllers/dictionary.controller.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'node:util';\nimport * as eventListener from '@controllers/eventListener.controller';\nimport type {\n ContentNode,\n DictionaryId,\n Dictionary as LocalDictionary,\n LocalDictionaryId,\n} from '@intlayer/types';\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';\nimport type {\n Dictionary,\n DictionaryAPI,\n DictionaryCreationData,\n DictionaryData,\n VersionedContent,\n} from '@/types/dictionary.types';\n\nexport type GetDictionariesParams =\n FiltersAndPagination<DictionaryFiltersParams>;\nexport type GetDictionariesResult = PaginatedResponse<DictionaryAPI>;\n\nconst removeMetadata = <T extends Record<string, any>>(obj: T): T => {\n if (Array.isArray(obj)) {\n return obj.map(removeMetadata) as unknown as T;\n }\n\n if (obj && typeof obj === 'object') {\n const clone: T = {} as T;\n for (const key in obj) {\n if (key !== 'metadata') {\n clone[key] = removeMetadata(obj[key]);\n }\n }\n return clone as T;\n }\n\n return obj as T;\n};\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, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getDictionaryFiltersAndPagination(req, res);\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 try {\n const dictionaries = await dictionaryService.findDictionaries(\n {\n ...filters,\n projectIds: project.id,\n },\n skip,\n pageSize,\n sortOptions\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) => mapDictionaryToAPI(el));\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 GetDictionariesUpdateTimestampResult = ResponseData<\n Record<DictionaryId, { key: string; updatedAt: number }>\n>;\n\n/**\n * Retrieves a list of dictionaries keys based on filters and pagination.\n */\nexport const getDictionariesUpdateTimestamp = async (\n _req: Request,\n res: ResponseWithSession<GetDictionariesUpdateTimestampResult>,\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 dictionariesUpdateTimestamp = dictionaries.reduce(\n (acc, dictionary) => ({\n ...acc,\n [dictionary.id]: {\n key: dictionary.key,\n updatedAt: new Date(dictionary.updatedAt).getTime(),\n },\n }),\n {}\n );\n\n const responseData = formatResponse<\n Record<string, { key: string; updatedAt: number }>\n >({\n data: dictionariesUpdateTimestamp,\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, 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 [\n 'v1',\n {\n // Remove metadata as markdown metadata are dynamic data inserted at build time\n content: removeMetadata(dictionaryData.content ?? {}) as ContentNode,\n },\n ],\n ]),\n creatorId: user.id,\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);\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),\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: {\n key: string;\n localId: LocalDictionaryId;\n id: string | undefined;\n }[];\n updatedDictionaries: {\n key: string;\n localId: LocalDictionaryId;\n id: string | undefined;\n }[];\n error: {\n id: string | undefined;\n key: string;\n localId: LocalDictionaryId | undefined;\n message: string;\n }[];\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\n // Normalize the input: handle both { dictionaries: [...] } and { dictionaries: { dictionaries: [...] } }\n // The latter can happen due to client-side double-wrapping issues\n let dictionaryData = req.body.dictionaries;\n if (\n dictionaryData &&\n !Array.isArray(dictionaryData) &&\n typeof dictionaryData === 'object' &&\n 'dictionaries' in dictionaryData &&\n Array.isArray(\n (dictionaryData as unknown as PushDictionariesBody).dictionaries\n )\n ) {\n dictionaryData = (dictionaryData as unknown as PushDictionariesBody)\n .dictionaries;\n }\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 existingDictionaries = dictionaryData.filter(\n (dictionary) => dictionary.id !== undefined\n );\n const newDictionaries = dictionaryData.filter(\n (dictionary) => dictionary.id === undefined\n );\n\n const newDictionariesResult: PushDictionariesResultData['newDictionaries'] =\n [];\n const updatedDictionariesResult: PushDictionariesResultData['updatedDictionaries'] =\n [];\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 // Remove metadata as markdown metadata are dynamic data inserted at build time\n\n [\n 'v1',\n {\n content:\n removeMetadata(dictionaryDataEl.content) ?? ({} as ContentNode),\n },\n ],\n ]),\n key: dictionaryDataEl.key,\n };\n\n try {\n const newDictionary =\n await dictionaryService.createDictionary(dictionary);\n newDictionariesResult.push({\n key: newDictionary.key,\n localId: dictionaryDataEl.localId!,\n id: newDictionary.id,\n });\n } catch (error) {\n errorResult.push({\n id: dictionaryDataEl.id!,\n key: dictionaryDataEl.key,\n localId: dictionaryDataEl.localId!,\n message: (error as AppError).message,\n });\n }\n }\n\n for (const dictionaryDataEl of existingDictionaries) {\n const remoteDictionary = await dictionaryService.getDictionaryById(\n dictionaryDataEl.id!\n );\n\n // Remove metadata as markdown metadata are dynamic data inserted at build time\n const cleanedContent = removeMetadata(dictionaryDataEl.content);\n\n const versionList = [...(remoteDictionary.content.keys() ?? [])];\n const lastVersion = versionList[versionList.length - 1];\n\n const lastContent =\n (remoteDictionary.content.get(lastVersion)\n ?.content as DictionaryAPI['content']) ?? null;\n\n const isSameContent = isDeepStrictEqual(lastContent, cleanedContent);\n\n const newContent: VersionedContent = new Map(remoteDictionary.content);\n\n if (!isSameContent) {\n const newContentVersion =\n dictionaryService.incrementVersion(remoteDictionary);\n\n newContent.set(newContentVersion, {\n // Remove metadata as markdown metadata are dynamic data inserted at build time\n content: cleanedContent,\n });\n }\n\n const dictionary: DictionaryData = {\n ...ensureMongoDocumentToObject(remoteDictionary),\n ...dictionaryDataEl,\n content: newContent,\n projectIds: [String(project.id)],\n creatorId: user.id,\n key: remoteDictionary.key,\n };\n\n try {\n const updatedDictionary = await dictionaryService.updateDictionaryByKey(\n remoteDictionary.key,\n dictionary,\n project.id\n );\n updatedDictionariesResult.push({\n key: updatedDictionary.key,\n localId: dictionaryDataEl.localId!,\n id: updatedDictionary.id,\n });\n } catch (error) {\n errorResult.push({\n id: dictionaryDataEl.id!,\n key: dictionaryDataEl.key,\n localId: dictionaryDataEl.localId!,\n message: (error as AppError).message,\n });\n }\n }\n\n const result: PushDictionariesResultData = {\n newDictionaries: newDictionariesResult,\n updatedDictionaries: updatedDictionariesResult,\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);\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);\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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"}
|
|
1
|
+
{"version":3,"file":"dictionary.controller.mjs","names":["clone: T","dictionaryService.findDictionaries","dictionaryService.countDictionaries","dictionariesUpdateTimestamp: Record<\n string,\n { key: string; updatedAt: number }\n >","dictionaryService.getDictionaryByKey","dictionary: DictionaryData","dictionaryService.createDictionary","projectService.getProjectById","webhooksService.triggerAll","newDictionariesResult: PushDictionariesResultData['newDictionaries']","updatedDictionariesResult: PushDictionariesResultData['updatedDictionaries']","errorResult: PushDictionariesResultData['error']","dictionaryService.getDictionaryById","newContent: VersionedContent","dictionaryService.incrementVersion","dictionaryService.updateDictionaryByKey","result: PushDictionariesResultData","dictionaryService.updateDictionaryById","dictionaryService.deleteDictionaryById"],"sources":["../../../src/controllers/dictionary.controller.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'node:util';\nimport * as eventListener from '@controllers/eventListener.controller';\nimport type {\n ContentNode,\n DictionaryId,\n Dictionary as LocalDictionary,\n LocalDictionaryId,\n} from '@intlayer/types';\nimport { logger } from '@logger';\nimport * as dictionaryService from '@services/dictionary.service';\nimport * as projectService from '@services/project.service';\nimport * as webhooksService from '@services/webhook.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 { FastifyReply, FastifyRequest } from 'fastify';\nimport { t } from 'fastify-intlayer';\nimport type {\n Dictionary,\n DictionaryAPI,\n DictionaryCreationData,\n DictionaryData,\n VersionedContent,\n} from '@/types/dictionary.types';\n\nexport type GetDictionariesParams =\n FiltersAndPagination<DictionaryFiltersParams>;\nexport type GetDictionariesResult = PaginatedResponse<DictionaryAPI>;\n\nconst removeMetadata = <T extends Record<string, any>>(obj: T): T => {\n if (Array.isArray(obj)) {\n return obj.map(removeMetadata) as unknown as T;\n }\n\n if (obj && typeof obj === 'object') {\n const clone: T = {} as T;\n for (const key in obj) {\n if (key !== 'metadata') {\n clone[key] = removeMetadata(obj[key]);\n }\n }\n return clone as T;\n }\n\n return obj as T;\n};\n\n/**\n * Retrieves a list of dictionaries based on filters and pagination.\n */\nexport const getDictionaries = async (\n request: FastifyRequest<{ Querystring: GetDictionariesParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, project, roles } = request.locals || {};\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getDictionaryFiltersAndPagination(request);\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n try {\n const dictionaries = await dictionaryService.findDictionaries(\n {\n ...filters,\n projectIds: project.id,\n },\n skip,\n pageSize,\n sortOptions\n );\n\n if (\n !hasPermission(\n roles || [],\n 'dictionary:read'\n )({\n ...request.locals,\n targetDictionaries: dictionaries,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const totalItems = await dictionaryService.countDictionaries(filters);\n\n const dictionariesAPI = dictionaries.map((el) => mapDictionaryToAPI(el));\n\n const responseData = formatPaginatedResponse<DictionaryAPI>({\n data: dictionariesAPI,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 _request: FastifyRequest,\n reply: FastifyReply\n) => {\n const { project, roles } = _request.locals || {};\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\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 ..._request.locals,\n targetDictionaries: dictionaries,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const dictionariesKeys = dictionaries.map((dictionary) => dictionary.key);\n\n const responseData = formatResponse<string[]>({\n data: dictionariesKeys,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetDictionariesUpdateTimestampResult = ResponseData<\n Record<DictionaryId, { key: string; updatedAt: number }>\n>;\n\n/**\n * Retrieves a list of dictionaries keys based on filters and pagination.\n */\nexport const getDictionariesUpdateTimestamp = async (\n _request: FastifyRequest,\n reply: FastifyReply\n) => {\n const { project, roles } = _request.locals || {};\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\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 ..._request.locals,\n targetDictionaries: dictionaries,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const dictionariesUpdateTimestamp: Record<\n string,\n { key: string; updatedAt: number }\n > = {};\n for (const dictionary of dictionaries) {\n dictionariesUpdateTimestamp[dictionary.id] = {\n key: dictionary.key,\n updatedAt: new Date(dictionary.updatedAt).getTime(),\n };\n }\n\n const responseData = formatResponse<\n Record<string, { key: string; updatedAt: number }>\n >({\n data: dictionariesUpdateTimestamp,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 request: FastifyRequest<{\n Params: GetDictionaryParams;\n Querystring: GetDictionaryQuery;\n }>,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user, roles } = request.locals || {};\n const { dictionaryKey } = request.params;\n const version = request.query.version;\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\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 ...request.locals,\n targetDictionaries: [dictionary],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n if (!dictionary.projectIds.map(String).includes(String(project.id))) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n }\n\n const apiResult = mapDictionaryToAPI(dictionary, version);\n\n const responseData = formatResponse<DictionaryAPI>({\n data: apiResult,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 request: FastifyRequest<{ Body: AddDictionaryBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user, roles } = request.locals || {};\n const dictionaryData = request.body.dictionary;\n\n if (!dictionaryData) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_DATA_NOT_FOUND'\n );\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!dictionaryData.projectIds?.includes(String(project.id))) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n }\n\n const dictionary: DictionaryData = {\n key: dictionaryData.key,\n title: dictionaryData.title,\n description: dictionaryData.description,\n content: new Map([\n [\n 'v1',\n {\n // Remove metadata as markdown metadata are dynamic data inserted at build time\n content: removeMetadata(dictionaryData.content ?? {}) as ContentNode,\n },\n ],\n ]),\n creatorId: user.id,\n projectIds: dictionaryData.projectIds ?? [String(project.id)],\n };\n\n if (!hasPermission(roles || [], 'dictionary:write')(request.locals)) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const newDictionary = await dictionaryService.createDictionary(dictionary);\n\n const apiResult = mapDictionaryToAPI(newDictionary);\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 eventListener.sendDictionaryUpdate([\n {\n dictionary: mapDictionaryToAPI(newDictionary),\n status: 'ADDED',\n },\n ]);\n\n // Trigger CI builds if configured\n if (project) {\n try {\n const fullProject = await projectService.getProjectById(project.id);\n await webhooksService.triggerAll(fullProject);\n } catch (error) {\n // Log error but don't fail the dictionary creation\n logger.error(\n 'Failed to trigger CI builds after dictionary creation',\n error\n );\n }\n }\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type PushDictionariesBody = {\n dictionaries: LocalDictionary[];\n};\ntype PushDictionariesResultData = {\n newDictionaries: {\n key: string;\n localId: LocalDictionaryId;\n id: string | undefined;\n }[];\n updatedDictionaries: {\n key: string;\n localId: LocalDictionaryId;\n id: string | undefined;\n }[];\n error: {\n id: string | undefined;\n key: string;\n localId: LocalDictionaryId | undefined;\n message: string;\n }[];\n};\nexport type PushDictionariesResult = ResponseData<PushDictionariesResultData>;\n\n/**\n * Check each dictionaries, add the new ones and update the existing ones.\n */\nexport const pushDictionaries = async (\n request: FastifyRequest<{ Body: PushDictionariesBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user, roles } = request.locals || {};\n\n // Normalize the input: handle both { dictionaries: [...] } and { dictionaries: { dictionaries: [...] } }\n // The latter can happen due to client-side double-wrapping issues\n let dictionaryData = request.body.dictionaries;\n if (\n dictionaryData &&\n !Array.isArray(dictionaryData) &&\n typeof dictionaryData === 'object' &&\n 'dictionaries' in dictionaryData &&\n Array.isArray(\n (dictionaryData as unknown as PushDictionariesBody).dictionaries\n )\n ) {\n dictionaryData = (dictionaryData as unknown as PushDictionariesBody)\n .dictionaries;\n }\n\n if (\n typeof dictionaryData === 'object' &&\n Array.isArray(dictionaryData) &&\n dictionaryData.length === 0\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARIES_NOT_PROVIDED'\n );\n } else if (!dictionaryData) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_DATA_NOT_FOUND'\n );\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!hasPermission(roles || [], 'dictionary:write')(request.locals)) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const existingDictionaries = dictionaryData.filter(\n (dictionary) => dictionary.id !== undefined\n );\n const newDictionaries = dictionaryData.filter(\n (dictionary) => dictionary.id === undefined\n );\n\n const newDictionariesResult: PushDictionariesResultData['newDictionaries'] =\n [];\n const updatedDictionariesResult: PushDictionariesResultData['updatedDictionaries'] =\n [];\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 // Remove metadata as markdown metadata are dynamic data inserted at build time\n\n [\n 'v1',\n {\n content:\n removeMetadata(dictionaryDataEl.content) ?? ({} as ContentNode),\n },\n ],\n ]),\n key: dictionaryDataEl.key,\n };\n\n try {\n const newDictionary =\n await dictionaryService.createDictionary(dictionary);\n newDictionariesResult.push({\n key: newDictionary.key,\n localId: dictionaryDataEl.localId!,\n id: newDictionary.id,\n });\n } catch (error) {\n errorResult.push({\n id: dictionaryDataEl.id!,\n key: dictionaryDataEl.key,\n localId: dictionaryDataEl.localId!,\n message: (error as AppError).message,\n });\n }\n }\n\n for (const dictionaryDataEl of existingDictionaries) {\n const remoteDictionary = await dictionaryService.getDictionaryById(\n dictionaryDataEl.id!\n );\n\n // Remove metadata as markdown metadata are dynamic data inserted at build time\n const cleanedContent = removeMetadata(dictionaryDataEl.content);\n\n const versionList = [...(remoteDictionary.content.keys() ?? [])];\n const lastVersion = versionList[versionList.length - 1];\n\n const lastContent =\n (remoteDictionary.content.get(lastVersion)\n ?.content as DictionaryAPI['content']) ?? null;\n\n const isSameContent = isDeepStrictEqual(lastContent, cleanedContent);\n\n const newContent: VersionedContent = new Map(remoteDictionary.content);\n\n if (!isSameContent) {\n const newContentVersion =\n dictionaryService.incrementVersion(remoteDictionary);\n\n newContent.set(newContentVersion, {\n // Remove metadata as markdown metadata are dynamic data inserted at build time\n content: cleanedContent,\n });\n }\n\n const dictionary: DictionaryData = {\n ...ensureMongoDocumentToObject(remoteDictionary),\n ...dictionaryDataEl,\n content: newContent,\n projectIds: [String(project.id)],\n creatorId: user.id,\n key: remoteDictionary.key,\n };\n\n try {\n const updatedDictionary = await dictionaryService.updateDictionaryByKey(\n remoteDictionary.key,\n dictionary,\n project.id\n );\n updatedDictionariesResult.push({\n key: updatedDictionary.key,\n localId: dictionaryDataEl.localId!,\n id: updatedDictionary.id,\n });\n } catch (error) {\n errorResult.push({\n id: dictionaryDataEl.id!,\n key: dictionaryDataEl.key,\n localId: dictionaryDataEl.localId!,\n message: (error as AppError).message,\n });\n }\n }\n\n const result: PushDictionariesResultData = {\n newDictionaries: newDictionariesResult,\n updatedDictionaries: updatedDictionariesResult,\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 // Trigger CI builds if configured (only if there were actual changes)\n if (\n project &&\n (newDictionariesResult.length > 0 || updatedDictionariesResult.length > 0)\n ) {\n try {\n const fullProject = await projectService.getProjectById(project.id);\n await webhooksService.triggerAll(fullProject);\n } catch (error) {\n // Log error but don't fail the dictionary push\n logger.error(\n 'Failed to trigger CI builds after dictionary push',\n error\n );\n }\n }\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 request: FastifyRequest<{\n Params: UpdateDictionaryParam;\n Body: UpdateDictionaryBody;\n }>,\n reply: FastifyReply\n): Promise<void> => {\n const { dictionaryId } = request.params;\n const { project, roles } = request.locals || {};\n const dictionaryData = request.body;\n\n if (!dictionaryData) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_DATA_NOT_FOUND'\n );\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!dictionaryData.projectIds?.includes(String(project.id))) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n }\n\n if (typeof dictionaryId === 'undefined') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_ID_NOT_FOUND'\n );\n }\n\n if (!hasPermission(roles || [], 'dictionary:write')(request.locals)) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const updatedDictionary = await dictionaryService.updateDictionaryById(\n dictionaryId,\n dictionaryData\n );\n\n const apiResult = mapDictionaryToAPI(updatedDictionary);\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 // Trigger CI builds if configured\n if (project) {\n try {\n const fullProject = await projectService.getProjectById(project.id);\n await webhooksService.triggerAll(fullProject);\n } catch (error) {\n // Log error but don't fail the dictionary update\n logger.error(\n 'Failed to trigger CI builds after dictionary update',\n error\n );\n }\n }\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 request: FastifyRequest<{ Params: DeleteDictionaryParam }>,\n reply: FastifyReply\n): Promise<void> => {\n const { project, roles } = request.locals || {};\n const { dictionaryId } = request.params;\n\n if (!dictionaryId) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_ID_NOT_FOUND'\n );\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!hasPermission(roles || [], 'dictionary:admin')(request.locals)) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const dictionaryToDelete =\n await dictionaryService.getDictionaryById(dictionaryId);\n\n if (!dictionaryToDelete.projectIds.includes(project.id)) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_PROJECT_MISMATCH'\n );\n }\n\n const deletedDictionary =\n await dictionaryService.deleteDictionaryById(dictionaryId);\n\n if (!deletedDictionary) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'DICTIONARY_NOT_FOUND',\n {\n dictionaryId,\n }\n );\n }\n\n logger.info(`Dictionary deleted: ${String(deletedDictionary.id)}`);\n\n const apiResult = mapDictionaryToAPI(deletedDictionary);\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 eventListener.sendDictionaryUpdate([\n {\n dictionary: apiResult,\n status: 'DELETED',\n },\n ]);\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n"],"mappings":"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"}
|