@intlayer/backend 7.5.8 → 7.5.10

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 (216) hide show
  1. package/README.md +9 -2
  2. package/dist/assets/utils/AI/askDocQuestion/PROMPT.md +1 -1
  3. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/cli/init.json +2054 -0
  4. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_fastify.json +9 -0
  5. package/dist/esm/controllers/ai.controller.mjs +95 -128
  6. package/dist/esm/controllers/ai.controller.mjs.map +1 -1
  7. package/dist/esm/controllers/dictionary.controller.mjs +86 -198
  8. package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
  9. package/dist/esm/controllers/eventListener.controller.mjs +13 -19
  10. package/dist/esm/controllers/eventListener.controller.mjs.map +1 -1
  11. package/dist/esm/controllers/github.controller.mjs +77 -0
  12. package/dist/esm/controllers/github.controller.mjs.map +1 -0
  13. package/dist/esm/controllers/newsletter.controller.mjs +30 -60
  14. package/dist/esm/controllers/newsletter.controller.mjs.map +1 -1
  15. package/dist/esm/controllers/oAuth2.controller.mjs +11 -8
  16. package/dist/esm/controllers/oAuth2.controller.mjs.map +1 -1
  17. package/dist/esm/controllers/organization.controller.mjs +100 -225
  18. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  19. package/dist/esm/controllers/project.controller.mjs +87 -204
  20. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  21. package/dist/esm/controllers/projectAccessKey.controller.mjs +38 -71
  22. package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
  23. package/dist/esm/controllers/search.controller.mjs +3 -3
  24. package/dist/esm/controllers/search.controller.mjs.map +1 -1
  25. package/dist/esm/controllers/stripe.controller.mjs +34 -67
  26. package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
  27. package/dist/esm/controllers/tag.controller.mjs +51 -113
  28. package/dist/esm/controllers/tag.controller.mjs.map +1 -1
  29. package/dist/esm/controllers/user.controller.mjs +64 -113
  30. package/dist/esm/controllers/user.controller.mjs.map +1 -1
  31. package/dist/esm/export.mjs +2 -1
  32. package/dist/esm/index.mjs +101 -41
  33. package/dist/esm/index.mjs.map +1 -1
  34. package/dist/esm/middlewares/oAuth2.middleware.mjs +19 -14
  35. package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
  36. package/dist/esm/middlewares/sessionAuth.middleware.mjs +6 -7
  37. package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
  38. package/dist/esm/routes/ai.routes.mjs +19 -15
  39. package/dist/esm/routes/ai.routes.mjs.map +1 -1
  40. package/dist/esm/routes/dictionary.routes.mjs +10 -10
  41. package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
  42. package/dist/esm/routes/eventListener.routes.mjs +3 -3
  43. package/dist/esm/routes/eventListener.routes.mjs.map +1 -1
  44. package/dist/esm/routes/github.routes.mjs +43 -0
  45. package/dist/esm/routes/github.routes.mjs.map +1 -0
  46. package/dist/esm/routes/newsletter.routes.mjs +5 -5
  47. package/dist/esm/routes/newsletter.routes.mjs.map +1 -1
  48. package/dist/esm/routes/organization.routes.mjs +11 -11
  49. package/dist/esm/routes/organization.routes.mjs.map +1 -1
  50. package/dist/esm/routes/project.routes.mjs +13 -13
  51. package/dist/esm/routes/project.routes.mjs.map +1 -1
  52. package/dist/esm/routes/search.routes.mjs +3 -3
  53. package/dist/esm/routes/search.routes.mjs.map +1 -1
  54. package/dist/esm/routes/stripe.routes.mjs +5 -5
  55. package/dist/esm/routes/stripe.routes.mjs.map +1 -1
  56. package/dist/esm/routes/tags.routes.mjs +6 -6
  57. package/dist/esm/routes/tags.routes.mjs.map +1 -1
  58. package/dist/esm/routes/user.routes.mjs +9 -9
  59. package/dist/esm/routes/user.routes.mjs.map +1 -1
  60. package/dist/esm/schemas/project.schema.mjs +35 -1
  61. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  62. package/dist/esm/services/email.service.mjs +1 -1
  63. package/dist/esm/services/email.service.mjs.map +1 -1
  64. package/dist/esm/services/github.service.mjs +130 -0
  65. package/dist/esm/services/github.service.mjs.map +1 -0
  66. package/dist/esm/services/oAuth2.service.mjs +1 -1
  67. package/dist/esm/services/subscription.service.mjs +1 -1
  68. package/dist/esm/services/subscription.service.mjs.map +1 -1
  69. package/dist/esm/utils/auth/getAuth.mjs +14 -8
  70. package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
  71. package/dist/esm/utils/cors.mjs +15 -5
  72. package/dist/esm/utils/cors.mjs.map +1 -1
  73. package/dist/esm/utils/errors/ErrorHandler.mjs +32 -4
  74. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  75. package/dist/esm/utils/errors/ErrorsClass.mjs +1 -1
  76. package/dist/esm/utils/errors/ErrorsClass.mjs.map +1 -1
  77. package/dist/esm/utils/errors/errorCodes.mjs +78 -0
  78. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  79. package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs +3 -2
  80. package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs.map +1 -1
  81. package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs +1 -1
  82. package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs.map +1 -1
  83. package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs +1 -1
  84. package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs.map +1 -1
  85. package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs +3 -2
  86. package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs.map +1 -1
  87. package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs +3 -2
  88. package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs.map +1 -1
  89. package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs +3 -2
  90. package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs.map +1 -1
  91. package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs +3 -2
  92. package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs.map +1 -1
  93. package/dist/esm/utils/mapper/project.mjs +28 -1
  94. package/dist/esm/utils/mapper/project.mjs.map +1 -1
  95. package/dist/esm/utils/mongoDB/connectDB.mjs +1 -1
  96. package/dist/esm/utils/rateLimiter.mjs +40 -30
  97. package/dist/esm/utils/rateLimiter.mjs.map +1 -1
  98. package/dist/esm/webhooks/stripe.webhook.mjs +2 -2
  99. package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -1
  100. package/dist/types/controllers/ai.controller.d.ts +29 -12
  101. package/dist/types/controllers/ai.controller.d.ts.map +1 -1
  102. package/dist/types/controllers/dictionary.controller.d.ts +23 -13
  103. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  104. package/dist/types/controllers/eventListener.controller.d.ts +4 -2
  105. package/dist/types/controllers/eventListener.controller.d.ts.map +1 -1
  106. package/dist/types/controllers/github.controller.d.ts +63 -0
  107. package/dist/types/controllers/github.controller.d.ts.map +1 -0
  108. package/dist/types/controllers/newsletter.controller.d.ts +8 -7
  109. package/dist/types/controllers/newsletter.controller.d.ts.map +1 -1
  110. package/dist/types/controllers/oAuth2.controller.d.ts +4 -2
  111. package/dist/types/controllers/oAuth2.controller.d.ts.map +1 -1
  112. package/dist/types/controllers/organization.controller.d.ts +28 -12
  113. package/dist/types/controllers/organization.controller.d.ts.map +1 -1
  114. package/dist/types/controllers/project.controller.d.ts +21 -16
  115. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  116. package/dist/types/controllers/projectAccessKey.controller.d.ts +10 -5
  117. package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
  118. package/dist/types/controllers/search.controller.d.ts +4 -2
  119. package/dist/types/controllers/search.controller.d.ts.map +1 -1
  120. package/dist/types/controllers/stripe.controller.d.ts +11 -12
  121. package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
  122. package/dist/types/controllers/tag.controller.d.ts +14 -9
  123. package/dist/types/controllers/tag.controller.d.ts.map +1 -1
  124. package/dist/types/controllers/user.controller.d.ts +22 -9
  125. package/dist/types/controllers/user.controller.d.ts.map +1 -1
  126. package/dist/types/emails/InviteUserEmail.d.ts +4 -4
  127. package/dist/types/emails/InviteUserEmail.d.ts.map +1 -1
  128. package/dist/types/emails/MagicLinkEmail.d.ts +4 -4
  129. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +4 -4
  130. package/dist/types/emails/ResetUserPassword.d.ts +4 -4
  131. package/dist/types/emails/ResetUserPassword.d.ts.map +1 -1
  132. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -4
  133. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
  134. package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -4
  135. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -4
  136. package/dist/types/emails/ValidateUserEmail.d.ts +4 -4
  137. package/dist/types/emails/ValidateUserEmail.d.ts.map +1 -1
  138. package/dist/types/emails/Welcome.d.ts +4 -4
  139. package/dist/types/emails/Welcome.d.ts.map +1 -1
  140. package/dist/types/export.d.ts +6 -4
  141. package/dist/types/middlewares/oAuth2.middleware.d.ts +9 -4
  142. package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
  143. package/dist/types/middlewares/sessionAuth.middleware.d.ts +13 -3
  144. package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
  145. package/dist/types/models/dictionary.model.d.ts +4 -4
  146. package/dist/types/models/discussion.model.d.ts +2 -2
  147. package/dist/types/models/oAuth2.model.d.ts +3 -3
  148. package/dist/types/routes/ai.routes.d.ts +2 -2
  149. package/dist/types/routes/ai.routes.d.ts.map +1 -1
  150. package/dist/types/routes/dictionary.routes.d.ts +2 -2
  151. package/dist/types/routes/dictionary.routes.d.ts.map +1 -1
  152. package/dist/types/routes/eventListener.routes.d.ts +2 -2
  153. package/dist/types/routes/eventListener.routes.d.ts.map +1 -1
  154. package/dist/types/routes/github.routes.d.ts +35 -0
  155. package/dist/types/routes/github.routes.d.ts.map +1 -0
  156. package/dist/types/routes/newsletter.routes.d.ts +2 -2
  157. package/dist/types/routes/newsletter.routes.d.ts.map +1 -1
  158. package/dist/types/routes/organization.routes.d.ts +2 -2
  159. package/dist/types/routes/organization.routes.d.ts.map +1 -1
  160. package/dist/types/routes/project.routes.d.ts +2 -2
  161. package/dist/types/routes/project.routes.d.ts.map +1 -1
  162. package/dist/types/routes/search.routes.d.ts +2 -2
  163. package/dist/types/routes/search.routes.d.ts.map +1 -1
  164. package/dist/types/routes/stripe.routes.d.ts +2 -2
  165. package/dist/types/routes/stripe.routes.d.ts.map +1 -1
  166. package/dist/types/routes/tags.routes.d.ts +2 -2
  167. package/dist/types/routes/tags.routes.d.ts.map +1 -1
  168. package/dist/types/routes/user.routes.d.ts +2 -2
  169. package/dist/types/routes/user.routes.d.ts.map +1 -1
  170. package/dist/types/schemas/dictionary.schema.d.ts +6 -6
  171. package/dist/types/schemas/discussion.schema.d.ts +6 -6
  172. package/dist/types/schemas/oAuth2.schema.d.ts +5 -5
  173. package/dist/types/schemas/project.schema.d.ts +6 -6
  174. package/dist/types/schemas/project.schema.d.ts.map +1 -1
  175. package/dist/types/schemas/session.schema.d.ts +6 -6
  176. package/dist/types/schemas/tag.schema.d.ts +6 -6
  177. package/dist/types/schemas/user.schema.d.ts +6 -6
  178. package/dist/types/services/email.service.d.ts +11 -11
  179. package/dist/types/services/github.service.d.ts +21 -0
  180. package/dist/types/services/github.service.d.ts.map +1 -0
  181. package/dist/types/types/project.types.d.ts +18 -5
  182. package/dist/types/types/project.types.d.ts.map +1 -1
  183. package/dist/types/types/session.types.d.ts +1 -1
  184. package/dist/types/types/user.types.d.ts +1 -1
  185. package/dist/types/utils/AI/auditTag/index.d.ts +1 -1
  186. package/dist/types/utils/auth/getAuth.d.ts.map +1 -1
  187. package/dist/types/utils/cors.d.ts +2 -2
  188. package/dist/types/utils/errors/ErrorHandler.d.ts +31 -3
  189. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  190. package/dist/types/utils/errors/ErrorsClass.d.ts +1 -1
  191. package/dist/types/utils/errors/errorCodes.d.ts +78 -0
  192. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  193. package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts +8 -4
  194. package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts.map +1 -1
  195. package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts +6 -3
  196. package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts.map +1 -1
  197. package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts +6 -2
  198. package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts.map +1 -1
  199. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +8 -4
  200. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts.map +1 -1
  201. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts +8 -4
  202. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts.map +1 -1
  203. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +8 -4
  204. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts.map +1 -1
  205. package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts +6 -2
  206. package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts.map +1 -1
  207. package/dist/types/utils/mapper/project.d.ts.map +1 -1
  208. package/dist/types/utils/mergeFunctionTypes.d.ts.map +1 -1
  209. package/dist/types/utils/permissions.d.ts +1 -1
  210. package/dist/types/utils/rateLimiter.d.ts +4 -2
  211. package/dist/types/utils/rateLimiter.d.ts.map +1 -1
  212. package/package.json +23 -27
  213. package/dist/esm/middlewares/request.middleware.mjs +0 -17
  214. package/dist/esm/middlewares/request.middleware.mjs.map +0 -1
  215. package/dist/types/middlewares/request.middleware.d.ts +0 -7
  216. package/dist/types/middlewares/request.middleware.d.ts.map +0 -1
@@ -8,32 +8,23 @@ import { SessionModel } from "../models/session.model.mjs";
8
8
  import { getPlanDetails } from "../utils/plan.mjs";
9
9
  import { getProjectFiltersAndPagination } from "../utils/filtersAndPagination/getProjectFiltersAndPagination.mjs";
10
10
  import { mapProjectToAPI, mapProjectsToAPI } from "../utils/mapper/project.mjs";
11
- import { t } from "express-intlayer";
11
+ import { t } from "fastify-intlayer";
12
12
 
13
13
  //#region src/controllers/project.controller.ts
14
14
  /**
15
15
  * Retrieves a list of projects based on filters and pagination.
16
16
  */
17
- const getProjects = async (req, res, _next) => {
18
- const { user, organization, roles } = res.locals;
19
- const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getProjectFiltersAndPagination(req, res);
20
- if (!user) {
21
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
22
- return;
23
- }
24
- if (!organization && !roles.includes("admin")) {
25
- ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
26
- return;
27
- }
17
+ const getProjects = async (request, reply) => {
18
+ const { user, organization, roles } = request.locals || {};
19
+ const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getProjectFiltersAndPagination(request);
20
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
21
+ if (!organization && !roles?.includes("admin")) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
28
22
  try {
29
23
  const projects = await findProjects(filters, skip, pageSize, sortOptions);
30
- if (!hasPermission(roles, "project:read")({
31
- ...res.locals,
24
+ if (!hasPermission(roles || [], "project:read")({
25
+ ...request.locals,
32
26
  targetProjects: projects
33
- })) {
34
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
35
- return;
36
- }
27
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
37
28
  const totalItems = await countProjects(filters);
38
29
  const responseData = formatPaginatedResponse({
39
30
  data: mapProjectsToAPI(projects),
@@ -42,42 +33,28 @@ const getProjects = async (req, res, _next) => {
42
33
  totalPages: getNumberOfPages(totalItems),
43
34
  totalItems
44
35
  });
45
- res.json(responseData);
46
- return;
36
+ return reply.send(responseData);
47
37
  } catch (error) {
48
- ErrorHandler.handleAppErrorResponse(res, error);
49
- return;
38
+ return ErrorHandler.handleAppErrorResponse(reply, error);
50
39
  }
51
40
  };
52
41
  /**
53
42
  * Adds a new project to the database.
54
43
  */
55
- const addProject = async (req, res, _next) => {
56
- const { organization, user, roles } = res.locals;
57
- const projectData = req.body;
58
- if (!user) {
59
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
60
- return;
61
- }
62
- if (!organization) {
63
- ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
64
- return;
65
- }
66
- if (!projectData) ErrorHandler.handleGenericErrorResponse(res, "PROJECT_DATA_NOT_FOUND");
67
- if (!hasPermission(roles, "organization:admin")({
68
- ...res.locals,
44
+ const addProject = async (request, reply) => {
45
+ const { organization, user, roles } = request.locals || {};
46
+ const projectData = request.body;
47
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
48
+ if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
49
+ if (!projectData) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_DATA_NOT_FOUND");
50
+ if (!hasPermission(roles || [], "organization:admin")({
51
+ ...request.locals,
69
52
  targetOrganizations: [organization]
70
- })) {
71
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
72
- return;
73
- }
53
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
74
54
  const { plan } = organization;
75
55
  const planType = getPlanDetails(plan);
76
56
  if (planType.numberOfProjects) {
77
- if (await countProjects({ organizationId: organization.id }) >= planType.numberOfProjects) {
78
- ErrorHandler.handleGenericErrorResponse(res, "PLAN_PROJECT_LIMIT_REACHED", { organizationId: organization.id });
79
- return;
80
- }
57
+ if (await countProjects({ organizationId: organization.id }) >= planType.numberOfProjects) return ErrorHandler.handleGenericErrorResponse(reply, "PLAN_PROJECT_LIMIT_REACHED", { organizationId: organization.id });
81
58
  }
82
59
  const project = {
83
60
  membersIds: [user.id],
@@ -101,42 +78,25 @@ const addProject = async (req, res, _next) => {
101
78
  }),
102
79
  data: formattedProject
103
80
  });
104
- res.json(responseData);
105
- return;
81
+ return reply.send(responseData);
106
82
  } catch (error) {
107
- ErrorHandler.handleAppErrorResponse(res, error);
108
- return;
83
+ return ErrorHandler.handleAppErrorResponse(reply, error);
109
84
  }
110
85
  };
111
86
  /**
112
87
  * Updates an existing project in the database.
113
88
  */
114
- const updateProject = async (req, res, _next) => {
115
- const { organization, project, user, roles } = res.locals;
116
- const projectData = req.body;
117
- if (!user) {
118
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
119
- return;
120
- }
121
- if (!project) {
122
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_DATA_NOT_FOUND");
123
- return;
124
- }
125
- if (!organization) {
126
- ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
127
- return;
128
- }
129
- if (String(project.organizationId) !== String(organization.id)) {
130
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_IN_ORGANIZATION");
131
- return;
132
- }
133
- if (!hasPermission(roles, "project:write")({
134
- ...res.locals,
89
+ const updateProject = async (request, reply) => {
90
+ const { organization, project, user, roles } = request.locals || {};
91
+ const projectData = request.body;
92
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
93
+ if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_DATA_NOT_FOUND");
94
+ if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
95
+ if (String(project.organizationId) !== String(organization.id)) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_IN_ORGANIZATION");
96
+ if (!hasPermission(roles || [], "project:write")({
97
+ ...request.locals,
135
98
  targetProjectIds: [String(project.id)]
136
- })) {
137
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
138
- return;
139
- }
99
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
140
100
  try {
141
101
  const formattedProject = mapProjectToAPI(await updateProjectById(project.id, projectData));
142
102
  const responseData = formatResponse({
@@ -152,46 +112,26 @@ const updateProject = async (req, res, _next) => {
152
112
  }),
153
113
  data: formattedProject
154
114
  });
155
- res.json(responseData);
156
- return;
115
+ return reply.send(responseData);
157
116
  } catch (error) {
158
- ErrorHandler.handleAppErrorResponse(res, error);
159
- return;
117
+ return ErrorHandler.handleAppErrorResponse(reply, error);
160
118
  }
161
119
  };
162
120
  /**
163
121
  * Update members to the dictionary in the database.
164
122
  */
165
- const updateProjectMembers = async (req, res, _next) => {
166
- const { user, project, organization, roles } = res.locals;
167
- const { membersIds } = req.body;
168
- if (!user) {
169
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
170
- return;
171
- }
172
- if (!project) {
173
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
174
- return;
175
- }
176
- if (!organization) {
177
- ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
178
- return;
179
- }
180
- if (membersIds?.length === 0) {
181
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_MUST_HAVE_MEMBER");
182
- return;
183
- }
184
- if (membersIds?.map((el) => el.isAdmin)?.length === 0) {
185
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_MUST_HAVE_ADMIN");
186
- return;
187
- }
188
- if (!hasPermission(roles, "project:write")({
189
- ...res.locals,
123
+ const updateProjectMembers = async (request, reply) => {
124
+ const { user, project, organization, roles } = request.locals || {};
125
+ const { membersIds } = request.body;
126
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
127
+ if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
128
+ if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
129
+ if (membersIds?.length === 0) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_MUST_HAVE_MEMBER");
130
+ if (membersIds?.map((el) => el.isAdmin)?.length === 0) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_MUST_HAVE_ADMIN");
131
+ if (!hasPermission(roles || [], "project:write")({
132
+ ...request.locals,
190
133
  targetProjectIds: [String(project.id)]
191
- })) {
192
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
193
- return;
194
- }
134
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
195
135
  try {
196
136
  const existingUsers = [];
197
137
  if (membersIds) {
@@ -225,45 +165,29 @@ const updateProjectMembers = async (req, res, _next) => {
225
165
  }),
226
166
  data: formattedProject
227
167
  });
228
- res.json(responseData);
229
- return;
168
+ return reply.send(responseData);
230
169
  } catch (error) {
231
- ErrorHandler.handleAppErrorResponse(res, error);
232
- return;
170
+ return ErrorHandler.handleAppErrorResponse(reply, error);
233
171
  }
234
172
  };
235
173
  /**
236
174
  * Pushes a project configuration to the database.
237
- * @param req - Express request object.
238
- * @param res - Express response object.
239
- * @returns Response confirming the deletion.
240
175
  */
241
- const pushProjectConfiguration = async (req, res, _next) => {
242
- const { user, project, roles } = res.locals;
243
- const projectConfiguration = req.body;
244
- if (!user) {
245
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
246
- return;
247
- }
248
- if (!project) {
249
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
250
- return;
251
- }
252
- if (!hasPermission(roles, "project:write")({
253
- ...res.locals,
176
+ const pushProjectConfiguration = async (request, reply) => {
177
+ const { user, project, roles } = request.locals || {};
178
+ const projectConfiguration = request.body;
179
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
180
+ if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
181
+ if (!hasPermission(roles || [], "project:write")({
182
+ ...request.locals,
254
183
  targetProjectIds: [String(project.id)]
255
- })) {
256
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
257
- return;
258
- }
184
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
259
185
  try {
260
186
  const projectObject = await getProjectById(project.id);
187
+ if (projectConfiguration.ai && projectObject.configuration?.ai?.apiKey && (!projectConfiguration.ai.apiKey || projectConfiguration.ai.apiKey.trim() === "")) projectConfiguration.ai.apiKey = projectObject.configuration.ai.apiKey;
261
188
  projectObject.configuration = projectConfiguration;
262
- projectObject.save();
263
- if (!projectObject.configuration) {
264
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_UPDATE_FAILED", { projectId: project.id });
265
- return;
266
- }
189
+ await projectObject.save();
190
+ if (!projectObject.configuration) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_UPDATE_FAILED", { projectId: project.id });
267
191
  const responseData = formatResponse({
268
192
  message: t({
269
193
  en: "Project configuration updated successfully",
@@ -275,57 +199,31 @@ const pushProjectConfiguration = async (req, res, _next) => {
275
199
  fr: "La configuration du projet a été mise à jour avec succès",
276
200
  es: "Su configuración del proyecto ha sido actualizada con éxito"
277
201
  }),
278
- data: projectObject.configuration
202
+ data: mapProjectToAPI(projectObject)
279
203
  });
280
- res.json(responseData);
281
- return;
204
+ return reply.send(responseData);
282
205
  } catch (error) {
283
- ErrorHandler.handleAppErrorResponse(res, error);
284
- return;
206
+ return ErrorHandler.handleAppErrorResponse(reply, error);
285
207
  }
286
208
  };
287
209
  /**
288
210
  * Deletes a project from the database by its ID.
289
- * @param req - Express request object.
290
- * @param res - Express response object.
291
- * @returns Response confirming the deletion.
292
211
  */
293
- const deleteProject = async (_req, res, _next) => {
294
- const { user, organization, project, session, roles } = res.locals;
295
- if (!user) {
296
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
297
- return;
298
- }
299
- if (!organization) {
300
- ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
301
- return;
302
- }
303
- if (!project) {
304
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
305
- return;
306
- }
307
- if (typeof session === "undefined") {
308
- ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
309
- return;
310
- }
311
- if (!hasPermission(roles, "project:admin")({
312
- ...res.locals,
212
+ const deleteProject = async (_request, reply) => {
213
+ const { user, organization, project, session, roles } = _request.locals || {};
214
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
215
+ if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
216
+ if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
217
+ if (typeof session === "undefined") return ErrorHandler.handleGenericErrorResponse(reply, "SESSION_NOT_DEFINED");
218
+ if (!hasPermission(roles || [], "project:admin")({
219
+ ..._request.locals,
313
220
  targetProjectIds: [String(project.id)]
314
- })) {
315
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
316
- return;
317
- }
221
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
318
222
  try {
319
223
  const projectToDelete = await getProjectById(project.id);
320
- if (String(projectToDelete.organizationId) !== String(organization.id)) {
321
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_IN_ORGANIZATION");
322
- return;
323
- }
224
+ if (String(projectToDelete.organizationId) !== String(organization.id)) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_IN_ORGANIZATION");
324
225
  const deletedProject = await deleteProjectById(project.id);
325
- if (!deletedProject) {
326
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED", { projectId: project.id });
327
- return;
328
- }
226
+ if (!deletedProject) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED", { projectId: project.id });
329
227
  logger.info(`Project deleted: ${String(deletedProject.id)}`);
330
228
  const responseData = formatResponse({
331
229
  message: t({
@@ -341,27 +239,19 @@ const deleteProject = async (_req, res, _next) => {
341
239
  data: mapProjectToAPI(deletedProject)
342
240
  });
343
241
  await SessionModel.updateOne({ _id: session.id }, { $set: { activeProjectId: null } });
344
- res.json(responseData);
345
- return;
242
+ return reply.send(responseData);
346
243
  } catch (error) {
347
- ErrorHandler.handleAppErrorResponse(res, error);
348
- return;
244
+ return ErrorHandler.handleAppErrorResponse(reply, error);
349
245
  }
350
246
  };
351
247
  /**
352
248
  * Select a project.
353
249
  */
354
- const selectProject = async (req, res, _next) => {
355
- const { projectId } = req.params;
356
- const { session } = res.locals;
357
- if (!projectId) {
358
- ErrorHandler.handleGenericErrorResponse(res, "PROJECT_ID_NOT_FOUND");
359
- return;
360
- }
361
- if (typeof session === "undefined") {
362
- ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
363
- return;
364
- }
250
+ const selectProject = async (request, reply) => {
251
+ const { projectId } = request.params;
252
+ const { session } = request.locals || {};
253
+ if (!projectId) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_ID_NOT_FOUND");
254
+ if (typeof session === "undefined") return ErrorHandler.handleGenericErrorResponse(reply, "SESSION_NOT_DEFINED");
365
255
  try {
366
256
  const project = await getProjectById(projectId);
367
257
  await SessionModel.updateOne({ _id: session.id }, { $set: { activeProjectId: String(projectId) } });
@@ -378,22 +268,17 @@ const selectProject = async (req, res, _next) => {
378
268
  }),
379
269
  data: mapProjectToAPI(project)
380
270
  });
381
- res.json(responseData);
382
- return;
271
+ return reply.send(responseData);
383
272
  } catch (error) {
384
- ErrorHandler.handleAppErrorResponse(res, error);
385
- return;
273
+ return ErrorHandler.handleAppErrorResponse(reply, error);
386
274
  }
387
275
  };
388
276
  /**
389
277
  * Unselect a project.
390
278
  */
391
- const unselectProject = async (_req, res, _next) => {
392
- const { session } = res.locals;
393
- if (typeof session === "undefined") {
394
- ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
395
- return;
396
- }
279
+ const unselectProject = async (_request, reply) => {
280
+ const { session } = _request.locals || {};
281
+ if (typeof session === "undefined") return ErrorHandler.handleGenericErrorResponse(reply, "SESSION_NOT_DEFINED");
397
282
  try {
398
283
  await SessionModel.updateOne({ _id: session.id }, { $set: { activeProjectId: null } });
399
284
  const responseData = formatResponse({
@@ -409,11 +294,9 @@ const unselectProject = async (_req, res, _next) => {
409
294
  }),
410
295
  data: null
411
296
  });
412
- res.json(responseData);
413
- return;
297
+ return reply.send(responseData);
414
298
  } catch (error) {
415
- ErrorHandler.handleAppErrorResponse(res, error);
416
- return;
299
+ return ErrorHandler.handleAppErrorResponse(reply, error);
417
300
  }
418
301
  };
419
302
 
@@ -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 type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\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 { NextFunction, Request } from 'express';\nimport { t } from 'express-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 req: Request<GetProjectsParams>,\n res: ResponseWithSession<GetProjectsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, roles } = res.locals;\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(req, res);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization && !roles.includes('admin')) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\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 ...res.locals,\n targetProjects: projects,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\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 res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\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 req: Request<any, any, AddProjectBody>,\n res: ResponseWithSession<AddProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, roles } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!projectData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\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 ErrorHandler.handleGenericErrorResponse(\n res,\n 'PLAN_PROJECT_LIMIT_REACHED',\n {\n organizationId: organization.id,\n }\n );\n return;\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 res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\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 req: Request<any, any, UpdateProjectBody>,\n res: ResponseWithSession<UpdateProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, project, user, roles } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (String(project.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_IN_ORGANIZATION');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\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 res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\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 req: Request<any, any, UpdateProjectMembersBody>,\n res: ResponseWithSession<UpdateProjectMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, organization, roles } = res.locals;\n const { membersIds } = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_MEMBER');\n return;\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_ADMIN');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\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 res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type PushProjectConfigurationBody = ProjectConfiguration;\nexport type PushProjectConfigurationResult = ResponseData<ProjectConfiguration>;\n\n/**\n * Pushes a project configuration to the database.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const pushProjectConfiguration = async (\n req: Request<any, any, PushProjectConfigurationBody>,\n res: ResponseWithSession<PushProjectConfigurationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n const projectConfiguration = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const projectObject = await projectService.getProjectById(project.id);\n projectObject.configuration = projectConfiguration;\n\n projectObject.save();\n\n if (!projectObject.configuration) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_UPDATE_FAILED', {\n projectId: project.id,\n });\n return;\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: projectObject.configuration,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Deletes a project from the database by its ID.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const deleteProject = async (\n _req: Request,\n res: ResponseWithSession<DeleteProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, project, session, roles } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:admin'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const projectToDelete = await projectService.getProjectById(project.id);\n\n if (String(projectToDelete.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n return;\n }\n\n const deletedProject = await projectService.deleteProjectById(project.id);\n\n if (!deletedProject) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED', {\n projectId: project.id,\n });\n\n return;\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 res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\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 req: Request<SelectProjectParam>,\n res: ResponseWithSession<SelectProjectResult>,\n _next: NextFunction\n) => {\n const { projectId } = req.params;\n const { session } = res.locals;\n\n if (!projectId) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_NOT_FOUND');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\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 res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UnselectProjectResult = ResponseData<null>;\n\n/**\n * Unselect a project.\n */\nexport const unselectProject = async (\n _req: Request,\n res: ResponseWithSession<UnselectProjectResult>,\n _next: NextFunction\n) => {\n const { session } = res.locals;\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\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 res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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"}
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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"}