@intlayer/backend 5.6.0 → 5.7.1

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 (508) hide show
  1. package/README.md +3 -0
  2. package/dist/cjs/controllers/ai.controller.cjs +10 -7
  3. package/dist/cjs/controllers/ai.controller.cjs.map +1 -1
  4. package/dist/cjs/controllers/dictionary.controller.cjs +50 -58
  5. package/dist/cjs/controllers/dictionary.controller.cjs.map +1 -1
  6. package/dist/cjs/controllers/eventListener.controller.cjs +2 -18
  7. package/dist/cjs/controllers/eventListener.controller.cjs.map +1 -1
  8. package/dist/cjs/controllers/newsletter.controller.cjs +38 -3
  9. package/dist/cjs/controllers/newsletter.controller.cjs.map +1 -1
  10. package/dist/cjs/controllers/oAuth2.controller.cjs +3 -3
  11. package/dist/cjs/controllers/oAuth2.controller.cjs.map +1 -1
  12. package/dist/cjs/controllers/organization.controller.cjs +92 -106
  13. package/dist/cjs/controllers/organization.controller.cjs.map +1 -1
  14. package/dist/cjs/controllers/project.controller.cjs +81 -83
  15. package/dist/cjs/controllers/project.controller.cjs.map +1 -1
  16. package/dist/cjs/controllers/projectAccessKey.controller.cjs +30 -24
  17. package/dist/cjs/controllers/projectAccessKey.controller.cjs.map +1 -1
  18. package/dist/cjs/controllers/search.controller.cjs.map +1 -1
  19. package/dist/cjs/controllers/stripe.controller.cjs +4 -25
  20. package/dist/cjs/controllers/stripe.controller.cjs.map +1 -1
  21. package/dist/cjs/controllers/tag.controller.cjs +27 -16
  22. package/dist/cjs/controllers/tag.controller.cjs.map +1 -1
  23. package/dist/cjs/controllers/user.controller.cjs +88 -24
  24. package/dist/cjs/controllers/user.controller.cjs.map +1 -1
  25. package/dist/cjs/emails/InviteUserEmail.cjs +30 -12
  26. package/dist/cjs/emails/InviteUserEmail.cjs.map +1 -1
  27. package/dist/cjs/emails/OAuthTokenCreatedEmail.cjs +266 -0
  28. package/dist/cjs/emails/OAuthTokenCreatedEmail.cjs.map +1 -0
  29. package/dist/cjs/emails/ResetUserPassword.cjs +27 -15
  30. package/dist/cjs/emails/ResetUserPassword.cjs.map +1 -1
  31. package/dist/cjs/emails/ValidateUserEmail.cjs +27 -36
  32. package/dist/cjs/emails/ValidateUserEmail.cjs.map +1 -1
  33. package/dist/cjs/emails/Welcome.cjs +27 -15
  34. package/dist/cjs/emails/Welcome.cjs.map +1 -1
  35. package/dist/cjs/emails/index.cjs +7 -5
  36. package/dist/cjs/emails/index.cjs.map +1 -1
  37. package/dist/cjs/export.cjs +2 -5
  38. package/dist/cjs/export.cjs.map +1 -1
  39. package/dist/cjs/index.cjs +61 -111
  40. package/dist/cjs/index.cjs.map +1 -1
  41. package/dist/cjs/middlewares/oAuth2.middleware.cjs +26 -38
  42. package/dist/cjs/middlewares/oAuth2.middleware.cjs.map +1 -1
  43. package/dist/cjs/middlewares/request.middleware.cjs.map +1 -1
  44. package/dist/cjs/middlewares/sessionAuth.middleware.cjs +17 -138
  45. package/dist/cjs/middlewares/sessionAuth.middleware.cjs.map +1 -1
  46. package/dist/cjs/models/dictionary.model.cjs.map +1 -1
  47. package/dist/cjs/models/discussion.model.cjs.map +1 -1
  48. package/dist/cjs/models/oAuth2.model.cjs +4 -1
  49. package/dist/cjs/models/oAuth2.model.cjs.map +1 -1
  50. package/dist/cjs/models/organization.model.cjs +1 -4
  51. package/dist/cjs/models/organization.model.cjs.map +1 -1
  52. package/dist/cjs/models/project.model.cjs +4 -1
  53. package/dist/cjs/models/project.model.cjs.map +1 -1
  54. package/dist/cjs/models/session.model.cjs +34 -0
  55. package/dist/cjs/models/session.model.cjs.map +1 -0
  56. package/dist/cjs/models/tag.model.cjs.map +1 -1
  57. package/dist/cjs/models/user.model.cjs.map +1 -1
  58. package/dist/cjs/routes/ai.routes.cjs +3 -1
  59. package/dist/cjs/routes/ai.routes.cjs.map +1 -1
  60. package/dist/cjs/routes/dictionary.routes.cjs.map +1 -1
  61. package/dist/cjs/routes/eventListener.routes.cjs +1 -1
  62. package/dist/cjs/routes/eventListener.routes.cjs.map +1 -1
  63. package/dist/cjs/routes/newsletter.routes.cjs.map +1 -1
  64. package/dist/cjs/routes/organization.routes.cjs +8 -8
  65. package/dist/cjs/routes/organization.routes.cjs.map +1 -1
  66. package/dist/cjs/routes/project.routes.cjs +23 -14
  67. package/dist/cjs/routes/project.routes.cjs.map +1 -1
  68. package/dist/cjs/routes/search.routes.cjs.map +1 -1
  69. package/dist/cjs/routes/stripe.routes.cjs.map +1 -1
  70. package/dist/cjs/routes/tags.routes.cjs +4 -4
  71. package/dist/cjs/routes/tags.routes.cjs.map +1 -1
  72. package/dist/cjs/routes/user.routes.cjs +12 -12
  73. package/dist/cjs/routes/user.routes.cjs.map +1 -1
  74. package/dist/cjs/schemas/dictionary.schema.cjs +18 -1
  75. package/dist/cjs/schemas/dictionary.schema.cjs.map +1 -1
  76. package/dist/cjs/schemas/discussion.schema.cjs +18 -1
  77. package/dist/cjs/schemas/discussion.schema.cjs.map +1 -1
  78. package/dist/cjs/schemas/oAuth2.schema.cjs +18 -1
  79. package/dist/cjs/schemas/oAuth2.schema.cjs.map +1 -1
  80. package/dist/cjs/schemas/organization.schema.cjs +21 -1
  81. package/dist/cjs/schemas/organization.schema.cjs.map +1 -1
  82. package/dist/cjs/schemas/plans.schema.cjs +18 -1
  83. package/dist/cjs/schemas/plans.schema.cjs.map +1 -1
  84. package/dist/cjs/schemas/project.schema.cjs +19 -14
  85. package/dist/cjs/schemas/project.schema.cjs.map +1 -1
  86. package/dist/cjs/schemas/session.schema.cjs +63 -0
  87. package/dist/cjs/schemas/session.schema.cjs.map +1 -0
  88. package/dist/cjs/schemas/tag.schema.cjs +18 -1
  89. package/dist/cjs/schemas/tag.schema.cjs.map +1 -1
  90. package/dist/cjs/schemas/user.schema.cjs +18 -48
  91. package/dist/cjs/schemas/user.schema.cjs.map +1 -1
  92. package/dist/cjs/services/dictionary.service.cjs +6 -5
  93. package/dist/cjs/services/dictionary.service.cjs.map +1 -1
  94. package/dist/cjs/services/email.service.cjs +13 -0
  95. package/dist/cjs/services/email.service.cjs.map +1 -1
  96. package/dist/cjs/services/oAuth2.service.cjs +49 -10
  97. package/dist/cjs/services/oAuth2.service.cjs.map +1 -1
  98. package/dist/cjs/services/organization.service.cjs +16 -15
  99. package/dist/cjs/services/organization.service.cjs.map +1 -1
  100. package/dist/cjs/services/project.service.cjs +1 -1
  101. package/dist/cjs/services/project.service.cjs.map +1 -1
  102. package/dist/cjs/services/projectAccessKey.service.cjs +17 -33
  103. package/dist/cjs/services/projectAccessKey.service.cjs.map +1 -1
  104. package/dist/cjs/services/subscription.service.cjs +10 -10
  105. package/dist/cjs/services/subscription.service.cjs.map +1 -1
  106. package/dist/cjs/services/tag.service.cjs.map +1 -1
  107. package/dist/cjs/services/user.service.cjs +2 -42
  108. package/dist/cjs/services/user.service.cjs.map +1 -1
  109. package/dist/cjs/types/dictionary.types.cjs.map +1 -1
  110. package/dist/cjs/types/discussion.types.cjs.map +1 -1
  111. package/dist/cjs/types/oAuth2.types.cjs.map +1 -1
  112. package/dist/cjs/types/organization.types.cjs.map +1 -1
  113. package/dist/cjs/types/plan.types.cjs.map +1 -1
  114. package/dist/cjs/types/project.types.cjs.map +1 -1
  115. package/dist/cjs/types/session.types.cjs.map +1 -1
  116. package/dist/cjs/types/tag.types.cjs.map +1 -1
  117. package/dist/cjs/types/user.types.cjs.map +1 -1
  118. package/dist/cjs/utils/AI/aiSdk.cjs.map +1 -1
  119. package/dist/cjs/utils/AI/askDocQuestion/askDocQuestion.cjs +14 -9
  120. package/dist/cjs/utils/AI/askDocQuestion/askDocQuestion.cjs.map +1 -1
  121. package/dist/cjs/utils/AI/autocomplete/PROMPT.md +18 -2
  122. package/dist/cjs/utils/AI/autocomplete/index.cjs +8 -5
  123. package/dist/cjs/utils/AI/autocomplete/index.cjs.map +1 -1
  124. package/dist/cjs/utils/access.cjs +2 -0
  125. package/dist/cjs/utils/access.cjs.map +1 -0
  126. package/dist/cjs/utils/accessControl.cjs +7 -0
  127. package/dist/cjs/utils/accessControl.cjs.map +1 -1
  128. package/dist/cjs/utils/auth/getAuth.cjs +248 -0
  129. package/dist/cjs/utils/auth/getAuth.cjs.map +1 -0
  130. package/dist/cjs/utils/cors.cjs +55 -0
  131. package/dist/cjs/utils/cors.cjs.map +1 -0
  132. package/dist/cjs/utils/ensureMongoDocumentToObject.cjs.map +1 -1
  133. package/dist/cjs/utils/errors/ErrorHandler.cjs +2 -2
  134. package/dist/cjs/utils/errors/ErrorHandler.cjs.map +1 -1
  135. package/dist/cjs/utils/errors/errorCodes.cjs +114 -153
  136. package/dist/cjs/utils/errors/errorCodes.cjs.map +1 -1
  137. package/dist/cjs/utils/filtersAndPagination/getOrganizationFiltersAndPagination.cjs.map +1 -1
  138. package/dist/cjs/utils/filtersAndPagination/getProjectFiltersAndPagination.cjs.map +1 -1
  139. package/dist/cjs/utils/filtersAndPagination/getTagFiltersAndPagination.cjs.map +1 -1
  140. package/dist/cjs/utils/filtersAndPagination/getUserFiltersAndPagination.cjs +1 -1
  141. package/dist/cjs/utils/filtersAndPagination/getUserFiltersAndPagination.cjs.map +1 -1
  142. package/dist/cjs/utils/mapper/dictionary.cjs.map +1 -1
  143. package/dist/cjs/utils/mapper/organization.cjs +10 -8
  144. package/dist/cjs/utils/mapper/organization.cjs.map +1 -1
  145. package/dist/cjs/utils/mapper/project.cjs +5 -18
  146. package/dist/cjs/utils/mapper/project.cjs.map +1 -1
  147. package/dist/cjs/utils/mapper/tag.cjs +4 -2
  148. package/dist/cjs/utils/mapper/tag.cjs.map +1 -1
  149. package/dist/cjs/utils/mapper/user.cjs +6 -3
  150. package/dist/cjs/utils/mapper/user.cjs.map +1 -1
  151. package/dist/cjs/utils/mergeFunctionTypes.cjs +17 -0
  152. package/dist/cjs/utils/mergeFunctionTypes.cjs.map +1 -0
  153. package/dist/cjs/utils/mongoDB/connectDB.cjs +3 -1
  154. package/dist/cjs/utils/mongoDB/connectDB.cjs.map +1 -1
  155. package/dist/cjs/utils/mongoDB/types.cjs +17 -0
  156. package/dist/cjs/utils/mongoDB/types.cjs.map +1 -0
  157. package/dist/cjs/utils/oAuth2.cjs.map +1 -1
  158. package/dist/cjs/utils/permissions.cjs +166 -0
  159. package/dist/cjs/utils/permissions.cjs.map +1 -0
  160. package/dist/cjs/utils/rateLimiter.cjs +88 -0
  161. package/dist/cjs/utils/rateLimiter.cjs.map +1 -0
  162. package/dist/esm/controllers/ai.controller.mjs +10 -7
  163. package/dist/esm/controllers/ai.controller.mjs.map +1 -1
  164. package/dist/esm/controllers/dictionary.controller.mjs +50 -58
  165. package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
  166. package/dist/esm/controllers/eventListener.controller.mjs +2 -8
  167. package/dist/esm/controllers/eventListener.controller.mjs.map +1 -1
  168. package/dist/esm/controllers/newsletter.controller.mjs +38 -3
  169. package/dist/esm/controllers/newsletter.controller.mjs.map +1 -1
  170. package/dist/esm/controllers/oAuth2.controller.mjs +2 -2
  171. package/dist/esm/controllers/oAuth2.controller.mjs.map +1 -1
  172. package/dist/esm/controllers/organization.controller.mjs +95 -106
  173. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  174. package/dist/esm/controllers/project.controller.mjs +81 -83
  175. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  176. package/dist/esm/controllers/projectAccessKey.controller.mjs +30 -24
  177. package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
  178. package/dist/esm/controllers/search.controller.mjs.map +1 -1
  179. package/dist/esm/controllers/stripe.controller.mjs +4 -25
  180. package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
  181. package/dist/esm/controllers/tag.controller.mjs +27 -16
  182. package/dist/esm/controllers/tag.controller.mjs.map +1 -1
  183. package/dist/esm/controllers/user.controller.mjs +85 -22
  184. package/dist/esm/controllers/user.controller.mjs.map +1 -1
  185. package/dist/esm/emails/InviteUserEmail.mjs +32 -14
  186. package/dist/esm/emails/InviteUserEmail.mjs.map +1 -1
  187. package/dist/esm/emails/OAuthTokenCreatedEmail.mjs +254 -0
  188. package/dist/esm/emails/OAuthTokenCreatedEmail.mjs.map +1 -0
  189. package/dist/esm/emails/ResetUserPassword.mjs +29 -17
  190. package/dist/esm/emails/ResetUserPassword.mjs.map +1 -1
  191. package/dist/esm/emails/ValidateUserEmail.mjs +29 -38
  192. package/dist/esm/emails/ValidateUserEmail.mjs.map +1 -1
  193. package/dist/esm/emails/Welcome.mjs +29 -17
  194. package/dist/esm/emails/Welcome.mjs.map +1 -1
  195. package/dist/esm/emails/index.mjs +3 -2
  196. package/dist/esm/emails/index.mjs.map +1 -1
  197. package/dist/esm/export.mjs +1 -3
  198. package/dist/esm/export.mjs.map +1 -1
  199. package/dist/esm/index.mjs +60 -111
  200. package/dist/esm/index.mjs.map +1 -1
  201. package/dist/esm/middlewares/oAuth2.middleware.mjs +27 -36
  202. package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
  203. package/dist/esm/middlewares/request.middleware.mjs.map +1 -1
  204. package/dist/esm/middlewares/sessionAuth.middleware.mjs +16 -127
  205. package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
  206. package/dist/esm/models/dictionary.model.mjs.map +1 -1
  207. package/dist/esm/models/discussion.model.mjs.map +1 -1
  208. package/dist/esm/models/oAuth2.model.mjs +4 -1
  209. package/dist/esm/models/oAuth2.model.mjs.map +1 -1
  210. package/dist/esm/models/organization.model.mjs +1 -4
  211. package/dist/esm/models/organization.model.mjs.map +1 -1
  212. package/dist/esm/models/project.model.mjs +4 -1
  213. package/dist/esm/models/project.model.mjs.map +1 -1
  214. package/dist/esm/models/session.model.mjs +10 -0
  215. package/dist/esm/models/session.model.mjs.map +1 -0
  216. package/dist/esm/models/tag.model.mjs.map +1 -1
  217. package/dist/esm/models/user.model.mjs.map +1 -1
  218. package/dist/esm/routes/ai.routes.mjs +3 -1
  219. package/dist/esm/routes/ai.routes.mjs.map +1 -1
  220. package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
  221. package/dist/esm/routes/eventListener.routes.mjs +1 -1
  222. package/dist/esm/routes/eventListener.routes.mjs.map +1 -1
  223. package/dist/esm/routes/newsletter.routes.mjs.map +1 -1
  224. package/dist/esm/routes/organization.routes.mjs +8 -8
  225. package/dist/esm/routes/organization.routes.mjs.map +1 -1
  226. package/dist/esm/routes/project.routes.mjs +23 -14
  227. package/dist/esm/routes/project.routes.mjs.map +1 -1
  228. package/dist/esm/routes/search.routes.mjs.map +1 -1
  229. package/dist/esm/routes/stripe.routes.mjs.map +1 -1
  230. package/dist/esm/routes/tags.routes.mjs +4 -4
  231. package/dist/esm/routes/tags.routes.mjs.map +1 -1
  232. package/dist/esm/routes/user.routes.mjs +14 -14
  233. package/dist/esm/routes/user.routes.mjs.map +1 -1
  234. package/dist/esm/schemas/dictionary.schema.mjs +18 -1
  235. package/dist/esm/schemas/dictionary.schema.mjs.map +1 -1
  236. package/dist/esm/schemas/discussion.schema.mjs +18 -1
  237. package/dist/esm/schemas/discussion.schema.mjs.map +1 -1
  238. package/dist/esm/schemas/oAuth2.schema.mjs +18 -1
  239. package/dist/esm/schemas/oAuth2.schema.mjs.map +1 -1
  240. package/dist/esm/schemas/organization.schema.mjs +21 -1
  241. package/dist/esm/schemas/organization.schema.mjs.map +1 -1
  242. package/dist/esm/schemas/plans.schema.mjs +18 -1
  243. package/dist/esm/schemas/plans.schema.mjs.map +1 -1
  244. package/dist/esm/schemas/project.schema.mjs +21 -15
  245. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  246. package/dist/esm/schemas/session.schema.mjs +39 -0
  247. package/dist/esm/schemas/session.schema.mjs.map +1 -0
  248. package/dist/esm/schemas/tag.schema.mjs +21 -4
  249. package/dist/esm/schemas/tag.schema.mjs.map +1 -1
  250. package/dist/esm/schemas/user.schema.mjs +18 -48
  251. package/dist/esm/schemas/user.schema.mjs.map +1 -1
  252. package/dist/esm/services/dictionary.service.mjs +6 -5
  253. package/dist/esm/services/dictionary.service.mjs.map +1 -1
  254. package/dist/esm/services/email.service.mjs +33 -16
  255. package/dist/esm/services/email.service.mjs.map +1 -1
  256. package/dist/esm/services/oAuth2.service.mjs +47 -10
  257. package/dist/esm/services/oAuth2.service.mjs.map +1 -1
  258. package/dist/esm/services/organization.service.mjs +16 -14
  259. package/dist/esm/services/organization.service.mjs.map +1 -1
  260. package/dist/esm/services/project.service.mjs +1 -1
  261. package/dist/esm/services/project.service.mjs.map +1 -1
  262. package/dist/esm/services/projectAccessKey.service.mjs +15 -31
  263. package/dist/esm/services/projectAccessKey.service.mjs.map +1 -1
  264. package/dist/esm/services/subscription.service.mjs +10 -10
  265. package/dist/esm/services/subscription.service.mjs.map +1 -1
  266. package/dist/esm/services/tag.service.mjs.map +1 -1
  267. package/dist/esm/services/user.service.mjs +2 -40
  268. package/dist/esm/services/user.service.mjs.map +1 -1
  269. package/dist/esm/types/user.types.mjs.map +1 -1
  270. package/dist/esm/utils/AI/aiSdk.mjs.map +1 -1
  271. package/dist/esm/utils/AI/askDocQuestion/askDocQuestion.mjs +14 -9
  272. package/dist/esm/utils/AI/askDocQuestion/askDocQuestion.mjs.map +1 -1
  273. package/dist/esm/utils/AI/autocomplete/PROMPT.md +18 -2
  274. package/dist/esm/utils/AI/autocomplete/index.mjs +8 -5
  275. package/dist/esm/utils/AI/autocomplete/index.mjs.map +1 -1
  276. package/dist/esm/utils/access.mjs +1 -0
  277. package/dist/esm/utils/access.mjs.map +1 -0
  278. package/dist/esm/utils/accessControl.mjs +7 -0
  279. package/dist/esm/utils/accessControl.mjs.map +1 -1
  280. package/dist/esm/utils/auth/getAuth.mjs +227 -0
  281. package/dist/esm/utils/auth/getAuth.mjs.map +1 -0
  282. package/dist/esm/utils/cors.mjs +31 -0
  283. package/dist/esm/utils/cors.mjs.map +1 -0
  284. package/dist/esm/utils/ensureMongoDocumentToObject.mjs.map +1 -1
  285. package/dist/esm/utils/errors/ErrorHandler.mjs +2 -2
  286. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  287. package/dist/esm/utils/errors/errorCodes.mjs +114 -153
  288. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  289. package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs.map +1 -1
  290. package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs.map +1 -1
  291. package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs.map +1 -1
  292. package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs +1 -1
  293. package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs.map +1 -1
  294. package/dist/esm/utils/mapper/dictionary.mjs.map +1 -1
  295. package/dist/esm/utils/mapper/organization.mjs +8 -7
  296. package/dist/esm/utils/mapper/organization.mjs.map +1 -1
  297. package/dist/esm/utils/mapper/project.mjs +5 -18
  298. package/dist/esm/utils/mapper/project.mjs.map +1 -1
  299. package/dist/esm/utils/mapper/tag.mjs +4 -2
  300. package/dist/esm/utils/mapper/tag.mjs.map +1 -1
  301. package/dist/esm/utils/mapper/user.mjs +6 -3
  302. package/dist/esm/utils/mapper/user.mjs.map +1 -1
  303. package/dist/esm/utils/mergeFunctionTypes.mjs +1 -0
  304. package/dist/esm/utils/mergeFunctionTypes.mjs.map +1 -0
  305. package/dist/esm/utils/mongoDB/connectDB.mjs +3 -1
  306. package/dist/esm/utils/mongoDB/connectDB.mjs.map +1 -1
  307. package/dist/esm/utils/mongoDB/types.mjs +1 -0
  308. package/dist/esm/utils/mongoDB/types.mjs.map +1 -0
  309. package/dist/esm/utils/oAuth2.mjs +3 -3
  310. package/dist/esm/utils/oAuth2.mjs.map +1 -1
  311. package/dist/esm/utils/permissions.mjs +138 -0
  312. package/dist/esm/utils/permissions.mjs.map +1 -0
  313. package/dist/esm/utils/rateLimiter.mjs +53 -0
  314. package/dist/esm/utils/rateLimiter.mjs.map +1 -0
  315. package/dist/types/controllers/ai.controller.d.ts +12 -10
  316. package/dist/types/controllers/ai.controller.d.ts.map +1 -1
  317. package/dist/types/controllers/dictionary.controller.d.ts +8 -9
  318. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  319. package/dist/types/controllers/eventListener.controller.d.ts +2 -3
  320. package/dist/types/controllers/eventListener.controller.d.ts.map +1 -1
  321. package/dist/types/controllers/newsletter.controller.d.ts +5 -6
  322. package/dist/types/controllers/newsletter.controller.d.ts.map +1 -1
  323. package/dist/types/controllers/oAuth2.controller.d.ts +3 -3
  324. package/dist/types/controllers/oAuth2.controller.d.ts.map +1 -1
  325. package/dist/types/controllers/organization.controller.d.ts +22 -23
  326. package/dist/types/controllers/organization.controller.d.ts.map +1 -1
  327. package/dist/types/controllers/project.controller.d.ts +13 -14
  328. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  329. package/dist/types/controllers/projectAccessKey.controller.d.ts +5 -6
  330. package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
  331. package/dist/types/controllers/search.controller.d.ts +2 -3
  332. package/dist/types/controllers/search.controller.d.ts.map +1 -1
  333. package/dist/types/controllers/stripe.controller.d.ts +5 -6
  334. package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
  335. package/dist/types/controllers/tag.controller.d.ts +9 -10
  336. package/dist/types/controllers/tag.controller.d.ts.map +1 -1
  337. package/dist/types/controllers/user.controller.d.ts +16 -19
  338. package/dist/types/controllers/user.controller.d.ts.map +1 -1
  339. package/dist/types/emails/InviteUserEmail.d.ts.map +1 -1
  340. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +21 -0
  341. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts.map +1 -0
  342. package/dist/types/emails/ResetUserPassword.d.ts.map +1 -1
  343. package/dist/types/emails/Welcome.d.ts.map +1 -1
  344. package/dist/types/emails/index.d.ts +3 -2
  345. package/dist/types/emails/index.d.ts.map +1 -1
  346. package/dist/types/export.d.ts +2 -3
  347. package/dist/types/export.d.ts.map +1 -1
  348. package/dist/types/index.d.ts +1 -3
  349. package/dist/types/index.d.ts.map +1 -1
  350. package/dist/types/middlewares/oAuth2.middleware.d.ts +1 -2
  351. package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
  352. package/dist/types/middlewares/request.middleware.d.ts +3 -3
  353. package/dist/types/middlewares/request.middleware.d.ts.map +1 -1
  354. package/dist/types/middlewares/sessionAuth.middleware.d.ts +3 -25
  355. package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
  356. package/dist/types/models/dictionary.model.d.ts +6 -5
  357. package/dist/types/models/dictionary.model.d.ts.map +1 -1
  358. package/dist/types/models/discussion.model.d.ts +7 -2
  359. package/dist/types/models/discussion.model.d.ts.map +1 -1
  360. package/dist/types/models/oAuth2.model.d.ts +3 -2
  361. package/dist/types/models/oAuth2.model.d.ts.map +1 -1
  362. package/dist/types/models/organization.model.d.ts +2 -12
  363. package/dist/types/models/organization.model.d.ts.map +1 -1
  364. package/dist/types/models/project.model.d.ts +2 -11
  365. package/dist/types/models/project.model.d.ts.map +1 -1
  366. package/dist/types/models/session.model.d.ts +3 -0
  367. package/dist/types/models/session.model.d.ts.map +1 -0
  368. package/dist/types/models/tag.model.d.ts.map +1 -1
  369. package/dist/types/models/user.model.d.ts.map +1 -1
  370. package/dist/types/routes/ai.routes.d.ts.map +1 -1
  371. package/dist/types/routes/organization.routes.d.ts +4 -4
  372. package/dist/types/routes/project.routes.d.ts +4 -4
  373. package/dist/types/routes/project.routes.d.ts.map +1 -1
  374. package/dist/types/routes/tags.routes.d.ts +2 -2
  375. package/dist/types/routes/user.routes.d.ts +6 -7
  376. package/dist/types/routes/user.routes.d.ts.map +1 -1
  377. package/dist/types/schemas/dictionary.schema.d.ts +6 -8
  378. package/dist/types/schemas/dictionary.schema.d.ts.map +1 -1
  379. package/dist/types/schemas/discussion.schema.d.ts +7 -5
  380. package/dist/types/schemas/discussion.schema.d.ts.map +1 -1
  381. package/dist/types/schemas/oAuth2.schema.d.ts +4 -3
  382. package/dist/types/schemas/oAuth2.schema.d.ts.map +1 -1
  383. package/dist/types/schemas/organization.schema.d.ts +6 -10
  384. package/dist/types/schemas/organization.schema.d.ts.map +1 -1
  385. package/dist/types/schemas/plans.schema.d.ts +6 -8
  386. package/dist/types/schemas/plans.schema.d.ts.map +1 -1
  387. package/dist/types/schemas/project.schema.d.ts +5 -17
  388. package/dist/types/schemas/project.schema.d.ts.map +1 -1
  389. package/dist/types/schemas/session.schema.d.ts +14 -0
  390. package/dist/types/schemas/session.schema.d.ts.map +1 -0
  391. package/dist/types/schemas/tag.schema.d.ts +6 -8
  392. package/dist/types/schemas/tag.schema.d.ts.map +1 -1
  393. package/dist/types/schemas/user.schema.d.ts +7 -5
  394. package/dist/types/schemas/user.schema.d.ts.map +1 -1
  395. package/dist/types/services/dictionary.service.d.ts +9 -9
  396. package/dist/types/services/dictionary.service.d.ts.map +1 -1
  397. package/dist/types/services/email.service.d.ts +4 -0
  398. package/dist/types/services/email.service.d.ts.map +1 -1
  399. package/dist/types/services/oAuth2.service.d.ts +23 -14
  400. package/dist/types/services/oAuth2.service.d.ts.map +1 -1
  401. package/dist/types/services/organization.service.d.ts +6 -12
  402. package/dist/types/services/organization.service.d.ts.map +1 -1
  403. package/dist/types/services/project.service.d.ts +5 -5
  404. package/dist/types/services/project.service.d.ts.map +1 -1
  405. package/dist/types/services/projectAccessKey.service.d.ts +5 -5
  406. package/dist/types/services/projectAccessKey.service.d.ts.map +1 -1
  407. package/dist/types/services/subscription.service.d.ts +1 -1
  408. package/dist/types/services/subscription.service.d.ts.map +1 -1
  409. package/dist/types/services/tag.service.d.ts +6 -6
  410. package/dist/types/services/tag.service.d.ts.map +1 -1
  411. package/dist/types/services/user.service.d.ts +7 -21
  412. package/dist/types/services/user.service.d.ts.map +1 -1
  413. package/dist/types/types/dictionary.types.d.ts +11 -9
  414. package/dist/types/types/dictionary.types.d.ts.map +1 -1
  415. package/dist/types/types/discussion.types.d.ts +5 -2
  416. package/dist/types/types/discussion.types.d.ts.map +1 -1
  417. package/dist/types/types/oAuth2.types.d.ts +5 -2
  418. package/dist/types/types/oAuth2.types.d.ts.map +1 -1
  419. package/dist/types/types/organization.types.d.ts +11 -8
  420. package/dist/types/types/organization.types.d.ts.map +1 -1
  421. package/dist/types/types/plan.types.d.ts +6 -3
  422. package/dist/types/types/plan.types.d.ts.map +1 -1
  423. package/dist/types/types/project.types.d.ts +25 -25
  424. package/dist/types/types/project.types.d.ts.map +1 -1
  425. package/dist/types/types/session.types.d.ts +31 -17
  426. package/dist/types/types/session.types.d.ts.map +1 -1
  427. package/dist/types/types/tag.types.d.ts +8 -6
  428. package/dist/types/types/tag.types.d.ts.map +1 -1
  429. package/dist/types/types/user.types.d.ts +14 -21
  430. package/dist/types/types/user.types.d.ts.map +1 -1
  431. package/dist/types/utils/AI/aiSdk.d.ts +2 -2
  432. package/dist/types/utils/AI/aiSdk.d.ts.map +1 -1
  433. package/dist/types/utils/AI/askDocQuestion/askDocQuestion.d.ts.map +1 -1
  434. package/dist/types/utils/AI/autocomplete/index.d.ts +4 -1
  435. package/dist/types/utils/AI/autocomplete/index.d.ts.map +1 -1
  436. package/dist/types/utils/access.d.ts +1 -0
  437. package/dist/types/utils/access.d.ts.map +1 -0
  438. package/dist/types/utils/accessControl.d.ts +9 -9
  439. package/dist/types/utils/accessControl.d.ts.map +1 -1
  440. package/dist/types/utils/auth/getAuth.d.ts +7 -0
  441. package/dist/types/utils/auth/getAuth.d.ts.map +1 -0
  442. package/dist/types/utils/cors.d.ts +3 -0
  443. package/dist/types/utils/cors.d.ts.map +1 -0
  444. package/dist/types/utils/ensureMongoDocumentToObject.d.ts +2 -2
  445. package/dist/types/utils/ensureMongoDocumentToObject.d.ts.map +1 -1
  446. package/dist/types/utils/errors/ErrorHandler.d.ts +1 -1
  447. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  448. package/dist/types/utils/errors/errorCodes.d.ts +57 -96
  449. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  450. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +1 -1
  451. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts.map +1 -1
  452. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts +1 -1
  453. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts.map +1 -1
  454. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +1 -1
  455. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts.map +1 -1
  456. package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts +1 -1
  457. package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts.map +1 -1
  458. package/dist/types/utils/mapper/dictionary.d.ts +1 -1
  459. package/dist/types/utils/mapper/dictionary.d.ts.map +1 -1
  460. package/dist/types/utils/mapper/organization.d.ts +3 -2
  461. package/dist/types/utils/mapper/organization.d.ts.map +1 -1
  462. package/dist/types/utils/mapper/project.d.ts +4 -5
  463. package/dist/types/utils/mapper/project.d.ts.map +1 -1
  464. package/dist/types/utils/mapper/tag.d.ts +1 -1
  465. package/dist/types/utils/mapper/tag.d.ts.map +1 -1
  466. package/dist/types/utils/mapper/user.d.ts +2 -2
  467. package/dist/types/utils/mapper/user.d.ts.map +1 -1
  468. package/dist/types/utils/mergeFunctionTypes.d.ts +18 -0
  469. package/dist/types/utils/mergeFunctionTypes.d.ts.map +1 -0
  470. package/dist/types/utils/mongoDB/connectDB.d.ts +1 -1
  471. package/dist/types/utils/mongoDB/connectDB.d.ts.map +1 -1
  472. package/dist/types/utils/mongoDB/types.d.ts +11 -0
  473. package/dist/types/utils/mongoDB/types.d.ts.map +1 -0
  474. package/dist/types/utils/permissions.d.ts +115 -0
  475. package/dist/types/utils/permissions.d.ts.map +1 -0
  476. package/dist/types/utils/rateLimiter.d.ts +4 -0
  477. package/dist/types/utils/rateLimiter.d.ts.map +1 -0
  478. package/package.json +14 -14
  479. package/dist/cjs/controllers/sessionAuth.controller.cjs +0 -839
  480. package/dist/cjs/controllers/sessionAuth.controller.cjs.map +0 -1
  481. package/dist/cjs/routes/sessionAuth.routes.cjs +0 -154
  482. package/dist/cjs/routes/sessionAuth.routes.cjs.map +0 -1
  483. package/dist/cjs/services/sessionAuth.service.cjs +0 -385
  484. package/dist/cjs/services/sessionAuth.service.cjs.map +0 -1
  485. package/dist/cjs/utils/CSRF.cjs +0 -50
  486. package/dist/cjs/utils/CSRF.cjs.map +0 -1
  487. package/dist/cjs/utils/cookies.cjs +0 -59
  488. package/dist/cjs/utils/cookies.cjs.map +0 -1
  489. package/dist/esm/controllers/sessionAuth.controller.mjs +0 -790
  490. package/dist/esm/controllers/sessionAuth.controller.mjs.map +0 -1
  491. package/dist/esm/routes/sessionAuth.routes.mjs +0 -142
  492. package/dist/esm/routes/sessionAuth.routes.mjs.map +0 -1
  493. package/dist/esm/services/sessionAuth.service.mjs +0 -337
  494. package/dist/esm/services/sessionAuth.service.mjs.map +0 -1
  495. package/dist/esm/utils/CSRF.mjs +0 -24
  496. package/dist/esm/utils/CSRF.mjs.map +0 -1
  497. package/dist/esm/utils/cookies.mjs +0 -32
  498. package/dist/esm/utils/cookies.mjs.map +0 -1
  499. package/dist/types/controllers/sessionAuth.controller.d.ts +0 -140
  500. package/dist/types/controllers/sessionAuth.controller.d.ts.map +0 -1
  501. package/dist/types/routes/sessionAuth.routes.d.ts +0 -77
  502. package/dist/types/routes/sessionAuth.routes.d.ts.map +0 -1
  503. package/dist/types/services/sessionAuth.service.d.ts +0 -141
  504. package/dist/types/services/sessionAuth.service.d.ts.map +0 -1
  505. package/dist/types/utils/CSRF.d.ts +0 -3
  506. package/dist/types/utils/CSRF.d.ts.map +0 -1
  507. package/dist/types/utils/cookies.d.ts +0 -12
  508. package/dist/types/utils/cookies.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/projectAccessKey.controller.ts"],"sourcesContent":["import type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as projectAccessKeyService from '@services/projectAccessKey.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { type ResponseData, formatResponse } from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport type { AccessKeyData, OAuth2Access } from '@/types/project.types';\n\nexport type AddNewAccessKeyBody = AccessKeyData;\nexport type AddNewAccessKeyResponse = ResponseData<OAuth2Access>;\n\n/**\n * Adds a new access key to a project.\n */\nexport const addNewAccessKey = async (\n req: Request<AddNewAccessKeyBody>,\n res: ResponseWithInformation<AddNewAccessKeyResponse>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, organizationRights, projectRights, dictionaryRights } =\n res.locals;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organizationRights) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_RIGHTS_NOT_READ'\n );\n return;\n }\n\n if (!projectRights) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_RIGHTS_NOT_READ');\n return;\n }\n\n if (!dictionaryRights) {\n ErrorHandler.handleGenericErrorResponse(res, 'DICTIONARY_RIGHTS_NOT_READ');\n return;\n }\n\n try {\n const newAccessKey = await projectAccessKeyService.addNewAccessKey(\n req.body,\n project._id,\n user,\n organizationRights,\n projectRights,\n dictionaryRights\n );\n\n const responseData = formatResponse<OAuth2Access>({\n message: t({\n en: 'Access key created successfully',\n es: 'Clave de acceso creada con éxito',\n fr: \"Clé d'accès créée avec succès\",\n }),\n description: t({\n en: 'The access key has been created successfully',\n es: 'La clave de acceso ha sido creada con éxito',\n fr: \"La clé d'accès a été créée avec succès\",\n }),\n data: newAccessKey,\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 DeleteAccessKeyBody = { clientId: string };\nexport type DeleteAccessKeyResponse = ResponseData<null>;\n\n/**\n * Deletes an access key from a project.\n */\nexport const deleteAccessKey = async (\n req: Request,\n res: ResponseWithInformation<AddNewAccessKeyResponse>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project } = res.locals;\n const { clientId } = req.body;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!clientId) {\n ErrorHandler.handleGenericErrorResponse(res, 'CLIENT_ID_NOT_FOUND');\n return;\n }\n\n try {\n const deletedAccessKey = await projectAccessKeyService.deleteAccessKey(\n clientId,\n project,\n user._id\n );\n\n if (!deletedAccessKey) {\n ErrorHandler.handleGenericErrorResponse(res, 'ACCESS_KEY_NOT_FOUND', {\n clientId,\n });\n return;\n }\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Access key deleted successfully',\n es: 'Clave de acceso eliminada con éxito',\n fr: \"Clé d'accès supprimée avec succès\",\n }),\n description: t({\n en: 'The access key has been deleted successfully',\n es: 'La clave de acceso ha sido eliminada con éxito',\n fr: \"La clé d'accès a été supprimée avec succès\",\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\nexport type RefreshAccessKeyBody = { clientId: string };\nexport type RefreshAccessKeyResponse = ResponseData<OAuth2Access>;\n\n/**\n * Refreshes an access key from a project.\n */\nexport const refreshAccessKey = async (\n req: Request<RefreshAccessKeyBody>,\n res: ResponseWithInformation<RefreshAccessKeyResponse>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project } = res.locals;\n const { clientId } = req.body;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n }\n\n if (!clientId) {\n ErrorHandler.handleGenericErrorResponse(res, 'CLIENT_ID_NOT_FOUND');\n }\n\n try {\n const newAccessKey = await projectAccessKeyService.refreshAccessKey(\n clientId,\n project!._id,\n user!._id\n );\n\n const responseData = formatResponse<OAuth2Access>({\n message: t({\n en: 'Access key refreshed successfully',\n es: 'Clave de acceso actualizada con éxito',\n fr: \"Clé d'accès actualisée avec succès\",\n }),\n description: t({\n en: 'The access key has been refreshed successfully',\n es: 'La clave de acceso ha sido actualizada con éxito',\n fr: \"La clé d'accès a été actualisée avec succès\",\n }),\n data: newAccessKey,\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/projectAccessKey.controller.ts"],"sourcesContent":["import type { AccessKeyData, OAuth2Access } from '@/types/project.types';\nimport { sendEmail } from '@services/email.service';\nimport * as projectAccessKeyService from '@services/projectAccessKey.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { hasPermission } from '@utils/permissions';\nimport { type ResponseData, formatResponse } from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport { t } from 'express-intlayer';\n\nexport type AddNewAccessKeyBody = AccessKeyData;\nexport type AddNewAccessKeyResponse = ResponseData<OAuth2Access>;\n\n/**\n * Adds a new access key to a project.\n */\nexport const addNewAccessKey = async (\n req: Request<AddNewAccessKeyBody>,\n res: Response<AddNewAccessKeyResponse>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'project:write')()) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const newAccessKey = await projectAccessKeyService.addNewAccessKey(\n req.body,\n project.id,\n user\n );\n\n const responseData = formatResponse<OAuth2Access>({\n message: t({\n en: 'Access key created successfully',\n es: 'Clave de acceso creada con éxito',\n fr: \"Clé d'accès créée avec succès\",\n }),\n description: t({\n en: 'The access key has been created successfully',\n es: 'La clave de acceso ha sido creada con éxito',\n fr: \"La clé d'accès a été créée avec succès\",\n }),\n data: newAccessKey,\n });\n\n res.json(responseData);\n\n sendEmail({\n type: 'oAuthTokenCreated',\n to: user.email,\n username: user.name,\n applicationName: newAccessKey.clientId,\n scopes: newAccessKey.grants,\n tokenDetailsUrl: `${process.env.CLIENT_URL}/oauth2/token`,\n securityLogUrl: `${process.env.CLIENT_URL}/security-log`,\n supportUrl: `${process.env.CLIENT_URL}/support`,\n });\n\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteAccessKeyBody = { clientId: string };\nexport type DeleteAccessKeyResponse = ResponseData<null>;\n\n/**\n * Deletes an access key from a project.\n */\nexport const deleteAccessKey = async (\n req: Request,\n res: Response<AddNewAccessKeyResponse>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n const { clientId } = req.body;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!clientId) {\n ErrorHandler.handleGenericErrorResponse(res, 'CLIENT_ID_NOT_FOUND');\n return;\n }\n\n if (!hasPermission(roles, 'project:write')()) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const deletedAccessKey = await projectAccessKeyService.deleteAccessKey(\n clientId,\n project,\n user.id\n );\n\n if (!deletedAccessKey) {\n ErrorHandler.handleGenericErrorResponse(res, 'ACCESS_KEY_NOT_FOUND', {\n clientId,\n });\n return;\n }\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Access key deleted successfully',\n es: 'Clave de acceso eliminada con éxito',\n fr: \"Clé d'accès supprimée avec succès\",\n }),\n description: t({\n en: 'The access key has been deleted successfully',\n es: 'La clave de acceso ha sido eliminada con éxito',\n fr: \"La clé d'accès a été supprimée avec succès\",\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\nexport type RefreshAccessKeyBody = { clientId: string };\nexport type RefreshAccessKeyResponse = ResponseData<OAuth2Access>;\n\n/**\n * Refreshes an access key from a project.\n */\nexport const refreshAccessKey = async (\n req: Request<RefreshAccessKeyBody>,\n res: Response<RefreshAccessKeyResponse>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n const { clientId } = req.body;\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n }\n\n if (!clientId) {\n ErrorHandler.handleGenericErrorResponse(res, 'CLIENT_ID_NOT_FOUND');\n }\n\n if (!hasPermission(roles, 'project:write')()) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const newAccessKey = await projectAccessKeyService.refreshAccessKey(\n clientId,\n project!.id,\n user!.id\n );\n\n const responseData = formatResponse<OAuth2Access>({\n message: t({\n en: 'Access key refreshed successfully',\n es: 'Clave de acceso actualizada con éxito',\n fr: \"Clé d'accès actualisée avec succès\",\n }),\n description: t({\n en: 'The access key has been refreshed successfully',\n es: 'La clave de acceso ha sido actualizada con éxito',\n fr: \"La clé d'accès a été actualisée avec succès\",\n }),\n data: newAccessKey,\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 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/search.controller.ts"],"sourcesContent":["import type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as askDocQuestionUtil from '@utils/AI/askDocQuestion/askDocQuestion';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { Request } from 'express';\n\nexport type SearchDocUtilParams = {\n input: string;\n};\nexport type SearchDocUtilResult = ResponseData<string[]>;\n\nexport const searchDocUtil = async (\n req: Request<unknown, unknown, unknown, SearchDocUtilParams>,\n res: ResponseWithInformation<SearchDocUtilResult>\n) => {\n const { input } = req.query;\n\n const response = await askDocQuestionUtil.searchChunkReference(\n input,\n 30,\n 0.2\n );\n const docFileList = response.map((doc) => doc.fileKey);\n\n const uniqueDocFileList = Array.from(new Set(docFileList));\n\n const responseData = formatResponse<string[]>({\n data: uniqueDocFileList,\n });\n\n res.json(responseData);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,yBAAoC;AACpC,0BAAkD;AAQ3C,MAAM,gBAAgB,OAC3B,KACA,QACG;AACH,QAAM,EAAE,MAAM,IAAI,IAAI;AAEtB,QAAM,WAAW,MAAM,mBAAmB;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,cAAc,SAAS,IAAI,CAAC,QAAQ,IAAI,OAAO;AAErD,QAAM,oBAAoB,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC;AAEzD,QAAM,mBAAe,oCAAyB;AAAA,IAC5C,MAAM;AAAA,EACR,CAAC;AAED,MAAI,KAAK,YAAY;AACvB;","names":[]}
1
+ {"version":3,"sources":["../../../src/controllers/search.controller.ts"],"sourcesContent":["import * as askDocQuestionUtil from '@utils/AI/askDocQuestion/askDocQuestion';\n\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { Request, Response } from 'express';\n\nexport type SearchDocUtilParams = {\n input: string;\n};\nexport type SearchDocUtilResult = ResponseData<string[]>;\n\nexport const searchDocUtil = async (\n req: Request<unknown, unknown, unknown, SearchDocUtilParams>,\n res: Response<SearchDocUtilResult>\n) => {\n const { input } = req.query;\n\n const response = await askDocQuestionUtil.searchChunkReference(\n input,\n 30,\n 0.2\n );\n const docFileList = response.map((doc) => doc.fileKey);\n\n const uniqueDocFileList = Array.from(new Set(docFileList));\n\n const responseData = formatResponse<string[]>({\n data: uniqueDocFileList,\n });\n\n res.json(responseData);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAoC;AAEpC,0BAAkD;AAQ3C,MAAM,gBAAgB,OAC3B,KACA,QACG;AACH,QAAM,EAAE,MAAM,IAAI,IAAI;AAEtB,QAAM,WAAW,MAAM,mBAAmB;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,cAAc,SAAS,IAAI,CAAC,QAAQ,IAAI,OAAO;AAErD,QAAM,oBAAoB,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC;AAEzD,QAAM,mBAAe,oCAAyB;AAAA,IAC5C,MAAM;AAAA,EACR,CAAC;AAED,MAAI,KAAK,YAAY;AACvB;","names":[]}
@@ -64,24 +64,10 @@ const getSubscription = async (req, res) => {
64
64
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_FOUND");
65
65
  return;
66
66
  }
67
- if (!organization.membersIds.map(String).includes(String(user._id))) {
68
- import_errors.ErrorHandler.handleGenericErrorResponse(
69
- res,
70
- "USER_NOT_ORGANIZATION_MEMBER"
71
- );
72
- return;
73
- }
74
- if (!organization.adminsIds.map(String).includes(String(user._id))) {
75
- import_errors.ErrorHandler.handleGenericErrorResponse(
76
- res,
77
- "USER_NOT_ORGANIZATION_ADMIN"
78
- );
79
- return;
80
- }
81
67
  const { period, type } = (0, import_plan.retrievePlanInformation)(priceId);
82
68
  if (organization.plan?.subscriptionId && organization.plan?.type === type && organization.plan?.period === period && organization.plan?.status === "active") {
83
69
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "ALREADY_SUBSCRIBED", {
84
- organizationId: organization._id
70
+ organizationId: organization.id
85
71
  });
86
72
  return;
87
73
  }
@@ -89,8 +75,8 @@ const getSubscription = async (req, res) => {
89
75
  if (!customerId) {
90
76
  const customer = await stripe.customers.create({
91
77
  metadata: {
92
- organizationId: String(organization._id),
93
- userId: String(user._id),
78
+ organizationId: String(organization.id),
79
+ userId: String(user.id),
94
80
  // Include the locale for potential localization
95
81
  locale: res.locals.locale
96
82
  }
@@ -148,13 +134,6 @@ const cancelSubscription = async (_req, res) => {
148
134
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_FOUND");
149
135
  return;
150
136
  }
151
- if (!organization.adminsIds.map(String).includes(String(user._id))) {
152
- import_errors.ErrorHandler.handleGenericErrorResponse(
153
- res,
154
- "USER_NOT_ORGANIZATION_ADMIN"
155
- );
156
- return;
157
- }
158
137
  if (!organization.plan?.subscriptionId) {
159
138
  import_errors.ErrorHandler.handleGenericErrorResponse(
160
139
  res,
@@ -165,7 +144,7 @@ const cancelSubscription = async (_req, res) => {
165
144
  await stripe.subscriptions.cancel(organization.plan.subscriptionId);
166
145
  const plan = await subscriptionService.cancelSubscription(
167
146
  organization.plan.subscriptionId,
168
- String(organization._id)
147
+ String(organization.id)
169
148
  );
170
149
  if (!plan) {
171
150
  import_errors.ErrorHandler.handleGenericErrorResponse(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/stripe.controller.ts"],"sourcesContent":["import type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as emailService from '@services/email.service';\nimport * as subscriptionService from '@services/subscription.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { retrievePlanInformation } from '@utils/plan';\nimport { type ResponseData, formatResponse } from '@utils/responseData';\nimport type { Request } from 'express';\nimport { t } from 'express-intlayer';\nimport type { Locales } from 'intlayer';\nimport { Stripe } from 'stripe';\nimport type { Organization } from '@/types/organization.types';\n\nexport type GetPricingBody = {\n priceIds: string[];\n promoCode?: string;\n};\n\nexport type GetPricingResult = ResponseData<subscriptionService.PricingResult>;\n\n/**\n * Simulate pricing for a given set of prices and a promotion code.\n *\n * @param req - The request object containing the price IDs and promotion code.\n * @param res - The response object to send the simulated pricing result.\n */\nexport const getPricing = async (\n req: Request<undefined, undefined, GetPricingBody>,\n res: ResponseWithInformation<GetPricingResult>\n) => {\n const { priceIds, promoCode } = req.body;\n\n const pricingResult = await subscriptionService.getPricing(\n priceIds,\n promoCode\n );\n\n const formattedPricingResult =\n formatResponse<subscriptionService.PricingResult>({\n data: pricingResult,\n });\n\n res.status(200).json(formattedPricingResult);\n};\n\nexport type GetCheckoutSessionBody = {\n priceId: string;\n promoCode?: string;\n};\n\nexport type GetCheckoutSessionResult = ResponseData<\n Stripe.Response<Stripe.Subscription>\n>;\n\n/**\n * Handles subscription creation or update with Stripe and returns a ClientSecret.\n * @param req - Express request object.\n * @param res - Express response object.\n */\nexport const getSubscription = async (\n req: Request<undefined, undefined, GetCheckoutSessionBody>,\n res: ResponseWithInformation<GetCheckoutSessionResult>\n): Promise<void> => {\n try {\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\n // Extract organization and user from response locals (set by authentication middleware)\n const { organization, user } = res.locals;\n // Get the price ID (Stripe Price ID) from the request body\n const { priceId, promoCode } = req.body;\n\n // Validate that the organization exists\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND');\n return;\n }\n\n // Validate that the user exists\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n // Ensure the user is a member of the organization\n if (!organization.membersIds.map(String).includes(String(user._id))) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_NOT_ORGANIZATION_MEMBER'\n );\n return;\n }\n\n // Ensure the user is an admin of the organization\n if (!organization.adminsIds.map(String).includes(String(user._id))) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_NOT_ORGANIZATION_ADMIN'\n );\n return;\n }\n\n const { period, type } = retrievePlanInformation(priceId);\n\n if (\n organization.plan?.subscriptionId &&\n organization.plan?.type === type &&\n organization.plan?.period === period &&\n organization.plan?.status === 'active'\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'ALREADY_SUBSCRIBED', {\n organizationId: organization._id,\n });\n return;\n }\n\n // Attempt to retrieve the Stripe customer ID from the organization's plan\n let customerId = organization.plan?.customerId;\n\n if (!customerId) {\n // If no customer ID exists, create a new Stripe customer for the organization\n const customer = await stripe.customers.create({\n metadata: {\n organizationId: String(organization._id),\n userId: String(user._id),\n // Include the locale for potential localization\n locale: (res.locals as unknown as { locale: Locales }).locale,\n },\n });\n customerId = customer.id;\n }\n\n const promoCodeId = promoCode\n ? await subscriptionService.getCouponId(promoCode)\n : null;\n\n const discounts: Stripe.SubscriptionCreateParams.Discount[] = promoCodeId\n ? [{ coupon: promoCodeId }]\n : [];\n\n // If no subscription exists, create a new one\n const subscription = await stripe.subscriptions.create({\n customer: customerId, // Associate the subscription with the customer\n items: [{ price: priceId }], // Set the price ID for the subscription\n expand: ['latest_invoice.payment_intent'], // Expand to get payment intent details\n payment_settings: {\n payment_method_types: ['card'], // Specify payment method types\n },\n payment_behavior: 'default_incomplete', // Create the subscription in an incomplete state until payment is confirmed\n discounts: discounts,\n });\n\n // Handle subscription creation failure\n if (!subscription) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'SUBSCRIPTION_CREATION_FAILED',\n {\n user,\n organization,\n priceId,\n }\n );\n return;\n }\n\n // Prepare the response data with subscription details\n const responseData = formatResponse<Stripe.Response<Stripe.Subscription>>({\n data: subscription,\n });\n\n // Send the response back to the client\n res.json(responseData);\n\n return;\n } catch (error) {\n // Handle any errors that occur during the process\n\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\ntype CancelSubscriptionData = Organization['plan'];\n\ntype CancelSubscriptionResult = ResponseData<CancelSubscriptionData>;\n\n/**\n * Cancels a subscription for an organization.\n * @param _req - Express request object.\n * @param res - Express response object.\n */\nexport const cancelSubscription = async (\n _req: Request,\n res: ResponseWithInformation<CancelSubscriptionResult>\n): Promise<void> => {\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\n try {\n // Extract the organization and user from the response locals\n // These are typically set by authentication middleware earlier in the request pipeline\n const { organization, user } = res.locals;\n\n // Validate that the organization exists\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND');\n return;\n }\n\n // Validate that the user exists\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n // Check if the user is an admin of the organization\n if (!organization.adminsIds.map(String).includes(String(user._id))) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'USER_NOT_ORGANIZATION_ADMIN'\n );\n return;\n }\n\n // Check if the organization has an active subscription to cancel\n if (!organization.plan?.subscriptionId) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_PLAN_NOT_FOUND'\n );\n return;\n }\n\n // Cancel the subscription on Stripe immediately using the subscription ID\n await stripe.subscriptions.cancel(organization.plan.subscriptionId);\n\n // Update the organization's plan in the database to reflect the cancellation\n const plan = await subscriptionService.cancelSubscription(\n organization.plan.subscriptionId,\n String(organization._id)\n );\n\n // If the plan could not be updated in the database, handle the error\n if (!plan) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_PLAN_NOT_FOUND'\n );\n return;\n }\n\n // Prepare a formatted response with a success message and the updated plan data\n const formattedPlan = formatResponse<CancelSubscriptionData>({\n message: t({\n en: 'Subscription cancelled successfully',\n fr: 'Souscription annulée avec succès',\n es: 'Suscripción cancelada con éxito',\n }),\n description: t({\n en: 'Your subscription has been cancelled successfully',\n fr: 'Votre souscription a été annulée avec succès',\n es: 'Su suscripción ha sido cancelada con éxito',\n }),\n data: plan!,\n });\n\n // Send the response back to the client\n res.json(formattedPlan);\n\n await emailService.sendEmail({\n type: 'subscriptionPaymentCancellation',\n to: user.email,\n email: user.email,\n cancellationDate: new Date().toLocaleDateString(),\n reactivateLink: `${process.env.CLIENT_URL}/pricing`,\n username: user.name,\n organizationName: organization.name,\n planName: plan.type,\n });\n } catch (error) {\n // Handle any errors that occur during the cancellation process\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n }\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/controllers/stripe.controller.ts"],"sourcesContent":["import type { Organization } from '@/types/organization.types';\nimport * as emailService from '@services/email.service';\nimport * as subscriptionService from '@services/subscription.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { retrievePlanInformation } from '@utils/plan';\nimport { type ResponseData, formatResponse } from '@utils/responseData';\nimport type { Request, Response } from 'express';\nimport { t } from 'express-intlayer';\nimport type { Locales } from 'intlayer';\nimport { Stripe } from 'stripe';\n\nexport type GetPricingBody = {\n priceIds: string[];\n promoCode?: string;\n};\n\nexport type GetPricingResult = ResponseData<subscriptionService.PricingResult>;\n\n/**\n * Simulate pricing for a given set of prices and a promotion code.\n *\n * @param req - The request object containing the price IDs and promotion code.\n * @param res - The response object to send the simulated pricing result.\n */\nexport const getPricing = async (\n req: Request<undefined, undefined, GetPricingBody>,\n res: Response<GetPricingResult>\n) => {\n const { priceIds, promoCode } = req.body;\n\n const pricingResult = await subscriptionService.getPricing(\n priceIds,\n promoCode\n );\n\n const formattedPricingResult =\n formatResponse<subscriptionService.PricingResult>({\n data: pricingResult,\n });\n\n res.status(200).json(formattedPricingResult);\n};\n\nexport type GetCheckoutSessionBody = {\n priceId: string;\n promoCode?: string;\n};\n\nexport type GetCheckoutSessionResult = ResponseData<\n Stripe.Response<Stripe.Subscription>\n>;\n\n/**\n * Handles subscription creation or update with Stripe and returns a ClientSecret.\n * @param req - Express request object.\n * @param res - Express response object.\n */\nexport const getSubscription = async (\n req: Request<undefined, undefined, GetCheckoutSessionBody>,\n res: Response<GetCheckoutSessionResult>\n): Promise<void> => {\n try {\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\n // Extract organization and user from response locals (set by authentication middleware)\n const { organization, user } = res.locals;\n // Get the price ID (Stripe Price ID) from the request body\n const { priceId, promoCode } = req.body;\n\n // Validate that the organization exists\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND');\n return;\n }\n\n // Validate that the user exists\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n const { period, type } = retrievePlanInformation(priceId);\n\n if (\n organization.plan?.subscriptionId &&\n organization.plan?.type === type &&\n organization.plan?.period === period &&\n organization.plan?.status === 'active'\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'ALREADY_SUBSCRIBED', {\n organizationId: organization.id,\n });\n return;\n }\n\n // Attempt to retrieve the Stripe customer ID from the organization's plan\n let customerId = organization.plan?.customerId;\n\n if (!customerId) {\n // If no customer ID exists, create a new Stripe customer for the organization\n const customer = await stripe.customers.create({\n metadata: {\n organizationId: String(organization.id),\n userId: String(user.id),\n // Include the locale for potential localization\n locale: (res.locals as unknown as { locale: Locales }).locale,\n },\n });\n customerId = customer.id;\n }\n\n const promoCodeId = promoCode\n ? await subscriptionService.getCouponId(promoCode)\n : null;\n\n const discounts: Stripe.SubscriptionCreateParams.Discount[] = promoCodeId\n ? [{ coupon: promoCodeId }]\n : [];\n\n // If no subscription exists, create a new one\n const subscription = await stripe.subscriptions.create({\n customer: customerId, // Associate the subscription with the customer\n items: [{ price: priceId }], // Set the price ID for the subscription\n expand: ['latest_invoice.payment_intent'], // Expand to get payment intent details\n payment_settings: {\n payment_method_types: ['card'], // Specify payment method types\n },\n payment_behavior: 'default_incomplete', // Create the subscription in an incomplete state until payment is confirmed\n discounts: discounts,\n });\n\n // Handle subscription creation failure\n if (!subscription) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'SUBSCRIPTION_CREATION_FAILED',\n {\n user,\n organization,\n priceId,\n }\n );\n return;\n }\n\n // Prepare the response data with subscription details\n const responseData = formatResponse<Stripe.Response<Stripe.Subscription>>({\n data: subscription,\n });\n\n // Send the response back to the client\n res.json(responseData);\n\n return;\n } catch (error) {\n // Handle any errors that occur during the process\n\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\ntype CancelSubscriptionData = Organization['plan'];\n\ntype CancelSubscriptionResult = ResponseData<CancelSubscriptionData>;\n\n/**\n * Cancels a subscription for an organization.\n * @param _req - Express request object.\n * @param res - Express response object.\n */\nexport const cancelSubscription = async (\n _req: Request,\n res: Response<CancelSubscriptionResult>\n): Promise<void> => {\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\n try {\n // Extract the organization and user from the response locals\n // These are typically set by authentication middleware earlier in the request pipeline\n const { organization, user } = res.locals;\n\n // Validate that the organization exists\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND');\n return;\n }\n\n // Validate that the user exists\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n // Check if the organization has an active subscription to cancel\n if (!organization.plan?.subscriptionId) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_PLAN_NOT_FOUND'\n );\n return;\n }\n\n // Cancel the subscription on Stripe immediately using the subscription ID\n await stripe.subscriptions.cancel(organization.plan.subscriptionId);\n\n // Update the organization's plan in the database to reflect the cancellation\n const plan = await subscriptionService.cancelSubscription(\n organization.plan.subscriptionId,\n String(organization.id)\n );\n\n // If the plan could not be updated in the database, handle the error\n if (!plan) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_PLAN_NOT_FOUND'\n );\n return;\n }\n\n // Prepare a formatted response with a success message and the updated plan data\n const formattedPlan = formatResponse<CancelSubscriptionData>({\n message: t({\n en: 'Subscription cancelled successfully',\n fr: 'Souscription annulée avec succès',\n es: 'Suscripción cancelada con éxito',\n }),\n description: t({\n en: 'Your subscription has been cancelled successfully',\n fr: 'Votre souscription a été annulée avec succès',\n es: 'Su suscripción ha sido cancelada con éxito',\n }),\n data: plan!,\n });\n\n // Send the response back to the client\n res.json(formattedPlan);\n\n await emailService.sendEmail({\n type: 'subscriptionPaymentCancellation',\n to: user.email,\n email: user.email,\n cancellationDate: new Date().toLocaleDateString(),\n reactivateLink: `${process.env.CLIENT_URL}/pricing`,\n username: user.name,\n organizationName: organization.name,\n planName: plan.type,\n });\n } catch (error) {\n // Handle any errors that occur during the cancellation process\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n }\n};\n"],"mappings":"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","names":[]}
@@ -39,10 +39,11 @@ var tagService = __toESM(require('./../services/tag.service.cjs'), 1);
39
39
  var import_errors = require('./../utils/errors/index.cjs');
40
40
  var import_getTagFiltersAndPagination = require('./../utils/filtersAndPagination/getTagFiltersAndPagination.cjs');
41
41
  var import_tag = require('./../utils/mapper/tag.cjs');
42
+ var import_permissions = require('./../utils/permissions.cjs');
42
43
  var import_responseData = require('./../utils/responseData.cjs');
43
44
  var import_express_intlayer = require("express-intlayer");
44
45
  const getTags = async (req, res, _next) => {
45
- const { user, organization } = res.locals;
46
+ const { user, organization, roles } = res.locals;
46
47
  const { filters, pageSize, skip, page, getNumberOfPages } = (0, import_getTagFiltersAndPagination.getTagFiltersAndPagination)(req);
47
48
  if (!user) {
48
49
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
@@ -52,9 +53,13 @@ const getTags = async (req, res, _next) => {
52
53
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
53
54
  return;
54
55
  }
56
+ if (!(0, import_permissions.hasPermission)(roles, "tag:read")()) {
57
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
58
+ return;
59
+ }
55
60
  const restrictedFilter = {
56
61
  ...filters,
57
- organizationId: String(organization._id)
62
+ organizationId: String(organization.id)
58
63
  };
59
64
  try {
60
65
  const tags = await tagService.findTags(restrictedFilter, skip, pageSize);
@@ -75,7 +80,7 @@ const getTags = async (req, res, _next) => {
75
80
  }
76
81
  };
77
82
  const addTag = async (req, res, _next) => {
78
- const { organization, user, isOrganizationAdmin } = res.locals;
83
+ const { organization, user, roles } = res.locals;
79
84
  const tagData = req.body;
80
85
  if (!user) {
81
86
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
@@ -85,18 +90,16 @@ const addTag = async (req, res, _next) => {
85
90
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
86
91
  return;
87
92
  }
88
- if (!isOrganizationAdmin) {
89
- import_errors.ErrorHandler.handleGenericErrorResponse(
90
- res,
91
- "USER_IS_NOT_ADMIN_OF_ORGANIZATION"
92
- );
93
- }
94
93
  if (!tagData) {
95
94
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "PROJECT_DATA_NOT_FOUND");
96
95
  }
96
+ if (!(0, import_permissions.hasPermission)(roles, "tag:admin")(res.locals)) {
97
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
98
+ return;
99
+ }
97
100
  const tag = {
98
- creatorId: user._id,
99
- organizationId: organization._id,
101
+ creatorId: user.id,
102
+ organizationId: organization.id,
100
103
  ...tagData
101
104
  };
102
105
  try {
@@ -124,7 +127,7 @@ const addTag = async (req, res, _next) => {
124
127
  };
125
128
  const updateTag = async (req, res, _next) => {
126
129
  const { tagId } = req.params;
127
- const { organization, user } = res.locals;
130
+ const { organization, user, roles } = res.locals;
128
131
  if (!user) {
129
132
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
130
133
  return;
@@ -133,6 +136,10 @@ const updateTag = async (req, res, _next) => {
133
136
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
134
137
  return;
135
138
  }
139
+ if (!(0, import_permissions.hasPermission)(roles, "tag:write")()) {
140
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
141
+ return;
142
+ }
136
143
  try {
137
144
  const tag = {
138
145
  _id: tagId,
@@ -142,7 +149,7 @@ const updateTag = async (req, res, _next) => {
142
149
  instructions: req.body.instructions
143
150
  };
144
151
  const tagToDelete = await tagService.getTagById(tagId);
145
- if (String(tagToDelete.organizationId) !== String(organization._id)) {
152
+ if (String(tagToDelete.organizationId) !== String(organization.id)) {
146
153
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "TAG_NOT_IN_ORGANIZATION");
147
154
  return;
148
155
  }
@@ -169,7 +176,7 @@ const updateTag = async (req, res, _next) => {
169
176
  }
170
177
  };
171
178
  const deleteTag = async (req, res, _next) => {
172
- const { user, organization } = res.locals;
179
+ const { user, organization, roles } = res.locals;
173
180
  const { tagId } = req.params;
174
181
  if (!user) {
175
182
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
@@ -183,9 +190,13 @@ const deleteTag = async (req, res, _next) => {
183
190
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "TAG_ID_NOT_FOUND");
184
191
  return;
185
192
  }
193
+ if (!(0, import_permissions.hasPermission)(roles, "tag:admin")(res.locals)) {
194
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
195
+ return;
196
+ }
186
197
  try {
187
198
  const tagToDelete = await tagService.getTagById(tagId);
188
- if (String(tagToDelete.organizationId) !== String(organization._id)) {
199
+ if (String(tagToDelete.organizationId) !== String(organization.id)) {
189
200
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "TAG_NOT_IN_ORGANIZATION");
190
201
  return;
191
202
  }
@@ -196,7 +207,7 @@ const deleteTag = async (req, res, _next) => {
196
207
  });
197
208
  return;
198
209
  }
199
- import_logger.logger.info(`Tag deleted: ${String(deletedTag._id)}`);
210
+ import_logger.logger.info(`Tag deleted: ${String(deletedTag.id)}`);
200
211
  const formattedTag = (0, import_tag.mapTagToAPI)(deletedTag);
201
212
  const responseData = (0, import_responseData.formatResponse)({
202
213
  message: (0, import_express_intlayer.t)({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/tag.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport * as tagService from '@services/tag.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getTagFiltersAndPagination,\n type TagFilters,\n type TagFiltersParams,\n} from '@utils/filtersAndPagination/getTagFiltersAndPagination';\nimport { mapTagsToAPI, mapTagToAPI } from '@utils/mapper/tag';\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 { Tag, TagAPI, TagCreationData, TagData } from '@/types/tag.types';\n\nexport type GetTagsParams = FiltersAndPagination<TagFiltersParams>;\nexport type GetTagsResult = PaginatedResponse<TagAPI>;\n\n/**\n * Retrieves a list of tags based on filters and pagination.\n */\nexport const getTags = async (\n req: Request<GetTagsParams>,\n res: ResponseWithInformation<GetTagsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getTagFiltersAndPagination(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 const restrictedFilter: TagFilters = {\n ...filters,\n organizationId: String(organization._id),\n };\n\n try {\n const tags = await tagService.findTags(restrictedFilter, skip, pageSize);\n const totalItems = await tagService.countTags(filters);\n\n const formattedTags = mapTagsToAPI(tags);\n\n const responseData = formatPaginatedResponse<TagAPI>({\n data: formattedTags,\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 AddTagBody = TagCreationData;\nexport type AddTagResult = ResponseData<TagAPI>;\n\n/**\n * Adds a new tag to the database.\n */\nexport const addTag = async (\n req: Request<any, any, AddTagBody>,\n res: ResponseWithInformation<AddTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, isOrganizationAdmin } = res.locals;\n const tagData = 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 (!tagData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n }\n\n const tag: TagData = {\n creatorId: user._id,\n organizationId: organization._id,\n ...tagData,\n };\n\n try {\n const newTag = await tagService.createTag(tag);\n\n const formattedTag = mapTagToAPI(newTag);\n\n const responseData = formatResponse<TagAPI>({\n message: t({\n en: 'Tag created successfully',\n fr: 'Tag créé avec succès',\n es: 'Tag creado con éxito',\n }),\n description: t({\n en: 'Your tag has been created successfully',\n fr: 'Votre tag a été créé avec succès',\n es: 'Su tag ha sido creado con éxito',\n }),\n data: formattedTag,\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 UpdateTagParams = { tagId: string | Tag['_id'] };\nexport type UpdateTagBody = Partial<TagData>;\nexport type UpdateTagResult = ResponseData<TagAPI>;\n\n/**\n * Updates an existing tag in the database.\n */\nexport const updateTag = async (\n req: Request<UpdateTagParams, any, UpdateTagBody>,\n res: ResponseWithInformation<UpdateTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { tagId } = req.params;\n const { organization, user } = 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 try {\n const tag = {\n _id: tagId as TagAPI['_id'],\n name: req.body.name,\n key: req.body.key,\n description: req.body.description,\n instructions: req.body.instructions,\n };\n\n const tagToDelete = await tagService.getTagById(tagId);\n\n if (String(tagToDelete.organizationId) !== String(organization._id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_NOT_IN_ORGANIZATION');\n return;\n }\n\n const updatedTag = await tagService.updateTagById(tag._id, tag);\n\n const formattedTag = mapTagToAPI(updatedTag);\n\n const responseData = formatResponse<TagAPI>({\n message: t({\n en: 'Tag updated successfully',\n fr: 'Tag mis à jour avec succès',\n es: 'Tag actualizado con éxito',\n }),\n description: t({\n en: 'Your tag has been updated successfully',\n fr: 'Votre tag a été mis à jour avec succès',\n es: 'Su tag ha sido actualizado con éxito',\n }),\n data: formattedTag,\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 DeleteTagParams = { tagId: string | Tag['_id'] };\nexport type DeleteTagResult = ResponseData<TagAPI>;\n\n/**\n * Deletes a tag 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 deleteTag = async (\n req: Request<DeleteTagParams>,\n res: ResponseWithInformation<DeleteTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization } = res.locals;\n const { tagId } = req.params;\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 (!tagId) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_ID_NOT_FOUND');\n return;\n }\n\n try {\n const tagToDelete = await tagService.getTagById(tagId);\n\n if (String(tagToDelete.organizationId) !== String(organization._id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_NOT_IN_ORGANIZATION');\n return;\n }\n\n const deletedTag = await tagService.deleteTagById(tagId);\n\n if (!deletedTag) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_NOT_FOUND', {\n tagId,\n });\n\n return;\n }\n\n logger.info(`Tag deleted: ${String(deletedTag._id)}`);\n\n const formattedTag = mapTagToAPI(deletedTag);\n\n const responseData = formatResponse<TagAPI>({\n message: t({\n en: 'Tag deleted successfully',\n fr: 'Tag supprimé avec succès',\n es: 'Tag eliminado con éxito',\n }),\n description: t({\n en: 'Your tag has been deleted successfully',\n fr: 'Votre tag a été supprimé avec succès',\n es: 'Su tag ha sido eliminado con éxito',\n }),\n data: formattedTag,\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/tag.controller.ts"],"sourcesContent":["import type {\n Tag,\n TagAPI,\n TagCreationData,\n TagData,\n TagSchema,\n} from '@/types/tag.types';\nimport { logger } from '@logger';\nimport * as tagService from '@services/tag.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getTagFiltersAndPagination,\n type TagFilters,\n type TagFiltersParams,\n} from '@utils/filtersAndPagination/getTagFiltersAndPagination';\nimport { mapTagsToAPI, mapTagToAPI } from '@utils/mapper/tag';\nimport { hasPermission } from '@utils/permissions';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport { t } from 'express-intlayer';\n\nexport type GetTagsParams = FiltersAndPagination<TagFiltersParams>;\nexport type GetTagsResult = PaginatedResponse<TagAPI>;\n\n/**\n * Retrieves a list of tags based on filters and pagination.\n */\nexport const getTags = async (\n req: Request<GetTagsParams>,\n res: Response<GetTagsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, roles } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getTagFiltersAndPagination(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 (!hasPermission(roles, 'tag:read')()) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const restrictedFilter: TagFilters = {\n ...filters,\n organizationId: String(organization.id),\n };\n\n try {\n const tags = await tagService.findTags(restrictedFilter, skip, pageSize);\n const totalItems = await tagService.countTags(filters);\n\n const formattedTags = mapTagsToAPI(tags);\n\n const responseData = formatPaginatedResponse<TagAPI>({\n data: formattedTags,\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 AddTagBody = TagCreationData;\nexport type AddTagResult = ResponseData<TagAPI>;\n\n/**\n * Adds a new tag to the database.\n */\nexport const addTag = async (\n req: Request<any, any, AddTagBody>,\n res: Response<AddTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, roles } = res.locals;\n const tagData = 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 (!tagData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n }\n\n if (!hasPermission(roles, 'tag:admin')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const tag: TagData = {\n creatorId: user.id,\n organizationId: organization.id,\n ...tagData,\n };\n\n try {\n const newTag = await tagService.createTag(tag);\n\n const formattedTag = mapTagToAPI(newTag);\n\n const responseData = formatResponse<TagAPI>({\n message: t({\n en: 'Tag created successfully',\n fr: 'Tag créé avec succès',\n es: 'Tag creado con éxito',\n }),\n description: t({\n en: 'Your tag has been created successfully',\n fr: 'Votre tag a été créé avec succès',\n es: 'Su tag ha sido creado con éxito',\n }),\n data: formattedTag,\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 UpdateTagParams = { tagId: string | Tag['id'] };\nexport type UpdateTagBody = Partial<TagData>;\nexport type UpdateTagResult = ResponseData<TagAPI>;\n\n/**\n * Updates an existing tag in the database.\n */\nexport const updateTag = async (\n req: Request<UpdateTagParams, any, UpdateTagBody>,\n res: Response<UpdateTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { tagId } = req.params;\n const { organization, user, roles } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!hasPermission(roles, 'tag:write')()) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const tag = {\n _id: tagId,\n name: req.body.name,\n key: req.body.key,\n description: req.body.description,\n instructions: req.body.instructions,\n } as Partial<TagSchema> & { _id: Tag['id'] };\n\n const tagToDelete = await tagService.getTagById(tagId);\n\n if (String(tagToDelete.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_NOT_IN_ORGANIZATION');\n return;\n }\n\n const updatedTag = await tagService.updateTagById(tag._id, tag);\n\n const formattedTag = mapTagToAPI(updatedTag);\n\n const responseData = formatResponse<TagAPI>({\n message: t({\n en: 'Tag updated successfully',\n fr: 'Tag mis à jour avec succès',\n es: 'Tag actualizado con éxito',\n }),\n description: t({\n en: 'Your tag has been updated successfully',\n fr: 'Votre tag a été mis à jour avec succès',\n es: 'Su tag ha sido actualizado con éxito',\n }),\n data: formattedTag,\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 DeleteTagParams = { tagId: string | Tag['id'] };\nexport type DeleteTagResult = ResponseData<TagAPI>;\n\n/**\n * Deletes a tag 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 deleteTag = async (\n req: Request<DeleteTagParams>,\n res: Response<DeleteTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, roles } = res.locals;\n const { tagId } = req.params;\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 (!tagId) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_ID_NOT_FOUND');\n return;\n }\n\n if (!hasPermission(roles, 'tag:admin')(res.locals)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const tagToDelete = await tagService.getTagById(tagId);\n\n if (String(tagToDelete.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_NOT_IN_ORGANIZATION');\n return;\n }\n\n const deletedTag = await tagService.deleteTagById(tagId);\n\n if (!deletedTag) {\n ErrorHandler.handleGenericErrorResponse(res, 'TAG_NOT_FOUND', {\n tagId,\n });\n\n return;\n }\n\n logger.info(`Tag deleted: ${String(deletedTag.id)}`);\n\n const formattedTag = mapTagToAPI(deletedTag);\n\n const responseData = formatResponse<TagAPI>({\n message: t({\n en: 'Tag deleted successfully',\n fr: 'Tag supprimé avec succès',\n es: 'Tag eliminado con éxito',\n }),\n description: t({\n en: 'Your tag has been deleted successfully',\n fr: 'Votre tag a été supprimé avec succès',\n es: 'Su tag ha sido eliminado con éxito',\n }),\n data: formattedTag,\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":[]}
@@ -30,20 +30,21 @@ var user_controller_exports = {};
30
30
  __export(user_controller_exports, {
31
31
  createUser: () => createUser,
32
32
  deleteUser: () => deleteUser,
33
- getUserByAccount: () => getUserByAccount,
34
33
  getUserByEmail: () => getUserByEmail,
35
34
  getUserById: () => getUserById,
36
35
  getUsers: () => getUsers,
37
- updateUser: () => updateUser
36
+ sendVerificationUpdate: () => sendVerificationUpdate,
37
+ updateUser: () => updateUser,
38
+ verifyEmailStatusSSE: () => verifyEmailStatusSSE
38
39
  });
39
40
  module.exports = __toCommonJS(user_controller_exports);
40
41
  var import_logger = require('./../logger/index.cjs');
41
- var import_sessionAuth = require('./../routes/sessionAuth.routes.cjs');
42
42
  var import_email = require('./../services/email.service.cjs');
43
43
  var userService = __toESM(require('./../services/user.service.cjs'), 1);
44
44
  var import_errors = require('./../utils/errors/index.cjs');
45
45
  var import_getOrganizationFiltersAndPagination = require('./../utils/filtersAndPagination/getOrganizationFiltersAndPagination.cjs');
46
46
  var import_user = require('./../utils/mapper/user.cjs');
47
+ var import_permissions = require('./../utils/permissions.cjs');
47
48
  var import_responseData = require('./../utils/responseData.cjs');
48
49
  var import_express_intlayer = require("express-intlayer");
49
50
  const createUser = async (req, res, _next) => {
@@ -58,7 +59,7 @@ const createUser = async (req, res, _next) => {
58
59
  type: "welcome",
59
60
  to: newUser.email,
60
61
  username: newUser.name,
61
- loginLink: (0, import_sessionAuth.getSessionAuthRoutes)().loginEmailPassword.url
62
+ loginLink: `${process.env.CLIENT_URL}/auth/login`
62
63
  });
63
64
  const formattedUser = (0, import_user.mapUserToAPI)(newUser);
64
65
  const responseData = (0, import_responseData.formatResponse)({
@@ -82,7 +83,7 @@ const createUser = async (req, res, _next) => {
82
83
  }
83
84
  };
84
85
  const getUsers = async (req, res, _next) => {
85
- const { user } = res.locals;
86
+ const { user, roles } = res.locals;
86
87
  if (!user) {
87
88
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
88
89
  return;
@@ -90,6 +91,16 @@ const getUsers = async (req, res, _next) => {
90
91
  const { filters, pageSize, skip, page, getNumberOfPages } = (0, import_getOrganizationFiltersAndPagination.getOrganizationFiltersAndPagination)(req);
91
92
  try {
92
93
  const users = await userService.findUsers(filters, skip, pageSize);
94
+ if (!(0, import_permissions.hasPermission)(
95
+ roles,
96
+ "user:read"
97
+ )({
98
+ ...res.locals,
99
+ targetUserIds: users.map((user2) => user2.id)
100
+ })) {
101
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
102
+ return;
103
+ }
93
104
  const totalItems = await userService.countUsers(filters);
94
105
  const formattedUsers = (0, import_user.mapUsersToAPI)(users);
95
106
  const responseData = (0, import_responseData.formatPaginatedResponse)({
@@ -125,12 +136,23 @@ const getUserById = async (req, res, _next) => {
125
136
  };
126
137
  const getUserByEmail = async (req, res, _next) => {
127
138
  const { email } = req.params;
139
+ const { roles } = res.locals;
128
140
  try {
129
141
  const user = await userService.getUserByEmail(email);
130
142
  if (!user) {
131
143
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
132
144
  return;
133
145
  }
146
+ if (!(0, import_permissions.hasPermission)(
147
+ roles,
148
+ "user:read"
149
+ )({
150
+ ...res.locals,
151
+ targetUserIds: [user.id]
152
+ })) {
153
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
154
+ return;
155
+ }
134
156
  const formattedUser = (0, import_user.mapUserToAPI)(user);
135
157
  const responseData = (0, import_responseData.formatResponse)({ data: formattedUser });
136
158
  res.json(responseData);
@@ -139,23 +161,9 @@ const getUserByEmail = async (req, res, _next) => {
139
161
  return;
140
162
  }
141
163
  };
142
- const getUserByAccount = async (req, res, _next) => {
143
- const { providerAccountId, provider } = req.params;
144
- try {
145
- const user = await userService.getUserByAccount(
146
- provider,
147
- providerAccountId
148
- );
149
- const formattedUser = (0, import_user.mapUserToAPI)(user);
150
- const responseData = (0, import_responseData.formatResponse)({ data: formattedUser });
151
- res.json(responseData);
152
- } catch (error) {
153
- import_errors.ErrorHandler.handleAppErrorResponse(res, error);
154
- }
155
- };
156
164
  const updateUser = async (req, res, _next) => {
157
165
  const userData = req.body;
158
- const { user } = res.locals;
166
+ const { user, roles } = res.locals;
159
167
  if (!user) {
160
168
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
161
169
  return;
@@ -164,10 +172,20 @@ const updateUser = async (req, res, _next) => {
164
172
  import_errors.ErrorHandler.handleGenericErrorResponse(res, "USER_DATA_NOT_FOUND");
165
173
  return;
166
174
  }
175
+ if (!(0, import_permissions.hasPermission)(
176
+ roles,
177
+ "user:write"
178
+ )({
179
+ ...res.locals,
180
+ targetUserIds: [user.id]
181
+ })) {
182
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
183
+ return;
184
+ }
167
185
  try {
168
- const updatedUser = await userService.updateUserById(user._id, userData);
186
+ const updatedUser = await userService.updateUserById(user.id, userData);
169
187
  import_logger.logger.info(
170
- `User updated: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`
188
+ `User updated: Name: ${updatedUser.name}, id: ${String(updatedUser.id)}`
171
189
  );
172
190
  const formattedUser = (0, import_user.mapUserToAPI)(updatedUser);
173
191
  const responseData = (0, import_responseData.formatResponse)({
@@ -192,6 +210,11 @@ const updateUser = async (req, res, _next) => {
192
210
  };
193
211
  const deleteUser = async (req, res, _next) => {
194
212
  const { userId } = req.params;
213
+ const { roles } = res.locals;
214
+ if (!(0, import_permissions.hasPermission)(roles, "user:admin")()) {
215
+ import_errors.ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
216
+ return;
217
+ }
195
218
  try {
196
219
  const user = await userService.deleteUser(userId);
197
220
  const formattedUser = (0, import_user.mapUserToAPI)(user);
@@ -214,14 +237,55 @@ const deleteUser = async (req, res, _next) => {
214
237
  return;
215
238
  }
216
239
  };
240
+ let clients = [];
241
+ const sendVerificationUpdate = (user) => {
242
+ const filteredClients = clients.filter(
243
+ (client) => String(client.userId) === String(user.id)
244
+ );
245
+ for (const client of filteredClients) {
246
+ if (user.emailVerified) {
247
+ client.res.write(
248
+ `data: ${JSON.stringify({ userId: user.id, status: "verified" })}
249
+
250
+ `
251
+ );
252
+ }
253
+ }
254
+ };
255
+ const verifyEmailStatusSSE = async (req, res) => {
256
+ res.setHeader("Content-Type", "text/event-stream;charset=utf-8");
257
+ res.setHeader("Cache-Control", "no-cache, no-transform");
258
+ res.setHeader("Connection", "keep-alive");
259
+ res.setHeader("X-Accel-Buffering", "no");
260
+ res.write(":\n\n");
261
+ res.flushHeaders();
262
+ const { userId } = req.params;
263
+ const clientId = Date.now();
264
+ const user = await userService.getUserById(userId);
265
+ if (!user) {
266
+ import_logger.logger.error(`User not found - User ID: ${userId}`);
267
+ res.write(`data: ${JSON.stringify({ userId, status: "error" })}
268
+
269
+ `);
270
+ res.end();
271
+ return;
272
+ }
273
+ const newClient = { id: clientId, userId, res };
274
+ clients.push(newClient);
275
+ sendVerificationUpdate(user);
276
+ req.on("close", () => {
277
+ clients = clients.filter((client) => client.id !== clientId);
278
+ });
279
+ };
217
280
  // Annotate the CommonJS export names for ESM import in node:
218
281
  0 && (module.exports = {
219
282
  createUser,
220
283
  deleteUser,
221
- getUserByAccount,
222
284
  getUserByEmail,
223
285
  getUserById,
224
286
  getUsers,
225
- updateUser
287
+ sendVerificationUpdate,
288
+ updateUser,
289
+ verifyEmailStatusSSE
226
290
  });
227
291
  //# sourceMappingURL=user.controller.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/user.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 userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport { getOrganizationFiltersAndPagination } from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport type { UserFiltersParam } from '@utils/filtersAndPagination/getUserFiltersAndPagination';\nimport { mapUsersToAPI, mapUserToAPI } from '@utils/mapper/user';\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 { SessionProviders } from '@/types/session.types';\nimport type {\n User,\n UserAPI,\n UserWithPasswordNotHashed,\n} from '@/types/user.types';\n\nexport type CreateUserBody = { email: string; password?: string };\nexport type CreateUserResult = ResponseData<UserAPI>;\n\n/**\n * Creates a new user.\n */\nexport const createUser = async (\n req: Request<any, any, UserWithPasswordNotHashed>,\n res: ResponseWithInformation<CreateUserResult>,\n _next: NextFunction\n): Promise<void> => {\n const user: UserWithPasswordNotHashed | undefined = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const newUser = await userService.createUser(user);\n\n await sendEmail({\n type: 'welcome',\n to: newUser.email,\n username: newUser.name,\n loginLink: getSessionAuthRoutes().loginEmailPassword.url,\n });\n\n const formattedUser = mapUserToAPI(newUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User created',\n fr: 'Utilisateur créé',\n es: 'Usuario creado',\n }),\n description: t({\n en: 'User created successfully',\n fr: 'Utilisateur créé avec succès',\n es: 'Usuario creado 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\nexport type GetUsersParams = FiltersAndPagination<UserFiltersParam>;\nexport type GetUsersResult = PaginatedResponse<UserAPI>;\n\n/**\n * Retrieves a list of users based on filters and pagination.\n */\nexport const getUsers = async (\n req: Request<GetUsersParams>,\n res: ResponseWithInformation<GetUsersResult>,\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 const { filters, pageSize, skip, page, getNumberOfPages } =\n getOrganizationFiltersAndPagination(req);\n\n try {\n const users = await userService.findUsers(filters, skip, pageSize);\n const totalItems = await userService.countUsers(filters);\n\n const formattedUsers = mapUsersToAPI(users);\n\n const responseData = formatPaginatedResponse<UserAPI>({\n data: formattedUsers,\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 GetUserByIdParams = { userId: string };\nexport type GetUserByIdResult = ResponseData<UserAPI>;\n\nexport const getUserById = async (\n req: Request<GetUserByIdParams>,\n res: ResponseWithInformation<GetUserByIdResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId } = req.params;\n\n try {\n const user = await userService.getUserById(userId);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetUserByEmailParams = { email: string };\nexport type GetUserByEmailResult = ResponseData<UserAPI>;\n\nexport const getUserByEmail = async (\n req: Request<GetUserByEmailParams>,\n res: ResponseWithInformation<GetUserByEmailResult>,\n _next: NextFunction\n): Promise<void> => {\n const { email } = req.params;\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n res.json(responseData);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetUserByAccountParams = {\n providerAccountId: string;\n provider: SessionProviders['provider'];\n};\nexport type GetUserByAccountResult = ResponseData<UserAPI>;\n\n/**\n * Retrieves a user by account.\n */\nexport const getUserByAccount = async (\n req: Request<GetUserByAccountParams>,\n res: ResponseWithInformation<GetUserByAccountResult>,\n _next: NextFunction\n): Promise<void> => {\n const { providerAccountId, provider } = req.params;\n\n try {\n const user = await userService.getUserByAccount(\n provider,\n providerAccountId\n );\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n res.json(responseData);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n }\n};\n\nexport type UpdateUserBody = Partial<User>;\nexport type UpdateUserResult = ResponseData<UserAPI>;\n\n/**\n * Updates user information (phone number, date of birth).\n */\nexport const updateUser = async (\n req: Request<any, any, UpdateUserBody | undefined>,\n res: ResponseWithInformation<UpdateUserResult>,\n _next: NextFunction\n): Promise<void> => {\n const userData = req.body;\n const { user } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (typeof userData !== 'object') {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n try {\n const updatedUser = await userService.updateUserById(user._id, userData);\n\n logger.info(\n `User updated: Name: ${updatedUser.name}, id: ${String(updatedUser._id)}`\n );\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User updated',\n fr: 'Utilisateur mis à jour',\n es: 'Usuario actualizado',\n }),\n description: t({\n en: 'User updated successfully',\n fr: 'Utilisateur mis à jour avec succès',\n es: 'Usuario actualizado 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\nexport type DeleteUserParams = { userId: string };\nexport type DeleteUserResult = ResponseData<UserAPI>;\n\n/**\n * Deletes a user based on the provided ID.\n */\nexport const deleteUser = async (\n req: Request<any, any, DeleteUserParams>,\n res: ResponseWithInformation<DeleteUserResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId } = req.params;\n\n try {\n const user = await userService.deleteUser(userId);\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User deleted',\n fr: 'Utilisateur supprimé',\n es: 'Usuario eliminado',\n }),\n description: t({\n en: 'User deleted successfully',\n fr: 'Utilisateur supprimé avec succès',\n es: 'Usuario eliminado con éxito',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/controllers/user.controller.ts"],"sourcesContent":["import type { User, UserAPI } from '@/types/user.types';\nimport { logger } from '@logger';\nimport { sendEmail } from '@services/email.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport { getOrganizationFiltersAndPagination } from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport type { UserFiltersParam } from '@utils/filtersAndPagination/getUserFiltersAndPagination';\nimport { mapUsersToAPI, mapUserToAPI } from '@utils/mapper/user';\nimport { hasPermission } from '@utils/permissions';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport { t } from 'express-intlayer';\n\nexport type CreateUserBody = { email: string; password?: string };\nexport type CreateUserResult = ResponseData<UserAPI>;\n\n/**\n * Creates a new user.\n */\nexport const createUser = async (\n req: Request<any, any, User>,\n res: Response<CreateUserResult>,\n _next: NextFunction\n): Promise<void> => {\n const user: User | undefined = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const newUser = await userService.createUser(user);\n\n await sendEmail({\n type: 'welcome',\n to: newUser.email,\n username: newUser.name,\n loginLink: `${process.env.CLIENT_URL}/auth/login`,\n });\n\n const formattedUser = mapUserToAPI(newUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User created',\n fr: 'Utilisateur créé',\n es: 'Usuario creado',\n }),\n description: t({\n en: 'User created successfully',\n fr: 'Utilisateur créé avec succès',\n es: 'Usuario creado 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\nexport type GetUsersParams = FiltersAndPagination<UserFiltersParam>;\nexport type GetUsersResult = PaginatedResponse<UserAPI>;\n\n/**\n * Retrieves a list of users based on filters and pagination.\n */\nexport const getUsers = async (\n req: Request<GetUsersParams>,\n res: Response<GetUsersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, roles } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getOrganizationFiltersAndPagination(req);\n\n try {\n const users = await userService.findUsers(filters, skip, pageSize);\n\n if (\n !hasPermission(\n roles,\n 'user:read'\n )({\n ...res.locals,\n targetUserIds: users.map((user) => user.id),\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const totalItems = await userService.countUsers(filters);\n\n const formattedUsers = mapUsersToAPI(users);\n\n const responseData = formatPaginatedResponse<UserAPI>({\n data: formattedUsers,\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 GetUserByIdParams = { userId: string };\nexport type GetUserByIdResult = ResponseData<UserAPI>;\n\nexport const getUserById = async (\n req: Request<GetUserByIdParams>,\n res: Response<GetUserByIdResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId } = req.params;\n\n try {\n const user = await userService.getUserById(userId);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetUserByEmailParams = { email: string };\nexport type GetUserByEmailResult = ResponseData<UserAPI>;\n\nexport const getUserByEmail = async (\n req: Request<GetUserByEmailParams>,\n res: Response<GetUserByEmailResult>,\n _next: NextFunction\n): Promise<void> => {\n const { email } = req.params;\n const { roles } = res.locals;\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:read'\n )({\n ...res.locals,\n targetUserIds: [user.id],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({ data: formattedUser });\n\n res.json(responseData);\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateUserBody = Partial<User>;\nexport type UpdateUserResult = ResponseData<UserAPI>;\n\n/**\n * Updates user information (phone number, date of birth).\n */\nexport const updateUser = async (\n req: Request<any, any, UpdateUserBody | undefined>,\n res: Response<UpdateUserResult>,\n _next: NextFunction\n): Promise<void> => {\n const userData = req.body;\n const { user, roles } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (typeof userData !== 'object') {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:write'\n )({\n ...res.locals,\n targetUserIds: [user.id],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const updatedUser = await userService.updateUserById(user.id, userData);\n\n logger.info(\n `User updated: Name: ${updatedUser.name}, id: ${String(updatedUser.id)}`\n );\n\n const formattedUser = mapUserToAPI(updatedUser);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User updated',\n fr: 'Utilisateur mis à jour',\n es: 'Usuario actualizado',\n }),\n description: t({\n en: 'User updated successfully',\n fr: 'Utilisateur mis à jour avec succès',\n es: 'Usuario actualizado 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\nexport type DeleteUserParams = { userId: string };\nexport type DeleteUserResult = ResponseData<UserAPI>;\n\n/**\n * Deletes a user based on the provided ID.\n */\nexport const deleteUser = async (\n req: Request<any, any, DeleteUserParams>,\n res: Response<DeleteUserResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId } = req.params;\n const { roles } = res.locals;\n\n if (!hasPermission(roles, 'user:admin')()) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const user = await userService.deleteUser(userId);\n\n const formattedUser = mapUserToAPI(user);\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'User deleted',\n fr: 'Utilisateur supprimé',\n es: 'Usuario eliminado',\n }),\n description: t({\n en: 'User deleted successfully',\n fr: 'Utilisateur supprimé avec succès',\n es: 'Usuario eliminado con éxito',\n }),\n data: formattedUser,\n });\n\n res.json(responseData);\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 if (user.emailVerified) {\n client.res.write(\n `data: ${JSON.stringify({ userId: user.id, status: 'verified' })}\\n\\n`\n );\n }\n }\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: Response\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"],"mappings":"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","names":["user"]}