@intlayer/backend 7.5.8 → 7.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/README.md +9 -2
  2. package/dist/assets/utils/AI/askDocQuestion/PROMPT.md +1 -1
  3. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/cli/init.json +2054 -0
  4. package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_fastify.json +9 -0
  5. package/dist/esm/controllers/ai.controller.mjs +95 -128
  6. package/dist/esm/controllers/ai.controller.mjs.map +1 -1
  7. package/dist/esm/controllers/dictionary.controller.mjs +86 -198
  8. package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
  9. package/dist/esm/controllers/eventListener.controller.mjs +13 -19
  10. package/dist/esm/controllers/eventListener.controller.mjs.map +1 -1
  11. package/dist/esm/controllers/github.controller.mjs +77 -0
  12. package/dist/esm/controllers/github.controller.mjs.map +1 -0
  13. package/dist/esm/controllers/newsletter.controller.mjs +30 -60
  14. package/dist/esm/controllers/newsletter.controller.mjs.map +1 -1
  15. package/dist/esm/controllers/oAuth2.controller.mjs +11 -8
  16. package/dist/esm/controllers/oAuth2.controller.mjs.map +1 -1
  17. package/dist/esm/controllers/organization.controller.mjs +100 -225
  18. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  19. package/dist/esm/controllers/project.controller.mjs +87 -204
  20. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  21. package/dist/esm/controllers/projectAccessKey.controller.mjs +38 -71
  22. package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
  23. package/dist/esm/controllers/search.controller.mjs +3 -3
  24. package/dist/esm/controllers/search.controller.mjs.map +1 -1
  25. package/dist/esm/controllers/stripe.controller.mjs +34 -67
  26. package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
  27. package/dist/esm/controllers/tag.controller.mjs +51 -113
  28. package/dist/esm/controllers/tag.controller.mjs.map +1 -1
  29. package/dist/esm/controllers/user.controller.mjs +64 -113
  30. package/dist/esm/controllers/user.controller.mjs.map +1 -1
  31. package/dist/esm/export.mjs +2 -1
  32. package/dist/esm/index.mjs +101 -41
  33. package/dist/esm/index.mjs.map +1 -1
  34. package/dist/esm/middlewares/oAuth2.middleware.mjs +19 -14
  35. package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
  36. package/dist/esm/middlewares/sessionAuth.middleware.mjs +6 -7
  37. package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
  38. package/dist/esm/routes/ai.routes.mjs +19 -15
  39. package/dist/esm/routes/ai.routes.mjs.map +1 -1
  40. package/dist/esm/routes/dictionary.routes.mjs +10 -10
  41. package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
  42. package/dist/esm/routes/eventListener.routes.mjs +3 -3
  43. package/dist/esm/routes/eventListener.routes.mjs.map +1 -1
  44. package/dist/esm/routes/github.routes.mjs +43 -0
  45. package/dist/esm/routes/github.routes.mjs.map +1 -0
  46. package/dist/esm/routes/newsletter.routes.mjs +5 -5
  47. package/dist/esm/routes/newsletter.routes.mjs.map +1 -1
  48. package/dist/esm/routes/organization.routes.mjs +11 -11
  49. package/dist/esm/routes/organization.routes.mjs.map +1 -1
  50. package/dist/esm/routes/project.routes.mjs +13 -13
  51. package/dist/esm/routes/project.routes.mjs.map +1 -1
  52. package/dist/esm/routes/search.routes.mjs +3 -3
  53. package/dist/esm/routes/search.routes.mjs.map +1 -1
  54. package/dist/esm/routes/stripe.routes.mjs +5 -5
  55. package/dist/esm/routes/stripe.routes.mjs.map +1 -1
  56. package/dist/esm/routes/tags.routes.mjs +6 -6
  57. package/dist/esm/routes/tags.routes.mjs.map +1 -1
  58. package/dist/esm/routes/user.routes.mjs +9 -9
  59. package/dist/esm/routes/user.routes.mjs.map +1 -1
  60. package/dist/esm/schemas/project.schema.mjs +35 -1
  61. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  62. package/dist/esm/services/email.service.mjs +1 -1
  63. package/dist/esm/services/email.service.mjs.map +1 -1
  64. package/dist/esm/services/github.service.mjs +130 -0
  65. package/dist/esm/services/github.service.mjs.map +1 -0
  66. package/dist/esm/services/oAuth2.service.mjs +1 -1
  67. package/dist/esm/services/subscription.service.mjs +1 -1
  68. package/dist/esm/services/subscription.service.mjs.map +1 -1
  69. package/dist/esm/utils/auth/getAuth.mjs +14 -8
  70. package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
  71. package/dist/esm/utils/cors.mjs +15 -5
  72. package/dist/esm/utils/cors.mjs.map +1 -1
  73. package/dist/esm/utils/errors/ErrorHandler.mjs +32 -4
  74. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  75. package/dist/esm/utils/errors/ErrorsClass.mjs +1 -1
  76. package/dist/esm/utils/errors/ErrorsClass.mjs.map +1 -1
  77. package/dist/esm/utils/errors/errorCodes.mjs +78 -0
  78. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  79. package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs +3 -2
  80. package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs.map +1 -1
  81. package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs +1 -1
  82. package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs.map +1 -1
  83. package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs +1 -1
  84. package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs.map +1 -1
  85. package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs +3 -2
  86. package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs.map +1 -1
  87. package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs +3 -2
  88. package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs.map +1 -1
  89. package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs +3 -2
  90. package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs.map +1 -1
  91. package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs +3 -2
  92. package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs.map +1 -1
  93. package/dist/esm/utils/mapper/project.mjs +28 -1
  94. package/dist/esm/utils/mapper/project.mjs.map +1 -1
  95. package/dist/esm/utils/mongoDB/connectDB.mjs +1 -1
  96. package/dist/esm/utils/rateLimiter.mjs +40 -30
  97. package/dist/esm/utils/rateLimiter.mjs.map +1 -1
  98. package/dist/esm/webhooks/stripe.webhook.mjs +2 -2
  99. package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -1
  100. package/dist/types/controllers/ai.controller.d.ts +29 -12
  101. package/dist/types/controllers/ai.controller.d.ts.map +1 -1
  102. package/dist/types/controllers/dictionary.controller.d.ts +23 -13
  103. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  104. package/dist/types/controllers/eventListener.controller.d.ts +4 -2
  105. package/dist/types/controllers/eventListener.controller.d.ts.map +1 -1
  106. package/dist/types/controllers/github.controller.d.ts +63 -0
  107. package/dist/types/controllers/github.controller.d.ts.map +1 -0
  108. package/dist/types/controllers/newsletter.controller.d.ts +8 -7
  109. package/dist/types/controllers/newsletter.controller.d.ts.map +1 -1
  110. package/dist/types/controllers/oAuth2.controller.d.ts +4 -2
  111. package/dist/types/controllers/oAuth2.controller.d.ts.map +1 -1
  112. package/dist/types/controllers/organization.controller.d.ts +28 -12
  113. package/dist/types/controllers/organization.controller.d.ts.map +1 -1
  114. package/dist/types/controllers/project.controller.d.ts +21 -16
  115. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  116. package/dist/types/controllers/projectAccessKey.controller.d.ts +10 -5
  117. package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
  118. package/dist/types/controllers/search.controller.d.ts +4 -2
  119. package/dist/types/controllers/search.controller.d.ts.map +1 -1
  120. package/dist/types/controllers/stripe.controller.d.ts +11 -12
  121. package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
  122. package/dist/types/controllers/tag.controller.d.ts +14 -9
  123. package/dist/types/controllers/tag.controller.d.ts.map +1 -1
  124. package/dist/types/controllers/user.controller.d.ts +22 -9
  125. package/dist/types/controllers/user.controller.d.ts.map +1 -1
  126. package/dist/types/emails/InviteUserEmail.d.ts +4 -4
  127. package/dist/types/emails/InviteUserEmail.d.ts.map +1 -1
  128. package/dist/types/emails/MagicLinkEmail.d.ts +4 -4
  129. package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +4 -4
  130. package/dist/types/emails/ResetUserPassword.d.ts +4 -4
  131. package/dist/types/emails/ResetUserPassword.d.ts.map +1 -1
  132. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -4
  133. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
  134. package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -4
  135. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -4
  136. package/dist/types/emails/ValidateUserEmail.d.ts +4 -4
  137. package/dist/types/emails/ValidateUserEmail.d.ts.map +1 -1
  138. package/dist/types/emails/Welcome.d.ts +4 -4
  139. package/dist/types/emails/Welcome.d.ts.map +1 -1
  140. package/dist/types/export.d.ts +6 -4
  141. package/dist/types/middlewares/oAuth2.middleware.d.ts +9 -4
  142. package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
  143. package/dist/types/middlewares/sessionAuth.middleware.d.ts +13 -3
  144. package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
  145. package/dist/types/models/dictionary.model.d.ts +4 -4
  146. package/dist/types/models/discussion.model.d.ts +2 -2
  147. package/dist/types/models/oAuth2.model.d.ts +3 -3
  148. package/dist/types/routes/ai.routes.d.ts +2 -2
  149. package/dist/types/routes/ai.routes.d.ts.map +1 -1
  150. package/dist/types/routes/dictionary.routes.d.ts +2 -2
  151. package/dist/types/routes/dictionary.routes.d.ts.map +1 -1
  152. package/dist/types/routes/eventListener.routes.d.ts +2 -2
  153. package/dist/types/routes/eventListener.routes.d.ts.map +1 -1
  154. package/dist/types/routes/github.routes.d.ts +35 -0
  155. package/dist/types/routes/github.routes.d.ts.map +1 -0
  156. package/dist/types/routes/newsletter.routes.d.ts +2 -2
  157. package/dist/types/routes/newsletter.routes.d.ts.map +1 -1
  158. package/dist/types/routes/organization.routes.d.ts +2 -2
  159. package/dist/types/routes/organization.routes.d.ts.map +1 -1
  160. package/dist/types/routes/project.routes.d.ts +2 -2
  161. package/dist/types/routes/project.routes.d.ts.map +1 -1
  162. package/dist/types/routes/search.routes.d.ts +2 -2
  163. package/dist/types/routes/search.routes.d.ts.map +1 -1
  164. package/dist/types/routes/stripe.routes.d.ts +2 -2
  165. package/dist/types/routes/stripe.routes.d.ts.map +1 -1
  166. package/dist/types/routes/tags.routes.d.ts +2 -2
  167. package/dist/types/routes/tags.routes.d.ts.map +1 -1
  168. package/dist/types/routes/user.routes.d.ts +2 -2
  169. package/dist/types/routes/user.routes.d.ts.map +1 -1
  170. package/dist/types/schemas/dictionary.schema.d.ts +6 -6
  171. package/dist/types/schemas/discussion.schema.d.ts +6 -6
  172. package/dist/types/schemas/oAuth2.schema.d.ts +5 -5
  173. package/dist/types/schemas/project.schema.d.ts +6 -6
  174. package/dist/types/schemas/project.schema.d.ts.map +1 -1
  175. package/dist/types/schemas/session.schema.d.ts +6 -6
  176. package/dist/types/schemas/tag.schema.d.ts +6 -6
  177. package/dist/types/schemas/user.schema.d.ts +6 -6
  178. package/dist/types/services/email.service.d.ts +11 -11
  179. package/dist/types/services/github.service.d.ts +21 -0
  180. package/dist/types/services/github.service.d.ts.map +1 -0
  181. package/dist/types/types/project.types.d.ts +18 -5
  182. package/dist/types/types/project.types.d.ts.map +1 -1
  183. package/dist/types/types/session.types.d.ts +1 -1
  184. package/dist/types/types/user.types.d.ts +1 -1
  185. package/dist/types/utils/AI/auditTag/index.d.ts +1 -1
  186. package/dist/types/utils/auth/getAuth.d.ts.map +1 -1
  187. package/dist/types/utils/cors.d.ts +2 -2
  188. package/dist/types/utils/errors/ErrorHandler.d.ts +31 -3
  189. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  190. package/dist/types/utils/errors/ErrorsClass.d.ts +1 -1
  191. package/dist/types/utils/errors/errorCodes.d.ts +78 -0
  192. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  193. package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts +8 -4
  194. package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts.map +1 -1
  195. package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts +6 -3
  196. package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts.map +1 -1
  197. package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts +6 -2
  198. package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts.map +1 -1
  199. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +8 -4
  200. package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts.map +1 -1
  201. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts +8 -4
  202. package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts.map +1 -1
  203. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +8 -4
  204. package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts.map +1 -1
  205. package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts +6 -2
  206. package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts.map +1 -1
  207. package/dist/types/utils/mapper/project.d.ts.map +1 -1
  208. package/dist/types/utils/mergeFunctionTypes.d.ts.map +1 -1
  209. package/dist/types/utils/permissions.d.ts +1 -1
  210. package/dist/types/utils/rateLimiter.d.ts +4 -2
  211. package/dist/types/utils/rateLimiter.d.ts.map +1 -1
  212. package/package.json +23 -27
  213. package/dist/esm/middlewares/request.middleware.mjs +0 -17
  214. package/dist/esm/middlewares/request.middleware.mjs.map +0 -1
  215. package/dist/types/middlewares/request.middleware.d.ts +0 -7
  216. package/dist/types/middlewares/request.middleware.d.ts.map +0 -1
@@ -0,0 +1,77 @@
1
+ import { formatResponse } from "../utils/responseData.mjs";
2
+ import { ErrorHandler } from "../utils/errors/ErrorHandler.mjs";
3
+ import { checkIntlayerConfig, exchangeCodeForToken, getAuthorizationUrl, getGitHubTokenFromUser, getRepositoryFileContents, getUserRepos } from "../services/github.service.mjs";
4
+
5
+ //#region src/controllers/github.controller.ts
6
+ const getAuthUrl = async (request, reply) => {
7
+ const { redirectUri, login } = request.query;
8
+ if (!redirectUri) return ErrorHandler.handleGenericErrorResponse(reply, "GITHUB_REDIRECT_URI_MISSING");
9
+ try {
10
+ const responseData = formatResponse({ data: { authUrl: getAuthorizationUrl(redirectUri, login) } });
11
+ return reply.send(responseData);
12
+ } catch (error) {
13
+ return ErrorHandler.handleAppErrorResponse(reply, error);
14
+ }
15
+ };
16
+ const authCallback = async (request, reply) => {
17
+ const { code } = request.body;
18
+ if (!code) return ErrorHandler.handleGenericErrorResponse(reply, "GITHUB_CODE_MISSING");
19
+ try {
20
+ const responseData = formatResponse({ data: { token: await exchangeCodeForToken(code) } });
21
+ return reply.send(responseData);
22
+ } catch (error) {
23
+ return ErrorHandler.handleAppErrorResponse(reply, error);
24
+ }
25
+ };
26
+ const listRepos = async (request, reply) => {
27
+ const { token } = request.query;
28
+ const userId = request.locals?.user?.id;
29
+ try {
30
+ let accessToken = token;
31
+ if (!accessToken && userId) accessToken = await getGitHubTokenFromUser(String(userId)) ?? void 0;
32
+ if (!accessToken) return ErrorHandler.handleGenericErrorResponse(reply, "GITHUB_TOKEN_MISSING");
33
+ const responseData = formatResponse({ data: await getUserRepos(accessToken) });
34
+ return reply.send(responseData);
35
+ } catch (error) {
36
+ return ErrorHandler.handleAppErrorResponse(reply, error);
37
+ }
38
+ };
39
+ /**
40
+ * Check if intlayer.config.ts (or candidates) exists in a repository
41
+ */
42
+ const checkConfig = async (request, reply) => {
43
+ const { token, owner, repository, branch = "main" } = request.body;
44
+ const userId = request.locals?.user?.id;
45
+ try {
46
+ let accessToken = token;
47
+ if (!accessToken && userId) accessToken = await getGitHubTokenFromUser(String(userId)) ?? void 0;
48
+ if (!accessToken || !owner || !repository) return ErrorHandler.handleGenericErrorResponse(reply, "GITHUB_CHECK_CONFIG_MISSING_PARAMS");
49
+ const configPaths = await checkIntlayerConfig(accessToken, owner, repository, branch);
50
+ const responseData = formatResponse({ data: {
51
+ hasConfig: configPaths.length > 0,
52
+ configPaths
53
+ } });
54
+ return reply.send(responseData);
55
+ } catch (error) {
56
+ return ErrorHandler.handleAppErrorResponse(reply, error);
57
+ }
58
+ };
59
+ const getConfigFile = async (request, reply) => {
60
+ const { token, owner, repository, branch = "main", path = "intlayer.config.ts" } = request.body;
61
+ const userId = request.locals?.user?.id;
62
+ try {
63
+ let accessToken = token;
64
+ if (!accessToken && userId) accessToken = await getGitHubTokenFromUser(String(userId)) ?? void 0;
65
+ if (!accessToken || !owner || !repository) return ErrorHandler.handleGenericErrorResponse(reply, "GITHUB_GET_CONFIG_FILE_MISSING_PARAMS");
66
+ const content = await getRepositoryFileContents(accessToken, owner, repository, path, branch);
67
+ if (!content) return ErrorHandler.handleGenericErrorResponse(reply, "GITHUB_CONFIG_FILE_NOT_FOUND");
68
+ const responseData = formatResponse({ data: { content } });
69
+ return reply.send(responseData);
70
+ } catch (error) {
71
+ return ErrorHandler.handleAppErrorResponse(reply, error);
72
+ }
73
+ };
74
+
75
+ //#endregion
76
+ export { authCallback, checkConfig, getAuthUrl, getConfigFile, listRepos };
77
+ //# sourceMappingURL=github.controller.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.controller.mjs","names":["githubService.getAuthorizationUrl","githubService.exchangeCodeForToken","accessToken: string | undefined","githubService.getUserRepos","githubService.checkIntlayerConfig","githubService.getRepositoryFileContents"],"sources":["../../../src/controllers/github.controller.ts"],"sourcesContent":["import * as githubService from '@services/github.service';\nimport { getGitHubTokenFromUser } from '@services/github.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\n\nexport type GitHubGetAuthUrlQuerystring = {\n redirectUri: string;\n login?: string;\n};\n\nexport type GitHubGetAuthUrlResult = ResponseData<{\n authUrl: string;\n}>;\n\nexport const getAuthUrl = async (\n request: FastifyRequest<{ Querystring: GitHubGetAuthUrlQuerystring }>,\n reply: FastifyReply\n): Promise<void> => {\n const { redirectUri, login } = request.query;\n\n if (!redirectUri) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'GITHUB_REDIRECT_URI_MISSING'\n );\n }\n\n try {\n const authUrl = githubService.getAuthorizationUrl(redirectUri, login);\n const responseData = formatResponse<{ authUrl: string }>({\n data: { authUrl },\n });\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GitHubAuthCallbackBody = {\n code: string;\n};\n\nexport type GitHubAuthCallbackResult = ResponseData<{\n token: string;\n}>;\n\nexport const authCallback = async (\n request: FastifyRequest<{ Body: GitHubAuthCallbackBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { code } = request.body;\n\n if (!code) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'GITHUB_CODE_MISSING'\n );\n }\n\n try {\n const token = await githubService.exchangeCodeForToken(code);\n const responseData = formatResponse<{ token: string }>({\n data: { token },\n });\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GitHubListReposQuerystring = {\n token?: string;\n};\n\nexport type GitHubListReposResult = ResponseData<\n githubService.GitHubRepository[]\n>;\n\nexport const listRepos = async (\n request: FastifyRequest<{ Querystring: GitHubListReposQuerystring }>,\n reply: FastifyReply\n): Promise<void> => {\n const { token } = request.query;\n const userId = request.locals?.user?.id;\n\n try {\n let accessToken: string | undefined = token;\n\n if (!accessToken && userId) {\n accessToken = (await getGitHubTokenFromUser(String(userId))) ?? undefined;\n }\n\n if (!accessToken) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'GITHUB_TOKEN_MISSING'\n );\n }\n\n const repos = await githubService.getUserRepos(accessToken);\n const responseData = formatResponse<githubService.GitHubRepository[]>({\n data: repos,\n });\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type GitHubCheckConfigBody = {\n token?: string;\n owner: string;\n repository: string;\n branch?: string;\n};\n\nexport type GitHubCheckConfigResult = ResponseData<{\n hasConfig: boolean;\n configPaths: string[]; // Changed from single path to array\n}>;\n\n/**\n * Check if intlayer.config.ts (or candidates) exists in a repository\n */\nexport const checkConfig = async (\n request: FastifyRequest<{ Body: GitHubCheckConfigBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { token, owner, repository, branch = 'main' } = request.body;\n const userId = request.locals?.user?.id;\n\n try {\n let accessToken: string | undefined = token;\n\n if (!accessToken && userId) {\n accessToken = (await getGitHubTokenFromUser(String(userId))) ?? undefined;\n }\n\n if (!accessToken || !owner || !repository) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'GITHUB_CHECK_CONFIG_MISSING_PARAMS'\n );\n }\n\n // Returns array of strings\n const configPaths = await githubService.checkIntlayerConfig(\n accessToken,\n owner,\n repository,\n branch\n );\n\n const responseData = formatResponse<{\n hasConfig: boolean;\n configPaths: string[];\n }>({\n data: {\n hasConfig: configPaths.length > 0,\n configPaths: configPaths,\n },\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\n// ... [getConfigFile remains unchanged] ...\n\nexport type GitHubGetConfigFileBody = {\n token?: string;\n owner: string;\n repository: string;\n branch?: string;\n path?: string;\n};\n\nexport type GitHubGetConfigFileResult = ResponseData<{\n content: string;\n}>;\n\nexport const getConfigFile = async (\n request: FastifyRequest<{ Body: GitHubGetConfigFileBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const {\n token,\n owner,\n repository,\n branch = 'main',\n path = 'intlayer.config.ts',\n } = request.body;\n const userId = request.locals?.user?.id;\n\n try {\n let accessToken: string | undefined = token;\n\n if (!accessToken && userId) {\n accessToken = (await getGitHubTokenFromUser(String(userId))) ?? undefined;\n }\n\n if (!accessToken || !owner || !repository) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'GITHUB_GET_CONFIG_FILE_MISSING_PARAMS'\n );\n }\n\n const content = await githubService.getRepositoryFileContents(\n accessToken,\n owner,\n repository,\n path,\n branch\n );\n\n if (!content) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'GITHUB_CONFIG_FILE_NOT_FOUND'\n );\n }\n\n const responseData = formatResponse<{ content: string }>({\n data: { content },\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n"],"mappings":";;;;;AAeA,MAAa,aAAa,OACxB,SACA,UACkB;CAClB,MAAM,EAAE,aAAa,UAAU,QAAQ;AAEvC,KAAI,CAAC,YACH,QAAO,aAAa,2BAClB,OACA,8BACD;AAGH,KAAI;EAEF,MAAM,eAAe,eAAoC,EACvD,MAAM,EAAE,SAFMA,oBAAkC,aAAa,MAAM,EAElD,EAClB,CAAC;AACF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;AAYxE,MAAa,eAAe,OAC1B,SACA,UACkB;CAClB,MAAM,EAAE,SAAS,QAAQ;AAEzB,KAAI,CAAC,KACH,QAAO,aAAa,2BAClB,OACA,sBACD;AAGH,KAAI;EAEF,MAAM,eAAe,eAAkC,EACrD,MAAM,EAAE,OAFI,MAAMC,qBAAmC,KAAK,EAE3C,EAChB,CAAC;AACF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;AAYxE,MAAa,YAAY,OACvB,SACA,UACkB;CAClB,MAAM,EAAE,UAAU,QAAQ;CAC1B,MAAM,SAAS,QAAQ,QAAQ,MAAM;AAErC,KAAI;EACF,IAAIC,cAAkC;AAEtC,MAAI,CAAC,eAAe,OAClB,eAAe,MAAM,uBAAuB,OAAO,OAAO,CAAC,IAAK;AAGlE,MAAI,CAAC,YACH,QAAO,aAAa,2BAClB,OACA,uBACD;EAIH,MAAM,eAAe,eAAiD,EACpE,MAFY,MAAMC,aAA2B,YAAY,EAG1D,CAAC;AACF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;;;;AAmBxE,MAAa,cAAc,OACzB,SACA,UACkB;CAClB,MAAM,EAAE,OAAO,OAAO,YAAY,SAAS,WAAW,QAAQ;CAC9D,MAAM,SAAS,QAAQ,QAAQ,MAAM;AAErC,KAAI;EACF,IAAID,cAAkC;AAEtC,MAAI,CAAC,eAAe,OAClB,eAAe,MAAM,uBAAuB,OAAO,OAAO,CAAC,IAAK;AAGlE,MAAI,CAAC,eAAe,CAAC,SAAS,CAAC,WAC7B,QAAO,aAAa,2BAClB,OACA,qCACD;EAIH,MAAM,cAAc,MAAME,oBACxB,aACA,OACA,YACA,OACD;EAED,MAAM,eAAe,eAGlB,EACD,MAAM;GACJ,WAAW,YAAY,SAAS;GACnB;GACd,EACF,CAAC;AAEF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB;;;AAkBxE,MAAa,gBAAgB,OAC3B,SACA,UACkB;CAClB,MAAM,EACJ,OACA,OACA,YACA,SAAS,QACT,OAAO,yBACL,QAAQ;CACZ,MAAM,SAAS,QAAQ,QAAQ,MAAM;AAErC,KAAI;EACF,IAAIF,cAAkC;AAEtC,MAAI,CAAC,eAAe,OAClB,eAAe,MAAM,uBAAuB,OAAO,OAAO,CAAC,IAAK;AAGlE,MAAI,CAAC,eAAe,CAAC,SAAS,CAAC,WAC7B,QAAO,aAAa,2BAClB,OACA,wCACD;EAGH,MAAM,UAAU,MAAMG,0BACpB,aACA,OACA,YACA,MACA,OACD;AAED,MAAI,CAAC,QACH,QAAO,aAAa,2BAClB,OACA,+BACD;EAGH,MAAM,eAAe,eAAoC,EACvD,MAAM,EAAE,SAAS,EAClB,CAAC;AAEF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB"}
@@ -4,7 +4,7 @@ import { ErrorHandler } from "../utils/errors/ErrorHandler.mjs";
4
4
  import { hasPermission } from "../utils/permissions.mjs";
5
5
  import { createUser, getUserByEmail, getUserById, updateUserById } from "../services/user.service.mjs";
6
6
  import { mapUserToAPI } from "../utils/mapper/user.mjs";
7
- import { t } from "express-intlayer";
7
+ import { t } from "fastify-intlayer";
8
8
 
9
9
  //#region src/controllers/newsletter.controller.ts
10
10
  /**
@@ -12,13 +12,10 @@ import { t } from "express-intlayer";
12
12
  * If the user doesn't exist, creates a new user.
13
13
  * If the user exists, updates their newsletter subscription to true.
14
14
  */
15
- const subscribeToNewsletter = async (req, res, _next) => {
16
- const { roles } = res.locals;
17
- const { email, emailList } = req.body;
18
- if (!email) {
19
- ErrorHandler.handleGenericErrorResponse(res, "USER_DATA_NOT_FOUND");
20
- return;
21
- }
15
+ const subscribeToNewsletter = async (request, reply) => {
16
+ const { roles } = request.locals || {};
17
+ const { email, emailList } = request.body;
18
+ if (!email) return ErrorHandler.handleGenericErrorResponse(reply, "USER_DATA_NOT_FOUND");
22
19
  const emailLists = Array.isArray(emailList) ? emailList : [emailList];
23
20
  const emailsListObject = Object.fromEntries(emailLists.map((list) => [list, true]));
24
21
  try {
@@ -30,13 +27,10 @@ const subscribeToNewsletter = async (req, res, _next) => {
30
27
  });
31
28
  logger.info(`New user created and subscribed to newsletter: ${email}`);
32
29
  } else {
33
- if (!hasPermission(roles, "user:write")({
34
- ...res.locals,
30
+ if (!hasPermission(roles || [], "user:write")({
31
+ ...request.locals,
35
32
  targetUsers: [user]
36
- })) {
37
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
38
- return;
39
- }
33
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
40
34
  user = await updateUserById(user.id, { emailsList: {
41
35
  ...user.emailsList,
42
36
  ...emailsListObject
@@ -57,37 +51,26 @@ const subscribeToNewsletter = async (req, res, _next) => {
57
51
  }),
58
52
  data: formattedUser
59
53
  });
60
- res.json(responseData);
61
- return;
54
+ return reply.send(responseData);
62
55
  } catch (error) {
63
- ErrorHandler.handleAppErrorResponse(res, error);
64
- return;
56
+ return ErrorHandler.handleAppErrorResponse(reply, error);
65
57
  }
66
58
  };
67
59
  /**
68
60
  * Unsubscribes a user from the newsletter.
69
61
  * Only works if the user exists.
70
62
  */
71
- const unsubscribeFromNewsletter = async (req, res, _next) => {
72
- const { userId, emailList } = req.body;
73
- const { roles } = res.locals;
74
- if (!userId) {
75
- ErrorHandler.handleGenericErrorResponse(res, "USER_DATA_NOT_FOUND");
76
- return;
77
- }
63
+ const unsubscribeFromNewsletter = async (request, reply) => {
64
+ const { userId, emailList } = request.body;
65
+ const { roles } = request.locals || {};
66
+ if (!userId) return ErrorHandler.handleGenericErrorResponse(reply, "USER_DATA_NOT_FOUND");
78
67
  try {
79
68
  const user = await getUserById(userId);
80
- if (!user) {
81
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_FOUND");
82
- return;
83
- }
84
- if (!hasPermission(roles, "user:write")({
85
- ...res.locals,
69
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_FOUND");
70
+ if (!hasPermission(roles || [], "user:write")({
71
+ ...request.locals,
86
72
  targetUsers: [user]
87
- })) {
88
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
89
- return;
90
- }
73
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
91
74
  const emailLists = Array.isArray(emailList) ? emailList : [emailList];
92
75
  const emailsListObject = Object.fromEntries(emailLists.map((list) => [list, false]));
93
76
  const updatedUser = await updateUserById(user.id, { emailsList: {
@@ -109,36 +92,25 @@ const unsubscribeFromNewsletter = async (req, res, _next) => {
109
92
  }),
110
93
  data: formattedUser
111
94
  });
112
- res.json(responseData);
113
- return;
95
+ return reply.send(responseData);
114
96
  } catch (error) {
115
- ErrorHandler.handleAppErrorResponse(res, error);
116
- return;
97
+ return ErrorHandler.handleAppErrorResponse(reply, error);
117
98
  }
118
99
  };
119
100
  /**
120
101
  * Gets the newsletter subscription status for a user.
121
102
  */
122
- const getNewsletterStatus = async (_req, res, _next) => {
123
- const email = res.locals.user?.email;
124
- const { roles } = res.locals;
125
- if (!email) {
126
- ErrorHandler.handleGenericErrorResponse(res, "USER_DATA_NOT_FOUND");
127
- return;
128
- }
103
+ const getNewsletterStatus = async (_request, reply) => {
104
+ const email = _request.locals?.user?.email;
105
+ const { roles } = _request.locals || {};
106
+ if (!email) return ErrorHandler.handleGenericErrorResponse(reply, "USER_DATA_NOT_FOUND");
129
107
  try {
130
108
  const user = await getUserByEmail(email);
131
- if (!user) {
132
- ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_FOUND");
133
- return;
134
- }
135
- if (!hasPermission(roles, "user:read")({
136
- ...res.locals,
109
+ if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_FOUND");
110
+ if (!hasPermission(roles || [], "user:read")({
111
+ ..._request.locals,
137
112
  targetUsers: [user]
138
- })) {
139
- ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
140
- return;
141
- }
113
+ })) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
142
114
  const formattedUser = mapUserToAPI(user);
143
115
  const responseData = formatResponse({
144
116
  message: t({
@@ -148,11 +120,9 @@ const getNewsletterStatus = async (_req, res, _next) => {
148
120
  }),
149
121
  data: formattedUser
150
122
  });
151
- res.json(responseData);
152
- return;
123
+ return reply.send(responseData);
153
124
  } catch (error) {
154
- ErrorHandler.handleAppErrorResponse(res, error);
155
- return;
125
+ return ErrorHandler.handleAppErrorResponse(reply, error);
156
126
  }
157
127
  };
158
128
 
@@ -1 +1 @@
1
- {"version":3,"file":"newsletter.controller.mjs","names":["userService.getUserByEmail","userService.createUser","userService.updateUserById","userService.getUserById"],"sources":["../../../src/controllers/newsletter.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { hasPermission } from '@utils/permissions';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport type { EmailsList, UserAPI } from '@/types/user.types';\n\nexport type NewsletterSubscriptionBody = {\n email: string;\n emailList: EmailsList | EmailsList[];\n};\nexport type NewsletterSubscriptionResult = ResponseData<UserAPI>;\n\n/**\n * Subscribes a user to the newsletter.\n * If the user doesn't exist, creates a new user.\n * If the user exists, updates their newsletter subscription to true.\n */\nexport const subscribeToNewsletter = async (\n req: Request<any, any, NewsletterSubscriptionBody>,\n res: ResponseWithSession<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const { roles } = res.locals;\n const { email, emailList } = req.body;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, true])\n ) as Record<EmailsList, boolean>;\n\n try {\n // Check if user exists\n let user = await userService.getUserByEmail(email);\n\n if (!user) {\n user = await userService.createUser({\n email,\n emailsList: emailsListObject,\n });\n\n logger.info(`New user created and subscribed to newsletter: ${email}`);\n } else {\n if (\n !hasPermission(\n roles,\n 'user:write'\n )({\n ...res.locals,\n targetUsers: [user],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n // Update existing user's newsletter subscription\n user = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User subscribed to newsletter: ${email}`);\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully subscribed to newsletter',\n fr: 'Abonnement à la newsletter réussi',\n es: 'Suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully subscribed to our newsletter',\n fr: 'Vous avez été abonné avec succès à notre newsletter',\n es: 'Te has suscrito exitosamente a nuestro boletín',\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 NewsletterUnsubscriptionBody = {\n userId: string;\n emailList: EmailsList | EmailsList[];\n};\n\n/**\n * Unsubscribes a user from the newsletter.\n * Only works if the user exists.\n */\nexport const unsubscribeFromNewsletter = async (\n req: Request<any, any, NewsletterUnsubscriptionBody>,\n res: ResponseWithSession<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const { userId, emailList } = req.body;\n const { roles } = res.locals;\n\n if (!userId) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n try {\n // Check if user exists\n const user = await userService.getUserById(userId);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:write'\n )({\n ...res.locals,\n targetUsers: [user],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, false])\n ) as Record<EmailsList, boolean>;\n\n // Update user's newsletter subscription to false\n const updatedUser = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User unsubscribed from newsletter: ${updatedUser.email}`);\n\n const formattedUser = mapUserToAPI(updatedUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully unsubscribed from newsletter',\n fr: 'Désabonnement de la newsletter réussi',\n es: 'Cancelación de suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully unsubscribed from our newsletter',\n fr: 'Vous avez été désabonné avec succès de notre newsletter',\n es: 'Te has desuscrito exitosamente de nuestro boletín',\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\n/**\n * Gets the newsletter subscription status for a user.\n */\nexport const getNewsletterStatus = async (\n _req: Request<{ email: string }>,\n res: ResponseWithSession<NewsletterSubscriptionResult>,\n _next: NextFunction\n): Promise<void> => {\n const email = res.locals.user?.email;\n const { roles } = res.locals;\n\n if (!email) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_DATA_NOT_FOUND');\n return;\n }\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'user:read'\n )({\n ...res.locals,\n targetUsers: [user],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Newsletter subscription status retrieved',\n fr: \"Statut d'abonnement à la newsletter récupéré\",\n es: 'Estado de suscripción al boletín obtenido',\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"],"mappings":"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"}
1
+ {"version":3,"file":"newsletter.controller.mjs","names":["userService.getUserByEmail","userService.createUser","userService.updateUserById","userService.getUserById"],"sources":["../../../src/controllers/newsletter.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { hasPermission } from '@utils/permissions';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { t } from 'fastify-intlayer';\nimport type { EmailsList, UserAPI } from '@/types/user.types';\n\nexport type NewsletterSubscriptionBody = {\n email: string;\n emailList: EmailsList | EmailsList[];\n};\nexport type NewsletterSubscriptionResult = ResponseData<UserAPI>;\n\n/**\n * Subscribes a user to the newsletter.\n * If the user doesn't exist, creates a new user.\n * If the user exists, updates their newsletter subscription to true.\n */\nexport const subscribeToNewsletter = async (\n request: FastifyRequest<{ Body: NewsletterSubscriptionBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { roles } = request.locals || {};\n const { email, emailList } = request.body;\n\n if (!email) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_DATA_NOT_FOUND'\n );\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, true])\n ) as Record<EmailsList, boolean>;\n\n try {\n // Check if user exists\n let user = await userService.getUserByEmail(email);\n\n if (!user) {\n user = await userService.createUser({\n email,\n emailsList: emailsListObject,\n });\n\n logger.info(`New user created and subscribed to newsletter: ${email}`);\n } else {\n if (\n !hasPermission(\n roles || [],\n 'user:write'\n )({\n ...request.locals,\n targetUsers: [user],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n // Update existing user's newsletter subscription\n user = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User subscribed to newsletter: ${email}`);\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully subscribed to newsletter',\n fr: 'Abonnement à la newsletter réussi',\n es: 'Suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully subscribed to our newsletter',\n fr: 'Vous avez été abonné avec succès à notre newsletter',\n es: 'Te has suscrito exitosamente a nuestro boletín',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\nexport type NewsletterUnsubscriptionBody = {\n userId: string;\n emailList: EmailsList | EmailsList[];\n};\n\n/**\n * Unsubscribes a user from the newsletter.\n * Only works if the user exists.\n */\nexport const unsubscribeFromNewsletter = async (\n request: FastifyRequest<{ Body: NewsletterUnsubscriptionBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { userId, emailList } = request.body;\n const { roles } = request.locals || {};\n\n if (!userId) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_DATA_NOT_FOUND'\n );\n }\n\n try {\n // Check if user exists\n const user = await userService.getUserById(userId);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:write'\n )({\n ...request.locals,\n targetUsers: [user],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const emailLists = Array.isArray(emailList) ? emailList : [emailList];\n\n // Create new user with newsletter subscription enabled\n const emailsListObject = Object.fromEntries(\n emailLists.map((list) => [list, false])\n ) as Record<EmailsList, boolean>;\n\n // Update user's newsletter subscription to false\n const updatedUser = await userService.updateUserById(user.id, {\n emailsList: { ...user.emailsList, ...emailsListObject },\n });\n\n logger.info(`User unsubscribed from newsletter: ${updatedUser.email}`);\n\n const formattedUser = mapUserToAPI(updatedUser);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Successfully unsubscribed from newsletter',\n fr: 'Désabonnement de la newsletter réussi',\n es: 'Cancelación de suscripción al boletín exitosa',\n }),\n description: t({\n en: 'You have been successfully unsubscribed from our newsletter',\n fr: 'Vous avez été désabonné avec succès de notre newsletter',\n es: 'Te has desuscrito exitosamente de nuestro boletín',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n\n/**\n * Gets the newsletter subscription status for a user.\n */\nexport const getNewsletterStatus = async (\n _request: FastifyRequest,\n reply: FastifyReply\n): Promise<void> => {\n const email = _request.locals?.user?.email;\n const { roles } = _request.locals || {};\n\n if (!email) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'USER_DATA_NOT_FOUND'\n );\n }\n\n try {\n const user = await userService.getUserByEmail(email);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles || [],\n 'user:read'\n )({\n ..._request.locals,\n targetUsers: [user],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n const formattedUser = mapUserToAPI(user);\n\n const responseData = formatResponse<UserAPI>({\n message: t({\n en: 'Newsletter subscription status retrieved',\n fr: \"Statut d'abonnement à la newsletter récupéré\",\n es: 'Estado de suscripción al boletín obtenido',\n }),\n data: formattedUser,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n"],"mappings":"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"}
@@ -3,16 +3,19 @@ import { ErrorHandler } from "../utils/errors/ErrorHandler.mjs";
3
3
  import { Request, Response } from "oauth2-server";
4
4
 
5
5
  //#region src/controllers/oAuth2.controller.ts
6
- const getOAuth2AccessToken = async (req, res, _next) => {
7
- const oauthRequest = new Request(req);
8
- const oauthResponse = new Response(res);
6
+ const getOAuth2AccessToken = async (request, reply) => {
7
+ const oauthRequest = new Request({
8
+ headers: request.headers,
9
+ method: request.method,
10
+ query: request.query,
11
+ body: request.body
12
+ });
13
+ const oauthResponse = new Response(reply.raw);
9
14
  try {
10
- const responseData = formatResponse({ data: await req.oauth.token(oauthRequest, oauthResponse) });
11
- res.json(responseData);
12
- return;
15
+ const responseData = formatResponse({ data: await request.oauth.token(oauthRequest, oauthResponse) });
16
+ return reply.send(responseData);
13
17
  } catch (error) {
14
- ErrorHandler.handleAppErrorResponse(res, error);
15
- return;
18
+ return ErrorHandler.handleAppErrorResponse(reply, error);
16
19
  }
17
20
  };
18
21
 
@@ -1 +1 @@
1
- {"version":3,"file":"oAuth2.controller.mjs","names":["OAuthRequest","OAuthResponse"],"sources":["../../../src/controllers/oAuth2.controller.ts"],"sourcesContent":["import type { RequestWithOAuth2Information } from '@middlewares/oAuth2.middleware';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { NextFunction, Request, Response } from 'express';\nimport {\n Request as OAuthRequest,\n Response as OAuthResponse,\n} from 'oauth2-server';\nimport type { OAuth2Token } from '@/types/oAuth2.types';\n\nexport type GetOAuth2TokenBody = {\n grant_type: 'client_credentials';\n client_id: string;\n client_secret: string;\n};\nexport type GetOAuth2TokenResult = ResponseData<OAuth2Token>;\n\n// Method to get the token\nexport const getOAuth2AccessToken = async (\n req: Request,\n res: Response<GetOAuth2TokenResult>,\n _next: NextFunction\n): Promise<void> => {\n const oauthRequest = new OAuthRequest(req);\n const oauthResponse = new OAuthResponse(res);\n\n try {\n const token: OAuth2Token = (await (\n req as unknown as RequestWithOAuth2Information<\n undefined,\n undefined,\n GetOAuth2TokenBody\n >\n ).oauth.token(oauthRequest, oauthResponse)) as OAuth2Token;\n\n const responseData = formatResponse<OAuth2Token>({\n data: token,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":";;;;;AAkBA,MAAa,uBAAuB,OAClC,KACA,KACA,UACkB;CAClB,MAAM,eAAe,IAAIA,QAAa,IAAI;CAC1C,MAAM,gBAAgB,IAAIC,SAAc,IAAI;AAE5C,KAAI;EASF,MAAM,eAAe,eAA4B,EAC/C,MAT0B,MAC1B,IAKA,MAAM,MAAM,cAAc,cAAc,EAIzC,CAAC;AAEF,MAAI,KAAK,aAAa;AACtB;UACO,OAAO;AACd,eAAa,uBAAuB,KAAK,MAAkB;AAC3D"}
1
+ {"version":3,"file":"oAuth2.controller.mjs","names":["OAuthRequest","OAuthResponse"],"sources":["../../../src/controllers/oAuth2.controller.ts"],"sourcesContent":["import type { RequestWithOAuth2Information } from '@middlewares/oAuth2.middleware';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport { formatResponse, type ResponseData } from '@utils/responseData';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport {\n Request as OAuthRequest,\n Response as OAuthResponse,\n} from 'oauth2-server';\nimport type { OAuth2Token } from '@/types/oAuth2.types';\n\nexport type GetOAuth2TokenBody = {\n grant_type: 'client_credentials';\n client_id: string;\n client_secret: string;\n};\nexport type GetOAuth2TokenResult = ResponseData<OAuth2Token>;\n\n// Method to get the token\nexport const getOAuth2AccessToken = async (\n request: FastifyRequest<{ Body: GetOAuth2TokenBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const oauthRequest = new OAuthRequest({\n headers: request.headers,\n method: request.method,\n query: request.query as any,\n body: request.body as any,\n });\n const oauthResponse = new OAuthResponse(reply.raw);\n\n try {\n const token: OAuth2Token = (await (\n request as unknown as RequestWithOAuth2Information\n ).oauth.token(oauthRequest, oauthResponse)) as OAuth2Token;\n\n const responseData = formatResponse<OAuth2Token>({\n data: token,\n });\n\n return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n"],"mappings":";;;;;AAkBA,MAAa,uBAAuB,OAClC,SACA,UACkB;CAClB,MAAM,eAAe,IAAIA,QAAa;EACpC,SAAS,QAAQ;EACjB,QAAQ,QAAQ;EAChB,OAAO,QAAQ;EACf,MAAM,QAAQ;EACf,CAAC;CACF,MAAM,gBAAgB,IAAIC,SAAc,MAAM,IAAI;AAElD,KAAI;EAKF,MAAM,eAAe,eAA4B,EAC/C,MAL0B,MAC1B,QACA,MAAM,MAAM,cAAc,cAAc,EAIzC,CAAC;AAEF,SAAO,MAAM,KAAK,aAAa;UACxB,OAAO;AACd,SAAO,aAAa,uBAAuB,OAAO,MAAkB"}