@intlayer/backend 7.5.10 → 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.
Files changed (109) hide show
  1. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/cli/ci.json +3080 -0
  2. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/cli/list_projects.json +1 -0
  3. package/dist/esm/controllers/bitbucket.controller.mjs +77 -0
  4. package/dist/esm/controllers/bitbucket.controller.mjs.map +1 -0
  5. package/dist/esm/controllers/dictionary.controller.mjs +20 -0
  6. package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
  7. package/dist/esm/controllers/github.controller.mjs.map +1 -1
  8. package/dist/esm/controllers/gitlab.controller.mjs +77 -0
  9. package/dist/esm/controllers/gitlab.controller.mjs.map +1 -0
  10. package/dist/esm/controllers/project.controller.mjs +109 -2
  11. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  12. package/dist/esm/export.mjs +3 -1
  13. package/dist/esm/index.mjs +5 -1
  14. package/dist/esm/index.mjs.map +1 -1
  15. package/dist/esm/routes/bitbucket.routes.mjs +43 -0
  16. package/dist/esm/routes/bitbucket.routes.mjs.map +1 -0
  17. package/dist/esm/routes/gitlab.routes.mjs +43 -0
  18. package/dist/esm/routes/gitlab.routes.mjs.map +1 -0
  19. package/dist/esm/routes/project.routes.mjs +25 -1
  20. package/dist/esm/routes/project.routes.mjs.map +1 -1
  21. package/dist/esm/schemas/project.schema.mjs +39 -4
  22. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  23. package/dist/esm/services/bitbucket.service.mjs +173 -0
  24. package/dist/esm/services/bitbucket.service.mjs.map +1 -0
  25. package/dist/esm/services/ci.service.mjs +134 -0
  26. package/dist/esm/services/ci.service.mjs.map +1 -0
  27. package/dist/esm/services/github.service.mjs +90 -2
  28. package/dist/esm/services/github.service.mjs.map +1 -1
  29. package/dist/esm/services/gitlab.service.mjs +217 -0
  30. package/dist/esm/services/gitlab.service.mjs.map +1 -0
  31. package/dist/esm/services/webhook.service.mjs +164 -0
  32. package/dist/esm/services/webhook.service.mjs.map +1 -0
  33. package/dist/esm/utils/auth/getAuth.mjs +15 -9
  34. package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
  35. package/dist/esm/utils/errors/errorCodes.mjs +156 -0
  36. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  37. package/dist/types/controllers/ai.controller.d.ts.map +1 -1
  38. package/dist/types/controllers/bitbucket.controller.d.ts +62 -0
  39. package/dist/types/controllers/bitbucket.controller.d.ts.map +1 -0
  40. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  41. package/dist/types/controllers/github.controller.d.ts.map +1 -1
  42. package/dist/types/controllers/gitlab.controller.d.ts +67 -0
  43. package/dist/types/controllers/gitlab.controller.d.ts.map +1 -0
  44. package/dist/types/controllers/project.controller.d.ts +39 -1
  45. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  46. package/dist/types/emails/InviteUserEmail.d.ts +4 -4
  47. package/dist/types/emails/MagicLinkEmail.d.ts +4 -4
  48. package/dist/types/emails/MagicLinkEmail.d.ts.map +1 -1
  49. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +4 -4
  50. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts.map +1 -1
  51. package/dist/types/emails/PasswordChangeConfirmation.d.ts +4 -4
  52. package/dist/types/emails/PasswordChangeConfirmation.d.ts.map +1 -1
  53. package/dist/types/emails/ResetUserPassword.d.ts +4 -4
  54. package/dist/types/emails/ResetUserPassword.d.ts.map +1 -1
  55. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -4
  56. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
  57. package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -4
  58. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -4
  59. package/dist/types/emails/ValidateUserEmail.d.ts +4 -4
  60. package/dist/types/emails/ValidateUserEmail.d.ts.map +1 -1
  61. package/dist/types/emails/Welcome.d.ts +4 -4
  62. package/dist/types/export.d.ts +8 -4
  63. package/dist/types/models/dictionary.model.d.ts +4 -4
  64. package/dist/types/models/dictionary.model.d.ts.map +1 -1
  65. package/dist/types/models/discussion.model.d.ts +3 -3
  66. package/dist/types/models/discussion.model.d.ts.map +1 -1
  67. package/dist/types/models/oAuth2.model.d.ts +3 -3
  68. package/dist/types/models/oAuth2.model.d.ts.map +1 -1
  69. package/dist/types/routes/bitbucket.routes.d.ts +35 -0
  70. package/dist/types/routes/bitbucket.routes.d.ts.map +1 -0
  71. package/dist/types/routes/gitlab.routes.d.ts +35 -0
  72. package/dist/types/routes/gitlab.routes.d.ts.map +1 -0
  73. package/dist/types/routes/project.routes.d.ts +20 -0
  74. package/dist/types/routes/project.routes.d.ts.map +1 -1
  75. package/dist/types/schemas/dictionary.schema.d.ts +6 -6
  76. package/dist/types/schemas/discussion.schema.d.ts +6 -6
  77. package/dist/types/schemas/oAuth2.schema.d.ts +5 -5
  78. package/dist/types/schemas/oAuth2.schema.d.ts.map +1 -1
  79. package/dist/types/schemas/organization.schema.d.ts +6 -6
  80. package/dist/types/schemas/plans.schema.d.ts +6 -6
  81. package/dist/types/schemas/plans.schema.d.ts.map +1 -1
  82. package/dist/types/schemas/project.schema.d.ts +6 -6
  83. package/dist/types/schemas/project.schema.d.ts.map +1 -1
  84. package/dist/types/schemas/session.schema.d.ts +6 -6
  85. package/dist/types/schemas/tag.schema.d.ts +6 -6
  86. package/dist/types/schemas/user.schema.d.ts +6 -6
  87. package/dist/types/services/bitbucket.service.d.ts +71 -0
  88. package/dist/types/services/bitbucket.service.d.ts.map +1 -0
  89. package/dist/types/services/ci.service.d.ts +27 -0
  90. package/dist/types/services/ci.service.d.ts.map +1 -0
  91. package/dist/types/services/email.service.d.ts +11 -11
  92. package/dist/types/services/github.service.d.ts +20 -1
  93. package/dist/types/services/github.service.d.ts.map +1 -1
  94. package/dist/types/services/gitlab.service.d.ts +58 -0
  95. package/dist/types/services/gitlab.service.d.ts.map +1 -0
  96. package/dist/types/services/webhook.service.d.ts +19 -0
  97. package/dist/types/services/webhook.service.d.ts.map +1 -0
  98. package/dist/types/types/project.types.d.ts +32 -4
  99. package/dist/types/types/project.types.d.ts.map +1 -1
  100. package/dist/types/utils/errors/ErrorHandler.d.ts +3 -3
  101. package/dist/types/utils/errors/errorCodes.d.ts +156 -0
  102. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  103. package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts +2 -2
  104. package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts +2 -2
  105. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +2 -2
  106. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts +2 -2
  107. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +2 -2
  108. package/dist/types/utils/mergeFunctionTypes.d.ts.map +1 -1
  109. package/package.json +11 -11
@@ -1 +1 @@
1
- {"version":3,"file":"project.controller.mjs","names":["projectService.findProjects","projectService.countProjects","project: ProjectData","projectService.createProject","projectService.updateProjectById","existingUsers: UserAndAdmin[]","userService.getUsersByIds","userMap: UserAndAdmin[]","user","formattedMembers: Types.ObjectId[]","formattedAdmin: Types.ObjectId[]","projectService.getProjectById","projectService.deleteProjectById"],"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport { SessionModel } from '@models/session.model';\nimport * as projectService from '@services/project.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getProjectFiltersAndPagination,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { hasPermission } from '@utils/permissions';\nimport { getPlanDetails } from '@utils/plan';\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 { Types } from 'mongoose';\nimport type {\n ProjectAPI,\n ProjectConfiguration,\n ProjectCreationData,\n ProjectData,\n} from '@/types/project.types';\nimport type { User } from '@/types/user.types';\n\nexport type GetProjectsParams = FiltersAndPagination<ProjectFiltersParams>;\nexport type GetProjectsResult = PaginatedResponse<ProjectAPI>;\n\n/**\n * Retrieves a list of projects based on filters and pagination.\n */\nexport const getProjects = async (\n request: FastifyRequest<{ Querystring: GetProjectsParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, organization, roles } = request.locals || {};\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(request);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization && !roles?.includes('admin')) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n try {\n const projects = await projectService.findProjects(\n filters,\n skip,\n pageSize,\n sortOptions\n );\n\n if (\n !hasPermission(\n roles || [],\n 'project:read'\n )({\n ...request.locals,\n targetProjects: projects,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(projects);\n\n const responseData = formatPaginatedResponse<ProjectAPI>({\n data: formattedProjects,\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 AddProjectBody = ProjectCreationData;\nexport type AddProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Adds a new project to the database.\n */\nexport const addProject = async (\n request: FastifyRequest<{ Body: AddProjectBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { organization, user, roles } = request.locals || {};\n const projectData = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (!projectData) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_DATA_NOT_FOUND'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'organization:admin'\n )({\n ...request.locals,\n targetOrganizations: [organization],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n const { plan } = organization;\n\n const planType = getPlanDetails(plan);\n\n if (planType.numberOfProjects) {\n const projectCount = await projectService.countProjects({\n organizationId: organization.id,\n });\n\n if (projectCount >= planType.numberOfProjects) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PLAN_PROJECT_LIMIT_REACHED',\n {\n organizationId: organization.id,\n }\n );\n }\n }\n\n const project: ProjectData = {\n membersIds: [user.id],\n adminsIds: [user.id],\n creatorId: user.id,\n organizationId: organization.id,\n ...projectData,\n };\n\n try {\n const newProject = await projectService.createProject(project);\n\n const formattedProject = mapProjectToAPI(newProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project created successfully',\n fr: 'Projet créé avec succès',\n es: 'Proyecto creado con éxito',\n }),\n description: t({\n en: 'Your project has been created successfully',\n fr: 'Votre projet a été créé avec succès',\n es: 'Su proyecto ha sido creado con éxito',\n }),\n data: formattedProject,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UpdateProjectBody = Partial<ProjectAPI>;\nexport type UpdateProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Updates an existing project in the database.\n */\nexport const updateProject = async (\n request: FastifyRequest<{ Body: UpdateProjectBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { organization, project, user, roles } = request.locals || {};\n const projectData = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_DATA_NOT_FOUND'\n );\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (String(project.organizationId) !== String(organization.id)) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const updatedProject = await projectService.updateProjectById(\n project.id,\n projectData\n );\n\n const formattedProject = mapProjectToAPI(updatedProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project updated successfully',\n fr: 'Projet mis à jour avec succès',\n es: 'Proyecto actualizado con éxito',\n }),\n description: t({\n en: 'Your project has been updated successfully',\n fr: 'Votre projet a été mis à jour avec succès',\n es: 'Su proyecto ha sido actualizado con éxito',\n }),\n data: formattedProject,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\ntype UserAndAdmin = { user: User; isAdmin: boolean };\nexport type ProjectMemberByIdOption = {\n userId: string | Types.ObjectId;\n isAdmin?: boolean;\n};\n\nexport type UpdateProjectMembersBody = Partial<{\n membersIds: ProjectMemberByIdOption[];\n}>;\nexport type UpdateProjectMembersResult = ResponseData<ProjectAPI>;\n\n/**\n * Update members to the dictionary in the database.\n */\nexport const updateProjectMembers = async (\n request: FastifyRequest<{ Body: UpdateProjectMembersBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, project, organization, roles } = request.locals || {};\n const { membersIds } = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (membersIds?.length === 0) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_MUST_HAVE_MEMBER'\n );\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_MUST_HAVE_ADMIN'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds\n ?.filter(\n (member) =>\n // Remove members that are not in the organization\n !organization?.membersIds.includes(member.userId as Types.ObjectId)\n )\n .map((member) => member.userId);\n\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => ({\n user,\n isAdmin:\n membersIds.find(\n (member) => String(member.userId) === String(user.id)\n )?.isAdmin ?? false,\n }));\n\n existingUsers.push(...userMap);\n }\n }\n\n const formattedMembers: Types.ObjectId[] = existingUsers.map(\n (user) => user.user.id\n );\n const formattedAdmin: Types.ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user.id);\n\n const updatedOrganization = await projectService.updateProjectById(\n project.id,\n {\n ...project,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n }\n );\n\n const formattedProject = mapProjectToAPI(updatedOrganization);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project members updated successfully',\n fr: 'Membres du projet mis à jour avec succès',\n es: 'Miembros del proyecto actualizados con éxito',\n }),\n description: t({\n en: 'Your project members have been updated successfully',\n fr: 'Les membres de votre projet ont été mis à jour avec succès',\n es: 'Los miembros de su proyecto han sido actualizados con éxito',\n }),\n data: formattedProject,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type PushProjectConfigurationBody = ProjectConfiguration;\nexport type PushProjectConfigurationResult = ResponseData<ProjectConfiguration>;\n\n/**\n * Pushes a project configuration to the database.\n */\nexport const pushProjectConfiguration = async (\n request: FastifyRequest<{ Body: PushProjectConfigurationBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, project, roles } = request.locals || {};\n const projectConfiguration = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const projectObject = await projectService.getProjectById(project.id);\n\n // Preserve existing API key if not provided in the update\n if (\n projectConfiguration.ai &&\n projectObject.configuration?.ai?.apiKey &&\n (!projectConfiguration.ai.apiKey ||\n projectConfiguration.ai.apiKey.trim() === '')\n ) {\n projectConfiguration.ai.apiKey = projectObject.configuration.ai.apiKey;\n }\n\n projectObject.configuration = projectConfiguration;\n\n await projectObject.save();\n\n if (!projectObject.configuration) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_UPDATE_FAILED',\n {\n projectId: project.id,\n }\n );\n }\n\n const responseData = formatResponse<ProjectConfiguration>({\n message: t({\n en: 'Project configuration updated successfully',\n fr: 'Configuration du projet mise à jour avec succès',\n es: 'Configuración del proyecto actualizada con éxito',\n }),\n description: t({\n en: 'Your project configuration has been updated successfully',\n fr: 'La configuration du projet a été mise à jour avec succès',\n es: 'Su configuración del proyecto ha sido actualizada con éxito',\n }),\n data: mapProjectToAPI(projectObject) as ProjectConfiguration,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type DeleteProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Deletes a project from the database by its ID.\n */\nexport const deleteProject = async (\n _request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { user, organization, project, session, roles } = _request.locals || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (typeof session === 'undefined') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'SESSION_NOT_DEFINED'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:admin'\n )({\n ..._request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const projectToDelete = await projectService.getProjectById(project.id);\n\n if (String(projectToDelete.organizationId) !== String(organization.id)) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n }\n\n const deletedProject = await projectService.deleteProjectById(project.id);\n\n if (!deletedProject) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED',\n {\n projectId: project.id,\n }\n );\n }\n\n logger.info(`Project deleted: ${String(deletedProject.id)}`);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project deleted successfully',\n fr: 'Projet supprimé avec succès',\n es: 'Proyecto eliminado con éxito',\n }),\n description: t({\n en: 'Your project has been deleted successfully',\n fr: 'Votre projet a été supprimé avec succès',\n es: 'Su proyecto ha sido eliminado con éxito',\n }),\n data: mapProjectToAPI(deletedProject),\n });\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type SelectProjectParam = { projectId: string | Types.ObjectId };\nexport type SelectProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n request: FastifyRequest<{ Params: SelectProjectParam }>,\n reply: FastifyReply\n) => {\n const { projectId } = request.params;\n const { session } = request.locals || {};\n\n if (!projectId) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_ID_NOT_FOUND'\n );\n }\n\n if (typeof session === 'undefined') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'SESSION_NOT_DEFINED'\n );\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: String(projectId) } }\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project selected successfully',\n fr: 'Projet sélectionné avec succès',\n es: 'Proyecto seleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been selected successfully',\n fr: 'Votre projet a été sélectionné avec succès',\n es: 'Su proyecto ha sido seleccionado con éxito',\n }),\n data: mapProjectToAPI(project),\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UnselectProjectResult = ResponseData<null>;\n\n/**\n * Unselect a project.\n */\nexport const unselectProject = async (\n _request: FastifyRequest,\n reply: FastifyReply\n) => {\n const { session } = _request.locals || {};\n\n if (typeof session === 'undefined') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'SESSION_NOT_DEFINED'\n );\n }\n\n try {\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Project unselected successfully',\n fr: 'Projet désélectionné avec succès',\n es: 'Proyecto deseleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been unselected successfully',\n fr: 'Votre projet a été désélectionné avec succès',\n es: 'Su proyecto ha sido deseleccionado con éxito',\n }),\n data: null,\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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"}
1
+ {"version":3,"file":"project.controller.mjs","names":["projectService.findProjects","projectService.countProjects","project: ProjectData","projectService.createProject","projectService.updateProjectById","existingUsers: UserAndAdmin[]","userService.getUsersByIds","userMap: UserAndAdmin[]","user","formattedMembers: Types.ObjectId[]","formattedAdmin: Types.ObjectId[]","projectService.getProjectById","webhooksService.triggerAll","webhooksService.triggerSingleWebhook","projectService.deleteProjectById","ciService.getCIStatus","ciService.installCI"],"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport { SessionModel } from '@models/session.model';\nimport * as ciService from '@services/ci.service';\nimport * as projectService from '@services/project.service';\nimport * as userService from '@services/user.service';\nimport * as webhooksService from '@services/webhook.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getProjectFiltersAndPagination,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { hasPermission } from '@utils/permissions';\nimport { getPlanDetails } from '@utils/plan';\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 { Types } from 'mongoose';\nimport type {\n ProjectAPI,\n ProjectConfiguration,\n ProjectCreationData,\n ProjectData,\n} from '@/types/project.types';\nimport type { User } from '@/types/user.types';\n\nexport type GetProjectsParams = FiltersAndPagination<ProjectFiltersParams>;\nexport type GetProjectsResult = PaginatedResponse<ProjectAPI>;\n\n/**\n * Retrieves a list of projects based on filters and pagination.\n */\nexport const getProjects = async (\n request: FastifyRequest<{ Querystring: GetProjectsParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, organization, roles } = request.locals || {};\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(request);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization && !roles?.includes('admin')) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n try {\n const projects = await projectService.findProjects(\n filters,\n skip,\n pageSize,\n sortOptions\n );\n\n if (\n !hasPermission(\n roles || [],\n 'project:read'\n )({\n ...request.locals,\n targetProjects: projects,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(projects);\n\n const responseData = formatPaginatedResponse<ProjectAPI>({\n data: formattedProjects,\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 AddProjectBody = ProjectCreationData;\nexport type AddProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Adds a new project to the database.\n */\nexport const addProject = async (\n request: FastifyRequest<{ Body: AddProjectBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { organization, user, roles } = request.locals || {};\n const projectData = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (!projectData) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_DATA_NOT_FOUND'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'organization:admin'\n )({\n ...request.locals,\n targetOrganizations: [organization],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n const { plan } = organization;\n\n const planType = getPlanDetails(plan);\n\n if (planType.numberOfProjects) {\n const projectCount = await projectService.countProjects({\n organizationId: organization.id,\n });\n\n if (projectCount >= planType.numberOfProjects) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PLAN_PROJECT_LIMIT_REACHED',\n {\n organizationId: organization.id,\n }\n );\n }\n }\n\n const project: ProjectData = {\n membersIds: [user.id],\n adminsIds: [user.id],\n creatorId: user.id,\n organizationId: organization.id,\n ...projectData,\n };\n\n try {\n const newProject = await projectService.createProject(project);\n\n const formattedProject = mapProjectToAPI(newProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project created successfully',\n fr: 'Projet créé avec succès',\n es: 'Proyecto creado con éxito',\n }),\n description: t({\n en: 'Your project has been created successfully',\n fr: 'Votre projet a été créé avec succès',\n es: 'Su proyecto ha sido creado con éxito',\n }),\n data: formattedProject,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UpdateProjectBody = Partial<ProjectAPI>;\nexport type UpdateProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Updates an existing project in the database.\n */\nexport const updateProject = async (\n request: FastifyRequest<{ Body: UpdateProjectBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { organization, project, user, roles } = request.locals || {};\n const projectData = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_DATA_NOT_FOUND'\n );\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (String(project.organizationId) !== String(organization.id)) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const updatedProject = await projectService.updateProjectById(\n project.id,\n projectData\n );\n\n const formattedProject = mapProjectToAPI(updatedProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project updated successfully',\n fr: 'Projet mis à jour avec succès',\n es: 'Proyecto actualizado con éxito',\n }),\n description: t({\n en: 'Your project has been updated successfully',\n fr: 'Votre projet a été mis à jour avec succès',\n es: 'Su proyecto ha sido actualizado con éxito',\n }),\n data: formattedProject,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\ntype UserAndAdmin = { user: User; isAdmin: boolean };\nexport type ProjectMemberByIdOption = {\n userId: string | Types.ObjectId;\n isAdmin?: boolean;\n};\n\nexport type UpdateProjectMembersBody = Partial<{\n membersIds: ProjectMemberByIdOption[];\n}>;\nexport type UpdateProjectMembersResult = ResponseData<ProjectAPI>;\n\n/**\n * Update members to the dictionary in the database.\n */\nexport const updateProjectMembers = async (\n request: FastifyRequest<{ Body: UpdateProjectMembersBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, project, organization, roles } = request.locals || {};\n const { membersIds } = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (membersIds?.length === 0) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_MUST_HAVE_MEMBER'\n );\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_MUST_HAVE_ADMIN'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds\n ?.filter(\n (member) =>\n // Remove members that are not in the organization\n !organization?.membersIds.includes(member.userId as Types.ObjectId)\n )\n .map((member) => member.userId);\n\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => ({\n user,\n isAdmin:\n membersIds.find(\n (member) => String(member.userId) === String(user.id)\n )?.isAdmin ?? false,\n }));\n\n existingUsers.push(...userMap);\n }\n }\n\n const formattedMembers: Types.ObjectId[] = existingUsers.map(\n (user) => user.user.id\n );\n const formattedAdmin: Types.ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user.id);\n\n const updatedOrganization = await projectService.updateProjectById(\n project.id,\n {\n ...project,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n }\n );\n\n const formattedProject = mapProjectToAPI(updatedOrganization);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project members updated successfully',\n fr: 'Membres du projet mis à jour avec succès',\n es: 'Miembros del proyecto actualizados con éxito',\n }),\n description: t({\n en: 'Your project members have been updated successfully',\n fr: 'Les membres de votre projet ont été mis à jour avec succès',\n es: 'Los miembros de su proyecto han sido actualizados con éxito',\n }),\n data: formattedProject,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type PushProjectConfigurationBody = ProjectConfiguration;\nexport type PushProjectConfigurationResult = ResponseData<ProjectConfiguration>;\n\n/**\n * Pushes a project configuration to the database.\n */\nexport const pushProjectConfiguration = async (\n request: FastifyRequest<{ Body: PushProjectConfigurationBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, project, roles } = request.locals || {};\n const projectConfiguration = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const projectObject = await projectService.getProjectById(project.id);\n\n // Preserve existing API key if not provided in the update\n if (projectConfiguration.ai && projectObject.configuration?.ai?.apiKey) {\n projectConfiguration.ai.apiKey = projectObject.configuration.ai.apiKey;\n }\n\n projectObject.configuration = projectConfiguration;\n\n await projectObject.save();\n\n if (!projectObject.configuration) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_UPDATE_FAILED',\n {\n projectId: project.id,\n }\n );\n }\n\n const responseData = formatResponse<ProjectConfiguration>({\n message: t({\n en: 'Project configuration updated successfully',\n fr: 'Configuration du projet mise à jour avec succès',\n es: 'Configuración del proyecto actualizada con éxito',\n }),\n description: t({\n en: 'Your project configuration has been updated successfully',\n fr: 'La configuration du projet a été mise à jour avec succès',\n es: 'Su configuración del proyecto ha sido actualizada con éxito',\n }),\n data: mapProjectToAPI(projectObject) as ProjectConfiguration,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type TriggerBuildResult = ResponseData<{\n results: Array<{\n target: string;\n success: boolean;\n message?: string;\n }>;\n}>;\n\nexport type TriggerWebhookBody = {\n webhookIndex: number;\n};\n\nexport type TriggerWebhookResult = ResponseData<{\n target: string;\n success: boolean;\n message?: string;\n}>;\n\n/**\n * Triggers CI builds for a project (Git provider pipelines and webhooks)\n */\nexport const triggerBuild = async (\n request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { project, roles } = request.locals || {};\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n // Get full project with all relations\n const fullProject = await projectService.getProjectById(project.id);\n const results = await webhooksService.triggerAll(fullProject);\n\n const responseData = formatResponse<{\n results: Array<{\n target: string;\n success: boolean;\n message?: string;\n }>;\n }>({\n message: t({\n en: 'Build triggers initiated',\n fr: 'Déclenchement des builds initié',\n es: 'Inicio de los triggers de build',\n }),\n description: t({\n en: 'CI pipelines and webhooks have been triggered',\n fr: 'Les pipelines CI et webhooks ont été déclenchés',\n es: 'Los pipelines CI y webhooks han sido activados',\n }),\n data: { results },\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\n/**\n * Triggers a single webhook by index\n */\nexport const triggerWebhook = async (\n request: FastifyRequest<{ Body: TriggerWebhookBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { project, roles } = request.locals || {};\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:write'\n )({\n ...request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const { webhookIndex } = request.body;\n\n if (typeof webhookIndex !== 'number' || webhookIndex < 0) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'INVALID_REQUEST_BODY'\n );\n }\n\n // Get full project with all relations\n const fullProject = await projectService.getProjectById(project.id);\n const result = await webhooksService.triggerSingleWebhook(\n fullProject,\n webhookIndex\n );\n\n const responseData = formatResponse<{\n target: string;\n success: boolean;\n message?: string;\n }>({\n message: t({\n en: 'Webhook triggered',\n fr: 'Webhook déclenché',\n es: 'Webhook activado',\n }),\n description: t({\n en: `Webhook \"${result.target}\" has been triggered`,\n fr: `Le webhook \"${result.target}\" a été déclenché`,\n es: `El webhook \"${result.target}\" ha sido activado`,\n }),\n data: result,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type DeleteProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Deletes a project from the database by its ID.\n */\nexport const deleteProject = async (\n _request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { user, organization, project, session, roles } = _request.locals || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (typeof session === 'undefined') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'SESSION_NOT_DEFINED'\n );\n }\n\n if (\n !hasPermission(\n roles || [],\n 'project:admin'\n )({\n ..._request.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\n }\n\n try {\n const projectToDelete = await projectService.getProjectById(project.id);\n\n if (String(projectToDelete.organizationId) !== String(organization.id)) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n }\n\n const deletedProject = await projectService.deleteProjectById(project.id);\n\n if (!deletedProject) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED',\n {\n projectId: project.id,\n }\n );\n }\n\n logger.info(`Project deleted: ${String(deletedProject.id)}`);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project deleted successfully',\n fr: 'Projet supprimé avec succès',\n es: 'Proyecto eliminado con éxito',\n }),\n description: t({\n en: 'Your project has been deleted successfully',\n fr: 'Votre projet a été supprimé avec succès',\n es: 'Su proyecto ha sido eliminado con éxito',\n }),\n data: mapProjectToAPI(deletedProject),\n });\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type SelectProjectParam = { projectId: string | Types.ObjectId };\nexport type SelectProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n request: FastifyRequest<{ Params: SelectProjectParam }>,\n reply: FastifyReply\n) => {\n const { projectId } = request.params;\n const { session } = request.locals || {};\n\n if (!projectId) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_ID_NOT_FOUND'\n );\n }\n\n if (typeof session === 'undefined') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'SESSION_NOT_DEFINED'\n );\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: String(projectId) } }\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project selected successfully',\n fr: 'Projet sélectionné avec succès',\n es: 'Proyecto seleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been selected successfully',\n fr: 'Votre projet a été sélectionné avec succès',\n es: 'Su proyecto ha sido seleccionado con éxito',\n }),\n data: mapProjectToAPI(project),\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type UnselectProjectResult = ResponseData<null>;\n\n/**\n * Unselect a project.\n */\nexport const unselectProject = async (\n _request: FastifyRequest,\n reply: FastifyReply\n) => {\n const { session } = _request.locals || {};\n\n if (typeof session === 'undefined') {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'SESSION_NOT_DEFINED'\n );\n }\n\n try {\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Project unselected successfully',\n fr: 'Projet désélectionné avec succès',\n es: 'Proyecto deseleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been unselected successfully',\n fr: 'Votre projet a été désélectionné avec succès',\n es: 'Su proyecto ha sido deseleccionado con éxito',\n }),\n data: null,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GetCIConfigurationResult = ResponseData<ciService.CIStatus>;\n\n/**\n * Get CI configuration status for the current project\n */\nexport const getCIConfiguration = async (\n request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user } = request.locals || {};\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 ciStatus = await ciService.getCIStatus(project);\n\n const responseData = formatResponse<ciService.CIStatus>({\n data: ciStatus,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type PushCIConfigurationResult = ResponseData<{ success: boolean }>;\n\n/**\n * Push CI configuration file to the repository\n */\nexport const pushCIConfiguration = async (\n request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const { project, user } = request.locals || {};\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 await ciService.installCI(project);\n\n const responseData = formatResponse<{ success: boolean }>({\n message: t({\n en: 'CI configuration installed successfully',\n fr: 'Configuration CI installée avec succès',\n es: 'Configuración CI instalada con éxito',\n }),\n description: t({\n en: 'The CI workflow file has been added to your repository',\n fr: 'Le fichier de workflow CI a été ajouté à votre dépôt',\n es: 'El archivo de flujo de trabajo CI se ha agregado a su repositorio',\n }),\n data: { success: true },\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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"}
@@ -1,12 +1,14 @@
1
1
  import { HttpStatusCodes } from "./utils/httpStatusCodes.mjs";
2
2
  import { formatPaginatedResponse, formatResponse } from "./utils/responseData.mjs";
3
3
  import { getAiRoutes } from "./routes/ai.routes.mjs";
4
+ import { getBitbucketRoutes } from "./routes/bitbucket.routes.mjs";
4
5
  import { getDictionaryRoutes } from "./routes/dictionary.routes.mjs";
5
6
  import { getGithubRoutes } from "./routes/github.routes.mjs";
7
+ import { getGitlabRoutes } from "./routes/gitlab.routes.mjs";
6
8
  import { getNewsletterRoutes } from "./routes/newsletter.routes.mjs";
7
9
  import { getOrganizationRoutes } from "./routes/organization.routes.mjs";
8
10
  import { getProjectRoutes } from "./routes/project.routes.mjs";
9
11
  import { getUserRoutes } from "./routes/user.routes.mjs";
10
12
  import { formatSession, getAuth } from "./utils/auth/getAuth.mjs";
11
13
 
12
- export { HttpStatusCodes, formatPaginatedResponse, formatResponse, formatSession, getAiRoutes, getAuth, getDictionaryRoutes, getGithubRoutes, getNewsletterRoutes, getOrganizationRoutes, getProjectRoutes, getUserRoutes };
14
+ export { HttpStatusCodes, formatPaginatedResponse, formatResponse, formatSession, getAiRoutes, getAuth, getBitbucketRoutes, getDictionaryRoutes, getGithubRoutes, getGitlabRoutes, getNewsletterRoutes, getOrganizationRoutes, getProjectRoutes, getUserRoutes };
@@ -1,9 +1,11 @@
1
1
  import { logger } from "./logger/index.mjs";
2
2
  import { ipLimiter } from "./utils/rateLimiter.mjs";
3
3
  import { aiRoute, aiRouter } from "./routes/ai.routes.mjs";
4
- import { dictionaryRoute, dictionaryRouter } from "./routes/dictionary.routes.mjs";
5
4
  import { connectDB } from "./utils/mongoDB/connectDB.mjs";
5
+ import { bitbucketRoute, bitbucketRouter } from "./routes/bitbucket.routes.mjs";
6
+ import { dictionaryRoute, dictionaryRouter } from "./routes/dictionary.routes.mjs";
6
7
  import { githubRoute, githubRouter } from "./routes/github.routes.mjs";
8
+ import { gitlabRoute, gitlabRouter } from "./routes/gitlab.routes.mjs";
7
9
  import { newsletterRoute, newsletterRouter } from "./routes/newsletter.routes.mjs";
8
10
  import { organizationRoute, organizationRouter } from "./routes/organization.routes.mjs";
9
11
  import { projectRoute, projectRouter } from "./routes/project.routes.mjs";
@@ -132,6 +134,8 @@ const startServer = async () => {
132
134
  await app.register(searchRouter, { prefix: searchRoute });
133
135
  await app.register(newsletterRouter, { prefix: newsletterRoute });
134
136
  await app.register(githubRouter, { prefix: githubRoute });
137
+ await app.register(gitlabRouter, { prefix: gitlabRoute });
138
+ await app.register(bitbucketRouter, { prefix: bitbucketRoute });
135
139
  await app.listen({
136
140
  port: Number(process.env.PORT) || 3100,
137
141
  host: "0.0.0.0"
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["app: FastifyInstance"],"sources":["../../src/index.ts"],"sourcesContent":["/// Controllers\nimport { getOAuth2AccessToken } from '@controllers/oAuth2.controller';\nimport fastifyCompress from '@fastify/compress';\nimport fastifyCookie from '@fastify/cookie';\nimport fastifyCors from '@fastify/cors';\nimport fastifyFormbody from '@fastify/formbody';\nimport fastifyHelmet from '@fastify/helmet';\nimport fastifyRateLimit from '@fastify/rate-limit';\n// Middlewares\nimport {\n attachOAuthInstance,\n oAuth2Middleware,\n} from '@middlewares/oAuth2.middleware';\nimport { authMiddleware } from '@middlewares/sessionAuth.middleware';\n// Routes\nimport { aiRoute, aiRouter } from '@routes/ai.routes';\nimport { dictionaryRoute, dictionaryRouter } from '@routes/dictionary.routes';\nimport {\n eventListenerRoute,\n eventListenerRouter,\n} from '@routes/eventListener.routes';\nimport { githubRoute, githubRouter } from '@routes/github.routes';\nimport { newsletterRoute, newsletterRouter } from '@routes/newsletter.routes';\nimport {\n organizationRoute,\n organizationRouter,\n} from '@routes/organization.routes';\nimport { projectRoute, projectRouter } from '@routes/project.routes';\nimport { searchRoute, searchRouter } from '@routes/search.routes';\nimport { stripeRoute, stripeRouter } from '@routes/stripe.routes';\nimport { tagRoute, tagRouter } from '@routes/tags.routes';\nimport { userRoute, userRouter } from '@routes/user.routes';\n// Utils\nimport { getAuth } from '@utils/auth/getAuth';\nimport { corsOptions } from '@utils/cors';\nimport { connectDB } from '@utils/mongoDB/connectDB';\nimport { ipLimiter } from '@utils/rateLimiter';\n// Webhooks\nimport { stripeWebhook } from '@webhooks/stripe.webhook';\n// Libraries\nimport dotenv from 'dotenv';\nimport Fastify, { type FastifyInstance } from 'fastify';\nimport { intlayer, t } from 'fastify-intlayer';\n/// Logger\nimport { logger } from './logger/index';\n\nconst startServer = async () => {\n const app: FastifyInstance = Fastify({\n disableRequestLogging: true,\n trustProxy: true,\n ignoreTrailingSlash: true,\n });\n\n // Environment variables\n const env = process.env.NODE_ENV || 'development';\n\n logger.info(`run as ${env}`);\n\n dotenv.config({\n path: [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env'],\n });\n\n // Security Headers\n await app.register(fastifyHelmet, {\n contentSecurityPolicy: false,\n global: true,\n });\n\n // CORS\n await app.register(fastifyCors, corsOptions);\n\n // Compression\n await app.register(fastifyCompress);\n\n // Cookie Parser\n await app.register(fastifyCookie);\n\n // Parse application/x-www-form-urlencoded\n await app.register(fastifyFormbody);\n\n // Load internationalization request handler\n await app.register(intlayer);\n\n // Rate limiter\n await app.register(fastifyRateLimit, ipLimiter);\n\n // Connect to MongoDB\n const dbClient = await connectDB();\n\n // Stripe webhook (needs raw body)\n // Register a content type parser for raw body\n await app.register(async (stripeScope) => {\n stripeScope.addContentTypeParser(\n 'application/json',\n { parseAs: 'buffer' },\n (_req, body, done) => {\n done(null, body);\n }\n );\n\n stripeScope.post('/webhook/stripe', async (request, reply) => {\n // For Stripe webhooks, we need the raw body as a Buffer\n // Fastify will parse it as buffer when content-type parser is set\n const rawBody = request.body as Buffer;\n // Create a mock request object for the webhook handler\n const mockReq = {\n ...request.raw,\n body: rawBody,\n headers: request.headers,\n } as any;\n await stripeWebhook(mockReq, reply as any);\n });\n });\n\n // Liveness check\n app.get('/', async (_request, reply) => {\n return reply.send(\n t({\n en: 'Ok - locale: en',\n fr: 'Ok - locale: fr',\n es: 'Ok - locale: es',\n })\n );\n });\n\n // Session Auth\n const auth = getAuth(dbClient as any);\n\n // Better Auth handler - Using Fetch API approach for Fastify compatibility\n app.route({\n method: ['GET', 'POST'],\n url: '/api/auth/*',\n async handler(request, reply) {\n try {\n // This respects the X-Forwarded-Proto header from Coolify\n const protocol = request.protocol;\n const host = request.headers.host;\n\n // Construct request URL using the detected protocol\n const url = new URL(request.url, `${protocol}://${host}`);\n\n const headers = new Headers();\n Object.entries(request.headers).forEach(([key, value]) => {\n if (value) headers.append(key, String(value));\n });\n\n // Create Fetch API-compatible request\n const req = new Request(url.toString(), {\n method: request.method,\n headers,\n ...(request.body ? { body: JSON.stringify(request.body) } : {}),\n });\n\n // Process authentication request\n const response = await auth.handler(req);\n\n // Forward response to client\n reply.status(response.status);\n response.headers.forEach((value, key) => {\n reply.header(key, value);\n });\n\n const responseBody = response.body ? await response.text() : null;\n return reply.send(responseBody);\n } catch (error) {\n logger.error('Authentication Error:', error);\n return reply.status(500).send({\n error: 'Internal authentication error',\n code: 'AUTH_FAILURE',\n });\n }\n },\n });\n\n // Register auth middleware as a hook\n app.addHook('onRequest', authMiddleware(auth));\n\n // // oAuth2 Auth\n app.addHook('onRequest', attachOAuthInstance);\n app.post('/oauth2/token', getOAuth2AccessToken); // Route to get the token\n app.addHook('preHandler', oAuth2Middleware);\n\n // // debug\n const isDev = env === 'development';\n if (isDev) {\n app.addHook('onRequest', async (request) => {\n const queryDetails = {\n params: request.params,\n query: request.query,\n body: request.body,\n locals: request.locals,\n };\n\n logger.info(\n `API Request - ${request.method} - ${request.url} - ${JSON.stringify(queryDetails, null, 2)}`\n );\n });\n }\n\n // Routes\n await app.register(userRouter, { prefix: userRoute });\n await app.register(organizationRouter, { prefix: organizationRoute });\n await app.register(projectRouter, { prefix: projectRoute });\n await app.register(tagRouter, { prefix: tagRoute });\n await app.register(dictionaryRouter, { prefix: dictionaryRoute });\n await app.register(stripeRouter, { prefix: stripeRoute });\n await app.register(aiRouter, { prefix: aiRoute });\n await app.register(eventListenerRouter, { prefix: eventListenerRoute });\n await app.register(searchRouter, { prefix: searchRoute });\n await app.register(newsletterRouter, { prefix: newsletterRoute });\n await app.register(githubRouter, { prefix: githubRoute });\n\n // Server\n await app.listen({\n port: Number(process.env.PORT) || 3100,\n host: '0.0.0.0',\n });\n logger.info(`Listening on port ${process.env.PORT || 3100}`);\n};\n\nstartServer();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["app: FastifyInstance"],"sources":["../../src/index.ts"],"sourcesContent":["/// Controllers\nimport { getOAuth2AccessToken } from '@controllers/oAuth2.controller';\nimport fastifyCompress from '@fastify/compress';\nimport fastifyCookie from '@fastify/cookie';\nimport fastifyCors from '@fastify/cors';\nimport fastifyFormbody from '@fastify/formbody';\nimport fastifyHelmet from '@fastify/helmet';\nimport fastifyRateLimit from '@fastify/rate-limit';\n// Middlewares\nimport {\n attachOAuthInstance,\n oAuth2Middleware,\n} from '@middlewares/oAuth2.middleware';\nimport { authMiddleware } from '@middlewares/sessionAuth.middleware';\n// Routes\nimport { aiRoute, aiRouter } from '@routes/ai.routes';\nimport { bitbucketRoute, bitbucketRouter } from '@routes/bitbucket.routes';\nimport { dictionaryRoute, dictionaryRouter } from '@routes/dictionary.routes';\nimport {\n eventListenerRoute,\n eventListenerRouter,\n} from '@routes/eventListener.routes';\nimport { githubRoute, githubRouter } from '@routes/github.routes';\nimport { gitlabRoute, gitlabRouter } from '@routes/gitlab.routes';\nimport { newsletterRoute, newsletterRouter } from '@routes/newsletter.routes';\nimport {\n organizationRoute,\n organizationRouter,\n} from '@routes/organization.routes';\nimport { projectRoute, projectRouter } from '@routes/project.routes';\nimport { searchRoute, searchRouter } from '@routes/search.routes';\nimport { stripeRoute, stripeRouter } from '@routes/stripe.routes';\nimport { tagRoute, tagRouter } from '@routes/tags.routes';\nimport { userRoute, userRouter } from '@routes/user.routes';\n// Utils\nimport { getAuth } from '@utils/auth/getAuth';\nimport { corsOptions } from '@utils/cors';\nimport { connectDB } from '@utils/mongoDB/connectDB';\nimport { ipLimiter } from '@utils/rateLimiter';\n// Webhooks\nimport { stripeWebhook } from '@webhooks/stripe.webhook';\n// Libraries\nimport dotenv from 'dotenv';\nimport Fastify, { type FastifyInstance } from 'fastify';\nimport { intlayer, t } from 'fastify-intlayer';\n/// Logger\nimport { logger } from './logger/index';\n\nconst startServer = async () => {\n const app: FastifyInstance = Fastify({\n disableRequestLogging: true,\n trustProxy: true,\n ignoreTrailingSlash: true,\n });\n\n // Environment variables\n const env = process.env.NODE_ENV || 'development';\n\n logger.info(`run as ${env}`);\n\n dotenv.config({\n path: [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env'],\n });\n\n // Security Headers\n await app.register(fastifyHelmet, {\n contentSecurityPolicy: false,\n global: true,\n });\n\n // CORS\n await app.register(fastifyCors, corsOptions);\n\n // Compression\n await app.register(fastifyCompress);\n\n // Cookie Parser\n await app.register(fastifyCookie);\n\n // Parse application/x-www-form-urlencoded\n await app.register(fastifyFormbody);\n\n // Load internationalization request handler\n await app.register(intlayer);\n\n // Rate limiter\n await app.register(fastifyRateLimit, ipLimiter);\n\n // Connect to MongoDB\n const dbClient = await connectDB();\n\n // Stripe webhook (needs raw body)\n // Register a content type parser for raw body\n await app.register(async (stripeScope) => {\n stripeScope.addContentTypeParser(\n 'application/json',\n { parseAs: 'buffer' },\n (_req, body, done) => {\n done(null, body);\n }\n );\n\n stripeScope.post('/webhook/stripe', async (request, reply) => {\n // For Stripe webhooks, we need the raw body as a Buffer\n // Fastify will parse it as buffer when content-type parser is set\n const rawBody = request.body as Buffer;\n // Create a mock request object for the webhook handler\n const mockReq = {\n ...request.raw,\n body: rawBody,\n headers: request.headers,\n } as any;\n await stripeWebhook(mockReq, reply as any);\n });\n });\n\n // Liveness check\n app.get('/', async (_request, reply) => {\n return reply.send(\n t({\n en: 'Ok - locale: en',\n fr: 'Ok - locale: fr',\n es: 'Ok - locale: es',\n })\n );\n });\n\n // Session Auth\n const auth = getAuth(dbClient as any);\n\n // Better Auth handler - Using Fetch API approach for Fastify compatibility\n app.route({\n method: ['GET', 'POST'],\n url: '/api/auth/*',\n async handler(request, reply) {\n try {\n // This respects the X-Forwarded-Proto header from Coolify\n const protocol = request.protocol;\n const host = request.headers.host;\n\n // Construct request URL using the detected protocol\n const url = new URL(request.url, `${protocol}://${host}`);\n\n const headers = new Headers();\n Object.entries(request.headers).forEach(([key, value]) => {\n if (value) headers.append(key, String(value));\n });\n\n // Create Fetch API-compatible request\n const req = new Request(url.toString(), {\n method: request.method,\n headers,\n ...(request.body ? { body: JSON.stringify(request.body) } : {}),\n });\n\n // Process authentication request\n const response = await auth.handler(req);\n\n // Forward response to client\n reply.status(response.status);\n response.headers.forEach((value, key) => {\n reply.header(key, value);\n });\n\n const responseBody = response.body ? await response.text() : null;\n return reply.send(responseBody);\n } catch (error) {\n logger.error('Authentication Error:', error);\n return reply.status(500).send({\n error: 'Internal authentication error',\n code: 'AUTH_FAILURE',\n });\n }\n },\n });\n\n // Register auth middleware as a hook\n app.addHook('onRequest', authMiddleware(auth));\n\n // // oAuth2 Auth\n app.addHook('onRequest', attachOAuthInstance);\n app.post('/oauth2/token', getOAuth2AccessToken); // Route to get the token\n app.addHook('preHandler', oAuth2Middleware);\n\n // // debug\n const isDev = env === 'development';\n if (isDev) {\n app.addHook('onRequest', async (request) => {\n const queryDetails = {\n params: request.params,\n query: request.query,\n body: request.body,\n locals: request.locals,\n };\n\n logger.info(\n `API Request - ${request.method} - ${request.url} - ${JSON.stringify(queryDetails, null, 2)}`\n );\n });\n }\n\n // Routes\n await app.register(userRouter, { prefix: userRoute });\n await app.register(organizationRouter, { prefix: organizationRoute });\n await app.register(projectRouter, { prefix: projectRoute });\n await app.register(tagRouter, { prefix: tagRoute });\n await app.register(dictionaryRouter, { prefix: dictionaryRoute });\n await app.register(stripeRouter, { prefix: stripeRoute });\n await app.register(aiRouter, { prefix: aiRoute });\n await app.register(eventListenerRouter, { prefix: eventListenerRoute });\n await app.register(searchRouter, { prefix: searchRoute });\n await app.register(newsletterRouter, { prefix: newsletterRoute });\n await app.register(githubRouter, { prefix: githubRoute });\n await app.register(gitlabRouter, { prefix: gitlabRoute });\n await app.register(bitbucketRouter, { prefix: bitbucketRoute });\n\n // Server\n await app.listen({\n port: Number(process.env.PORT) || 3100,\n host: '0.0.0.0',\n });\n logger.info(`Listening on port ${process.env.PORT || 3100}`);\n};\n\nstartServer();\n"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { authCallback, checkConfig, getAuthUrl, getConfigFile, listRepos } from "../controllers/bitbucket.controller.mjs";
2
+
3
+ //#region src/routes/bitbucket.routes.ts
4
+ const bitbucketRoute = "/api/bitbucket";
5
+ const baseURL = () => `${process.env.BACKEND_URL}${bitbucketRoute}`;
6
+ const getBitbucketRoutes = () => ({
7
+ getAuthUrl: {
8
+ urlModel: "/auth-url",
9
+ url: `${baseURL()}/auth-url`,
10
+ method: "GET"
11
+ },
12
+ authCallback: {
13
+ urlModel: "/auth",
14
+ url: `${baseURL()}/auth`,
15
+ method: "POST"
16
+ },
17
+ listRepos: {
18
+ urlModel: "/repos",
19
+ url: `${baseURL()}/repos`,
20
+ method: "GET"
21
+ },
22
+ checkConfig: {
23
+ urlModel: "/check-config",
24
+ url: `${baseURL()}/check-config`,
25
+ method: "POST"
26
+ },
27
+ getConfigFile: {
28
+ urlModel: "/get-config-file",
29
+ url: `${baseURL()}/get-config-file`,
30
+ method: "POST"
31
+ }
32
+ });
33
+ const bitbucketRouter = async (fastify) => {
34
+ fastify.get(getBitbucketRoutes().getAuthUrl.urlModel, getAuthUrl);
35
+ fastify.post(getBitbucketRoutes().authCallback.urlModel, authCallback);
36
+ fastify.get(getBitbucketRoutes().listRepos.urlModel, listRepos);
37
+ fastify.post(getBitbucketRoutes().checkConfig.urlModel, checkConfig);
38
+ fastify.post(getBitbucketRoutes().getConfigFile.urlModel, getConfigFile);
39
+ };
40
+
41
+ //#endregion
42
+ export { bitbucketRoute, bitbucketRouter, getBitbucketRoutes };
43
+ //# sourceMappingURL=bitbucket.routes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitbucket.routes.mjs","names":[],"sources":["../../../src/routes/bitbucket.routes.ts"],"sourcesContent":["import {\n authCallback,\n checkConfig,\n getAuthUrl,\n getConfigFile,\n listRepos,\n} from '@controllers/bitbucket.controller';\nimport type { FastifyInstance } from 'fastify';\nimport type { Routes } from '@/types/Routes';\n\nexport const bitbucketRoute = '/api/bitbucket';\n\nconst baseURL = () => `${process.env.BACKEND_URL}${bitbucketRoute}`;\n\nexport const getBitbucketRoutes = () =>\n ({\n getAuthUrl: {\n urlModel: '/auth-url',\n url: `${baseURL()}/auth-url`,\n method: 'GET',\n },\n authCallback: {\n urlModel: '/auth',\n url: `${baseURL()}/auth`,\n method: 'POST',\n },\n listRepos: {\n urlModel: '/repos',\n url: `${baseURL()}/repos`,\n method: 'GET',\n },\n checkConfig: {\n urlModel: '/check-config',\n url: `${baseURL()}/check-config`,\n method: 'POST',\n },\n getConfigFile: {\n urlModel: '/get-config-file',\n url: `${baseURL()}/get-config-file`,\n method: 'POST',\n },\n }) satisfies Routes;\n\nexport const bitbucketRouter = async (fastify: FastifyInstance) => {\n fastify.get(getBitbucketRoutes().getAuthUrl.urlModel, getAuthUrl);\n fastify.post(getBitbucketRoutes().authCallback.urlModel, authCallback);\n fastify.get(getBitbucketRoutes().listRepos.urlModel, listRepos);\n fastify.post(getBitbucketRoutes().checkConfig.urlModel, checkConfig);\n fastify.post(getBitbucketRoutes().getConfigFile.urlModel, getConfigFile);\n};\n"],"mappings":";;;AAUA,MAAa,iBAAiB;AAE9B,MAAM,gBAAgB,GAAG,QAAQ,IAAI,cAAc;AAEnD,MAAa,4BACV;CACC,YAAY;EACV,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,cAAc;EACZ,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,WAAW;EACT,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,aAAa;EACX,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACF;AAEH,MAAa,kBAAkB,OAAO,YAA6B;AACjE,SAAQ,IAAI,oBAAoB,CAAC,WAAW,UAAU,WAAW;AACjE,SAAQ,KAAK,oBAAoB,CAAC,aAAa,UAAU,aAAa;AACtE,SAAQ,IAAI,oBAAoB,CAAC,UAAU,UAAU,UAAU;AAC/D,SAAQ,KAAK,oBAAoB,CAAC,YAAY,UAAU,YAAY;AACpE,SAAQ,KAAK,oBAAoB,CAAC,cAAc,UAAU,cAAc"}
@@ -0,0 +1,43 @@
1
+ import { authCallback, checkConfig, getAuthUrl, getConfigFile, listProjects } from "../controllers/gitlab.controller.mjs";
2
+
3
+ //#region src/routes/gitlab.routes.ts
4
+ const gitlabRoute = "/api/gitlab";
5
+ const baseURL = () => `${process.env.BACKEND_URL}${gitlabRoute}`;
6
+ const getGitlabRoutes = () => ({
7
+ getAuthUrl: {
8
+ urlModel: "/auth-url",
9
+ url: `${baseURL()}/auth-url`,
10
+ method: "GET"
11
+ },
12
+ authCallback: {
13
+ urlModel: "/auth",
14
+ url: `${baseURL()}/auth`,
15
+ method: "POST"
16
+ },
17
+ listProjects: {
18
+ urlModel: "/projects",
19
+ url: `${baseURL()}/projects`,
20
+ method: "GET"
21
+ },
22
+ checkConfig: {
23
+ urlModel: "/check-config",
24
+ url: `${baseURL()}/check-config`,
25
+ method: "POST"
26
+ },
27
+ getConfigFile: {
28
+ urlModel: "/get-config-file",
29
+ url: `${baseURL()}/get-config-file`,
30
+ method: "POST"
31
+ }
32
+ });
33
+ const gitlabRouter = async (fastify) => {
34
+ fastify.get(getGitlabRoutes().getAuthUrl.urlModel, getAuthUrl);
35
+ fastify.post(getGitlabRoutes().authCallback.urlModel, authCallback);
36
+ fastify.get(getGitlabRoutes().listProjects.urlModel, listProjects);
37
+ fastify.post(getGitlabRoutes().checkConfig.urlModel, checkConfig);
38
+ fastify.post(getGitlabRoutes().getConfigFile.urlModel, getConfigFile);
39
+ };
40
+
41
+ //#endregion
42
+ export { getGitlabRoutes, gitlabRoute, gitlabRouter };
43
+ //# sourceMappingURL=gitlab.routes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitlab.routes.mjs","names":[],"sources":["../../../src/routes/gitlab.routes.ts"],"sourcesContent":["import {\n authCallback,\n checkConfig,\n getAuthUrl,\n getConfigFile,\n listProjects,\n} from '@controllers/gitlab.controller';\nimport type { FastifyInstance } from 'fastify';\nimport type { Routes } from '@/types/Routes';\n\nexport const gitlabRoute = '/api/gitlab';\n\nconst baseURL = () => `${process.env.BACKEND_URL}${gitlabRoute}`;\n\nexport const getGitlabRoutes = () =>\n ({\n getAuthUrl: {\n urlModel: '/auth-url',\n url: `${baseURL()}/auth-url`,\n method: 'GET',\n },\n authCallback: {\n urlModel: '/auth',\n url: `${baseURL()}/auth`,\n method: 'POST',\n },\n listProjects: {\n urlModel: '/projects',\n url: `${baseURL()}/projects`,\n method: 'GET',\n },\n checkConfig: {\n urlModel: '/check-config',\n url: `${baseURL()}/check-config`,\n method: 'POST',\n },\n getConfigFile: {\n urlModel: '/get-config-file',\n url: `${baseURL()}/get-config-file`,\n method: 'POST',\n },\n }) satisfies Routes;\n\nexport const gitlabRouter = async (fastify: FastifyInstance) => {\n fastify.get(getGitlabRoutes().getAuthUrl.urlModel, getAuthUrl);\n fastify.post(getGitlabRoutes().authCallback.urlModel, authCallback);\n fastify.get(getGitlabRoutes().listProjects.urlModel, listProjects);\n fastify.post(getGitlabRoutes().checkConfig.urlModel, checkConfig);\n fastify.post(getGitlabRoutes().getConfigFile.urlModel, getConfigFile);\n};\n"],"mappings":";;;AAUA,MAAa,cAAc;AAE3B,MAAM,gBAAgB,GAAG,QAAQ,IAAI,cAAc;AAEnD,MAAa,yBACV;CACC,YAAY;EACV,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,cAAc;EACZ,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,cAAc;EACZ,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,aAAa;EACX,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACF;AAEH,MAAa,eAAe,OAAO,YAA6B;AAC9D,SAAQ,IAAI,iBAAiB,CAAC,WAAW,UAAU,WAAW;AAC9D,SAAQ,KAAK,iBAAiB,CAAC,aAAa,UAAU,aAAa;AACnE,SAAQ,IAAI,iBAAiB,CAAC,aAAa,UAAU,aAAa;AAClE,SAAQ,KAAK,iBAAiB,CAAC,YAAY,UAAU,YAAY;AACjE,SAAQ,KAAK,iBAAiB,CAAC,cAAc,UAAU,cAAc"}
@@ -1,4 +1,4 @@
1
- import { addProject, deleteProject, getProjects, pushProjectConfiguration, selectProject, unselectProject, updateProject, updateProjectMembers } from "../controllers/project.controller.mjs";
1
+ import { addProject, deleteProject, getCIConfiguration, getProjects, pushCIConfiguration, pushProjectConfiguration, selectProject, triggerBuild, triggerWebhook, unselectProject, updateProject, updateProjectMembers } from "../controllers/project.controller.mjs";
2
2
  import { addNewAccessKey, deleteAccessKey, refreshAccessKey } from "../controllers/projectAccessKey.controller.mjs";
3
3
 
4
4
  //#region src/routes/project.routes.ts
@@ -59,6 +59,26 @@ const getProjectRoutes = () => ({
59
59
  urlModel: "/access_key",
60
60
  url: `${baseURL()}/access_key`,
61
61
  method: "DELETE"
62
+ },
63
+ triggerBuild: {
64
+ urlModel: "/build",
65
+ url: `${baseURL()}/build`,
66
+ method: "POST"
67
+ },
68
+ triggerWebhook: {
69
+ urlModel: "/webhook",
70
+ url: `${baseURL()}/webhook`,
71
+ method: "POST"
72
+ },
73
+ getCIConfiguration: {
74
+ urlModel: "/ci",
75
+ url: `${baseURL()}/ci`,
76
+ method: "GET"
77
+ },
78
+ pushCIConfiguration: {
79
+ urlModel: "/ci",
80
+ url: `${baseURL()}/ci`,
81
+ method: "POST"
62
82
  }
63
83
  });
64
84
  const projectRouter = async (fastify) => {
@@ -73,6 +93,10 @@ const projectRouter = async (fastify) => {
73
93
  fastify.delete(getProjectRoutes().deleteAccessKey.urlModel, deleteAccessKey);
74
94
  fastify.post(getProjectRoutes().unselectProject.urlModel, unselectProject);
75
95
  fastify.put(getProjectRoutes().selectProject.urlModel, selectProject);
96
+ fastify.post(getProjectRoutes().triggerBuild.urlModel, triggerBuild);
97
+ fastify.post(getProjectRoutes().triggerWebhook.urlModel, triggerWebhook);
98
+ fastify.get(getProjectRoutes().getCIConfiguration.urlModel, getCIConfiguration);
99
+ fastify.post(getProjectRoutes().pushCIConfiguration.urlModel, pushCIConfiguration);
76
100
  };
77
101
 
78
102
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"project.routes.mjs","names":[],"sources":["../../../src/routes/project.routes.ts"],"sourcesContent":["import {\n addProject,\n deleteProject,\n getProjects,\n pushProjectConfiguration,\n selectProject,\n unselectProject,\n updateProject,\n updateProjectMembers,\n} from '@controllers/project.controller';\nimport {\n addNewAccessKey,\n deleteAccessKey,\n refreshAccessKey,\n} from '@controllers/projectAccessKey.controller';\nimport type { FastifyInstance } from 'fastify';\nimport type { Routes } from '@/types/Routes';\n\nexport const projectRoute = '/api/project';\n\nconst baseURL = () => `${process.env.BACKEND_URL}${projectRoute}`;\n\nexport const getProjectRoutes = () =>\n ({\n getProjects: {\n urlModel: '/',\n url: baseURL(),\n method: 'GET',\n },\n addProject: {\n urlModel: '/',\n url: baseURL(),\n method: 'POST',\n },\n updateProject: {\n urlModel: '/',\n url: baseURL(),\n method: 'PUT',\n },\n updateProjectMembers: {\n urlModel: '/members',\n url: `${baseURL()}/members`,\n method: 'PUT',\n },\n pushProjectConfiguration: {\n urlModel: '/configuration',\n url: `${baseURL()}/configuration`,\n method: 'PUT',\n },\n deleteProject: {\n urlModel: '/',\n url: baseURL(),\n method: 'DELETE',\n },\n selectProject: {\n urlModel: '/:projectId',\n url: ({ projectId }: { projectId: string }) =>\n `${baseURL()}/${projectId}`,\n method: 'PUT',\n },\n unselectProject: {\n urlModel: '/logout',\n url: `${baseURL()}/logout`,\n method: 'POST',\n },\n addNewAccessKey: {\n urlModel: '/access_key',\n url: `${baseURL()}/access_key`,\n method: 'POST',\n },\n refreshAccessKey: {\n urlModel: '/access_key',\n url: `${baseURL()}/access_key`,\n method: 'PATCH',\n },\n deleteAccessKey: {\n urlModel: '/access_key',\n url: `${baseURL()}/access_key`,\n method: 'DELETE',\n },\n }) satisfies Routes;\n\nexport const projectRouter = async (fastify: FastifyInstance) => {\n fastify.get(getProjectRoutes().getProjects.urlModel, getProjects);\n fastify.post(getProjectRoutes().addProject.urlModel, addProject);\n fastify.put(getProjectRoutes().updateProject.urlModel, updateProject);\n fastify.put(\n getProjectRoutes().updateProjectMembers.urlModel,\n updateProjectMembers\n );\n fastify.put(\n getProjectRoutes().pushProjectConfiguration.urlModel,\n pushProjectConfiguration\n );\n fastify.delete(getProjectRoutes().deleteProject.urlModel, deleteProject);\n fastify.post(getProjectRoutes().addNewAccessKey.urlModel, addNewAccessKey);\n fastify.patch(getProjectRoutes().refreshAccessKey.urlModel, refreshAccessKey);\n fastify.delete(getProjectRoutes().deleteAccessKey.urlModel, deleteAccessKey);\n fastify.post(getProjectRoutes().unselectProject.urlModel, unselectProject);\n fastify.put(getProjectRoutes().selectProject.urlModel, selectProject);\n};\n"],"mappings":";;;;AAkBA,MAAa,eAAe;AAE5B,MAAM,gBAAgB,GAAG,QAAQ,IAAI,cAAc;AAEnD,MAAa,0BACV;CACC,aAAa;EACX,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,YAAY;EACV,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,sBAAsB;EACpB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,0BAA0B;EACxB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,MAAM,EAAE,gBACN,GAAG,SAAS,CAAC,GAAG;EAClB,QAAQ;EACT;CACD,iBAAiB;EACf,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,iBAAiB;EACf,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,kBAAkB;EAChB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,iBAAiB;EACf,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACF;AAEH,MAAa,gBAAgB,OAAO,YAA6B;AAC/D,SAAQ,IAAI,kBAAkB,CAAC,YAAY,UAAU,YAAY;AACjE,SAAQ,KAAK,kBAAkB,CAAC,WAAW,UAAU,WAAW;AAChE,SAAQ,IAAI,kBAAkB,CAAC,cAAc,UAAU,cAAc;AACrE,SAAQ,IACN,kBAAkB,CAAC,qBAAqB,UACxC,qBACD;AACD,SAAQ,IACN,kBAAkB,CAAC,yBAAyB,UAC5C,yBACD;AACD,SAAQ,OAAO,kBAAkB,CAAC,cAAc,UAAU,cAAc;AACxE,SAAQ,KAAK,kBAAkB,CAAC,gBAAgB,UAAU,gBAAgB;AAC1E,SAAQ,MAAM,kBAAkB,CAAC,iBAAiB,UAAU,iBAAiB;AAC7E,SAAQ,OAAO,kBAAkB,CAAC,gBAAgB,UAAU,gBAAgB;AAC5E,SAAQ,KAAK,kBAAkB,CAAC,gBAAgB,UAAU,gBAAgB;AAC1E,SAAQ,IAAI,kBAAkB,CAAC,cAAc,UAAU,cAAc"}
1
+ {"version":3,"file":"project.routes.mjs","names":[],"sources":["../../../src/routes/project.routes.ts"],"sourcesContent":["import {\n addProject,\n deleteProject,\n getCIConfiguration,\n getProjects,\n pushCIConfiguration,\n pushProjectConfiguration,\n selectProject,\n triggerBuild,\n triggerWebhook,\n unselectProject,\n updateProject,\n updateProjectMembers,\n} from '@controllers/project.controller';\nimport {\n addNewAccessKey,\n deleteAccessKey,\n refreshAccessKey,\n} from '@controllers/projectAccessKey.controller';\nimport type { FastifyInstance } from 'fastify';\nimport type { Routes } from '@/types/Routes';\n\nexport const projectRoute = '/api/project';\n\nconst baseURL = () => `${process.env.BACKEND_URL}${projectRoute}`;\n\nexport const getProjectRoutes = () =>\n ({\n getProjects: {\n urlModel: '/',\n url: baseURL(),\n method: 'GET',\n },\n addProject: {\n urlModel: '/',\n url: baseURL(),\n method: 'POST',\n },\n updateProject: {\n urlModel: '/',\n url: baseURL(),\n method: 'PUT',\n },\n updateProjectMembers: {\n urlModel: '/members',\n url: `${baseURL()}/members`,\n method: 'PUT',\n },\n pushProjectConfiguration: {\n urlModel: '/configuration',\n url: `${baseURL()}/configuration`,\n method: 'PUT',\n },\n deleteProject: {\n urlModel: '/',\n url: baseURL(),\n method: 'DELETE',\n },\n selectProject: {\n urlModel: '/:projectId',\n url: ({ projectId }: { projectId: string }) =>\n `${baseURL()}/${projectId}`,\n method: 'PUT',\n },\n unselectProject: {\n urlModel: '/logout',\n url: `${baseURL()}/logout`,\n method: 'POST',\n },\n addNewAccessKey: {\n urlModel: '/access_key',\n url: `${baseURL()}/access_key`,\n method: 'POST',\n },\n refreshAccessKey: {\n urlModel: '/access_key',\n url: `${baseURL()}/access_key`,\n method: 'PATCH',\n },\n deleteAccessKey: {\n urlModel: '/access_key',\n url: `${baseURL()}/access_key`,\n method: 'DELETE',\n },\n triggerBuild: {\n urlModel: '/build',\n url: `${baseURL()}/build`,\n method: 'POST',\n },\n triggerWebhook: {\n urlModel: '/webhook',\n url: `${baseURL()}/webhook`,\n method: 'POST',\n },\n getCIConfiguration: {\n urlModel: '/ci',\n url: `${baseURL()}/ci`,\n method: 'GET',\n },\n pushCIConfiguration: {\n urlModel: '/ci',\n url: `${baseURL()}/ci`,\n method: 'POST',\n },\n }) satisfies Routes;\n\nexport const projectRouter = async (fastify: FastifyInstance) => {\n fastify.get(getProjectRoutes().getProjects.urlModel, getProjects);\n fastify.post(getProjectRoutes().addProject.urlModel, addProject);\n fastify.put(getProjectRoutes().updateProject.urlModel, updateProject);\n fastify.put(\n getProjectRoutes().updateProjectMembers.urlModel,\n updateProjectMembers\n );\n fastify.put(\n getProjectRoutes().pushProjectConfiguration.urlModel,\n pushProjectConfiguration\n );\n fastify.delete(getProjectRoutes().deleteProject.urlModel, deleteProject);\n fastify.post(getProjectRoutes().addNewAccessKey.urlModel, addNewAccessKey);\n fastify.patch(getProjectRoutes().refreshAccessKey.urlModel, refreshAccessKey);\n fastify.delete(getProjectRoutes().deleteAccessKey.urlModel, deleteAccessKey);\n fastify.post(getProjectRoutes().unselectProject.urlModel, unselectProject);\n fastify.put(getProjectRoutes().selectProject.urlModel, selectProject);\n fastify.post(getProjectRoutes().triggerBuild.urlModel, triggerBuild);\n fastify.post(getProjectRoutes().triggerWebhook.urlModel, triggerWebhook);\n fastify.get(\n getProjectRoutes().getCIConfiguration.urlModel,\n getCIConfiguration\n );\n fastify.post(\n getProjectRoutes().pushCIConfiguration.urlModel,\n pushCIConfiguration\n );\n};\n"],"mappings":";;;;AAsBA,MAAa,eAAe;AAE5B,MAAM,gBAAgB,GAAG,QAAQ,IAAI,cAAc;AAEnD,MAAa,0BACV;CACC,aAAa;EACX,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,YAAY;EACV,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,sBAAsB;EACpB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,0BAA0B;EACxB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,KAAK,SAAS;EACd,QAAQ;EACT;CACD,eAAe;EACb,UAAU;EACV,MAAM,EAAE,gBACN,GAAG,SAAS,CAAC,GAAG;EAClB,QAAQ;EACT;CACD,iBAAiB;EACf,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,iBAAiB;EACf,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,kBAAkB;EAChB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,iBAAiB;EACf,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,cAAc;EACZ,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,gBAAgB;EACd,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,oBAAoB;EAClB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACD,qBAAqB;EACnB,UAAU;EACV,KAAK,GAAG,SAAS,CAAC;EAClB,QAAQ;EACT;CACF;AAEH,MAAa,gBAAgB,OAAO,YAA6B;AAC/D,SAAQ,IAAI,kBAAkB,CAAC,YAAY,UAAU,YAAY;AACjE,SAAQ,KAAK,kBAAkB,CAAC,WAAW,UAAU,WAAW;AAChE,SAAQ,IAAI,kBAAkB,CAAC,cAAc,UAAU,cAAc;AACrE,SAAQ,IACN,kBAAkB,CAAC,qBAAqB,UACxC,qBACD;AACD,SAAQ,IACN,kBAAkB,CAAC,yBAAyB,UAC5C,yBACD;AACD,SAAQ,OAAO,kBAAkB,CAAC,cAAc,UAAU,cAAc;AACxE,SAAQ,KAAK,kBAAkB,CAAC,gBAAgB,UAAU,gBAAgB;AAC1E,SAAQ,MAAM,kBAAkB,CAAC,iBAAiB,UAAU,iBAAiB;AAC7E,SAAQ,OAAO,kBAAkB,CAAC,gBAAgB,UAAU,gBAAgB;AAC5E,SAAQ,KAAK,kBAAkB,CAAC,gBAAgB,UAAU,gBAAgB;AAC1E,SAAQ,IAAI,kBAAkB,CAAC,cAAc,UAAU,cAAc;AACrE,SAAQ,KAAK,kBAAkB,CAAC,aAAa,UAAU,aAAa;AACpE,SAAQ,KAAK,kBAAkB,CAAC,eAAe,UAAU,eAAe;AACxE,SAAQ,IACN,kBAAkB,CAAC,mBAAmB,UACtC,mBACD;AACD,SAAQ,KACN,kBAAkB,CAAC,oBAAoB,UACvC,oBACD"}
@@ -33,6 +33,21 @@ const oAuth2AccessSchema = new Schema({
33
33
  default: []
34
34
  }
35
35
  }, { timestamps: true });
36
+ const webhookSchema = new Schema({
37
+ name: {
38
+ type: String,
39
+ required: true
40
+ },
41
+ url: {
42
+ type: String,
43
+ required: true
44
+ },
45
+ enabled: {
46
+ type: Boolean,
47
+ default: true
48
+ },
49
+ secret: { type: String }
50
+ }, { _id: true });
36
51
  const projectConfigSchema = new Schema({
37
52
  internationalization: {
38
53
  locales: {
@@ -60,7 +75,23 @@ const projectConfigSchema = new Schema({
60
75
  baseURL: { type: String }
61
76
  }
62
77
  }, { _id: false });
63
- const githubSchema = new Schema({
78
+ const webhooksConfigSchema = new Schema({
79
+ autoTriggerBuilds: {
80
+ type: Boolean,
81
+ default: false
82
+ },
83
+ webhooks: [webhookSchema]
84
+ }, { _id: false });
85
+ const repositorySchema = new Schema({
86
+ provider: {
87
+ type: String,
88
+ enum: [
89
+ "github",
90
+ "gitlab",
91
+ "bitbucket"
92
+ ],
93
+ required: true
94
+ },
64
95
  owner: {
65
96
  type: String,
66
97
  required: true
@@ -73,7 +104,6 @@ const githubSchema = new Schema({
73
104
  type: String,
74
105
  default: "main"
75
106
  },
76
- installationId: { type: Number },
77
107
  url: {
78
108
  type: String,
79
109
  required: true
@@ -81,7 +111,11 @@ const githubSchema = new Schema({
81
111
  configFilePath: {
82
112
  type: String,
83
113
  required: true
84
- }
114
+ },
115
+ installationId: { type: Number },
116
+ projectId: { type: Number },
117
+ instanceUrl: { type: String },
118
+ workspace: { type: String }
85
119
  }, { _id: false });
86
120
  const projectSchema = new Schema({
87
121
  organizationId: {
@@ -97,7 +131,8 @@ const projectSchema = new Schema({
97
131
  },
98
132
  configuration: projectConfigSchema,
99
133
  oAuth2Access: [oAuth2AccessSchema],
100
- github: githubSchema,
134
+ repository: repositorySchema,
135
+ webhooks: webhooksConfigSchema,
101
136
  membersIds: {
102
137
  type: [Schema.Types.ObjectId],
103
138
  ref: "User",
@@ -1 +1 @@
1
- {"version":3,"file":"project.schema.mjs","names":[],"sources":["../../../src/schemas/project.schema.ts"],"sourcesContent":["import { AiProviders, Locales } from '@intlayer/types';\nimport type { RenameId } from '@utils/mongoDB/types';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateProject';\nimport { Schema } from 'mongoose';\nimport type {\n OAuth2Access,\n Project,\n ProjectSchema,\n} from '@/types/project.types';\n\n// Define the oAuth2Access subdocument schema with timestamps\nconst oAuth2AccessSchema = new Schema<RenameId<OAuth2Access>>(\n {\n clientId: { type: String, required: true },\n clientSecret: { type: String, required: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n name: { type: String, required: true },\n expiresAt: { type: Date },\n accessToken: { type: [String], required: true, default: [] },\n grants: { type: [String], required: true, default: [] },\n },\n {\n timestamps: true,\n }\n);\n\nconst projectConfigSchema = new Schema<Project['configuration']>(\n {\n internationalization: {\n locales: {\n type: [String],\n enum: Object.values(Locales.ALL_LOCALES),\n required: true,\n },\n defaultLocale: {\n type: String,\n enum: Object.values(Locales.ALL_LOCALES),\n },\n },\n editor: {\n applicationURL: {\n type: String,\n },\n cmsURL: {\n type: String,\n },\n },\n ai: {\n provider: {\n type: String,\n enum: Object.values(AiProviders),\n },\n model: {\n type: String,\n },\n apiKey: {\n type: String,\n },\n applicationContext: {\n type: String,\n },\n baseURL: {\n type: String,\n },\n },\n },\n {\n _id: false, // Prevents the generation of an _id field for this subdocument\n }\n);\n\nconst githubSchema = new Schema<Project['github']>(\n {\n owner: { type: String, required: true },\n repository: { type: String, required: true },\n branch: { type: String, default: 'main' },\n installationId: { type: Number },\n url: { type: String, required: true },\n configFilePath: { type: String, required: true },\n },\n {\n _id: false,\n }\n);\n\nexport const projectSchema = new Schema<ProjectSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n configuration: projectConfigSchema,\n oAuth2Access: [oAuth2AccessSchema],\n github: githubSchema,\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":";;;;;AAeA,MAAM,qBAAqB,IAAI,OAC7B;CACE,UAAU;EAAE,MAAM;EAAQ,UAAU;EAAM;CAC1C,cAAc;EAAE,MAAM;EAAQ,UAAU;EAAM;CAC9C,QAAQ;EAAE,MAAM,OAAO,MAAM;EAAU,KAAK;EAAQ,UAAU;EAAM;CACpE,MAAM;EAAE,MAAM;EAAQ,UAAU;EAAM;CACtC,WAAW,EAAE,MAAM,MAAM;CACzB,aAAa;EAAE,MAAM,CAAC,OAAO;EAAE,UAAU;EAAM,SAAS,EAAE;EAAE;CAC5D,QAAQ;EAAE,MAAM,CAAC,OAAO;EAAE,UAAU;EAAM,SAAS,EAAE;EAAE;CACxD,EACD,EACE,YAAY,MACb,CACF;AAED,MAAM,sBAAsB,IAAI,OAC9B;CACE,sBAAsB;EACpB,SAAS;GACP,MAAM,CAAC,OAAO;GACd,MAAM,OAAO,OAAO,QAAQ,YAAY;GACxC,UAAU;GACX;EACD,eAAe;GACb,MAAM;GACN,MAAM,OAAO,OAAO,QAAQ,YAAY;GACzC;EACF;CACD,QAAQ;EACN,gBAAgB,EACd,MAAM,QACP;EACD,QAAQ,EACN,MAAM,QACP;EACF;CACD,IAAI;EACF,UAAU;GACR,MAAM;GACN,MAAM,OAAO,OAAO,YAAY;GACjC;EACD,OAAO,EACL,MAAM,QACP;EACD,QAAQ,EACN,MAAM,QACP;EACD,oBAAoB,EAClB,MAAM,QACP;EACD,SAAS,EACP,MAAM,QACP;EACF;CACF,EACD,EACE,KAAK,OACN,CACF;AAED,MAAM,eAAe,IAAI,OACvB;CACE,OAAO;EAAE,MAAM;EAAQ,UAAU;EAAM;CACvC,YAAY;EAAE,MAAM;EAAQ,UAAU;EAAM;CAC5C,QAAQ;EAAE,MAAM;EAAQ,SAAS;EAAQ;CACzC,gBAAgB,EAAE,MAAM,QAAQ;CAChC,KAAK;EAAE,MAAM;EAAQ,UAAU;EAAM;CACrC,gBAAgB;EAAE,MAAM;EAAQ,UAAU;EAAM;CACjD,EACD,EACE,KAAK,OACN,CACF;AAED,MAAa,gBAAgB,IAAI,OAC/B;CACE,gBAAgB;EACd,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACD,MAAM;EACJ,MAAM;EACN,UAAU;EACV,WAAW;EACX,WAAW;EACZ;CACD,eAAe;CACf,cAAc,CAAC,mBAAmB;CAClC,QAAQ;CACR,YAAY;EACV,MAAM,CAAC,OAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAW;EACZ;CACD,WAAW;EACT,MAAM,CAAC,OAAO,MAAM,SAAS;EAC7B,KAAK;EACL,UAAU;EACV,WAAW;EACZ;CACD,WAAW;EACT,MAAM,OAAO,MAAM;EACnB,KAAK;EACL,UAAU;EACX;CACF,EACD;CACE,YAAY;CAEZ,QAAQ;EACN,UAAU;EACV,YAAY;EACZ,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI,IAAI,UAAU;IACnB;;EAEJ;CACD,UAAU;EACR,UAAU;EACV,UAAU,MAAM,KAAU;GACxB,MAAM,EAAE,KAAK,GAAG,SAAS;AACzB,UAAO;IACL,GAAG;IACH,IAAI;IACL;;EAEJ;CACF,CACF"}
1
+ {"version":3,"file":"project.schema.mjs","names":[],"sources":["../../../src/schemas/project.schema.ts"],"sourcesContent":["import { AiProviders, Locales } from '@intlayer/types';\nimport type { RenameId } from '@utils/mongoDB/types';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateProject';\nimport { Schema } from 'mongoose';\nimport type {\n OAuth2Access,\n Project,\n ProjectSchema,\n} from '@/types/project.types';\n\n// Define the oAuth2Access subdocument schema with timestamps\nconst oAuth2AccessSchema = new Schema<RenameId<OAuth2Access>>(\n {\n clientId: { type: String, required: true },\n clientSecret: { type: String, required: true },\n userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },\n name: { type: String, required: true },\n expiresAt: { type: Date },\n accessToken: { type: [String], required: true, default: [] },\n grants: { type: [String], required: true, default: [] },\n },\n {\n timestamps: true,\n }\n);\n\n// Schema for generic webhooks (Vercel, Netlify, Custom, etc.)\nconst webhookSchema = new Schema(\n {\n name: { type: String, required: true },\n url: { type: String, required: true },\n enabled: { type: Boolean, default: true },\n secret: { type: String }, // Optional signature secret\n },\n { _id: true }\n);\n\nconst projectConfigSchema = new Schema<Project['configuration']>(\n {\n internationalization: {\n locales: {\n type: [String],\n enum: Object.values(Locales.ALL_LOCALES),\n required: true,\n },\n defaultLocale: {\n type: String,\n enum: Object.values(Locales.ALL_LOCALES),\n },\n },\n editor: {\n applicationURL: {\n type: String,\n },\n cmsURL: {\n type: String,\n },\n },\n ai: {\n provider: {\n type: String,\n enum: Object.values(AiProviders),\n },\n model: {\n type: String,\n },\n apiKey: {\n type: String,\n },\n applicationContext: {\n type: String,\n },\n baseURL: {\n type: String,\n },\n },\n },\n {\n _id: false, // Prevents the generation of an _id field for this subdocument\n }\n);\n\n// Schema for webhooks/CI configuration (top-level project property, not part of configuration)\nconst webhooksConfigSchema = new Schema<Project['webhooks']>(\n {\n autoTriggerBuilds: { type: Boolean, default: false }, // Master toggle\n webhooks: [webhookSchema], // Generic hooks (Vercel, Netlify, Custom)\n },\n {\n _id: false,\n }\n);\n\nconst repositorySchema = new Schema<Project['repository']>(\n {\n provider: {\n type: String,\n enum: ['github', 'gitlab', 'bitbucket'],\n required: true,\n },\n owner: { type: String, required: true },\n repository: { type: String, required: true },\n branch: { type: String, default: 'main' },\n url: { type: String, required: true },\n configFilePath: { type: String, required: true },\n // GitHub specific\n installationId: { type: Number },\n // GitLab specific\n projectId: { type: Number },\n instanceUrl: { type: String },\n // Bitbucket specific\n workspace: { type: String },\n },\n {\n _id: false,\n }\n);\n\nexport const projectSchema = new Schema<ProjectSchema>(\n {\n organizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: true,\n },\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n configuration: projectConfigSchema,\n oAuth2Access: [oAuth2AccessSchema],\n repository: repositorySchema,\n webhooks: webhooksConfigSchema,\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id.toString(),\n };\n },\n },\n toObject: {\n virtuals: true,\n transform(_doc, ret: any) {\n const { _id, ...rest } = ret;\n return {\n ...rest,\n id: _id,\n };\n },\n },\n }\n);\n"],"mappings":"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"}