@intlayer/backend 5.1.4 → 5.1.6

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 (252) hide show
  1. package/dist/cjs/controllers/ai.controller.cjs +61 -43
  2. package/dist/cjs/controllers/ai.controller.cjs.map +1 -1
  3. package/dist/cjs/controllers/dictionary.controller.cjs +8 -12
  4. package/dist/cjs/controllers/dictionary.controller.cjs.map +1 -1
  5. package/dist/cjs/controllers/organization.controller.cjs +17 -1
  6. package/dist/cjs/controllers/organization.controller.cjs.map +1 -1
  7. package/dist/cjs/controllers/project.controller.cjs +1 -0
  8. package/dist/cjs/controllers/project.controller.cjs.map +1 -1
  9. package/dist/cjs/controllers/sessionAuth.controller.cjs +6 -12
  10. package/dist/cjs/controllers/sessionAuth.controller.cjs.map +1 -1
  11. package/dist/cjs/controllers/stripe.controller.cjs +31 -10
  12. package/dist/cjs/controllers/stripe.controller.cjs.map +1 -1
  13. package/dist/cjs/controllers/tag.controller.cjs +0 -7
  14. package/dist/cjs/controllers/tag.controller.cjs.map +1 -1
  15. package/dist/cjs/controllers/user.controller.cjs +1 -1
  16. package/dist/cjs/controllers/user.controller.cjs.map +1 -1
  17. package/dist/cjs/emails/InviteUserEmail.cjs +3 -3
  18. package/dist/cjs/emails/InviteUserEmail.cjs.map +1 -1
  19. package/dist/cjs/emails/PasswordChangeConfirmation.cjs +3 -3
  20. package/dist/cjs/emails/PasswordChangeConfirmation.cjs.map +1 -1
  21. package/dist/cjs/emails/ResetUserPassword.cjs +3 -3
  22. package/dist/cjs/emails/ResetUserPassword.cjs.map +1 -1
  23. package/dist/cjs/emails/SubscriptionPaymentCancellation.cjs +19 -3
  24. package/dist/cjs/emails/SubscriptionPaymentCancellation.cjs.map +1 -1
  25. package/dist/cjs/emails/SubscriptionPaymentError.cjs +19 -3
  26. package/dist/cjs/emails/SubscriptionPaymentError.cjs.map +1 -1
  27. package/dist/cjs/emails/SubscriptionPaymentSuccess.cjs +19 -3
  28. package/dist/cjs/emails/SubscriptionPaymentSuccess.cjs.map +1 -1
  29. package/dist/cjs/emails/ValidateUserEmail.cjs +3 -3
  30. package/dist/cjs/emails/ValidateUserEmail.cjs.map +1 -1
  31. package/dist/cjs/emails/Welcome.cjs +3 -3
  32. package/dist/cjs/emails/Welcome.cjs.map +1 -1
  33. package/dist/cjs/export.cjs +10 -10
  34. package/dist/cjs/export.cjs.map +1 -1
  35. package/dist/cjs/routes/ai.routes.cjs +21 -15
  36. package/dist/cjs/routes/ai.routes.cjs.map +1 -1
  37. package/dist/cjs/routes/dictionary.routes.cjs +15 -12
  38. package/dist/cjs/routes/dictionary.routes.cjs.map +1 -1
  39. package/dist/cjs/routes/event-listener.routes.cjs +4 -4
  40. package/dist/cjs/routes/event-listener.routes.cjs.map +1 -1
  41. package/dist/cjs/routes/organization.routes.cjs +15 -15
  42. package/dist/cjs/routes/organization.routes.cjs.map +1 -1
  43. package/dist/cjs/routes/project.routes.cjs +30 -18
  44. package/dist/cjs/routes/project.routes.cjs.map +1 -1
  45. package/dist/cjs/routes/sessionAuth.routes.cjs +38 -35
  46. package/dist/cjs/routes/sessionAuth.routes.cjs.map +1 -1
  47. package/dist/cjs/routes/stripe.routes.cjs +23 -11
  48. package/dist/cjs/routes/stripe.routes.cjs.map +1 -1
  49. package/dist/cjs/routes/tags.routes.cjs +11 -11
  50. package/dist/cjs/routes/tags.routes.cjs.map +1 -1
  51. package/dist/cjs/routes/user.routes.cjs +13 -13
  52. package/dist/cjs/routes/user.routes.cjs.map +1 -1
  53. package/dist/cjs/schemas/dictionary.schema.cjs +0 -4
  54. package/dist/cjs/schemas/dictionary.schema.cjs.map +1 -1
  55. package/dist/cjs/schemas/project.schema.cjs +2 -2
  56. package/dist/cjs/schemas/project.schema.cjs.map +1 -1
  57. package/dist/cjs/services/dictionary.service.cjs.map +1 -1
  58. package/dist/cjs/services/email.service.cjs +1 -1
  59. package/dist/cjs/services/email.service.cjs.map +1 -1
  60. package/dist/cjs/services/subscription.service.cjs +81 -2
  61. package/dist/cjs/services/subscription.service.cjs.map +1 -1
  62. package/dist/cjs/types/dictionary.types.cjs.map +1 -1
  63. package/dist/cjs/utils/AI/{askDocQuestion.cjs → askDocQuestion/askDocQuestion.cjs} +1 -1
  64. package/dist/cjs/utils/AI/askDocQuestion/askDocQuestion.cjs.map +1 -0
  65. package/dist/{esm/utils/AI → cjs/utils/AI/askDocQuestion}/embeddings.json +4288 -4288
  66. package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/index.cjs +5 -3
  67. package/dist/cjs/utils/AI/auditDictionary/index.cjs.map +1 -0
  68. package/dist/cjs/utils/{auditDictionaryField → AI/auditDictionaryField}/PROMPT.md +17 -7
  69. package/dist/cjs/utils/{auditDictionaryField → AI/auditDictionaryField}/index.cjs +5 -3
  70. package/dist/cjs/utils/AI/auditDictionaryField/index.cjs.map +1 -0
  71. package/dist/cjs/utils/{auditDictionaryMetadata → AI/auditDictionaryMetadata}/index.cjs +5 -3
  72. package/dist/cjs/utils/AI/auditDictionaryMetadata/index.cjs.map +1 -0
  73. package/dist/cjs/utils/AI/autocomplete/PROMPT.md +13 -0
  74. package/dist/cjs/utils/AI/autocomplete/index.cjs +73 -0
  75. package/dist/cjs/utils/AI/autocomplete/index.cjs.map +1 -0
  76. package/dist/cjs/utils/auditTag/index.cjs +4 -2
  77. package/dist/cjs/utils/auditTag/index.cjs.map +1 -1
  78. package/dist/cjs/utils/errors/errorCodes.cjs +26 -0
  79. package/dist/cjs/utils/errors/errorCodes.cjs.map +1 -1
  80. package/dist/cjs/utils/mongoDB/connectDB.cjs +10 -0
  81. package/dist/cjs/utils/mongoDB/connectDB.cjs.map +1 -1
  82. package/dist/cjs/webhooks/stripe.webhook.cjs +42 -0
  83. package/dist/cjs/webhooks/stripe.webhook.cjs.map +1 -1
  84. package/dist/esm/controllers/ai.controller.mjs +59 -42
  85. package/dist/esm/controllers/ai.controller.mjs.map +1 -1
  86. package/dist/esm/controllers/dictionary.controller.mjs +8 -12
  87. package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
  88. package/dist/esm/controllers/organization.controller.mjs +18 -2
  89. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  90. package/dist/esm/controllers/project.controller.mjs +1 -0
  91. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  92. package/dist/esm/controllers/sessionAuth.controller.mjs +6 -12
  93. package/dist/esm/controllers/sessionAuth.controller.mjs.map +1 -1
  94. package/dist/esm/controllers/stripe.controller.mjs +30 -10
  95. package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
  96. package/dist/esm/controllers/tag.controller.mjs +0 -7
  97. package/dist/esm/controllers/tag.controller.mjs.map +1 -1
  98. package/dist/esm/controllers/user.controller.mjs +2 -2
  99. package/dist/esm/controllers/user.controller.mjs.map +1 -1
  100. package/dist/esm/emails/InviteUserEmail.mjs +3 -3
  101. package/dist/esm/emails/InviteUserEmail.mjs.map +1 -1
  102. package/dist/esm/emails/PasswordChangeConfirmation.mjs +3 -3
  103. package/dist/esm/emails/PasswordChangeConfirmation.mjs.map +1 -1
  104. package/dist/esm/emails/ResetUserPassword.mjs +3 -3
  105. package/dist/esm/emails/ResetUserPassword.mjs.map +1 -1
  106. package/dist/esm/emails/SubscriptionPaymentCancellation.mjs +19 -3
  107. package/dist/esm/emails/SubscriptionPaymentCancellation.mjs.map +1 -1
  108. package/dist/esm/emails/SubscriptionPaymentError.mjs +19 -3
  109. package/dist/esm/emails/SubscriptionPaymentError.mjs.map +1 -1
  110. package/dist/esm/emails/SubscriptionPaymentSuccess.mjs +19 -3
  111. package/dist/esm/emails/SubscriptionPaymentSuccess.mjs.map +1 -1
  112. package/dist/esm/emails/ValidateUserEmail.mjs +3 -3
  113. package/dist/esm/emails/ValidateUserEmail.mjs.map +1 -1
  114. package/dist/esm/emails/Welcome.mjs +3 -3
  115. package/dist/esm/emails/Welcome.mjs.map +1 -1
  116. package/dist/esm/export.mjs +10 -10
  117. package/dist/esm/export.mjs.map +1 -1
  118. package/dist/esm/routes/ai.routes.mjs +22 -15
  119. package/dist/esm/routes/ai.routes.mjs.map +1 -1
  120. package/dist/esm/routes/dictionary.routes.mjs +14 -11
  121. package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
  122. package/dist/esm/routes/event-listener.routes.mjs +4 -4
  123. package/dist/esm/routes/event-listener.routes.mjs.map +1 -1
  124. package/dist/esm/routes/organization.routes.mjs +13 -13
  125. package/dist/esm/routes/organization.routes.mjs.map +1 -1
  126. package/dist/esm/routes/project.routes.mjs +28 -16
  127. package/dist/esm/routes/project.routes.mjs.map +1 -1
  128. package/dist/esm/routes/sessionAuth.routes.mjs +37 -34
  129. package/dist/esm/routes/sessionAuth.routes.mjs.map +1 -1
  130. package/dist/esm/routes/stripe.routes.mjs +22 -9
  131. package/dist/esm/routes/stripe.routes.mjs.map +1 -1
  132. package/dist/esm/routes/tags.routes.mjs +9 -9
  133. package/dist/esm/routes/tags.routes.mjs.map +1 -1
  134. package/dist/esm/routes/user.routes.mjs +11 -11
  135. package/dist/esm/routes/user.routes.mjs.map +1 -1
  136. package/dist/esm/schemas/dictionary.schema.mjs +0 -4
  137. package/dist/esm/schemas/dictionary.schema.mjs.map +1 -1
  138. package/dist/esm/schemas/project.schema.mjs +2 -2
  139. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  140. package/dist/esm/services/dictionary.service.mjs.map +1 -1
  141. package/dist/esm/services/email.service.mjs +1 -1
  142. package/dist/esm/services/email.service.mjs.map +1 -1
  143. package/dist/esm/services/subscription.service.mjs +78 -1
  144. package/dist/esm/services/subscription.service.mjs.map +1 -1
  145. package/dist/esm/utils/AI/{askDocQuestion.mjs → askDocQuestion/askDocQuestion.mjs} +1 -1
  146. package/dist/esm/utils/AI/askDocQuestion/askDocQuestion.mjs.map +1 -0
  147. package/dist/{cjs/utils/AI → esm/utils/AI/askDocQuestion}/embeddings.json +4288 -4288
  148. package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/index.mjs +5 -3
  149. package/dist/esm/utils/AI/auditDictionary/index.mjs.map +1 -0
  150. package/dist/esm/utils/{auditDictionaryField → AI/auditDictionaryField}/PROMPT.md +17 -7
  151. package/dist/esm/utils/{auditDictionaryField → AI/auditDictionaryField}/index.mjs +5 -3
  152. package/dist/esm/utils/AI/auditDictionaryField/index.mjs.map +1 -0
  153. package/dist/esm/utils/{auditDictionaryMetadata → AI/auditDictionaryMetadata}/index.mjs +5 -3
  154. package/dist/esm/utils/AI/auditDictionaryMetadata/index.mjs.map +1 -0
  155. package/dist/esm/utils/AI/autocomplete/PROMPT.md +13 -0
  156. package/dist/esm/utils/AI/autocomplete/index.mjs +48 -0
  157. package/dist/esm/utils/AI/autocomplete/index.mjs.map +1 -0
  158. package/dist/esm/utils/auditTag/index.mjs +4 -2
  159. package/dist/esm/utils/auditTag/index.mjs.map +1 -1
  160. package/dist/esm/utils/errors/errorCodes.mjs +26 -0
  161. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  162. package/dist/esm/utils/mongoDB/connectDB.mjs +10 -0
  163. package/dist/esm/utils/mongoDB/connectDB.mjs.map +1 -1
  164. package/dist/esm/webhooks/stripe.webhook.mjs +32 -0
  165. package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -1
  166. package/dist/types/controllers/ai.controller.d.ts +17 -2
  167. package/dist/types/controllers/ai.controller.d.ts.map +1 -1
  168. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  169. package/dist/types/controllers/organization.controller.d.ts.map +1 -1
  170. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  171. package/dist/types/controllers/sessionAuth.controller.d.ts +4 -3
  172. package/dist/types/controllers/sessionAuth.controller.d.ts.map +1 -1
  173. package/dist/types/controllers/stripe.controller.d.ts +15 -7
  174. package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
  175. package/dist/types/controllers/tag.controller.d.ts.map +1 -1
  176. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -3
  177. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
  178. package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -3
  179. package/dist/types/emails/SubscriptionPaymentError.d.ts.map +1 -1
  180. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -3
  181. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts.map +1 -1
  182. package/dist/types/export.d.ts +5 -5
  183. package/dist/types/export.d.ts.map +1 -1
  184. package/dist/types/routes/ai.routes.d.ts +6 -1
  185. package/dist/types/routes/ai.routes.d.ts.map +1 -1
  186. package/dist/types/routes/dictionary.routes.d.ts +4 -4
  187. package/dist/types/routes/dictionary.routes.d.ts.map +1 -1
  188. package/dist/types/routes/event-listener.routes.d.ts +1 -1
  189. package/dist/types/routes/event-listener.routes.d.ts.map +1 -1
  190. package/dist/types/routes/organization.routes.d.ts +5 -5
  191. package/dist/types/routes/organization.routes.d.ts.map +1 -1
  192. package/dist/types/routes/project.routes.d.ts +5 -5
  193. package/dist/types/routes/project.routes.d.ts.map +1 -1
  194. package/dist/types/routes/sessionAuth.routes.d.ts +4 -7
  195. package/dist/types/routes/sessionAuth.routes.d.ts.map +1 -1
  196. package/dist/types/routes/stripe.routes.d.ts +6 -1
  197. package/dist/types/routes/stripe.routes.d.ts.map +1 -1
  198. package/dist/types/routes/tags.routes.d.ts +3 -3
  199. package/dist/types/routes/tags.routes.d.ts.map +1 -1
  200. package/dist/types/routes/user.routes.d.ts +4 -4
  201. package/dist/types/routes/user.routes.d.ts.map +1 -1
  202. package/dist/types/schemas/dictionary.schema.d.ts.map +1 -1
  203. package/dist/types/services/dictionary.service.d.ts.map +1 -1
  204. package/dist/types/services/subscription.service.d.ts +9 -0
  205. package/dist/types/services/subscription.service.d.ts.map +1 -1
  206. package/dist/types/types/dictionary.types.d.ts +0 -1
  207. package/dist/types/types/dictionary.types.d.ts.map +1 -1
  208. package/dist/types/utils/AI/askDocQuestion/askDocQuestion.d.ts.map +1 -0
  209. package/dist/types/utils/{auditDictionary → AI/auditDictionary}/index.d.ts +8 -5
  210. package/dist/types/utils/AI/auditDictionary/index.d.ts.map +1 -0
  211. package/dist/types/utils/{auditDictionaryField → AI/auditDictionaryField}/index.d.ts +8 -5
  212. package/dist/types/utils/AI/auditDictionaryField/index.d.ts.map +1 -0
  213. package/dist/types/utils/{auditDictionaryMetadata → AI/auditDictionaryMetadata}/index.d.ts +8 -5
  214. package/dist/types/utils/AI/auditDictionaryMetadata/index.d.ts.map +1 -0
  215. package/dist/types/utils/AI/autocomplete/index.d.ts +22 -0
  216. package/dist/types/utils/AI/autocomplete/index.d.ts.map +1 -0
  217. package/dist/types/utils/auditTag/index.d.ts +7 -4
  218. package/dist/types/utils/auditTag/index.d.ts.map +1 -1
  219. package/dist/types/utils/errors/errorCodes.d.ts +26 -0
  220. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  221. package/dist/types/utils/mongoDB/connectDB.d.ts.map +1 -1
  222. package/dist/types/webhooks/stripe.webhook.d.ts.map +1 -1
  223. package/package.json +11 -10
  224. package/dist/cjs/utils/AI/askDocQuestion.cjs.map +0 -1
  225. package/dist/cjs/utils/auditDictionary/index.cjs.map +0 -1
  226. package/dist/cjs/utils/auditDictionaryField/index.cjs.map +0 -1
  227. package/dist/cjs/utils/auditDictionaryMetadata/index.cjs.map +0 -1
  228. package/dist/esm/utils/AI/askDocQuestion.mjs.map +0 -1
  229. package/dist/esm/utils/auditDictionary/index.mjs.map +0 -1
  230. package/dist/esm/utils/auditDictionaryField/index.mjs.map +0 -1
  231. package/dist/esm/utils/auditDictionaryMetadata/index.mjs.map +0 -1
  232. package/dist/types/utils/AI/askDocQuestion.d.ts.map +0 -1
  233. package/dist/types/utils/auditDictionary/index.d.ts.map +0 -1
  234. package/dist/types/utils/auditDictionaryField/index.d.ts.map +0 -1
  235. package/dist/types/utils/auditDictionaryMetadata/index.d.ts.map +0 -1
  236. /package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/CJS_FORMAT.md +0 -0
  237. /package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/JSON_FORMAT.md +0 -0
  238. /package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/JSX_FORMAT.md +0 -0
  239. /package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/MJS_FORMAT.md +0 -0
  240. /package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/PROMPT.md +0 -0
  241. /package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/TSX_FORMAT.md +0 -0
  242. /package/dist/cjs/utils/{auditDictionary → AI/auditDictionary}/TS_FORMAT.md +0 -0
  243. /package/dist/cjs/utils/{auditDictionaryMetadata → AI/auditDictionaryMetadata}/PROMPT.md +0 -0
  244. /package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/CJS_FORMAT.md +0 -0
  245. /package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/JSON_FORMAT.md +0 -0
  246. /package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/JSX_FORMAT.md +0 -0
  247. /package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/MJS_FORMAT.md +0 -0
  248. /package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/PROMPT.md +0 -0
  249. /package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/TSX_FORMAT.md +0 -0
  250. /package/dist/esm/utils/{auditDictionary → AI/auditDictionary}/TS_FORMAT.md +0 -0
  251. /package/dist/esm/utils/{auditDictionaryMetadata → AI/auditDictionaryMetadata}/PROMPT.md +0 -0
  252. /package/dist/types/utils/AI/{askDocQuestion.d.ts → askDocQuestion/askDocQuestion.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/organization.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport { sessionAuthRoutes } from '@routes/sessionAuth.routes';\nimport { sendEmail } from '@services/email.service';\nimport * as sessionAuthService from '@services/sessionAuth.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getOrganizationFiltersAndPagination,\n type OrganizationFiltersParams,\n type OrganizationFilters,\n} from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\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 { ObjectId } from 'mongoose';\nimport type { User } from 'oauth2-server';\nimport * as organizationService from '@/services/organization.service';\nimport type {\n Organization,\n OrganizationCreationData,\n} from '@/types/organization.types';\n\nexport type GetOrganizationsParams =\n FiltersAndPagination<OrganizationFiltersParams>;\nexport type GetOrganizationsResult = PaginatedResponse<Organization>;\n\n/**\n * Retrieves a list of organizations based on filters and pagination.\n */\nexport const getOrganizations = async (\n req: Request<GetOrganizationsParams>,\n res: ResponseWithInformation<GetOrganizationsResult>,\n _next: NextFunction\n) => {\n const { user, organizationRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getOrganizationFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organizationRights?.read) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_READ'\n );\n return;\n }\n\n const restrictedFilter: OrganizationFilters = {\n ...filters,\n\n membersIds: { $in: [...(filters.membersIds ?? []), String(user._id)] },\n };\n\n try {\n const organizations = await organizationService.findOrganizations(\n restrictedFilter,\n skip,\n pageSize\n );\n const totalItems = await organizationService.countOrganizations(filters);\n\n const responseData = formatPaginatedResponse<Organization>({\n data: organizations,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.status(200).json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetOrganizationParam = { organizationId: string };\nexport type GetOrganizationResult = ResponseData<Organization>;\n\n/**\n * Retrieves an organization by its ID.\n */\nexport const getOrganization = async (\n req: Request<GetOrganizationParam, any, any>,\n res: ResponseWithInformation<GetOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organizationRights } = res.locals;\n const { organizationId } = req.params as Partial<GetOrganizationParam>;\n\n if (!organizationRights?.read) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_READ'\n );\n return;\n }\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n const responseData = formatResponse<Organization>({ data: organization });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddOrganizationBody = OrganizationCreationData;\nexport type AddOrganizationResult = ResponseData<Organization>;\n\n/**\n * Adds a new organization to the database.\n */\nexport const addOrganization = async (\n req: Request<any, any, AddOrganizationBody>,\n res: ResponseWithInformation<AddOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n const organization = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const newOrganization = await organizationService.createOrganization(\n organization,\n user._id\n );\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization created successfully',\n fr: 'Organisation créée avec succès',\n es: 'Organización creada con éxito',\n }),\n description: t({\n en: 'Your organization has been created successfully',\n fr: 'Votre organisation a été créée avec succès',\n es: 'Su organización ha sido creada con éxito',\n }),\n data: newOrganization,\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 UpdateOrganizationBody = Partial<Organization>;\nexport type UpdateOrganizationResult = ResponseData<Organization>;\n\n/**\n * Updates an existing organization in the database.\n */\nexport const updateOrganization = async (\n req: Request<undefined, undefined, UpdateOrganizationBody>,\n res: ResponseWithInformation<UpdateOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { isOrganizationAdmin, organization, organizationRights } = res.locals;\n const organizationFields = req.body;\n\n if (!organizationFields) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!organizationRights?.write) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_WRITE'\n );\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n try {\n const updatedOrganization =\n await organizationService.updateOrganizationById(\n organization._id,\n organizationFields\n );\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: updatedOrganization,\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 };\n\nexport type OrganizationMemberByIdOption = {\n userId: string | ObjectId;\n isAdmin?: boolean;\n};\n\nexport type AddOrganizationMemberBody = {\n userEmail: string;\n};\nexport type AddOrganizationMemberResult = ResponseData<Organization>;\n\n/**\n * Add member to the organization in the database.\n */\nexport const addOrganizationMember = async (\n req: Request<any, any, AddOrganizationMemberBody>,\n res: ResponseWithInformation<AddOrganizationMemberResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, isOrganizationAdmin, user, organizationRights } =\n res.locals;\n const { userEmail } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n if (!organizationRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_ADMIN'\n );\n return;\n }\n\n if (!organization.plan) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_NOT_FOUND', {\n organizationId: organization._id,\n });\n return;\n }\n\n const planType = getPLanDetails(organization.plan);\n\n if (\n planType.numberOfOrganizationUsers &&\n organization.membersIds.length >= planType.numberOfOrganizationUsers\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_USER_LIMIT_REACHED', {\n organizationId: organization._id,\n });\n return;\n }\n\n try {\n let newMember = await userService.getUserByEmail(userEmail);\n\n if (!newMember) {\n // Create user if not found\n const newUser = await userService.createUser({ email: userEmail });\n if (!newUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_CREATION_FAILED', {\n email: userEmail,\n });\n return;\n }\n\n newMember = newUser;\n }\n\n await sendEmail({\n type: 'invite',\n to: userEmail,\n username: newMember.email.slice(0, newMember.email.indexOf('@')),\n invitedByUsername: user.name,\n invitedByEmail: user.email,\n organizationName: organization.name,\n inviteLink: sessionAuthRoutes.loginEmailPassword.url,\n inviteFromIp: req.ip ?? '',\n inviteFromLocation: req.hostname,\n });\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization._id, {\n ...organization,\n membersIds: [...organization.membersIds, newMember._id],\n });\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: updatedOrganization,\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 UpdateOrganizationMembersBody = Partial<{\n membersIds: OrganizationMemberByIdOption[];\n}>;\nexport type UpdateOrganizationMembersResult = ResponseData<Organization>;\n\n/**\n * Update members to the organization in the database.\n */\nexport const updateOrganizationMembers = async (\n req: Request<any, any, UpdateOrganizationMembersBody>,\n res: ResponseWithInformation<UpdateOrganizationMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, organizationRights, isOrganizationAdmin } = res.locals;\n const { membersIds } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n if (!organizationRights?.write) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_WRITE'\n );\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_MEMBER'\n );\n return;\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_ADMIN'\n );\n return;\n }\n\n try {\n let existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds?.map((member) => member.userId);\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => {\n const isAdmin =\n membersIds.find(\n (member) => String(member.userId) === String(user._id)\n )?.isAdmin ?? false;\n\n return {\n user,\n isAdmin,\n };\n });\n\n existingUsers = userMap;\n }\n }\n\n const formattedMembers: ObjectId[] = existingUsers.map(\n (user) => user.user._id\n );\n const formattedAdmin: ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user._id);\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization._id, {\n ...organization,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n });\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: updatedOrganization,\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 DeleteOrganizationResult = ResponseData<Organization>;\n\n/**\n * Deletes an organization from the database by its ID.\n */\nexport const deleteOrganization = async (\n _req: Request,\n res: ResponseWithInformation,\n _next: NextFunction\n): Promise<void> => {\n const { isOrganizationAdmin, organization, organizationRights } = res.locals;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n if (!organizationRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_ADMIN'\n );\n return;\n }\n\n try {\n const deletedOrganization =\n await organizationService.deleteOrganizationById(organization._id);\n\n if (!deletedOrganization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND', {\n organizationId: organization._id,\n });\n return;\n }\n\n logger.info(`Organization deleted: ${String(deletedOrganization._id)}`);\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization deleted successfully',\n fr: 'Organisation supprimée avec succès',\n es: 'Organización eliminada con éxito',\n }),\n description: t({\n en: 'Your organization has been deleted successfully',\n fr: 'Votre organisation a été supprimée avec succès',\n es: 'Su organización ha sido eliminada con éxito',\n }),\n data: deletedOrganization,\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 SelectOrganizationParam = { organizationId: ObjectId | string };\nexport type SelectOrganizationResult = ResponseData<Organization>;\n\n/**\n * Select an organization.\n */\nexport const selectOrganization = async (\n req: Request<SelectOrganizationParam>,\n res: ResponseWithInformation<SelectOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organizationId } = req.params as Partial<SelectOrganizationParam>;\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n sessionAuthService.setOrganizationAuth(res, organization);\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization retrieved successfully',\n fr: 'Organisation récupérée avec succès',\n es: 'Organización recuperada con éxito',\n }),\n description: t({\n en: 'Your organization has been retrieved successfully',\n fr: 'Votre organisation a été récupérée avec succès',\n es: 'Su organización ha sido recuperada con éxito',\n }),\n data: organization,\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 UnselectOrganizationResult = ResponseData<null>;\n\n/**\n * Unselect an organization.\n */\nexport const unselectOrganization = (\n _req: Request,\n res: ResponseWithInformation<UnselectOrganizationResult>,\n _next: NextFunction\n): void => {\n try {\n sessionAuthService.clearOrganizationAuth(res);\n sessionAuthService.clearProjectAuth(res);\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Organization unselected successfully',\n fr: 'Organisation désélectionnée avec succès',\n es: 'Organización deseleccionada con éxito',\n }),\n description: t({\n en: 'Your organization has been unselected successfully',\n fr: 'Votre organisation a été désélectionnée avec succès',\n es: 'Su organización ha sido deseleccionada 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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","names":[]}
1
+ {"version":3,"sources":["../../../src/controllers/organization.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport { getSessionAuthRoutes } from '@routes/sessionAuth.routes';\nimport { sendEmail } from '@services/email.service';\nimport * as projectService from '@services/project.service';\nimport * as sessionAuthService from '@services/sessionAuth.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getOrganizationFiltersAndPagination,\n type OrganizationFiltersParams,\n type OrganizationFilters,\n} from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\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 { ObjectId } from 'mongoose';\nimport type { User } from 'oauth2-server';\nimport { Stripe } from 'stripe';\nimport * as organizationService from '@/services/organization.service';\nimport type {\n Organization,\n OrganizationCreationData,\n} from '@/types/organization.types';\n\nexport type GetOrganizationsParams =\n FiltersAndPagination<OrganizationFiltersParams>;\nexport type GetOrganizationsResult = PaginatedResponse<Organization>;\n\n/**\n * Retrieves a list of organizations based on filters and pagination.\n */\nexport const getOrganizations = async (\n req: Request<GetOrganizationsParams>,\n res: ResponseWithInformation<GetOrganizationsResult>,\n _next: NextFunction\n) => {\n const { user, organizationRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getOrganizationFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organizationRights?.read) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_READ'\n );\n return;\n }\n\n const restrictedFilter: OrganizationFilters = {\n ...filters,\n\n membersIds: { $in: [...(filters.membersIds ?? []), String(user._id)] },\n };\n\n try {\n const organizations = await organizationService.findOrganizations(\n restrictedFilter,\n skip,\n pageSize\n );\n const totalItems = await organizationService.countOrganizations(filters);\n\n const responseData = formatPaginatedResponse<Organization>({\n data: organizations,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.status(200).json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetOrganizationParam = { organizationId: string };\nexport type GetOrganizationResult = ResponseData<Organization>;\n\n/**\n * Retrieves an organization by its ID.\n */\nexport const getOrganization = async (\n req: Request<GetOrganizationParam, any, any>,\n res: ResponseWithInformation<GetOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organizationRights } = res.locals;\n const { organizationId } = req.params as Partial<GetOrganizationParam>;\n\n if (!organizationRights?.read) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_READ'\n );\n return;\n }\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n const responseData = formatResponse<Organization>({ data: organization });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddOrganizationBody = OrganizationCreationData;\nexport type AddOrganizationResult = ResponseData<Organization>;\n\n/**\n * Adds a new organization to the database.\n */\nexport const addOrganization = async (\n req: Request<any, any, AddOrganizationBody>,\n res: ResponseWithInformation<AddOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n const organization = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const newOrganization = await organizationService.createOrganization(\n organization,\n user._id\n );\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization created successfully',\n fr: 'Organisation créée avec succès',\n es: 'Organización creada con éxito',\n }),\n description: t({\n en: 'Your organization has been created successfully',\n fr: 'Votre organisation a été créée avec succès',\n es: 'Su organización ha sido creada con éxito',\n }),\n data: newOrganization,\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 UpdateOrganizationBody = Partial<Organization>;\nexport type UpdateOrganizationResult = ResponseData<Organization>;\n\n/**\n * Updates an existing organization in the database.\n */\nexport const updateOrganization = async (\n req: Request<undefined, undefined, UpdateOrganizationBody>,\n res: ResponseWithInformation<UpdateOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { isOrganizationAdmin, organization, organizationRights } = res.locals;\n const organizationFields = req.body;\n\n if (!organizationFields) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!organizationRights?.write) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_WRITE'\n );\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n try {\n const updatedOrganization =\n await organizationService.updateOrganizationById(\n organization._id,\n organizationFields\n );\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: updatedOrganization,\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 };\n\nexport type OrganizationMemberByIdOption = {\n userId: string | ObjectId;\n isAdmin?: boolean;\n};\n\nexport type AddOrganizationMemberBody = {\n userEmail: string;\n};\nexport type AddOrganizationMemberResult = ResponseData<Organization>;\n\n/**\n * Add member to the organization in the database.\n */\nexport const addOrganizationMember = async (\n req: Request<any, any, AddOrganizationMemberBody>,\n res: ResponseWithInformation<AddOrganizationMemberResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, isOrganizationAdmin, user, organizationRights } =\n res.locals;\n const { userEmail } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n if (!organizationRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_ADMIN'\n );\n return;\n }\n\n if (!organization.plan) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_NOT_FOUND', {\n organizationId: organization._id,\n });\n return;\n }\n\n const planType = getPLanDetails(organization.plan);\n\n if (\n planType.numberOfOrganizationUsers &&\n organization.membersIds.length >= planType.numberOfOrganizationUsers\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_USER_LIMIT_REACHED', {\n organizationId: organization._id,\n });\n return;\n }\n\n try {\n let newMember = await userService.getUserByEmail(userEmail);\n\n if (!newMember) {\n // Create user if not found\n const newUser = await userService.createUser({ email: userEmail });\n if (!newUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_CREATION_FAILED', {\n email: userEmail,\n });\n return;\n }\n\n newMember = newUser;\n }\n\n await sendEmail({\n type: 'invite',\n to: userEmail,\n username: newMember.email.slice(0, newMember.email.indexOf('@')),\n invitedByUsername: user.name,\n invitedByEmail: user.email,\n organizationName: organization.name,\n inviteLink: getSessionAuthRoutes().loginEmailPassword.url,\n inviteFromIp: req.ip ?? '',\n inviteFromLocation: req.hostname,\n });\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization._id, {\n ...organization,\n membersIds: [...organization.membersIds, newMember._id],\n });\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: updatedOrganization,\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 UpdateOrganizationMembersBody = Partial<{\n membersIds: OrganizationMemberByIdOption[];\n}>;\nexport type UpdateOrganizationMembersResult = ResponseData<Organization>;\n\n/**\n * Update members to the organization in the database.\n */\nexport const updateOrganizationMembers = async (\n req: Request<any, any, UpdateOrganizationMembersBody>,\n res: ResponseWithInformation<UpdateOrganizationMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, organizationRights, isOrganizationAdmin } = res.locals;\n const { membersIds } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n if (!organizationRights?.write) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_WRITE'\n );\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_MEMBER'\n );\n return;\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_ADMIN'\n );\n return;\n }\n\n try {\n let existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds?.map((member) => member.userId);\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => {\n const isAdmin =\n membersIds.find(\n (member) => String(member.userId) === String(user._id)\n )?.isAdmin ?? false;\n\n return {\n user,\n isAdmin,\n };\n });\n\n existingUsers = userMap;\n }\n }\n\n const formattedMembers: ObjectId[] = existingUsers.map(\n (user) => user.user._id\n );\n const formattedAdmin: ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user._id);\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization._id, {\n ...organization,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n });\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: updatedOrganization,\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 DeleteOrganizationResult = ResponseData<Organization>;\n\n/**\n * Deletes an organization from the database by its ID.\n */\nexport const deleteOrganization = async (\n _req: Request,\n res: ResponseWithInformation,\n _next: NextFunction\n): Promise<void> => {\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n const { isOrganizationAdmin, organization, organizationRights } = res.locals;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n return;\n }\n\n if (!organizationRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_ADMIN'\n );\n return;\n }\n\n const projects = await projectService.findProjects({\n organizationId: organization._id,\n });\n\n if (projects.length > 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECTS_EXIST', {\n organizationId: organization._id,\n });\n return;\n }\n\n try {\n // Cancel the subscription on Stripe if it exists\n if (organization.plan?.subscriptionId) {\n await stripe.subscriptions.cancel(organization.plan.subscriptionId);\n }\n\n const deletedOrganization =\n await organizationService.deleteOrganizationById(organization._id);\n\n if (!deletedOrganization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND', {\n organizationId: organization._id,\n });\n return;\n }\n\n logger.info(`Organization deleted: ${String(deletedOrganization._id)}`);\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization deleted successfully',\n fr: 'Organisation supprimée avec succès',\n es: 'Organización eliminada con éxito',\n }),\n description: t({\n en: 'Your organization has been deleted successfully',\n fr: 'Votre organisation a été supprimée avec succès',\n es: 'Su organización ha sido eliminada con éxito',\n }),\n data: deletedOrganization,\n });\n\n sessionAuthService.clearOrganizationAuth(res);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type SelectOrganizationParam = { organizationId: ObjectId | string };\nexport type SelectOrganizationResult = ResponseData<Organization>;\n\n/**\n * Select an organization.\n */\nexport const selectOrganization = async (\n req: Request<SelectOrganizationParam>,\n res: ResponseWithInformation<SelectOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organizationId } = req.params as Partial<SelectOrganizationParam>;\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n sessionAuthService.setOrganizationAuth(res, organization);\n\n const responseData = formatResponse<Organization>({\n message: t({\n en: 'Organization retrieved successfully',\n fr: 'Organisation récupérée avec succès',\n es: 'Organización recuperada con éxito',\n }),\n description: t({\n en: 'Your organization has been retrieved successfully',\n fr: 'Votre organisation a été récupérée avec succès',\n es: 'Su organización ha sido recuperada con éxito',\n }),\n data: organization,\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 UnselectOrganizationResult = ResponseData<null>;\n\n/**\n * Unselect an organization.\n */\nexport const unselectOrganization = (\n _req: Request,\n res: ResponseWithInformation<UnselectOrganizationResult>,\n _next: NextFunction\n): void => {\n try {\n sessionAuthService.clearOrganizationAuth(res);\n sessionAuthService.clearProjectAuth(res);\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Organization unselected successfully',\n fr: 'Organisation désélectionnée avec succès',\n es: 'Organización deseleccionada con éxito',\n }),\n description: t({\n en: 'Your organization has been unselected successfully',\n fr: 'Votre organisation a été désélectionnée avec succès',\n es: 'Su organización ha sido deseleccionada 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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","names":[]}
@@ -375,6 +375,7 @@ const deleteProject = async (_req, res, _next) => {
375
375
  }),
376
376
  data: formattedProject
377
377
  });
378
+ sessionAuthService.clearProjectAuth(res);
378
379
  res.json(responseData);
379
380
  return;
380
381
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as projectService from '@services/project.service';\nimport * as sessionAuthService from '@services/sessionAuth.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 ProjectFilters,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { getPLanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n type ResponseData,\n type PaginatedResponse,\n formatResponse,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport type { ObjectId } from 'mongoose';\nimport type { User } from 'oauth2-server';\nimport type {\n Project,\n ProjectAPI,\n ProjectCreationData,\n ProjectData,\n ProjectConfiguration,\n} from '@/types/project.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: ResponseWithInformation<GetProjectsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, projectRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(req);\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 (!projectRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_READ');\n return;\n }\n\n const restrictedFilter: ProjectFilters = {\n ...filters,\n membersIds: { $in: [...(filters.membersIds ?? []), String(user._id)] },\n organizationId: String(organization._id),\n };\n\n try {\n const projects = await projectService.findProjects(\n restrictedFilter,\n skip,\n pageSize\n );\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(\n projects,\n user,\n res.locals.isProjectAdmin\n );\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: ResponseWithInformation<AddProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, isOrganizationAdmin } = 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 (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n }\n\n if (!projectData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\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, user, true);\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<Project>;\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: ResponseWithInformation<UpdateProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, projectRights, project, user, isProjectAdmin } =\n 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 (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n if (!projectRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_WRITE');\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 try {\n const updatedProject = await projectService.updateProjectById(\n project._id,\n projectData\n );\n\n const formattedProject = mapProjectToAPI(\n updatedProject,\n user,\n isProjectAdmin\n );\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 | 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: ResponseWithInformation<UpdateProjectMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, isProjectAdmin, organization, projectRights } =\n 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 (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_PROJECT'\n );\n return;\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\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 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 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: ObjectId[] = existingUsers.map(\n (user) => user.user._id\n );\n const formattedAdmin: 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(\n updatedOrganization,\n user,\n isProjectAdmin\n );\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: ResponseWithInformation<PushProjectConfigurationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, isProjectAdmin } = 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 (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_PROJECT'\n );\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: ResponseWithInformation<DeleteProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, project, projectRights, isProjectAdmin } =\n 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 (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\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 formattedProject = mapProjectToAPI(\n deletedProject,\n user,\n isProjectAdmin\n );\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: 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 SelectProjectParam = { projectId: ObjectId | string };\nexport type SelectProjectResult = ResponseData<Project>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n req: Request<SelectProjectParam>,\n res: ResponseWithInformation<SelectProjectResult>,\n _next: NextFunction\n) => {\n const { projectId } = req.params;\n\n if (!projectId) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_NOT_FOUND');\n return;\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n sessionAuthService.setProjectAuth(res, project);\n\n const responseData = formatResponse<Project>({\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: 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 = (\n _req: Request,\n res: ResponseWithInformation<UnselectProjectResult>,\n _next: NextFunction\n) => {\n try {\n sessionAuthService.clearProjectAuth(res);\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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","names":["user"]}
1
+ {"version":3,"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as projectService from '@services/project.service';\nimport * as sessionAuthService from '@services/sessionAuth.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 ProjectFilters,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { getPLanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n type ResponseData,\n type PaginatedResponse,\n formatResponse,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport type { ObjectId } from 'mongoose';\nimport type { User } from 'oauth2-server';\nimport type {\n Project,\n ProjectAPI,\n ProjectCreationData,\n ProjectData,\n ProjectConfiguration,\n} from '@/types/project.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: ResponseWithInformation<GetProjectsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, projectRights } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(req);\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 (!projectRights?.read) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_READ');\n return;\n }\n\n const restrictedFilter: ProjectFilters = {\n ...filters,\n membersIds: { $in: [...(filters.membersIds ?? []), String(user._id)] },\n organizationId: String(organization._id),\n };\n\n try {\n const projects = await projectService.findProjects(\n restrictedFilter,\n skip,\n pageSize\n );\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(\n projects,\n user,\n res.locals.isProjectAdmin\n );\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: ResponseWithInformation<AddProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, isOrganizationAdmin } = 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 (!isOrganizationAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_ORGANIZATION'\n );\n }\n\n if (!projectData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\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, user, true);\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<Project>;\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: ResponseWithInformation<UpdateProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, projectRights, project, user, isProjectAdmin } =\n 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 (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\n return;\n }\n\n if (!projectRights?.write) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_WRITE');\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 try {\n const updatedProject = await projectService.updateProjectById(\n project._id,\n projectData\n );\n\n const formattedProject = mapProjectToAPI(\n updatedProject,\n user,\n isProjectAdmin\n );\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 | 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: ResponseWithInformation<UpdateProjectMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, isProjectAdmin, organization, projectRights } =\n 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 (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_PROJECT'\n );\n return;\n }\n\n if (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\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 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 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: ObjectId[] = existingUsers.map(\n (user) => user.user._id\n );\n const formattedAdmin: 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(\n updatedOrganization,\n user,\n isProjectAdmin\n );\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: ResponseWithInformation<PushProjectConfigurationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, isProjectAdmin } = 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 (!isProjectAdmin) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_IS_NOT_ADMIN_OF_PROJECT'\n );\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: ResponseWithInformation<DeleteProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, project, projectRights, isProjectAdmin } =\n 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 (!projectRights?.admin) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_ADMIN');\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 formattedProject = mapProjectToAPI(\n deletedProject,\n user,\n isProjectAdmin\n );\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: formattedProject,\n });\n\n sessionAuthService.clearProjectAuth(res);\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: ObjectId | string };\nexport type SelectProjectResult = ResponseData<Project>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n req: Request<SelectProjectParam>,\n res: ResponseWithInformation<SelectProjectResult>,\n _next: NextFunction\n) => {\n const { projectId } = req.params;\n\n if (!projectId) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_NOT_FOUND');\n return;\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n sessionAuthService.setProjectAuth(res, project);\n\n const responseData = formatResponse<Project>({\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: 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 = (\n _req: Request,\n res: ResponseWithInformation<UnselectProjectResult>,\n _next: NextFunction\n) => {\n try {\n sessionAuthService.clearProjectAuth(res);\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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","names":["user"]}
@@ -1,6 +1,6 @@
1
1
  import crypto from "crypto";
2
2
  import { logger } from "./../logger/index.mjs";
3
- import { sessionAuthRoutes } from "./../routes/sessionAuth.routes.mjs";
3
+ import { getSessionAuthRoutes } from "./../routes/sessionAuth.routes.mjs";
4
4
  import { sendEmail } from "./../services/email.service.mjs";
5
5
  import * as sessionAuthService from "./../services/sessionAuth.service.mjs";
6
6
  import * as userService from "./../services/user.service.mjs";
@@ -82,7 +82,7 @@ const registerEmailPassword = async (req, res, _next) => {
82
82
  type: "validate",
83
83
  to: user2.email,
84
84
  username: user2.name ?? user2.email.split("@")[0],
85
- validationLink: sessionAuthRoutes.validEmail.url({
85
+ validationLink: getSessionAuthRoutes().validEmail.url({
86
86
  userId: String(user2._id),
87
87
  secret: user2.provider?.find((provider) => provider.provider === "email")?.secret ?? "",
88
88
  callBack_url
@@ -376,12 +376,7 @@ const askResetPassword = async (req, res, _next) => {
376
376
  type: "resetPassword",
377
377
  to: updatedUser.email,
378
378
  username: updatedUser.name,
379
- resetLink: sessionAuthRoutes.resetPassword.url({
380
- userId: String(updatedUser._id),
381
- secret: updatedUser.provider?.find(
382
- (provider) => provider.provider === "email"
383
- )?.secret ?? ""
384
- })
379
+ resetLink: `${process.env.CLIENT_URL}/auth/password/reset/${String(updatedUser._id)}/${updatedUser.provider?.find((provider) => provider.provider === "email")?.secret ?? ""}`
385
380
  });
386
381
  const responseData = formatResponse({
387
382
  message: t({
@@ -403,9 +398,8 @@ const askResetPassword = async (req, res, _next) => {
403
398
  return;
404
399
  }
405
400
  };
406
- const resetPassword = async (req, res, _next) => {
407
- const { secret, userId } = req.params;
408
- const password = req.body.password;
401
+ const definePassword = async (req, res, _next) => {
402
+ const { secret, userId, password } = req.body;
409
403
  const userIdString = String(userId);
410
404
  if (!userId || !userIdString || !Types.ObjectId.isValid(userIdString)) {
411
405
  ErrorHandler.handleGenericErrorResponse(res, "INVALID_USER_ID", { userId });
@@ -778,6 +772,7 @@ const googleCallback = async (req, res, _next) => {
778
772
  export {
779
773
  askResetPassword,
780
774
  checkIfUserHasPassword,
775
+ definePassword,
781
776
  getSessionInformation,
782
777
  githubCallback,
783
778
  githubLoginQuery,
@@ -786,7 +781,6 @@ export {
786
781
  logOut,
787
782
  loginEmailPassword,
788
783
  registerEmailPassword,
789
- resetPassword,
790
784
  sendVerificationUpdate,
791
785
  setCSRFToken,
792
786
  updatePassword,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/sessionAuth.controller.ts"],"sourcesContent":["import crypto from 'crypto';\nimport { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport { sessionAuthRoutes } from '@routes/sessionAuth.routes';\nimport { sendEmail } from '@services/email.service';\nimport * as sessionAuthService from '@services/sessionAuth.service';\nimport * as userService from '@services/user.service';\nimport { generateToken } from '@utils/CSRF';\nimport { type AppError, ErrorHandler, GenericError } from '@utils/errors';\nimport { HttpStatusCodes } from '@utils/httpStatusCodes';\nimport { mapOrganizationToAPI } from '@utils/mapper/organization';\nimport { mapProjectToAPI } from '@utils/mapper/project';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport { t } from 'express-intlayer';\nimport { Types } from 'mongoose';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { OrganizationAPI } from '@/types/organization.types';\nimport type { ProjectAPI } from '@/types/project.types';\nimport type {\n Session,\n GithubSessionProvider,\n GoogleSessionProvider,\n} from '@/types/session.types';\nimport type { User, UserAPI, UserData } from '@/types/user.types';\n\nexport type CSRFTokenData = { csrf_token: string };\nexport type SetCSRFTokenResult = ResponseData<CSRFTokenData>;\n\nexport const setCSRFToken = (\n req: Request,\n res: Response<SetCSRFTokenResult>,\n _next: NextFunction\n) => {\n const csrf_token = generateToken(req, res);\n\n const responseData = formatResponse<CSRFTokenData>({\n data: { csrf_token },\n });\n\n res.locals.csrf_token = csrf_token;\n res.json(responseData);\n};\n\nexport type RegisterBody = { email: string; password?: string };\nexport type RegisterQuery = { callBack_url?: string };\nexport type RegisterResult = ResponseData<UserAPI>;\n\n/**\n * Handles user registration.\n */\nexport const registerEmailPassword = async (\n req: Request<any, any, RegisterBody, RegisterQuery>,\n res: ResponseWithInformation<RegisterResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n const { callBack_url } = req.query;\n\n if (user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_ALREADY_LOGGED_IN');\n return;\n }\n\n if (callBack_url && !callBack_url.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const userData = req.body;\n\n try {\n let user = await userService.getUserByEmail(userData.email);\n\n if (user) {\n const emailProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (emailProvider?.emailValidated) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'EMAIL_ALREADY_REGISTERED'\n );\n return;\n } else if (emailProvider) {\n user = await sessionAuthService.updateUserProvider(user._id, 'email', {\n provider: 'email',\n emailValidated: undefined,\n secret: uuidv4(),\n });\n } else {\n user = await sessionAuthService.addUserProvider(user._id, {\n provider: 'email',\n emailValidated: undefined,\n secret: uuidv4(),\n });\n }\n } else {\n user = await userService.createUser({\n ...userData,\n provider: [\n {\n provider: 'email',\n emailValidated: undefined,\n secret: uuidv4(),\n },\n ],\n });\n\n logger.info(`New registration: ${user.name} - ${user.email}`);\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_CREATION_FAILED', {\n email: userData.email,\n });\n return;\n }\n\n await sendEmail({\n type: 'validate',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n validationLink: sessionAuthRoutes.validEmail.url({\n userId: String(user._id),\n secret:\n user.provider?.find((provider) => provider.provider === 'email')\n ?.secret ?? '',\n callBack_url,\n }),\n });\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User registered successfully',\n fr: 'Utilisateur enregistré avec succès',\n es: 'Usuario registrado con éxito',\n }),\n description: t({\n en: 'Your user has been registered successfully. Please check your email to validate your account.',\n fr: 'Votre utilisateur a été enregistré avec succès. Veuillez vérifier votre e-mail pour valider votre compte.',\n es: 'Su usuario ha sido registrado con éxito. Por favor, revise su correo electrónico para validar su cuenta.',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type LoginBody = {\n email: string;\n password: string;\n};\nexport type LoginResult = ResponseData<UserAPI>;\n\n/**\n * Handles user login.\n */\nexport const loginEmailPassword = async (\n req: Request<any, any, LoginBody>,\n res: ResponseWithInformation<LoginResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n\n if (user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_ALREADY_LOGGED_IN');\n return;\n }\n\n const { email, password } = req.body;\n\n try {\n const { user: loggedInUser, error } =\n await sessionAuthService.testUserPassword(email, password);\n\n if (error) {\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'LOGIN_FAILED');\n return;\n }\n }\n\n if (!loggedInUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n await sessionAuthService.setUserAuth(res, loggedInUser);\n\n const formattedUser = mapUserToAPI(loggedInUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User logged in successfully',\n fr: 'Utilisateur connecté avec succès',\n es: 'Usuario conectado con éxito',\n }),\n description: t({\n en: 'Your user has been logged in successfully',\n fr: 'Votre utilisateur a été connecté avec succès',\n es: 'Su usuario ha sido conectado con éxito',\n }),\n data: formattedUser,\n });\n\n logger.info(`Login: ${loggedInUser.email}`);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type LogoutResult = ResponseData<undefined>;\n\n/**\n * Handles user logout and clears cookies.\n */\nexport const logOut = async (\n _req: Request,\n res: ResponseWithInformation<LogoutResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n await sessionAuthService.clearUserAuth(res);\n sessionAuthService.clearOrganizationAuth(res);\n sessionAuthService.clearProjectAuth(res);\n\n logger.info(`Logout: ${user.name} - ${user.email}`);\n\n const responseData = formatResponse<undefined>({\n message: t({\n en: 'User logged out successfully',\n fr: 'Utilisateur déconnecté avec succès',\n es: 'Usuario desconectado con éxito',\n }),\n description: t({\n en: 'Your user has been logged out successfully',\n fr: 'Votre utilisateur a été déconnecté avec succès',\n es: 'Su usuario ha sido desconectado con éxito',\n }),\n data: undefined,\n });\n\n res.json(responseData);\n};\n\nexport type UpdatePasswordBody = {\n oldPassword?: string;\n newPassword: string;\n};\nexport type UpdatePasswordResult = ResponseData<UserAPI>;\n\n/**\n * Updates the user's password.\n */\nexport const updatePassword = async (\n req: Request<undefined, any, UpdatePasswordBody>,\n res: ResponseWithInformation<UpdatePasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { oldPassword, newPassword } = req.body;\n let { user } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const userEmailProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (!userEmailProvider) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_PROVIDER_NOT_FOUND', {\n provider: 'email',\n });\n return;\n }\n\n if (userEmailProvider.passwordHash && !oldPassword) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_PREVIOUS_PASSWORD_NOT_PROVIDED'\n );\n return;\n }\n\n try {\n if (oldPassword) {\n const { error } = await sessionAuthService.testUserPassword(\n user.email,\n oldPassword\n );\n\n if (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'LOGIN_FAILED');\n return;\n }\n }\n\n user = await sessionAuthService.changeUserPassword(user._id, newPassword);\n\n if (!user || typeof user !== 'object') {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n logger.info(\n `Password changed - User : Name : ${user.name}, id : ${String(user._id)}`\n );\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Password changed successfully',\n fr: 'Mot de passe modifié avec succès',\n es: 'Contraseña cambiada con éxito',\n }),\n description: t({\n en: 'Your password has been changed successfully',\n fr: 'Votre mot de passe a été modifié avec succès',\n es: 'Su contraseña ha sido cambiada con éxito',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nlet clients: Array<{ id: number; userId: string; res: Response }> = [];\n\nexport const sendVerificationUpdate = (user: User) => {\n const filteredClients = clients.filter(\n (client) => String(client.userId) === String(user._id)\n );\n\n for (const client of filteredClients) {\n const provider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (provider?.emailValidated) {\n client.res.write(\n `data: ${JSON.stringify({ userId: user._id, status: 'verified' })}\\n\\n`\n );\n continue;\n }\n\n client.res.write(\n `data: ${JSON.stringify({ userId: user._id, status: 'waiting' })}\\n\\n`\n );\n }\n};\n\ntype CheckIfUserHasPasswordResultData = {\n hasPassword: boolean;\n};\nexport type CheckIfUserHasPasswordResult =\n ResponseData<CheckIfUserHasPasswordResultData>;\n\nexport const checkIfUserHasPassword = async (\n _req: Request,\n res: ResponseWithInformation<CheckIfUserHasPasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const userProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n const responseData = formatResponse<CheckIfUserHasPasswordResultData>({\n data: {\n hasPassword: Boolean(userProvider?.passwordHash),\n },\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type ValidEmailParams = { secret: string; userId: string };\nexport type ValidEmailQuery = { callBack_url?: string };\nexport type ValidEmailResult = ResponseData<UserAPI>;\n\n/**\n * Validates a user's email based on the provided secret and user ID.\n */\nexport const validEmail = async (\n req: Request<ValidEmailParams, any, any, ValidEmailQuery>,\n res: ResponseWithInformation<ValidEmailResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId, secret } = req.params;\n const callBack_url = `${req.query.callBack_url ?? `${process.env.CLIENT_URL}/auth/login`}?userId=${userId}`;\n\n if (!Types.ObjectId.isValid(userId.toString())) {\n ErrorHandler.handleGenericErrorResponse(res, 'INVALID_USER_ID');\n return;\n }\n\n const user = await userService.getUserById(userId);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED', {\n userId,\n });\n return;\n }\n\n if (callBack_url && !callBack_url.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const provider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (provider?.emailValidated) {\n res.redirect(callBack_url);\n }\n\n if (!provider?.secret) {\n throw new GenericError('USER_PROVIDER_SECRET_NOT_DEFINED', { userId });\n }\n\n if (\n !crypto.timingSafeEqual(Buffer.from(provider.secret), Buffer.from(secret))\n ) {\n throw new GenericError('USER_PROVIDER_SECRET_NOT_VALID', { userId });\n }\n\n await sessionAuthService.updateUserProvider(userId, 'email', {\n secret: undefined,\n emailValidated: new Date(),\n });\n\n logger.info(\n `User activated - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n\n sendVerificationUpdate(user);\n\n await sessionAuthService.setUserAuth(res, user);\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name,\n loginLink: callBack_url,\n });\n\n res.redirect(callBack_url);\n};\n\nexport type VerifyEmailStatusSSEParams = { userId: string };\n\n/**\n * SSE to check the email verification status\n */\nexport const verifyEmailStatusSSE = async (\n req: Request<VerifyEmailStatusSSEParams, any, any>,\n res: ResponseWithInformation\n) => {\n // Set headers for SSE\n res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');\n res.setHeader('Cache-Control', 'no-cache, no-transform');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no'); // For Nginx buffering\n\n // Send initial data to ensure the connection is open\n res.write(':\\n\\n'); // Comment to keep connection alive\n res.flushHeaders();\n\n const { userId } = req.params; // Get user ID from query parameters\n const clientId = Date.now();\n\n const user = await userService.getUserById(userId);\n\n if (!user) {\n logger.error(`User not found - User ID: ${userId}`);\n res.write(`data: ${JSON.stringify({ userId, status: 'error' })}\\n\\n`);\n res.end();\n return;\n }\n\n // Add client to the list\n const newClient = { id: clientId, userId, res };\n clients.push(newClient);\n\n sendVerificationUpdate(user);\n\n // Remove client on connection close\n req.on('close', () => {\n clients = clients.filter((client) => client.id !== clientId);\n });\n};\n\nexport type AskResetPasswordBody = {\n email: string;\n};\nexport type AskResetPasswordResult = ResponseData<undefined>;\n\n/**\n * Requests a password reset for a user.\n */\nexport const askResetPassword = async (\n req: Request<undefined, any, AskResetPasswordBody>,\n res: ResponseWithInformation<AskResetPasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { email } = req.body as Partial<AskResetPasswordBody>;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'EMAIL_NOT_PROVIDED');\n return;\n }\n\n try {\n const updatedUser = await sessionAuthService.requestPasswordReset(email);\n\n if (!updatedUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND', { email });\n return;\n }\n\n logger.info(\n `Ask changing password - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n await sendEmail({\n type: 'resetPassword',\n to: updatedUser.email,\n username: updatedUser.name,\n resetLink: sessionAuthRoutes.resetPassword.url({\n userId: String(updatedUser._id),\n secret:\n updatedUser.provider?.find(\n (provider) => provider.provider === 'email'\n )?.secret ?? '',\n }),\n });\n\n const responseData = formatResponse<undefined>({\n message: t({\n en: 'Password reset request sent successfully',\n fr: 'Demande de réinitialisation de mot de passe envoyée avec succès',\n es: 'Solicitud de restablecimiento de contraseña enviada con éxito',\n }),\n description: t({\n en: 'Your password reset request has been sent successfully. Please check your email to reset your password.',\n fr: 'Votre demande de réinitialisation de mot de passe a été envoyée avec succès. Veuillez vérifier votre e-mail pour réinitialiser votre mot de passe.',\n es: 'Su solicitud de restablecimiento de contraseña ha sido enviada con éxito. Por favor, revise su correo electrónico para restablecer su contraseña.',\n }),\n data: undefined,\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 ResetPasswordParams = { secret: string; userId: string };\nexport type ResetPasswordResult = ResponseData<UserAPI>;\n\n/**\n * Resets a user's password based on the provided secret and user ID.\n */\nexport const resetPassword = async (\n req: Request<ResetPasswordParams, any, any>,\n res: Response<ResetPasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { secret, userId } = req.params as Partial<ResetPasswordParams>;\n const password: string = req.body.password;\n\n const userIdString = String(userId);\n\n if (!userId || !userIdString || !Types.ObjectId.isValid(userIdString)) {\n ErrorHandler.handleGenericErrorResponse(res, 'INVALID_USER_ID', { userId });\n return;\n }\n\n if (!secret) {\n ErrorHandler.handleGenericErrorResponse(res, 'SECRET_NOT_PROVIDED');\n return;\n }\n\n try {\n const updatedUser = await sessionAuthService.resetUserPassword(\n userId,\n secret,\n password\n );\n\n logger.info(\n `Password changed - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n await sendEmail({\n type: 'passwordChangeConfirmation',\n to: updatedUser.email,\n username: updatedUser.name,\n });\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Password reset successfully',\n fr: 'Réinitialisation du mot de passe réussie',\n es: 'Restablecimiento de contraseña exitoso',\n }),\n description: t({\n en: 'Your password has been reset successfully. You can now log in with your new password',\n fr: 'Votre mot de passe a été réinitialisé avec succès. Vous pouvez maintenant vous connecter avec votre nouveau mot de passe',\n es: 'Su contraseña ha sido restablecida con éxito. Ahora puede iniciar sesión con su nueva contraseña',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type CreateSessionBody = {\n sessionToken: string;\n userId: string;\n expires: Date;\n};\nexport type CreateSessionResult = ResponseData<Session>;\n\nexport type GetSessionInformationQuery = {\n session_token?: string;\n};\ntype SessionInformation = {\n user: UserAPI | null;\n organization: OrganizationAPI | null;\n project: ProjectAPI | null;\n session: Session | null;\n};\nexport type GetSessionInformationResult = ResponseData<SessionInformation>;\n\n/**\n * Gets information about a session for a user.\n */\nexport const getSessionInformation = async (\n req: Request<undefined, undefined, undefined, GetSessionInformationQuery>,\n res: ResponseWithInformation<GetSessionInformationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { session_token: sessionToken } = req.query;\n\n let { user } = res.locals;\n const { organization, project, isOrganizationAdmin, isProjectAdmin } =\n res.locals;\n\n try {\n if (sessionToken) {\n user = await userService.getUserBySession(sessionToken);\n }\n\n if (!user || !user?.session) {\n const responseData = formatResponse<SessionInformation>({\n data: {\n session: null,\n user: null,\n organization: organization?._id\n ? mapOrganizationToAPI(organization, isOrganizationAdmin)\n : null,\n project: project?._id\n ? mapProjectToAPI(project, user, isProjectAdmin)\n : null,\n },\n });\n\n res.json(responseData);\n\n return;\n }\n\n const session = user.session;\n\n const formattedUser: SessionInformation['user'] = {\n ...mapUserToAPI(user),\n role: 'user',\n };\n\n const responseData = formatResponse<SessionInformation>({\n data: {\n session,\n user: formattedUser,\n organization: organization?._id\n ? mapOrganizationToAPI(organization, isOrganizationAdmin)\n : null,\n project: project?._id\n ? mapProjectToAPI(project, user, isProjectAdmin)\n : null,\n },\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GithubLoginQueryParams = {\n origin: string;\n};\nexport type GithubLoginQueryResult = ResponseData<undefined>;\n\nexport const githubLoginQuery = (\n req: Request<undefined, undefined, undefined, GithubLoginQueryParams>,\n res: ResponseWithInformation<GithubLoginQueryResult>,\n _next: NextFunction\n): void => {\n const { origin } = req.query;\n const { user } = res.locals;\n\n if (user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_ALREADY_LOGGED_IN');\n return;\n }\n\n if (origin && !origin.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const encodedOrigin = encodeURIComponent(origin);\n\n const redirectURI = `${process.env.BACKEND_URL}/api/auth/callback/github?redirect_uri=${encodedOrigin}`;\n const encodedRedirectURI = encodeURIComponent(redirectURI);\n\n res.redirect(\n `https://github.com/login/oauth/authorize?client_id=${process.env.GITHUB_CLIENT_ID}&redirect_uri=${encodedRedirectURI}&scope=user:email`\n );\n};\n\nexport type GithubCallbackQuery = {\n code: string;\n redirect_uri: string;\n};\n\nexport type GithubCallbackResult = ResponseData<UserAPI>;\n\n/**\n * Handles GitHub OAuth callback.\n */\nexport const githubCallback = async (\n req: Request<undefined, undefined, undefined, GithubCallbackQuery>,\n res: ResponseWithInformation<GithubCallbackResult>,\n _next: NextFunction\n): Promise<void> => {\n const { code, redirect_uri } = req.query;\n\n if (!code) {\n const errorMessage = 'Code not provided';\n\n logger.error(errorMessage);\n\n res.redirect(redirect_uri);\n return;\n }\n\n if (!redirect_uri) {\n const errorMessage = 'Redirect URI not provided';\n\n logger.error(errorMessage);\n\n res.redirect(redirect_uri);\n return;\n }\n\n if (redirect_uri && !redirect_uri.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n try {\n const tokenResponse = await fetch(\n 'https://github.com/login/oauth/access_token',\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({\n client_id: process.env.GITHUB_CLIENT_ID,\n client_secret: process.env.GITHUB_CLIENT_SECRET,\n code,\n }),\n }\n );\n\n const tokenData = await tokenResponse.json();\n\n const userResponse = await fetch('https://api.github.com/user', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${tokenData.access_token}`,\n Accept: 'application/vnd.github.v3+json',\n },\n });\n\n if (!userResponse.ok) {\n throw new GenericError('GITHUB_FETCH_USER_DATA_FAILED', { userResponse });\n }\n\n const userData = await userResponse.json();\n\n const emailResponse = await fetch('https://api.github.com/user/emails', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${tokenData.access_token}`,\n Accept: 'application/vnd.github.v3+json',\n },\n });\n\n if (!emailResponse.ok) {\n throw new GenericError('GIT_HUB_FETCH_USER_EMAIL_FAILED', {\n emailResponse,\n });\n }\n\n const emails: { primary: boolean; email: string }[] =\n await emailResponse.json();\n\n const primaryEmail = emails.find((email) => email.primary)?.email;\n\n if (!primaryEmail) {\n const errorMessage = 'Primary email not found';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.NOT_FOUND_404;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n let existingUser = await userService.getUserByEmail(primaryEmail);\n\n if (existingUser) {\n const existingProvider = await sessionAuthService.getUserProvider(\n existingUser._id,\n 'github'\n );\n\n if (existingProvider?.providerAccountId !== userData.id) {\n const updatedUser = await sessionAuthService.updateUserProvider(\n existingUser._id,\n 'github',\n {\n providerAccountId: userData.id,\n }\n );\n\n logger.info(\n `GitHub login provider updated - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n if (updatedUser) {\n existingUser = updatedUser;\n }\n }\n\n const updatedUser = await userService.updateUserById(existingUser._id, {\n name: existingUser.name ?? userData.name,\n });\n\n await sessionAuthService.setUserAuth(res, updatedUser);\n\n res.redirect(redirect_uri);\n return;\n }\n\n const userInformation: UserData = {\n name: userData.name,\n email: primaryEmail,\n };\n\n const userProvider: GithubSessionProvider = {\n provider: 'github',\n providerAccountId: userData.id,\n };\n\n const user = await userService.createUser({\n ...userInformation,\n provider: [userProvider],\n });\n\n await sessionAuthService.setUserAuth(res, user);\n\n logger.info(\n `GitHub login - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name,\n loginLink: `${process.env.CLIENT_URL}/auth/login`,\n });\n\n res.redirect(redirect_uri);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GoogleLoginQueryParams = {\n origin: string;\n};\n\nexport type GoogleLoginResult = ResponseData<undefined>;\n\nexport const googleLoginQuery = (\n req: Request<undefined, undefined, undefined, GoogleLoginQueryParams>,\n res: ResponseWithInformation<GoogleLoginResult>,\n _next: NextFunction\n): void => {\n const { origin } = req.query;\n const { user } = res.locals;\n\n if (user) {\n const errorMessage = `User already logged in - ${user?.email}`;\n\n logger.error(errorMessage);\n\n res.redirect(origin);\n return;\n }\n\n if (origin && !origin.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const responseType = 'code';\n const scope = [\n 'https%3A//www.googleapis.com/auth/userinfo.email',\n 'https%3A//www.googleapis.com/auth/userinfo.profile',\n ].join(' ');\n const includeGrantedScopes = 'false';\n\n const encodedOrigin = encodeURIComponent(origin);\n const state = JSON.stringify({ redirect_uri: encodedOrigin });\n\n const redirectURI = `${process.env.BACKEND_URL}/api/auth/callback/google`;\n\n res.redirect(\n `https://accounts.google.com/o/oauth2/v2/auth?client_id=${process.env.GOOGLE_CLIENT_ID}&redirect_uri=${redirectURI}&response_type=${responseType}&scope=${scope}&include_granted_scopes=${includeGrantedScopes}&state=${state}`\n );\n};\n\nexport type GoogleCallbackQuery = {\n code: string;\n state: string;\n};\n\nexport type GoogleCallbackResult = ResponseData<UserAPI>;\n\n/**\n * Handles Google OAuth 2 callback.\n */\nexport const googleCallback = async (\n req: Request<undefined, undefined, undefined, GoogleCallbackQuery>,\n res: ResponseWithInformation<GoogleCallbackResult>,\n _next: NextFunction\n): Promise<void> => {\n const { code, state } = req.query;\n\n const decodedState = decodeURIComponent(state);\n const { redirect_uri } = JSON.parse(decodedState);\n\n if (!code) {\n const errorMessage = 'code not provided';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.BAD_REQUEST_400;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n if (!redirect_uri) {\n const errorMessage = 'Redirect URI not provided';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.BAD_REQUEST_400;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n if (redirect_uri && !redirect_uri.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n try {\n // Exchange the authorization code for an access token\n const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n code,\n redirect_uri: `${process.env.BACKEND_URL}/api/auth/callback/google`,\n client_id: process.env.GOOGLE_CLIENT_ID!,\n client_secret: process.env.GOOGLE_CLIENT_SECRET!,\n grant_type: 'authorization_code',\n }),\n });\n\n const responseData = await tokenResponse.json();\n\n const { access_token: accessToken } = responseData;\n\n if (!accessToken) {\n const errorMessage = 'Failed to fetch access_token';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.INTERNAL_SERVER_ERROR_500;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n const userResponse = await fetch(\n 'https://www.googleapis.com/oauth2/v3/userinfo',\n {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n }\n );\n\n const userData = await userResponse.json();\n\n if (!userData.email) {\n const errorMessage = 'Failed to fetch user data from Google';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.INTERNAL_SERVER_ERROR_500;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n let existingUser = await userService.getUserByEmail(userData.email);\n\n if (existingUser) {\n const existingProvider = await sessionAuthService.getUserProvider(\n existingUser._id,\n 'google'\n );\n\n if (existingProvider?.providerAccountId !== userData.sub) {\n const updatedUser = await sessionAuthService.updateUserProvider(\n existingUser._id,\n 'google',\n {\n providerAccountId: userData.id,\n }\n );\n\n logger.info(\n `Google login provider updated - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n if (updatedUser) {\n existingUser = updatedUser;\n }\n }\n\n const updatedUser = await userService.updateUserById(existingUser._id, {\n name: existingUser.name ?? userData.name,\n });\n\n await sessionAuthService.setUserAuth(res, updatedUser);\n\n res.redirect(redirect_uri);\n return;\n }\n\n const userInformation: UserData = {\n name: userData.name,\n email: userData.email,\n };\n\n const userProvider: GoogleSessionProvider = {\n provider: 'google',\n providerAccountId: userData.id,\n };\n\n const user = await userService.createUser({\n ...userInformation,\n provider: [userProvider],\n });\n\n await sessionAuthService.setUserAuth(res, user);\n\n logger.info(\n `Google login - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name,\n loginLink: `${process.env.CLIENT_URL}/auth/login`,\n });\n\n res.redirect(redirect_uri);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":["user","provider","responseData","updatedUser"]}
1
+ {"version":3,"sources":["../../../src/controllers/sessionAuth.controller.ts"],"sourcesContent":["import crypto from 'crypto';\nimport { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport { getSessionAuthRoutes } from '@routes/sessionAuth.routes';\nimport { sendEmail } from '@services/email.service';\nimport * as sessionAuthService from '@services/sessionAuth.service';\nimport * as userService from '@services/user.service';\nimport { generateToken } from '@utils/CSRF';\nimport { type AppError, ErrorHandler, GenericError } from '@utils/errors';\nimport { HttpStatusCodes } from '@utils/httpStatusCodes';\nimport { mapOrganizationToAPI } from '@utils/mapper/organization';\nimport { mapProjectToAPI } from '@utils/mapper/project';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport { t } from 'express-intlayer';\nimport { Types } from 'mongoose';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { OrganizationAPI } from '@/types/organization.types';\nimport type { ProjectAPI } from '@/types/project.types';\nimport type {\n Session,\n GithubSessionProvider,\n GoogleSessionProvider,\n} from '@/types/session.types';\nimport type { User, UserAPI, UserData } from '@/types/user.types';\n\nexport type CSRFTokenData = { csrf_token: string };\nexport type SetCSRFTokenResult = ResponseData<CSRFTokenData>;\n\nexport const setCSRFToken = (\n req: Request,\n res: Response<SetCSRFTokenResult>,\n _next: NextFunction\n) => {\n const csrf_token = generateToken(req, res);\n\n const responseData = formatResponse<CSRFTokenData>({\n data: { csrf_token },\n });\n\n res.locals.csrf_token = csrf_token;\n res.json(responseData);\n};\n\nexport type RegisterBody = { email: string; password?: string };\nexport type RegisterQuery = { callBack_url?: string };\nexport type RegisterResult = ResponseData<UserAPI>;\n\n/**\n * Handles user registration.\n */\nexport const registerEmailPassword = async (\n req: Request<any, any, RegisterBody, RegisterQuery>,\n res: ResponseWithInformation<RegisterResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n const { callBack_url } = req.query;\n\n if (user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_ALREADY_LOGGED_IN');\n return;\n }\n\n if (callBack_url && !callBack_url.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const userData = req.body;\n\n try {\n let user = await userService.getUserByEmail(userData.email);\n\n if (user) {\n const emailProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (emailProvider?.emailValidated) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'EMAIL_ALREADY_REGISTERED'\n );\n return;\n } else if (emailProvider) {\n user = await sessionAuthService.updateUserProvider(user._id, 'email', {\n provider: 'email',\n emailValidated: undefined,\n secret: uuidv4(),\n });\n } else {\n user = await sessionAuthService.addUserProvider(user._id, {\n provider: 'email',\n emailValidated: undefined,\n secret: uuidv4(),\n });\n }\n } else {\n user = await userService.createUser({\n ...userData,\n provider: [\n {\n provider: 'email',\n emailValidated: undefined,\n secret: uuidv4(),\n },\n ],\n });\n\n logger.info(`New registration: ${user.name} - ${user.email}`);\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_CREATION_FAILED', {\n email: userData.email,\n });\n return;\n }\n\n await sendEmail({\n type: 'validate',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n validationLink: getSessionAuthRoutes().validEmail.url({\n userId: String(user._id),\n secret:\n user.provider?.find((provider) => provider.provider === 'email')\n ?.secret ?? '',\n callBack_url,\n }),\n });\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User registered successfully',\n fr: 'Utilisateur enregistré avec succès',\n es: 'Usuario registrado con éxito',\n }),\n description: t({\n en: 'Your user has been registered successfully. Please check your email to validate your account.',\n fr: 'Votre utilisateur a été enregistré avec succès. Veuillez vérifier votre e-mail pour valider votre compte.',\n es: 'Su usuario ha sido registrado con éxito. Por favor, revise su correo electrónico para validar su cuenta.',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type LoginBody = {\n email: string;\n password: string;\n};\nexport type LoginResult = ResponseData<UserAPI>;\n\n/**\n * Handles user login.\n */\nexport const loginEmailPassword = async (\n req: Request<any, any, LoginBody>,\n res: ResponseWithInformation<LoginResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n\n if (user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_ALREADY_LOGGED_IN');\n return;\n }\n\n const { email, password } = req.body;\n\n try {\n const { user: loggedInUser, error } =\n await sessionAuthService.testUserPassword(email, password);\n\n if (error) {\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'LOGIN_FAILED');\n return;\n }\n }\n\n if (!loggedInUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n await sessionAuthService.setUserAuth(res, loggedInUser);\n\n const formattedUser = mapUserToAPI(loggedInUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User logged in successfully',\n fr: 'Utilisateur connecté avec succès',\n es: 'Usuario conectado con éxito',\n }),\n description: t({\n en: 'Your user has been logged in successfully',\n fr: 'Votre utilisateur a été connecté avec succès',\n es: 'Su usuario ha sido conectado con éxito',\n }),\n data: formattedUser,\n });\n\n logger.info(`Login: ${loggedInUser.email}`);\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type LogoutResult = ResponseData<undefined>;\n\n/**\n * Handles user logout and clears cookies.\n */\nexport const logOut = async (\n _req: Request,\n res: ResponseWithInformation<LogoutResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n await sessionAuthService.clearUserAuth(res);\n sessionAuthService.clearOrganizationAuth(res);\n sessionAuthService.clearProjectAuth(res);\n\n logger.info(`Logout: ${user.name} - ${user.email}`);\n\n const responseData = formatResponse<undefined>({\n message: t({\n en: 'User logged out successfully',\n fr: 'Utilisateur déconnecté avec succès',\n es: 'Usuario desconectado con éxito',\n }),\n description: t({\n en: 'Your user has been logged out successfully',\n fr: 'Votre utilisateur a été déconnecté avec succès',\n es: 'Su usuario ha sido desconectado con éxito',\n }),\n data: undefined,\n });\n\n res.json(responseData);\n};\n\nexport type UpdatePasswordBody = {\n oldPassword?: string;\n newPassword: string;\n};\nexport type UpdatePasswordResult = ResponseData<UserAPI>;\n\n/**\n * Updates the user's password.\n */\nexport const updatePassword = async (\n req: Request<undefined, any, UpdatePasswordBody>,\n res: ResponseWithInformation<UpdatePasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { oldPassword, newPassword } = req.body;\n let { user } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const userEmailProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (!userEmailProvider) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_PROVIDER_NOT_FOUND', {\n provider: 'email',\n });\n return;\n }\n\n if (userEmailProvider.passwordHash && !oldPassword) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_PREVIOUS_PASSWORD_NOT_PROVIDED'\n );\n return;\n }\n\n try {\n if (oldPassword) {\n const { error } = await sessionAuthService.testUserPassword(\n user.email,\n oldPassword\n );\n\n if (error) {\n ErrorHandler.handleGenericErrorResponse(res, 'LOGIN_FAILED');\n return;\n }\n }\n\n user = await sessionAuthService.changeUserPassword(user._id, newPassword);\n\n if (!user || typeof user !== 'object') {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n logger.info(\n `Password changed - User : Name : ${user.name}, id : ${String(user._id)}`\n );\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Password changed successfully',\n fr: 'Mot de passe modifié avec succès',\n es: 'Contraseña cambiada con éxito',\n }),\n description: t({\n en: 'Your password has been changed successfully',\n fr: 'Votre mot de passe a été modifié avec succès',\n es: 'Su contraseña ha sido cambiada con éxito',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nlet clients: Array<{ id: number; userId: string; res: Response }> = [];\n\nexport const sendVerificationUpdate = (user: User) => {\n const filteredClients = clients.filter(\n (client) => String(client.userId) === String(user._id)\n );\n\n for (const client of filteredClients) {\n const provider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (provider?.emailValidated) {\n client.res.write(\n `data: ${JSON.stringify({ userId: user._id, status: 'verified' })}\\n\\n`\n );\n continue;\n }\n\n client.res.write(\n `data: ${JSON.stringify({ userId: user._id, status: 'waiting' })}\\n\\n`\n );\n }\n};\n\ntype CheckIfUserHasPasswordResultData = {\n hasPassword: boolean;\n};\nexport type CheckIfUserHasPasswordResult =\n ResponseData<CheckIfUserHasPasswordResultData>;\n\nexport const checkIfUserHasPassword = async (\n _req: Request,\n res: ResponseWithInformation<CheckIfUserHasPasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const userProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n const responseData = formatResponse<CheckIfUserHasPasswordResultData>({\n data: {\n hasPassword: Boolean(userProvider?.passwordHash),\n },\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type ValidEmailParams = { secret: string; userId: string };\nexport type ValidEmailQuery = { callBack_url?: string };\nexport type ValidEmailResult = ResponseData<UserAPI>;\n\n/**\n * Validates a user's email based on the provided secret and user ID.\n */\nexport const validEmail = async (\n req: Request<ValidEmailParams, any, any, ValidEmailQuery>,\n res: ResponseWithInformation<ValidEmailResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId, secret } = req.params;\n const callBack_url = `${req.query.callBack_url ?? `${process.env.CLIENT_URL}/auth/login`}?userId=${userId}`;\n\n if (!Types.ObjectId.isValid(userId.toString())) {\n ErrorHandler.handleGenericErrorResponse(res, 'INVALID_USER_ID');\n return;\n }\n\n const user = await userService.getUserById(userId);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED', {\n userId,\n });\n return;\n }\n\n if (callBack_url && !callBack_url.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const provider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (provider?.emailValidated) {\n res.redirect(callBack_url);\n }\n\n if (!provider?.secret) {\n throw new GenericError('USER_PROVIDER_SECRET_NOT_DEFINED', { userId });\n }\n\n if (\n !crypto.timingSafeEqual(Buffer.from(provider.secret), Buffer.from(secret))\n ) {\n throw new GenericError('USER_PROVIDER_SECRET_NOT_VALID', { userId });\n }\n\n await sessionAuthService.updateUserProvider(userId, 'email', {\n secret: undefined,\n emailValidated: new Date(),\n });\n\n logger.info(\n `User activated - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n\n sendVerificationUpdate(user);\n\n await sessionAuthService.setUserAuth(res, user);\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name,\n loginLink: callBack_url,\n });\n\n res.redirect(callBack_url);\n};\n\nexport type VerifyEmailStatusSSEParams = { userId: string };\n\n/**\n * SSE to check the email verification status\n */\nexport const verifyEmailStatusSSE = async (\n req: Request<VerifyEmailStatusSSEParams, any, any>,\n res: ResponseWithInformation\n) => {\n // Set headers for SSE\n res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');\n res.setHeader('Cache-Control', 'no-cache, no-transform');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no'); // For Nginx buffering\n\n // Send initial data to ensure the connection is open\n res.write(':\\n\\n'); // Comment to keep connection alive\n res.flushHeaders();\n\n const { userId } = req.params; // Get user ID from query parameters\n const clientId = Date.now();\n\n const user = await userService.getUserById(userId);\n\n if (!user) {\n logger.error(`User not found - User ID: ${userId}`);\n res.write(`data: ${JSON.stringify({ userId, status: 'error' })}\\n\\n`);\n res.end();\n return;\n }\n\n // Add client to the list\n const newClient = { id: clientId, userId, res };\n clients.push(newClient);\n\n sendVerificationUpdate(user);\n\n // Remove client on connection close\n req.on('close', () => {\n clients = clients.filter((client) => client.id !== clientId);\n });\n};\n\nexport type AskResetPasswordBody = {\n email: string;\n};\nexport type AskResetPasswordResult = ResponseData<undefined>;\n\n/**\n * Requests a password reset for a user.\n */\nexport const askResetPassword = async (\n req: Request<undefined, any, AskResetPasswordBody>,\n res: ResponseWithInformation<AskResetPasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { email } = req.body as Partial<AskResetPasswordBody>;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'EMAIL_NOT_PROVIDED');\n return;\n }\n\n try {\n const updatedUser = await sessionAuthService.requestPasswordReset(email);\n\n if (!updatedUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND', { email });\n return;\n }\n\n logger.info(\n `Ask changing password - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n await sendEmail({\n type: 'resetPassword',\n to: updatedUser.email,\n username: updatedUser.name,\n resetLink: `${process.env.CLIENT_URL}/auth/password/reset/${String(updatedUser._id)}/${\n updatedUser.provider?.find((provider) => provider.provider === 'email')\n ?.secret ?? ''\n }`,\n });\n\n const responseData = formatResponse<undefined>({\n message: t({\n en: 'Password reset request sent successfully',\n fr: 'Demande de réinitialisation de mot de passe envoyée avec succès',\n es: 'Solicitud de restablecimiento de contraseña enviada con éxito',\n }),\n description: t({\n en: 'Your password reset request has been sent successfully. Please check your email to reset your password.',\n fr: 'Votre demande de réinitialisation de mot de passe a été envoyée avec succès. Veuillez vérifier votre e-mail pour réinitialiser votre mot de passe.',\n es: 'Su solicitud de restablecimiento de contraseña ha sido enviada con éxito. Por favor, revise su correo electrónico para restablecer su contraseña.',\n }),\n data: undefined,\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 DefinePasswordBody = {\n password: string;\n secret: string;\n userId: string;\n};\nexport type DefinePasswordResult = ResponseData<UserAPI>;\n\n/**\n * Resets a user's password based on the provided secret and user ID.\n */\nexport const definePassword = async (\n req: Request<undefined, any, DefinePasswordBody>,\n res: Response<DefinePasswordResult>,\n _next: NextFunction\n): Promise<void> => {\n const { secret, userId, password } = req.body;\n\n const userIdString = String(userId);\n\n if (!userId || !userIdString || !Types.ObjectId.isValid(userIdString)) {\n ErrorHandler.handleGenericErrorResponse(res, 'INVALID_USER_ID', { userId });\n return;\n }\n\n if (!secret) {\n ErrorHandler.handleGenericErrorResponse(res, 'SECRET_NOT_PROVIDED');\n return;\n }\n\n try {\n const updatedUser = await sessionAuthService.resetUserPassword(\n userId,\n secret,\n password\n );\n\n logger.info(\n `Password changed - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n await sendEmail({\n type: 'passwordChangeConfirmation',\n to: updatedUser.email,\n username: updatedUser.name,\n });\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Password reset successfully',\n fr: 'Réinitialisation du mot de passe réussie',\n es: 'Restablecimiento de contraseña exitoso',\n }),\n description: t({\n en: 'Your password has been reset successfully. You can now log in with your new password',\n fr: 'Votre mot de passe a été réinitialisé avec succès. Vous pouvez maintenant vous connecter avec votre nouveau mot de passe',\n es: 'Su contraseña ha sido restablecida con éxito. Ahora puede iniciar sesión con su nueva contraseña',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type CreateSessionBody = {\n sessionToken: string;\n userId: string;\n expires: Date;\n};\nexport type CreateSessionResult = ResponseData<Session>;\n\nexport type GetSessionInformationQuery = {\n session_token?: string;\n};\ntype SessionInformation = {\n user: UserAPI | null;\n organization: OrganizationAPI | null;\n project: ProjectAPI | null;\n session: Session | null;\n};\nexport type GetSessionInformationResult = ResponseData<SessionInformation>;\n\n/**\n * Gets information about a session for a user.\n */\nexport const getSessionInformation = async (\n req: Request<undefined, undefined, undefined, GetSessionInformationQuery>,\n res: ResponseWithInformation<GetSessionInformationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { session_token: sessionToken } = req.query;\n\n let { user } = res.locals;\n const { organization, project, isOrganizationAdmin, isProjectAdmin } =\n res.locals;\n\n try {\n if (sessionToken) {\n user = await userService.getUserBySession(sessionToken);\n }\n\n if (!user || !user?.session) {\n const responseData = formatResponse<SessionInformation>({\n data: {\n session: null,\n user: null,\n organization: organization?._id\n ? mapOrganizationToAPI(organization, isOrganizationAdmin)\n : null,\n project: project?._id\n ? mapProjectToAPI(project, user, isProjectAdmin)\n : null,\n },\n });\n\n res.json(responseData);\n\n return;\n }\n\n const session = user.session;\n\n const formattedUser: SessionInformation['user'] = {\n ...mapUserToAPI(user),\n role: 'user',\n };\n\n const responseData = formatResponse<SessionInformation>({\n data: {\n session,\n user: formattedUser,\n organization: organization?._id\n ? mapOrganizationToAPI(organization, isOrganizationAdmin)\n : null,\n project: project?._id\n ? mapProjectToAPI(project, user, isProjectAdmin)\n : null,\n },\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GithubLoginQueryParams = {\n origin: string;\n};\nexport type GithubLoginQueryResult = ResponseData<undefined>;\n\nexport const githubLoginQuery = (\n req: Request<undefined, undefined, undefined, GithubLoginQueryParams>,\n res: ResponseWithInformation<GithubLoginQueryResult>,\n _next: NextFunction\n): void => {\n const { origin } = req.query;\n const { user } = res.locals;\n\n if (user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_ALREADY_LOGGED_IN');\n return;\n }\n\n if (origin && !origin.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const encodedOrigin = encodeURIComponent(origin);\n\n const redirectURI = `${process.env.BACKEND_URL}/api/auth/callback/github?redirect_uri=${encodedOrigin}`;\n const encodedRedirectURI = encodeURIComponent(redirectURI);\n\n res.redirect(\n `https://github.com/login/oauth/authorize?client_id=${process.env.GITHUB_CLIENT_ID}&redirect_uri=${encodedRedirectURI}&scope=user:email`\n );\n};\n\nexport type GithubCallbackQuery = {\n code: string;\n redirect_uri: string;\n};\n\nexport type GithubCallbackResult = ResponseData<UserAPI>;\n\n/**\n * Handles GitHub OAuth callback.\n */\nexport const githubCallback = async (\n req: Request<undefined, undefined, undefined, GithubCallbackQuery>,\n res: ResponseWithInformation<GithubCallbackResult>,\n _next: NextFunction\n): Promise<void> => {\n const { code, redirect_uri } = req.query;\n\n if (!code) {\n const errorMessage = 'Code not provided';\n\n logger.error(errorMessage);\n\n res.redirect(redirect_uri);\n return;\n }\n\n if (!redirect_uri) {\n const errorMessage = 'Redirect URI not provided';\n\n logger.error(errorMessage);\n\n res.redirect(redirect_uri);\n return;\n }\n\n if (redirect_uri && !redirect_uri.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n try {\n const tokenResponse = await fetch(\n 'https://github.com/login/oauth/access_token',\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify({\n client_id: process.env.GITHUB_CLIENT_ID,\n client_secret: process.env.GITHUB_CLIENT_SECRET,\n code,\n }),\n }\n );\n\n const tokenData = await tokenResponse.json();\n\n const userResponse = await fetch('https://api.github.com/user', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${tokenData.access_token}`,\n Accept: 'application/vnd.github.v3+json',\n },\n });\n\n if (!userResponse.ok) {\n throw new GenericError('GITHUB_FETCH_USER_DATA_FAILED', { userResponse });\n }\n\n const userData = await userResponse.json();\n\n const emailResponse = await fetch('https://api.github.com/user/emails', {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${tokenData.access_token}`,\n Accept: 'application/vnd.github.v3+json',\n },\n });\n\n if (!emailResponse.ok) {\n throw new GenericError('GIT_HUB_FETCH_USER_EMAIL_FAILED', {\n emailResponse,\n });\n }\n\n const emails: { primary: boolean; email: string }[] =\n await emailResponse.json();\n\n const primaryEmail = emails.find((email) => email.primary)?.email;\n\n if (!primaryEmail) {\n const errorMessage = 'Primary email not found';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.NOT_FOUND_404;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n let existingUser = await userService.getUserByEmail(primaryEmail);\n\n if (existingUser) {\n const existingProvider = await sessionAuthService.getUserProvider(\n existingUser._id,\n 'github'\n );\n\n if (existingProvider?.providerAccountId !== userData.id) {\n const updatedUser = await sessionAuthService.updateUserProvider(\n existingUser._id,\n 'github',\n {\n providerAccountId: userData.id,\n }\n );\n\n logger.info(\n `GitHub login provider updated - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n if (updatedUser) {\n existingUser = updatedUser;\n }\n }\n\n const updatedUser = await userService.updateUserById(existingUser._id, {\n name: existingUser.name ?? userData.name,\n });\n\n await sessionAuthService.setUserAuth(res, updatedUser);\n\n res.redirect(redirect_uri);\n return;\n }\n\n const userInformation: UserData = {\n name: userData.name,\n email: primaryEmail,\n };\n\n const userProvider: GithubSessionProvider = {\n provider: 'github',\n providerAccountId: userData.id,\n };\n\n const user = await userService.createUser({\n ...userInformation,\n provider: [userProvider],\n });\n\n await sessionAuthService.setUserAuth(res, user);\n\n logger.info(\n `GitHub login - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name,\n loginLink: `${process.env.CLIENT_URL}/auth/login`,\n });\n\n res.redirect(redirect_uri);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GoogleLoginQueryParams = {\n origin: string;\n};\n\nexport type GoogleLoginResult = ResponseData<undefined>;\n\nexport const googleLoginQuery = (\n req: Request<undefined, undefined, undefined, GoogleLoginQueryParams>,\n res: ResponseWithInformation<GoogleLoginResult>,\n _next: NextFunction\n): void => {\n const { origin } = req.query;\n const { user } = res.locals;\n\n if (user) {\n const errorMessage = `User already logged in - ${user?.email}`;\n\n logger.error(errorMessage);\n\n res.redirect(origin);\n return;\n }\n\n if (origin && !origin.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n const responseType = 'code';\n const scope = [\n 'https%3A//www.googleapis.com/auth/userinfo.email',\n 'https%3A//www.googleapis.com/auth/userinfo.profile',\n ].join(' ');\n const includeGrantedScopes = 'false';\n\n const encodedOrigin = encodeURIComponent(origin);\n const state = JSON.stringify({ redirect_uri: encodedOrigin });\n\n const redirectURI = `${process.env.BACKEND_URL}/api/auth/callback/google`;\n\n res.redirect(\n `https://accounts.google.com/o/oauth2/v2/auth?client_id=${process.env.GOOGLE_CLIENT_ID}&redirect_uri=${redirectURI}&response_type=${responseType}&scope=${scope}&include_granted_scopes=${includeGrantedScopes}&state=${state}`\n );\n};\n\nexport type GoogleCallbackQuery = {\n code: string;\n state: string;\n};\n\nexport type GoogleCallbackResult = ResponseData<UserAPI>;\n\n/**\n * Handles Google OAuth 2 callback.\n */\nexport const googleCallback = async (\n req: Request<undefined, undefined, undefined, GoogleCallbackQuery>,\n res: ResponseWithInformation<GoogleCallbackResult>,\n _next: NextFunction\n): Promise<void> => {\n const { code, state } = req.query;\n\n const decodedState = decodeURIComponent(state);\n const { redirect_uri } = JSON.parse(decodedState);\n\n if (!code) {\n const errorMessage = 'code not provided';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.BAD_REQUEST_400;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n if (!redirect_uri) {\n const errorMessage = 'Redirect URI not provided';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.BAD_REQUEST_400;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n if (redirect_uri && !redirect_uri.startsWith(process.env.CLIENT_URL ?? '')) {\n ErrorHandler.handleGenericErrorResponse(res, 'CALLBACK_URL_NOT_VALID');\n return;\n }\n\n try {\n // Exchange the authorization code for an access token\n const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n code,\n redirect_uri: `${process.env.BACKEND_URL}/api/auth/callback/google`,\n client_id: process.env.GOOGLE_CLIENT_ID!,\n client_secret: process.env.GOOGLE_CLIENT_SECRET!,\n grant_type: 'authorization_code',\n }),\n });\n\n const responseData = await tokenResponse.json();\n\n const { access_token: accessToken } = responseData;\n\n if (!accessToken) {\n const errorMessage = 'Failed to fetch access_token';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.INTERNAL_SERVER_ERROR_500;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n const userResponse = await fetch(\n 'https://www.googleapis.com/oauth2/v3/userinfo',\n {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n }\n );\n\n const userData = await userResponse.json();\n\n if (!userData.email) {\n const errorMessage = 'Failed to fetch user data from Google';\n\n logger.error(errorMessage);\n\n const responseCode = HttpStatusCodes.INTERNAL_SERVER_ERROR_500;\n\n res.redirect(responseCode, redirect_uri);\n return;\n }\n\n let existingUser = await userService.getUserByEmail(userData.email);\n\n if (existingUser) {\n const existingProvider = await sessionAuthService.getUserProvider(\n existingUser._id,\n 'google'\n );\n\n if (existingProvider?.providerAccountId !== userData.sub) {\n const updatedUser = await sessionAuthService.updateUserProvider(\n existingUser._id,\n 'google',\n {\n providerAccountId: userData.id,\n }\n );\n\n logger.info(\n `Google login provider updated - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n if (updatedUser) {\n existingUser = updatedUser;\n }\n }\n\n const updatedUser = await userService.updateUserById(existingUser._id, {\n name: existingUser.name ?? userData.name,\n });\n\n await sessionAuthService.setUserAuth(res, updatedUser);\n\n res.redirect(redirect_uri);\n return;\n }\n\n const userInformation: UserData = {\n name: userData.name,\n email: userData.email,\n };\n\n const userProvider: GoogleSessionProvider = {\n provider: 'google',\n providerAccountId: userData.id,\n };\n\n const user = await userService.createUser({\n ...userInformation,\n provider: [userProvider],\n });\n\n await sessionAuthService.setUserAuth(res, user);\n\n logger.info(\n `Google login - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name,\n loginLink: `${process.env.CLIENT_URL}/auth/login`,\n });\n\n res.redirect(redirect_uri);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":["user","provider","responseData","updatedUser"]}