@intlayer/backend 7.5.9 → 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.
- package/README.md +9 -2
- package/dist/assets/utils/AI/askDocQuestion/PROMPT.md +1 -1
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_fastify.json +9 -0
- package/dist/esm/controllers/ai.controller.mjs +95 -128
- package/dist/esm/controllers/ai.controller.mjs.map +1 -1
- package/dist/esm/controllers/dictionary.controller.mjs +86 -198
- package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
- package/dist/esm/controllers/eventListener.controller.mjs +13 -19
- package/dist/esm/controllers/eventListener.controller.mjs.map +1 -1
- package/dist/esm/controllers/github.controller.mjs +77 -0
- package/dist/esm/controllers/github.controller.mjs.map +1 -0
- package/dist/esm/controllers/newsletter.controller.mjs +30 -60
- package/dist/esm/controllers/newsletter.controller.mjs.map +1 -1
- package/dist/esm/controllers/oAuth2.controller.mjs +11 -8
- package/dist/esm/controllers/oAuth2.controller.mjs.map +1 -1
- package/dist/esm/controllers/organization.controller.mjs +100 -225
- package/dist/esm/controllers/organization.controller.mjs.map +1 -1
- package/dist/esm/controllers/project.controller.mjs +87 -204
- package/dist/esm/controllers/project.controller.mjs.map +1 -1
- package/dist/esm/controllers/projectAccessKey.controller.mjs +38 -71
- package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
- package/dist/esm/controllers/search.controller.mjs +3 -3
- package/dist/esm/controllers/search.controller.mjs.map +1 -1
- package/dist/esm/controllers/stripe.controller.mjs +34 -67
- package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
- package/dist/esm/controllers/tag.controller.mjs +51 -113
- package/dist/esm/controllers/tag.controller.mjs.map +1 -1
- package/dist/esm/controllers/user.controller.mjs +64 -113
- package/dist/esm/controllers/user.controller.mjs.map +1 -1
- package/dist/esm/export.mjs +2 -1
- package/dist/esm/index.mjs +101 -41
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/middlewares/oAuth2.middleware.mjs +19 -14
- package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
- package/dist/esm/middlewares/sessionAuth.middleware.mjs +6 -7
- package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
- package/dist/esm/routes/ai.routes.mjs +19 -15
- package/dist/esm/routes/ai.routes.mjs.map +1 -1
- package/dist/esm/routes/dictionary.routes.mjs +10 -10
- package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
- package/dist/esm/routes/eventListener.routes.mjs +3 -3
- package/dist/esm/routes/eventListener.routes.mjs.map +1 -1
- package/dist/esm/routes/github.routes.mjs +43 -0
- package/dist/esm/routes/github.routes.mjs.map +1 -0
- package/dist/esm/routes/newsletter.routes.mjs +5 -5
- package/dist/esm/routes/newsletter.routes.mjs.map +1 -1
- package/dist/esm/routes/organization.routes.mjs +11 -11
- package/dist/esm/routes/organization.routes.mjs.map +1 -1
- package/dist/esm/routes/project.routes.mjs +13 -13
- package/dist/esm/routes/project.routes.mjs.map +1 -1
- package/dist/esm/routes/search.routes.mjs +3 -3
- package/dist/esm/routes/search.routes.mjs.map +1 -1
- package/dist/esm/routes/stripe.routes.mjs +5 -5
- package/dist/esm/routes/stripe.routes.mjs.map +1 -1
- package/dist/esm/routes/tags.routes.mjs +6 -6
- package/dist/esm/routes/tags.routes.mjs.map +1 -1
- package/dist/esm/routes/user.routes.mjs +9 -9
- package/dist/esm/routes/user.routes.mjs.map +1 -1
- package/dist/esm/schemas/project.schema.mjs +35 -1
- package/dist/esm/schemas/project.schema.mjs.map +1 -1
- package/dist/esm/services/email.service.mjs +1 -1
- package/dist/esm/services/email.service.mjs.map +1 -1
- package/dist/esm/services/github.service.mjs +130 -0
- package/dist/esm/services/github.service.mjs.map +1 -0
- package/dist/esm/services/oAuth2.service.mjs +1 -1
- package/dist/esm/services/subscription.service.mjs +1 -1
- package/dist/esm/services/subscription.service.mjs.map +1 -1
- package/dist/esm/utils/auth/getAuth.mjs +14 -8
- package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
- package/dist/esm/utils/cors.mjs +15 -5
- package/dist/esm/utils/cors.mjs.map +1 -1
- package/dist/esm/utils/errors/ErrorHandler.mjs +32 -4
- package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
- package/dist/esm/utils/errors/ErrorsClass.mjs +1 -1
- package/dist/esm/utils/errors/ErrorsClass.mjs.map +1 -1
- package/dist/esm/utils/errors/errorCodes.mjs +78 -0
- package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs +1 -1
- package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs +1 -1
- package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs +3 -2
- package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/mapper/project.mjs +28 -1
- package/dist/esm/utils/mapper/project.mjs.map +1 -1
- package/dist/esm/utils/mongoDB/connectDB.mjs +1 -1
- package/dist/esm/utils/rateLimiter.mjs +40 -30
- package/dist/esm/utils/rateLimiter.mjs.map +1 -1
- package/dist/esm/webhooks/stripe.webhook.mjs +2 -2
- package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -1
- package/dist/types/controllers/ai.controller.d.ts +29 -12
- package/dist/types/controllers/ai.controller.d.ts.map +1 -1
- package/dist/types/controllers/dictionary.controller.d.ts +23 -13
- package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
- package/dist/types/controllers/eventListener.controller.d.ts +4 -2
- package/dist/types/controllers/eventListener.controller.d.ts.map +1 -1
- package/dist/types/controllers/github.controller.d.ts +63 -0
- package/dist/types/controllers/github.controller.d.ts.map +1 -0
- package/dist/types/controllers/newsletter.controller.d.ts +8 -7
- package/dist/types/controllers/newsletter.controller.d.ts.map +1 -1
- package/dist/types/controllers/oAuth2.controller.d.ts +4 -2
- package/dist/types/controllers/oAuth2.controller.d.ts.map +1 -1
- package/dist/types/controllers/organization.controller.d.ts +28 -12
- package/dist/types/controllers/organization.controller.d.ts.map +1 -1
- package/dist/types/controllers/project.controller.d.ts +21 -16
- package/dist/types/controllers/project.controller.d.ts.map +1 -1
- package/dist/types/controllers/projectAccessKey.controller.d.ts +10 -5
- package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
- package/dist/types/controllers/search.controller.d.ts +4 -2
- package/dist/types/controllers/search.controller.d.ts.map +1 -1
- package/dist/types/controllers/stripe.controller.d.ts +11 -12
- package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
- package/dist/types/controllers/tag.controller.d.ts +14 -9
- package/dist/types/controllers/tag.controller.d.ts.map +1 -1
- package/dist/types/controllers/user.controller.d.ts +22 -9
- package/dist/types/controllers/user.controller.d.ts.map +1 -1
- package/dist/types/emails/InviteUserEmail.d.ts +4 -4
- package/dist/types/emails/MagicLinkEmail.d.ts +4 -4
- package/dist/types/emails/MagicLinkEmail.d.ts.map +1 -1
- package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +4 -4
- package/dist/types/emails/PasswordChangeConfirmation.d.ts +4 -4
- package/dist/types/emails/PasswordChangeConfirmation.d.ts.map +1 -1
- package/dist/types/emails/ResetUserPassword.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
- package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -4
- package/dist/types/emails/ValidateUserEmail.d.ts +4 -4
- package/dist/types/emails/ValidateUserEmail.d.ts.map +1 -1
- package/dist/types/emails/Welcome.d.ts +4 -4
- package/dist/types/export.d.ts +6 -4
- package/dist/types/middlewares/oAuth2.middleware.d.ts +9 -4
- package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
- package/dist/types/middlewares/sessionAuth.middleware.d.ts +13 -3
- package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
- package/dist/types/models/dictionary.model.d.ts +4 -4
- package/dist/types/models/dictionary.model.d.ts.map +1 -1
- package/dist/types/models/discussion.model.d.ts +2 -2
- package/dist/types/models/discussion.model.d.ts.map +1 -1
- package/dist/types/models/oAuth2.model.d.ts +3 -3
- package/dist/types/models/oAuth2.model.d.ts.map +1 -1
- package/dist/types/routes/ai.routes.d.ts +2 -2
- package/dist/types/routes/ai.routes.d.ts.map +1 -1
- package/dist/types/routes/dictionary.routes.d.ts +2 -2
- package/dist/types/routes/dictionary.routes.d.ts.map +1 -1
- package/dist/types/routes/eventListener.routes.d.ts +2 -2
- package/dist/types/routes/eventListener.routes.d.ts.map +1 -1
- package/dist/types/routes/github.routes.d.ts +35 -0
- package/dist/types/routes/github.routes.d.ts.map +1 -0
- package/dist/types/routes/newsletter.routes.d.ts +2 -2
- package/dist/types/routes/newsletter.routes.d.ts.map +1 -1
- package/dist/types/routes/organization.routes.d.ts +2 -2
- package/dist/types/routes/organization.routes.d.ts.map +1 -1
- package/dist/types/routes/project.routes.d.ts +2 -2
- package/dist/types/routes/project.routes.d.ts.map +1 -1
- package/dist/types/routes/search.routes.d.ts +2 -2
- package/dist/types/routes/search.routes.d.ts.map +1 -1
- package/dist/types/routes/stripe.routes.d.ts +2 -2
- package/dist/types/routes/stripe.routes.d.ts.map +1 -1
- package/dist/types/routes/tags.routes.d.ts +2 -2
- package/dist/types/routes/tags.routes.d.ts.map +1 -1
- package/dist/types/routes/user.routes.d.ts +2 -2
- package/dist/types/routes/user.routes.d.ts.map +1 -1
- package/dist/types/schemas/dictionary.schema.d.ts +6 -6
- package/dist/types/schemas/discussion.schema.d.ts +6 -6
- package/dist/types/schemas/oAuth2.schema.d.ts +5 -5
- package/dist/types/schemas/organization.schema.d.ts +6 -6
- package/dist/types/schemas/plans.schema.d.ts +6 -6
- package/dist/types/schemas/plans.schema.d.ts.map +1 -1
- package/dist/types/schemas/project.schema.d.ts +6 -6
- package/dist/types/schemas/project.schema.d.ts.map +1 -1
- package/dist/types/schemas/session.schema.d.ts +6 -6
- package/dist/types/schemas/tag.schema.d.ts +6 -6
- package/dist/types/schemas/user.schema.d.ts +6 -6
- package/dist/types/schemas/user.schema.d.ts.map +1 -1
- package/dist/types/services/email.service.d.ts +11 -11
- package/dist/types/services/github.service.d.ts +21 -0
- package/dist/types/services/github.service.d.ts.map +1 -0
- package/dist/types/types/project.types.d.ts +18 -5
- package/dist/types/types/project.types.d.ts.map +1 -1
- package/dist/types/types/session.types.d.ts +1 -1
- package/dist/types/types/user.types.d.ts +1 -1
- package/dist/types/utils/AI/auditTag/index.d.ts +1 -1
- package/dist/types/utils/auth/getAuth.d.ts.map +1 -1
- package/dist/types/utils/cors.d.ts +2 -2
- package/dist/types/utils/errors/ErrorHandler.d.ts +31 -3
- package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
- package/dist/types/utils/errors/ErrorsClass.d.ts +1 -1
- package/dist/types/utils/errors/errorCodes.d.ts +78 -0
- package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts +8 -4
- package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts +6 -3
- package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts +6 -2
- package/dist/types/utils/filtersAndPagination/getFiltersAndPaginationFromBody.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +8 -4
- package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts +8 -4
- package/dist/types/utils/filtersAndPagination/getProjectFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +8 -4
- package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts +6 -2
- package/dist/types/utils/filtersAndPagination/getUserFiltersAndPagination.d.ts.map +1 -1
- package/dist/types/utils/mapper/project.d.ts.map +1 -1
- package/dist/types/utils/mergeFunctionTypes.d.ts.map +1 -1
- package/dist/types/utils/permissions.d.ts +1 -1
- package/dist/types/utils/rateLimiter.d.ts +4 -2
- package/dist/types/utils/rateLimiter.d.ts.map +1 -1
- package/package.json +23 -27
- package/dist/esm/middlewares/request.middleware.mjs +0 -17
- package/dist/esm/middlewares/request.middleware.mjs.map +0 -1
- package/dist/types/middlewares/request.middleware.d.ts +0 -7
- package/dist/types/middlewares/request.middleware.d.ts.map +0 -1
|
@@ -5,32 +5,23 @@ import { countTags, createTag, deleteTagById, findTags, getTagById, updateTagByI
|
|
|
5
5
|
import { hasPermission } from "../utils/permissions.mjs";
|
|
6
6
|
import { getTagFiltersAndPagination } from "../utils/filtersAndPagination/getTagFiltersAndPagination.mjs";
|
|
7
7
|
import { mapTagToAPI, mapTagsToAPI } from "../utils/mapper/tag.mjs";
|
|
8
|
-
import { t } from "
|
|
8
|
+
import { t } from "fastify-intlayer";
|
|
9
9
|
|
|
10
10
|
//#region src/controllers/tag.controller.ts
|
|
11
11
|
/**
|
|
12
12
|
* Retrieves a list of tags based on filters and pagination.
|
|
13
13
|
*/
|
|
14
|
-
const getTags = async (
|
|
15
|
-
const { user, organization, roles } =
|
|
16
|
-
const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getTagFiltersAndPagination(
|
|
17
|
-
if (!user)
|
|
18
|
-
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
if (!organization) {
|
|
22
|
-
ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
14
|
+
const getTags = async (request, reply) => {
|
|
15
|
+
const { user, organization, roles } = request.locals || {};
|
|
16
|
+
const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getTagFiltersAndPagination(request);
|
|
17
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
18
|
+
if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
|
|
25
19
|
try {
|
|
26
20
|
const tags = await findTags(filters, skip, pageSize, sortOptions);
|
|
27
|
-
if (!hasPermission(roles, "tag:read")({
|
|
28
|
-
...
|
|
21
|
+
if (!hasPermission(roles || [], "tag:read")({
|
|
22
|
+
...request.locals,
|
|
29
23
|
targetTags: tags
|
|
30
|
-
}))
|
|
31
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
24
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
34
25
|
const totalItems = await countTags(filters);
|
|
35
26
|
const responseData = formatPaginatedResponse({
|
|
36
27
|
data: mapTagsToAPI(tags),
|
|
@@ -39,45 +30,31 @@ const getTags = async (req, res, _next) => {
|
|
|
39
30
|
totalPages: getNumberOfPages(totalItems),
|
|
40
31
|
totalItems
|
|
41
32
|
});
|
|
42
|
-
|
|
43
|
-
return;
|
|
33
|
+
return reply.send(responseData);
|
|
44
34
|
} catch (error) {
|
|
45
|
-
ErrorHandler.handleAppErrorResponse(
|
|
46
|
-
return;
|
|
35
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
47
36
|
}
|
|
48
37
|
};
|
|
49
38
|
/**
|
|
50
39
|
* Adds a new tag to the database.
|
|
51
40
|
*/
|
|
52
|
-
const addTag = async (
|
|
53
|
-
const { organization, project, user, roles } =
|
|
54
|
-
const tagData =
|
|
55
|
-
if (!user)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (!organization) {
|
|
60
|
-
ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (!project) {
|
|
64
|
-
ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (!tagData) ErrorHandler.handleGenericErrorResponse(res, "PROJECT_DATA_NOT_FOUND");
|
|
41
|
+
const addTag = async (request, reply) => {
|
|
42
|
+
const { organization, project, user, roles } = request.locals || {};
|
|
43
|
+
const tagData = request.body;
|
|
44
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
45
|
+
if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
|
|
46
|
+
if (!project) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_NOT_DEFINED");
|
|
47
|
+
if (!tagData) return ErrorHandler.handleGenericErrorResponse(reply, "PROJECT_DATA_NOT_FOUND");
|
|
68
48
|
const tag = {
|
|
69
49
|
creatorId: user.id,
|
|
70
50
|
organizationId: organization.id,
|
|
71
51
|
projectId: project.id,
|
|
72
52
|
...tagData
|
|
73
53
|
};
|
|
74
|
-
if (!hasPermission(roles, "tag:admin")({
|
|
75
|
-
...
|
|
54
|
+
if (!hasPermission(roles || [], "tag:admin")({
|
|
55
|
+
...request.locals,
|
|
76
56
|
targetTags: [tag]
|
|
77
|
-
}))
|
|
78
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
57
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
81
58
|
try {
|
|
82
59
|
const formattedTag = mapTagToAPI(await createTag(tag));
|
|
83
60
|
const responseData = formatResponse({
|
|
@@ -93,47 +70,33 @@ const addTag = async (req, res, _next) => {
|
|
|
93
70
|
}),
|
|
94
71
|
data: formattedTag
|
|
95
72
|
});
|
|
96
|
-
|
|
97
|
-
return;
|
|
73
|
+
return reply.send(responseData);
|
|
98
74
|
} catch (error) {
|
|
99
|
-
ErrorHandler.handleAppErrorResponse(
|
|
100
|
-
return;
|
|
75
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
101
76
|
}
|
|
102
77
|
};
|
|
103
78
|
/**
|
|
104
79
|
* Updates an existing tag in the database.
|
|
105
80
|
*/
|
|
106
|
-
const updateTag = async (
|
|
107
|
-
const { tagId } =
|
|
108
|
-
const { organization, user, roles } =
|
|
109
|
-
if (!user)
|
|
110
|
-
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (!organization) {
|
|
114
|
-
ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
81
|
+
const updateTag = async (request, reply) => {
|
|
82
|
+
const { tagId } = request.params;
|
|
83
|
+
const { organization, user, roles } = request.locals || {};
|
|
84
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
85
|
+
if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
|
|
117
86
|
try {
|
|
118
87
|
const tag = {
|
|
119
88
|
_id: tagId,
|
|
120
|
-
name:
|
|
121
|
-
key:
|
|
122
|
-
description:
|
|
123
|
-
instructions:
|
|
89
|
+
name: request.body.name,
|
|
90
|
+
key: request.body.key,
|
|
91
|
+
description: request.body.description,
|
|
92
|
+
instructions: request.body.instructions
|
|
124
93
|
};
|
|
125
94
|
const tagToDelete = await getTagById(tagId);
|
|
126
|
-
if (!hasPermission(roles, "tag:write")({
|
|
127
|
-
...
|
|
95
|
+
if (!hasPermission(roles || [], "tag:write")({
|
|
96
|
+
...request.locals,
|
|
128
97
|
targetTags: [tagToDelete]
|
|
129
|
-
}))
|
|
130
|
-
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (String(tagToDelete.organizationId) !== String(organization.id)) {
|
|
134
|
-
ErrorHandler.handleGenericErrorResponse(res, "TAG_NOT_IN_ORGANIZATION");
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
98
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
99
|
+
if (String(tagToDelete.organizationId) !== String(organization.id)) return ErrorHandler.handleGenericErrorResponse(reply, "TAG_NOT_IN_ORGANIZATION");
|
|
137
100
|
const formattedTag = mapTagToAPI(await updateTagById(tag._id, tag));
|
|
138
101
|
const responseData = formatResponse({
|
|
139
102
|
message: t({
|
|
@@ -148,52 +111,29 @@ const updateTag = async (req, res, _next) => {
|
|
|
148
111
|
}),
|
|
149
112
|
data: formattedTag
|
|
150
113
|
});
|
|
151
|
-
|
|
152
|
-
return;
|
|
114
|
+
return reply.send(responseData);
|
|
153
115
|
} catch (error) {
|
|
154
|
-
ErrorHandler.handleAppErrorResponse(
|
|
155
|
-
return;
|
|
116
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
156
117
|
}
|
|
157
118
|
};
|
|
158
119
|
/**
|
|
159
120
|
* Deletes a tag from the database by its ID.
|
|
160
|
-
* @param req - Express request object.
|
|
161
|
-
* @param res - Express response object.
|
|
162
|
-
* @returns Response confirming the deletion.
|
|
163
121
|
*/
|
|
164
|
-
const deleteTag = async (
|
|
165
|
-
const { user, organization, roles } =
|
|
166
|
-
const { tagId } =
|
|
167
|
-
if (!user)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
if (!organization) {
|
|
172
|
-
ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
if (!tagId) {
|
|
176
|
-
ErrorHandler.handleGenericErrorResponse(res, "TAG_ID_NOT_FOUND");
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
122
|
+
const deleteTag = async (request, reply) => {
|
|
123
|
+
const { user, organization, roles } = request.locals || {};
|
|
124
|
+
const { tagId } = request.params;
|
|
125
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
126
|
+
if (!organization) return ErrorHandler.handleGenericErrorResponse(reply, "ORGANIZATION_NOT_DEFINED");
|
|
127
|
+
if (!tagId) return ErrorHandler.handleGenericErrorResponse(reply, "TAG_ID_NOT_FOUND");
|
|
179
128
|
try {
|
|
180
129
|
const tagToDelete = await getTagById(tagId);
|
|
181
|
-
if (!hasPermission(roles, "tag:admin")({
|
|
182
|
-
...
|
|
130
|
+
if (!hasPermission(roles || [], "tag:admin")({
|
|
131
|
+
...request.locals,
|
|
183
132
|
targetTags: [tagToDelete]
|
|
184
|
-
}))
|
|
185
|
-
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
if (String(tagToDelete.organizationId) !== String(organization.id)) {
|
|
189
|
-
ErrorHandler.handleGenericErrorResponse(res, "TAG_NOT_IN_ORGANIZATION");
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
133
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
134
|
+
if (String(tagToDelete.organizationId) !== String(organization.id)) return ErrorHandler.handleGenericErrorResponse(reply, "TAG_NOT_IN_ORGANIZATION");
|
|
192
135
|
const deletedTag = await deleteTagById(tagId);
|
|
193
|
-
if (!deletedTag) {
|
|
194
|
-
ErrorHandler.handleGenericErrorResponse(res, "TAG_NOT_FOUND", { tagId });
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
136
|
+
if (!deletedTag) return ErrorHandler.handleGenericErrorResponse(reply, "TAG_NOT_FOUND", { tagId });
|
|
197
137
|
logger.info(`Tag deleted: ${String(deletedTag.id)}`);
|
|
198
138
|
const formattedTag = mapTagToAPI(deletedTag);
|
|
199
139
|
const responseData = formatResponse({
|
|
@@ -209,11 +149,9 @@ const deleteTag = async (req, res, _next) => {
|
|
|
209
149
|
}),
|
|
210
150
|
data: formattedTag
|
|
211
151
|
});
|
|
212
|
-
|
|
213
|
-
return;
|
|
152
|
+
return reply.send(responseData);
|
|
214
153
|
} catch (error) {
|
|
215
|
-
ErrorHandler.handleAppErrorResponse(
|
|
216
|
-
return;
|
|
154
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
217
155
|
}
|
|
218
156
|
};
|
|
219
157
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag.controller.mjs","names":["tagService.findTags","tagService.countTags","tag: TagData","tagService.createTag","tagService.getTagById","tagService.updateTagById","tagService.deleteTagById"],"sources":["../../../src/controllers/tag.controller.ts"],"sourcesContent":["import { logger } from '@logger';\nimport type { ResponseWithSession } 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 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 } from 'express';\nimport { t } from 'express-intlayer';\nimport type {\n Tag,\n TagAPI,\n TagCreationData,\n TagData,\n TagSchema,\n} 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: ResponseWithSession<GetTagsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, roles } = res.locals;\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getTagFiltersAndPagination(req, res);\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 tags = await tagService.findTags(\n filters,\n skip,\n pageSize,\n sortOptions\n );\n\n if (\n !hasPermission(\n roles,\n 'tag:read'\n )({\n ...res.locals,\n targetTags: tags,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\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: ResponseWithSession<AddTagResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, project, 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 (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\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 projectId: project.id,\n ...tagData,\n };\n\n if (\n !hasPermission(\n roles,\n 'tag:admin'\n )({\n ...res.locals,\n targetTags: [tag as Tag],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\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: ResponseWithSession<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 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 (\n !hasPermission(\n roles,\n 'tag:write'\n )({\n ...res.locals,\n targetTags: [tagToDelete],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\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: ResponseWithSession<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 try {\n const tagToDelete = await tagService.getTagById(tagId);\n\n if (\n !hasPermission(\n roles,\n 'tag:admin'\n )({\n ...res.locals,\n targetTags: [tagToDelete],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\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":";;;;;;;;;;;;;AAiCA,MAAa,UAAU,OACrB,KACA,KACA,UACkB;CAClB,MAAM,EAAE,MAAM,cAAc,UAAU,IAAI;CAC1C,MAAM,EAAE,SAAS,aAAa,UAAU,MAAM,MAAM,qBAClD,2BAA2B,KAAK,IAAI;AAEtC,KAAI,CAAC,MAAM;AACT,eAAa,2BAA2B,KAAK,mBAAmB;AAChE;;AAGF,KAAI,CAAC,cAAc;AACjB,eAAa,2BAA2B,KAAK,2BAA2B;AACxE;;AAGF,KAAI;EACF,MAAM,OAAO,MAAMA,SACjB,SACA,MACA,UACA,YACD;AAED,MACE,CAAC,cACC,OACA,WACD,CAAC;GACA,GAAG,IAAI;GACP,YAAY;GACb,CAAC,EACF;AACA,gBAAa,2BAA2B,KAAK,oBAAoB;AACjE;;EAGF,MAAM,aAAa,MAAMC,UAAqB,QAAQ;EAItD,MAAM,eAAe,wBAAgC;GACnD,MAHoB,aAAa,KAAK;GAItC;GACA;GACA,YAAY,iBAAiB,WAAW;GACxC;GACD,CAAC;AAEF,MAAI,KAAK,aAAa;AACtB;UACO,OAAO;AACd,eAAa,uBAAuB,KAAK,MAAkB;AAC3D;;;;;;AAUJ,MAAa,SAAS,OACpB,KACA,KACA,UACkB;CAClB,MAAM,EAAE,cAAc,SAAS,MAAM,UAAU,IAAI;CACnD,MAAM,UAAU,IAAI;AAEpB,KAAI,CAAC,MAAM;AACT,eAAa,2BAA2B,KAAK,mBAAmB;AAChE;;AAGF,KAAI,CAAC,cAAc;AACjB,eAAa,2BAA2B,KAAK,2BAA2B;AACxE;;AAGF,KAAI,CAAC,SAAS;AACZ,eAAa,2BAA2B,KAAK,sBAAsB;AACnE;;AAGF,KAAI,CAAC,QACH,cAAa,2BAA2B,KAAK,yBAAyB;CAGxE,MAAMC,MAAe;EACnB,WAAW,KAAK;EAChB,gBAAgB,aAAa;EAC7B,WAAW,QAAQ;EACnB,GAAG;EACJ;AAED,KACE,CAAC,cACC,OACA,YACD,CAAC;EACA,GAAG,IAAI;EACP,YAAY,CAAC,IAAW;EACzB,CAAC,EACF;AACA,eAAa,2BAA2B,KAAK,oBAAoB;AACjE;;AAGF,KAAI;EAGF,MAAM,eAAe,YAFN,MAAMC,UAAqB,IAAI,CAEN;EAExC,MAAM,eAAe,eAAuB;GAC1C,SAAS,EAAE;IACT,IAAI;IACJ,IAAI;IACJ,IAAI;IACL,CAAC;GACF,aAAa,EAAE;IACb,IAAI;IACJ,IAAI;IACJ,IAAI;IACL,CAAC;GACF,MAAM;GACP,CAAC;AAEF,MAAI,KAAK,aAAa;AACtB;UACO,OAAO;AACd,eAAa,uBAAuB,KAAK,MAAkB;AAC3D;;;;;;AAWJ,MAAa,YAAY,OACvB,KACA,KACA,UACkB;CAClB,MAAM,EAAE,UAAU,IAAI;CACtB,MAAM,EAAE,cAAc,MAAM,UAAU,IAAI;AAE1C,KAAI,CAAC,MAAM;AACT,eAAa,2BAA2B,KAAK,mBAAmB;AAChE;;AAGF,KAAI,CAAC,cAAc;AACjB,eAAa,2BAA2B,KAAK,2BAA2B;AACxE;;AAGF,KAAI;EACF,MAAM,MAAM;GACV,KAAK;GACL,MAAM,IAAI,KAAK;GACf,KAAK,IAAI,KAAK;GACd,aAAa,IAAI,KAAK;GACtB,cAAc,IAAI,KAAK;GACxB;EAED,MAAM,cAAc,MAAMC,WAAsB,MAAM;AAEtD,MACE,CAAC,cACC,OACA,YACD,CAAC;GACA,GAAG,IAAI;GACP,YAAY,CAAC,YAAY;GAC1B,CAAC,EACF;AACA,gBAAa,2BAA2B,KAAK,oBAAoB;AACjE;;AAGF,MAAI,OAAO,YAAY,eAAe,KAAK,OAAO,aAAa,GAAG,EAAE;AAClE,gBAAa,2BAA2B,KAAK,0BAA0B;AACvE;;EAKF,MAAM,eAAe,YAFF,MAAMC,cAAyB,IAAI,KAAK,IAAI,CAEnB;EAE5C,MAAM,eAAe,eAAuB;GAC1C,SAAS,EAAE;IACT,IAAI;IACJ,IAAI;IACJ,IAAI;IACL,CAAC;GACF,aAAa,EAAE;IACb,IAAI;IACJ,IAAI;IACJ,IAAI;IACL,CAAC;GACF,MAAM;GACP,CAAC;AAEF,MAAI,KAAK,aAAa;AACtB;UACO,OAAO;AACd,eAAa,uBAAuB,KAAK,MAAkB;AAC3D;;;;;;;;;AAaJ,MAAa,YAAY,OACvB,KACA,KACA,UACkB;CAClB,MAAM,EAAE,MAAM,cAAc,UAAU,IAAI;CAC1C,MAAM,EAAE,UAAU,IAAI;AAEtB,KAAI,CAAC,MAAM;AACT,eAAa,2BAA2B,KAAK,mBAAmB;AAChE;;AAGF,KAAI,CAAC,cAAc;AACjB,eAAa,2BAA2B,KAAK,2BAA2B;AACxE;;AAGF,KAAI,CAAC,OAAO;AACV,eAAa,2BAA2B,KAAK,mBAAmB;AAChE;;AAGF,KAAI;EACF,MAAM,cAAc,MAAMD,WAAsB,MAAM;AAEtD,MACE,CAAC,cACC,OACA,YACD,CAAC;GACA,GAAG,IAAI;GACP,YAAY,CAAC,YAAY;GAC1B,CAAC,EACF;AACA,gBAAa,2BAA2B,KAAK,oBAAoB;AACjE;;AAGF,MAAI,OAAO,YAAY,eAAe,KAAK,OAAO,aAAa,GAAG,EAAE;AAClE,gBAAa,2BAA2B,KAAK,0BAA0B;AACvE;;EAGF,MAAM,aAAa,MAAME,cAAyB,MAAM;AAExD,MAAI,CAAC,YAAY;AACf,gBAAa,2BAA2B,KAAK,iBAAiB,EAC5D,OACD,CAAC;AAEF;;AAGF,SAAO,KAAK,gBAAgB,OAAO,WAAW,GAAG,GAAG;EAEpD,MAAM,eAAe,YAAY,WAAW;EAE5C,MAAM,eAAe,eAAuB;GAC1C,SAAS,EAAE;IACT,IAAI;IACJ,IAAI;IACJ,IAAI;IACL,CAAC;GACF,aAAa,EAAE;IACb,IAAI;IACJ,IAAI;IACJ,IAAI;IACL,CAAC;GACF,MAAM;GACP,CAAC;AAEF,MAAI,KAAK,aAAa;AACtB;UACO,OAAO;AACd,eAAa,uBAAuB,KAAK,MAAkB;AAC3D"}
|
|
1
|
+
{"version":3,"file":"tag.controller.mjs","names":["tagService.findTags","tagService.countTags","tag: TagData","tagService.createTag","tagService.getTagById","tagService.updateTagById","tagService.deleteTagById"],"sources":["../../../src/controllers/tag.controller.ts"],"sourcesContent":["import { 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 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 { FastifyReply, FastifyRequest } from 'fastify';\nimport { t } from 'fastify-intlayer';\nimport type {\n Tag,\n TagAPI,\n TagCreationData,\n TagData,\n TagSchema,\n} 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 request: FastifyRequest<{ Querystring: GetTagsParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, organization, roles } = request.locals || {};\n const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } =\n getTagFiltersAndPagination(request);\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n try {\n const tags = await tagService.findTags(\n filters,\n skip,\n pageSize,\n sortOptions\n );\n\n if (\n !hasPermission(\n roles || [],\n 'tag:read'\n )({\n ...request.locals,\n targetTags: tags,\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\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 return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 request: FastifyRequest<{ Body: AddTagBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { organization, project, user, roles } = request.locals || {};\n const tagData = request.body;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (!project) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_NOT_DEFINED'\n );\n }\n\n if (!tagData) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PROJECT_DATA_NOT_FOUND'\n );\n }\n\n const tag: TagData = {\n creatorId: user.id,\n organizationId: organization.id,\n projectId: project.id,\n ...tagData,\n };\n\n if (\n !hasPermission(\n roles || [],\n 'tag:admin'\n )({\n ...request.locals,\n targetTags: [tag as Tag],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'PERMISSION_DENIED');\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 return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 request: FastifyRequest<{ Params: UpdateTagParams; Body: UpdateTagBody }>,\n reply: FastifyReply\n): Promise<void> => {\n const { tagId } = request.params;\n const { organization, user, roles } = request.locals || {};\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n try {\n const tag = {\n _id: tagId,\n name: request.body.name,\n key: request.body.key,\n description: request.body.description,\n instructions: request.body.instructions,\n } as Partial<TagSchema> & { _id: Tag['id'] };\n\n const tagToDelete = await tagService.getTagById(tagId);\n\n if (\n !hasPermission(\n roles || [],\n 'tag:write'\n )({\n ...request.locals,\n targetTags: [tagToDelete],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n if (String(tagToDelete.organizationId) !== String(organization.id)) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'TAG_NOT_IN_ORGANIZATION'\n );\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 return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\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 */\nexport const deleteTag = async (\n request: FastifyRequest<{ Params: DeleteTagParams }>,\n reply: FastifyReply\n): Promise<void> => {\n const { user, organization, roles } = request.locals || {};\n const { tagId } = request.params;\n\n if (!user) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'USER_NOT_DEFINED');\n }\n\n if (!organization) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'ORGANIZATION_NOT_DEFINED'\n );\n }\n\n if (!tagId) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'TAG_ID_NOT_FOUND');\n }\n\n try {\n const tagToDelete = await tagService.getTagById(tagId);\n\n if (\n !hasPermission(\n roles || [],\n 'tag:admin'\n )({\n ...request.locals,\n targetTags: [tagToDelete],\n })\n ) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'PERMISSION_DENIED'\n );\n }\n\n if (String(tagToDelete.organizationId) !== String(organization.id)) {\n return ErrorHandler.handleGenericErrorResponse(\n reply,\n 'TAG_NOT_IN_ORGANIZATION'\n );\n }\n\n const deletedTag = await tagService.deleteTagById(tagId);\n\n if (!deletedTag) {\n return ErrorHandler.handleGenericErrorResponse(reply, 'TAG_NOT_FOUND', {\n tagId,\n });\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 return reply.send(responseData);\n } catch (error) {\n return ErrorHandler.handleAppErrorResponse(reply, error as AppError);\n }\n};\n"],"mappings":"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"}
|
|
@@ -6,25 +6,22 @@ import { countUsers, createUser as createUser$1, deleteUser as deleteUser$1, fin
|
|
|
6
6
|
import { mapUserToAPI, mapUsersToAPI } from "../utils/mapper/user.mjs";
|
|
7
7
|
import { sendEmail } from "../services/email.service.mjs";
|
|
8
8
|
import { getUserFiltersAndPagination } from "../utils/filtersAndPagination/getUserFiltersAndPagination.mjs";
|
|
9
|
-
import { t } from "
|
|
9
|
+
import { t } from "fastify-intlayer";
|
|
10
10
|
|
|
11
11
|
//#region src/controllers/user.controller.ts
|
|
12
12
|
/**
|
|
13
13
|
* Creates a new user.
|
|
14
14
|
*/
|
|
15
|
-
const createUser = async (
|
|
16
|
-
const user =
|
|
17
|
-
if (!user)
|
|
18
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
15
|
+
const createUser = async (request, reply) => {
|
|
16
|
+
const user = request.body;
|
|
17
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
21
18
|
try {
|
|
22
19
|
const newUser = await createUser$1(user);
|
|
23
20
|
await sendEmail({
|
|
24
21
|
type: "welcome",
|
|
25
22
|
to: newUser.email,
|
|
26
23
|
username: newUser.name,
|
|
27
|
-
loginLink: `${process.env.
|
|
24
|
+
loginLink: `${process.env.APP_URL}/auth/login`
|
|
28
25
|
});
|
|
29
26
|
const formattedUser = mapUserToAPI(newUser);
|
|
30
27
|
const responseData = formatResponse({
|
|
@@ -40,32 +37,24 @@ const createUser = async (req, res, _next) => {
|
|
|
40
37
|
}),
|
|
41
38
|
data: formattedUser
|
|
42
39
|
});
|
|
43
|
-
|
|
44
|
-
return;
|
|
40
|
+
return reply.send(responseData);
|
|
45
41
|
} catch (error) {
|
|
46
|
-
ErrorHandler.handleAppErrorResponse(
|
|
47
|
-
return;
|
|
42
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
48
43
|
}
|
|
49
44
|
};
|
|
50
45
|
/**
|
|
51
46
|
* Retrieves a list of users based on filters and pagination.
|
|
52
47
|
*/
|
|
53
|
-
const getUsers = async (
|
|
54
|
-
const { user, roles } =
|
|
55
|
-
if (!user)
|
|
56
|
-
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getUserFiltersAndPagination(req, res);
|
|
48
|
+
const getUsers = async (request, reply) => {
|
|
49
|
+
const { user, roles } = request.locals || {};
|
|
50
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
51
|
+
const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getUserFiltersAndPagination(request);
|
|
60
52
|
try {
|
|
61
53
|
const users = await findUsers(filters, skip, pageSize, sortOptions);
|
|
62
|
-
if (!hasPermission(roles, "user:read")({
|
|
63
|
-
...
|
|
54
|
+
if (!hasPermission(roles || [], "user:read")({
|
|
55
|
+
...request.locals,
|
|
64
56
|
targetUsers: users
|
|
65
|
-
}))
|
|
66
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
57
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
69
58
|
const totalItems = await countUsers(filters);
|
|
70
59
|
const responseData = formatPaginatedResponse({
|
|
71
60
|
data: mapUsersToAPI(users),
|
|
@@ -74,82 +63,53 @@ const getUsers = async (req, res, _next) => {
|
|
|
74
63
|
totalPages: getNumberOfPages(totalItems),
|
|
75
64
|
totalItems
|
|
76
65
|
});
|
|
77
|
-
|
|
78
|
-
return;
|
|
66
|
+
return reply.send(responseData);
|
|
79
67
|
} catch (error) {
|
|
80
|
-
ErrorHandler.handleAppErrorResponse(
|
|
81
|
-
return;
|
|
68
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
82
69
|
}
|
|
83
70
|
};
|
|
84
|
-
const getUserById = async (
|
|
85
|
-
const { userId } =
|
|
71
|
+
const getUserById = async (request, reply) => {
|
|
72
|
+
const { userId } = request.params;
|
|
86
73
|
try {
|
|
87
74
|
const user = await getUserById$1(userId);
|
|
88
|
-
if (!user)
|
|
89
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
75
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
92
76
|
const responseData = formatResponse({ data: mapUserToAPI(user) });
|
|
93
|
-
|
|
94
|
-
return;
|
|
77
|
+
return reply.send(responseData);
|
|
95
78
|
} catch (error) {
|
|
96
|
-
ErrorHandler.handleAppErrorResponse(
|
|
97
|
-
return;
|
|
79
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
98
80
|
}
|
|
99
81
|
};
|
|
100
|
-
const getUserByEmail = async (
|
|
101
|
-
const { email } =
|
|
102
|
-
const { roles } =
|
|
82
|
+
const getUserByEmail = async (request, reply) => {
|
|
83
|
+
const { email } = request.params;
|
|
84
|
+
const { roles } = request.locals || {};
|
|
103
85
|
try {
|
|
104
86
|
const user = await getUserByEmail$1(email);
|
|
105
|
-
if (!user)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
if (!hasPermission(roles, "user:read")({
|
|
110
|
-
...res.locals,
|
|
87
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
88
|
+
if (!hasPermission(roles || [], "user:read")({
|
|
89
|
+
...request.locals,
|
|
111
90
|
targetUsers: [user]
|
|
112
|
-
}))
|
|
113
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
91
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
116
92
|
const responseData = formatResponse({ data: mapUserToAPI(user) });
|
|
117
|
-
|
|
93
|
+
return reply.send(responseData);
|
|
118
94
|
} catch (error) {
|
|
119
|
-
ErrorHandler.handleAppErrorResponse(
|
|
120
|
-
return;
|
|
95
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
121
96
|
}
|
|
122
97
|
};
|
|
123
98
|
/**
|
|
124
99
|
* Updates user information (phone number, date of birth).
|
|
125
100
|
*/
|
|
126
|
-
const updateUser = async (
|
|
127
|
-
const userData =
|
|
128
|
-
const { user, roles } =
|
|
129
|
-
if (!user)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
if (typeof userData !== "object") {
|
|
134
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_DATA_NOT_FOUND");
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
if (!userData.id) {
|
|
138
|
-
ErrorHandler.handleGenericErrorResponse(res, "USER_INVALID_FIELDS");
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
101
|
+
const updateUser = async (request, reply) => {
|
|
102
|
+
const userData = request.body;
|
|
103
|
+
const { user, roles } = request.locals || {};
|
|
104
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_DEFINED");
|
|
105
|
+
if (typeof userData !== "object") return ErrorHandler.handleGenericErrorResponse(reply, "USER_DATA_NOT_FOUND");
|
|
106
|
+
if (!userData.id) return ErrorHandler.handleGenericErrorResponse(reply, "USER_INVALID_FIELDS");
|
|
141
107
|
const userDB = await getUserById$1(userData.id);
|
|
142
|
-
if (!userDB)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
if (!hasPermission(roles, "user:write")({
|
|
147
|
-
...res.locals,
|
|
108
|
+
if (!userDB) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_FOUND");
|
|
109
|
+
if (!hasPermission(roles || [], "user:write")({
|
|
110
|
+
...request.locals,
|
|
148
111
|
targetUsers: [userDB]
|
|
149
|
-
}))
|
|
150
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
112
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
153
113
|
try {
|
|
154
114
|
const updatedUser = await updateUserById(userDB.id, userData);
|
|
155
115
|
logger.info(`User updated: Name: ${updatedUser.name}, id: ${String(updatedUser.id)}`);
|
|
@@ -167,32 +127,24 @@ const updateUser = async (req, res, _next) => {
|
|
|
167
127
|
}),
|
|
168
128
|
data: formattedUser
|
|
169
129
|
});
|
|
170
|
-
|
|
171
|
-
return;
|
|
130
|
+
return reply.send(responseData);
|
|
172
131
|
} catch (error) {
|
|
173
|
-
ErrorHandler.handleAppErrorResponse(
|
|
174
|
-
return;
|
|
132
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
175
133
|
}
|
|
176
134
|
};
|
|
177
135
|
/**
|
|
178
136
|
* Deletes a user based on the provided ID.
|
|
179
137
|
*/
|
|
180
|
-
const deleteUser = async (
|
|
181
|
-
const { userId } =
|
|
182
|
-
const { roles } =
|
|
138
|
+
const deleteUser = async (request, reply) => {
|
|
139
|
+
const { userId } = request.params;
|
|
140
|
+
const { roles } = request.locals || {};
|
|
183
141
|
try {
|
|
184
142
|
const user = await getUserById$1(userId);
|
|
185
|
-
if (!user)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
if (!hasPermission(roles, "user:admin")({
|
|
190
|
-
...res.locals,
|
|
143
|
+
if (!user) return ErrorHandler.handleGenericErrorResponse(reply, "USER_NOT_FOUND");
|
|
144
|
+
if (!hasPermission(roles || [], "user:admin")({
|
|
145
|
+
...request.locals,
|
|
191
146
|
targetUsers: [user]
|
|
192
|
-
}))
|
|
193
|
-
ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
147
|
+
})) return ErrorHandler.handleGenericErrorResponse(reply, "PERMISSION_DENIED");
|
|
196
148
|
await deleteUser$1(userId);
|
|
197
149
|
const formattedUser = mapUserToAPI(user);
|
|
198
150
|
const responseData = formatResponse({
|
|
@@ -208,16 +160,15 @@ const deleteUser = async (req, res, _next) => {
|
|
|
208
160
|
}),
|
|
209
161
|
data: formattedUser
|
|
210
162
|
});
|
|
211
|
-
|
|
163
|
+
return reply.send(responseData);
|
|
212
164
|
} catch (error) {
|
|
213
|
-
ErrorHandler.handleAppErrorResponse(
|
|
214
|
-
return;
|
|
165
|
+
return ErrorHandler.handleAppErrorResponse(reply, error);
|
|
215
166
|
}
|
|
216
167
|
};
|
|
217
168
|
let clients = [];
|
|
218
169
|
const sendVerificationUpdate = (user) => {
|
|
219
170
|
const filteredClients = clients.filter((client) => String(client.userId) === String(user.id));
|
|
220
|
-
for (const client of filteredClients) if (user.emailVerified) client.res.write(`data: ${JSON.stringify({
|
|
171
|
+
for (const client of filteredClients) if (user.emailVerified) client.res.raw.write(`data: ${JSON.stringify({
|
|
221
172
|
userId: user.id,
|
|
222
173
|
status: "verified"
|
|
223
174
|
})}\n\n`);
|
|
@@ -225,33 +176,33 @@ const sendVerificationUpdate = (user) => {
|
|
|
225
176
|
/**
|
|
226
177
|
* SSE to check the email verification status
|
|
227
178
|
*/
|
|
228
|
-
const verifyEmailStatusSSE = async (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const { userId } =
|
|
179
|
+
const verifyEmailStatusSSE = async (request, reply) => {
|
|
180
|
+
reply.raw.setHeader("Content-Type", "text/event-stream;charset=utf-8");
|
|
181
|
+
reply.raw.setHeader("Cache-Control", "no-cache, no-transform");
|
|
182
|
+
reply.raw.setHeader("Connection", "keep-alive");
|
|
183
|
+
reply.raw.setHeader("X-Accel-Buffering", "no");
|
|
184
|
+
reply.raw.write(":\n\n");
|
|
185
|
+
reply.raw.flushHeaders?.();
|
|
186
|
+
const { userId } = request.params;
|
|
236
187
|
const clientId = Date.now();
|
|
237
188
|
const user = await getUserById$1(userId);
|
|
238
189
|
if (!user) {
|
|
239
190
|
logger.error(`User not found - User ID: ${userId}`);
|
|
240
|
-
|
|
191
|
+
reply.raw.write(`data: ${JSON.stringify({
|
|
241
192
|
userId,
|
|
242
193
|
status: "error"
|
|
243
194
|
})}\n\n`);
|
|
244
|
-
|
|
195
|
+
reply.raw.end();
|
|
245
196
|
return;
|
|
246
197
|
}
|
|
247
198
|
const newClient = {
|
|
248
199
|
id: clientId,
|
|
249
200
|
userId,
|
|
250
|
-
res
|
|
201
|
+
res: { raw: reply.raw }
|
|
251
202
|
};
|
|
252
203
|
clients.push(newClient);
|
|
253
204
|
sendVerificationUpdate(user);
|
|
254
|
-
|
|
205
|
+
request.raw.on("close", () => {
|
|
255
206
|
clients = clients.filter((client) => client.id !== clientId);
|
|
256
207
|
});
|
|
257
208
|
};
|