@raclettejs/core 0.1.18 → 0.1.20

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 (136) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/bin/cli.js +1 -1
  3. package/dev/README.md +4 -0
  4. package/dist/cli.js +135 -124
  5. package/dist/cli.js.map +4 -4
  6. package/dist/index.js +9 -8
  7. package/dist/index.js.map +4 -4
  8. package/package.json +9 -5
  9. package/services/backend/delay-api-debugger.sh +0 -0
  10. package/services/backend/package.json +1 -0
  11. package/services/backend/src/app.ts +4 -0
  12. package/services/backend/src/core/config/configService.ts +10 -1
  13. package/services/backend/src/core/events/eventEmitter.ts +32 -7
  14. package/services/backend/src/core/http/request-params.plugin.ts +2 -2
  15. package/services/backend/src/core/pluginSystem/pluginFastifyInstance.ts +4 -1
  16. package/services/backend/src/core/pluginSystem/pluginTypes.ts +3 -1
  17. package/services/backend/src/core/sockets/createSystemEventHandlers.ts +7 -0
  18. package/services/backend/src/core/sockets/index.ts +61 -13
  19. package/services/backend/src/core/sockets/socketManager.ts +452 -105
  20. package/services/backend/src/core/sockets/socketTypes.ts +13 -1
  21. package/services/backend/src/core/sockets/workSessionJoinPayload.ts +106 -0
  22. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.get.ts +3 -1
  23. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.getAll.ts +3 -1
  24. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.hardDelete.ts +16 -19
  25. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.patch.ts +3 -1
  26. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.post.ts +3 -1
  27. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.remove.ts +3 -1
  28. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/composition.service.ts +86 -3
  29. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/index.ts +2 -0
  30. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.get.ts +3 -1
  31. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.getAll.ts +3 -1
  32. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.hardDelete.ts +16 -19
  33. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.patch.ts +3 -1
  34. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.post.bulk.ts +60 -0
  35. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.post.ts +3 -1
  36. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.remove.ts +3 -1
  37. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.restore.ts +12 -15
  38. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/interactionLink.service.ts +96 -12
  39. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/index.ts +2 -0
  40. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.get.ts +3 -1
  41. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.getAll.ts +4 -2
  42. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.hardDelete.ts +12 -17
  43. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.patch.ts +3 -1
  44. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.post.bulk.ts +62 -0
  45. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.post.ts +3 -1
  46. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.remove.ts +3 -1
  47. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.restore.ts +12 -15
  48. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/project.service.ts +1 -0
  49. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.get.ts +3 -1
  50. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.getAll.ts +4 -2
  51. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.hardDelete.ts +3 -1
  52. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.patch.ts +3 -1
  53. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.post.ts +4 -2
  54. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.remove.ts +3 -1
  55. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/index.ts +2 -0
  56. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.get.ts +1 -0
  57. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.getAll.ts +1 -0
  58. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.hardDelete.ts +10 -15
  59. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.patch.ts +3 -1
  60. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.post.bulk.ts +60 -0
  61. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.post.ts +3 -1
  62. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.remove.ts +3 -1
  63. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.restore.ts +12 -15
  64. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/tag.service.ts +73 -3
  65. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.get.ts +1 -0
  66. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.getAll.ts +1 -0
  67. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.hardDelete.ts +10 -15
  68. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patch.ts +4 -6
  69. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patchLastProject.ts +4 -2
  70. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.post.ts +3 -1
  71. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.remove.ts +3 -4
  72. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.restore.ts +12 -15
  73. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/events/index.ts +45 -0
  74. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/helpers/crud.ts +12 -0
  75. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/helpers/payload.ts +21 -0
  76. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/index.ts +55 -0
  77. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/index.ts +19 -0
  78. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.get.ts +53 -0
  79. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.getAll.ts +39 -0
  80. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.hardDelete.ts +53 -0
  81. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.patch.ts +58 -0
  82. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.post.ts +53 -0
  83. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.remove.ts +52 -0
  84. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.model.ts +65 -0
  85. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.schema.ts +125 -0
  86. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.service.ts +351 -0
  87. package/services/backend/src/corePlugins/raclette__core/backend/index.ts +2 -0
  88. package/services/backend/src/corePlugins/raclette__core/frontend/generated-config.ts +159 -24
  89. package/services/backend/src/modules/authentication/index.ts +255 -4
  90. package/services/backend/src/modules/hooks/rate-limiter.ts +21 -0
  91. package/services/backend/src/types/custom-fastify.d.ts +17 -0
  92. package/services/backend/src/utils/request.utils.ts +4 -1
  93. package/services/backend/types/index.d.ts +15 -1
  94. package/services/backend/yarn.lock +13 -4
  95. package/services/frontend/index.html +1 -1
  96. package/services/frontend/provision/entrypoint.sh +0 -0
  97. package/services/frontend/src/core/lib/configService.ts +1 -1
  98. package/services/frontend/src/core/lib/data/dataApi.ts +10 -1
  99. package/services/frontend/src/core/lib/dataHelper.ts +1 -1
  100. package/services/frontend/src/core/lib/eggs/snow.ts +66 -48
  101. package/services/frontend/src/core/lib/helpers/index.ts +1 -0
  102. package/services/frontend/src/core/lib/helpers/removeEmpty.ts +69 -0
  103. package/services/frontend/src/core/lib/httpClient.ts +19 -0
  104. package/services/frontend/src/core/main.ts +20 -10
  105. package/services/frontend/src/core/setup/socket.ts +4 -3
  106. package/services/frontend/src/core/setup/socketClient.ts +31 -3
  107. package/services/frontend/src/core/setup/socketEvents.ts +92 -8
  108. package/services/frontend/src/core/store/index.ts +5 -1
  109. package/services/frontend/src/core/store/reducers/compositions/index.ts +2 -2
  110. package/services/frontend/src/core/store/reducers/interactionLinks/index.ts +1 -1
  111. package/services/frontend/src/core/store/reducers/widgets/reducers.ts +1 -2
  112. package/services/frontend/src/core/store/types/index.ts +0 -1
  113. package/services/frontend/src/core/types/PluginRegistrar.ts +8 -6
  114. package/services/frontend/src/core/types/Store.ts +1 -0
  115. package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +68 -8
  116. package/services/frontend/src/orchestrator/components/menu/UserMenu.vue +17 -5
  117. package/services/frontend/src/orchestrator/components/welcomeScreen/AdminWelcomeScreen.vue +1 -1
  118. package/services/frontend/src/orchestrator/composables/index.ts +1 -0
  119. package/services/frontend/src/orchestrator/composables/usePluginApi.ts +0 -3
  120. package/services/frontend/src/orchestrator/composables/useRouteState.ts +23 -4
  121. package/services/frontend/src/orchestrator/composables/useWidgetLifecycle.ts +166 -0
  122. package/services/frontend/src/orchestrator/helpers/index.ts +1 -0
  123. package/services/frontend/src/orchestrator/i18n/de-DE.json +15 -1
  124. package/services/frontend/src/orchestrator/i18n/en-EU.json +15 -1
  125. package/services/frontend/src/orchestrator/i18n/sk.json +15 -1
  126. package/services/frontend/src/orchestrator/index.ts +34 -4
  127. package/services/frontend/src/orchestrator/router/routeParserHelper.ts +106 -1
  128. package/services/frontend/src/orchestrator/types/Widgets.ts +2 -0
  129. package/services/frontend/types.ts +1 -0
  130. package/src/README.md +404 -0
  131. package/src/types.ts +19 -5
  132. package/templates/README.md +0 -0
  133. package/types/index.ts +18 -4
  134. package/services/backend/.gitignore +0 -17
  135. package/services/frontend/.gitignore +0 -35
  136. package/yarn.lock +0 -2937
@@ -97,11 +97,10 @@ export class InteractionLinkService {
97
97
  */
98
98
  async _readAllInteractionLinks(
99
99
  fastify: PluginFastifyInstance,
100
- filters: Record<string, any> = {},
100
+ filters: Record<string, any> = { isDeleted: false },
101
101
  ): Promise<InteractionLinkType[]> {
102
102
  try {
103
- if (filters.isDeleted !== true && filters.isDeleted !== "true")
104
- filters.isDeleted = false
103
+ filters = { isDeleted: false, ...filters }
105
104
  return await this.interactionLinkModel
106
105
  .find({
107
106
  ...filters,
@@ -130,16 +129,16 @@ export class InteractionLinkService {
130
129
  }
131
130
 
132
131
  /**
133
- * Core function to get interaction links by composition ID (returns raw data)
132
+ * Core function to get interaction links by interactionLink ID (returns raw data)
134
133
  */
135
- async _readInteractionLinksByComposition(
134
+ async _readInteractionLinksByInteractionLink(
136
135
  fastify: PluginFastifyInstance,
137
- compositionId: string,
136
+ interactionLinkId: string,
138
137
  ): Promise<InteractionLinkType[]> {
139
138
  try {
140
139
  return await this.interactionLinkModel
141
140
  .find({
142
- composition: compositionId,
141
+ interactionLink: interactionLinkId,
143
142
  isDeleted: false,
144
143
  })
145
144
  .lean()
@@ -150,16 +149,16 @@ export class InteractionLinkService {
150
149
  }
151
150
 
152
151
  /**
153
- * Get interaction links by composition ID with payload wrapping
152
+ * Get interaction links by interactionLink ID with payload wrapping
154
153
  */
155
- async readInteractionLinksByComposition(
154
+ async readInteractionLinksByInteractionLink(
156
155
  fastify: PluginFastifyInstance,
157
156
  requestData: FrontendPayloadRequestData,
158
- compositionId: string,
157
+ interactionLinkId: string,
159
158
  ): Promise<FrontendPayload<InteractionLinkType[]>> {
160
- const interactionLinks = await this._readInteractionLinksByComposition(
159
+ const interactionLinks = await this._readInteractionLinksByInteractionLink(
161
160
  fastify,
162
- compositionId,
161
+ interactionLinkId,
163
162
  )
164
163
 
165
164
  return createInteractionLinkPayload(fastify, interactionLinks, requestData)
@@ -439,6 +438,91 @@ export class InteractionLinkService {
439
438
 
440
439
  return createInteractionLinkPayload(fastify, interactionLinks, requestData)
441
440
  }
441
+ /**
442
+ * Core function to create multiple interactionLinks (returns raw data)
443
+ */
444
+ async _createInteractionLinks(
445
+ fastify: PluginFastifyInstance,
446
+ interactionLinkBodies: InteractionLinkBody[],
447
+ userId: string,
448
+ ): Promise<InteractionLinkType[]> {
449
+ try {
450
+ const interactionLinksToCreate: InteractionLinkBody[] = []
451
+
452
+ // Validate and prepare all interactionLinks
453
+ for (const interactionLinkBody of interactionLinkBodies) {
454
+ if (interactionLinkBody._id) {
455
+ const uuidValid = validate(interactionLinkBody._id)
456
+
457
+ if (!uuidValid) {
458
+ throw new Error(
459
+ `Invalid ID - not a valid uuid v4: ${interactionLinkBody._id}`,
460
+ )
461
+ }
462
+
463
+ const duplicate = await this.interactionLinkModel.findOne({
464
+ _id: interactionLinkBody._id,
465
+ })
466
+
467
+ if (duplicate) {
468
+ throw new Error(
469
+ `An entry with this id already exists: ${interactionLinkBody._id}`,
470
+ )
471
+ }
472
+ } else {
473
+ interactionLinkBody._id = uuidv4()
474
+ }
475
+
476
+ interactionLinksToCreate.push({
477
+ ...interactionLinkBody,
478
+ author: userId,
479
+ lastEditor: userId,
480
+ })
481
+ }
482
+
483
+ // Bulk insert
484
+ const interactionLinks = await this.interactionLinkModel.insertMany(
485
+ interactionLinksToCreate,
486
+ )
487
+
488
+ fastify.log.info(
489
+ `[API] Created ${interactionLinks.length} interactionLinks in bulk`,
490
+ )
491
+
492
+ return interactionLinks.map((comp) =>
493
+ comp.toObject ? comp.toObject() : comp,
494
+ )
495
+ } catch (error: any) {
496
+ fastify.log.error(error.message)
497
+ throw error
498
+ }
499
+ }
500
+
501
+ /**
502
+ * Create multiple interactionLinks with payload wrapping and event emission
503
+ */
504
+ async createInteractionLinks(
505
+ fastify: PluginFastifyInstance,
506
+ requestData: FrontendPayloadRequestData,
507
+ interactionLinkBodies: InteractionLinkBody[],
508
+ userId: string,
509
+ ): Promise<FrontendPayload<InteractionLinkType[]>> {
510
+ const interactionLinks = await this._createInteractionLinks(
511
+ fastify,
512
+ interactionLinkBodies,
513
+ userId,
514
+ )
515
+
516
+ const payload = await createInteractionLinkPayload(
517
+ fastify,
518
+ interactionLinks,
519
+ requestData,
520
+ )
521
+
522
+ fastify.emit("interactionLinksCreated", payload)
523
+
524
+ return payload
525
+ }
442
526
  }
443
527
 
444
528
  export const createInteractionLinkService = (
@@ -4,6 +4,7 @@ import getAll from "./route.interactionLink.getAll"
4
4
  import hardDelete from "./route.interactionLink.hardDelete"
5
5
  import patch from "./route.interactionLink.patch"
6
6
  import post from "./route.interactionLink.post"
7
+ import postBulk from "./route.interactionLink.post.bulk"
7
8
  import remove from "./route.interactionLink.remove"
8
9
  import restore from "./route.interactionLink.restore"
9
10
 
@@ -13,6 +14,7 @@ const registerRoutes = async (fastify: PluginFastifyInstance) => {
13
14
  await fastify.patch("/interactionLink/:_id", patch(fastify))
14
15
  await fastify.patch("/interactionLink/:_id/restore", restore(fastify))
15
16
  await fastify.post("/interactionLink", post(fastify))
17
+ await fastify.post("/interactionLink/bulk", postBulk(fastify))
16
18
  await fastify.delete("/interactionLink/:_id", remove(fastify))
17
19
  await fastify.delete("/interactionLink/:_id/hard", hardDelete(fastify))
18
20
  }
@@ -3,6 +3,8 @@ import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
 
6
+ const permissions = ["user.isAdmin"]
7
+
6
8
  const ParamsSchema = Type.Object({
7
9
  _id: Type.String(),
8
10
  })
@@ -39,7 +41,7 @@ export default (fastify: PluginFastifyInstance) => {
39
41
 
40
42
  return {
41
43
  handler,
42
- onRequest: [fastify.authenticate],
44
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
43
45
  config: {
44
46
  type: "dataRead",
45
47
  },
@@ -1,5 +1,7 @@
1
1
  import type { FastifyReply, FastifyRequest } from "fastify"
2
- import { PluginFastifyInstance } from "types"
2
+ import type { PluginFastifyInstance } from "types"
3
+
4
+ const permissions = ["user.isAdmin"]
3
5
 
4
6
  export default (fastify: PluginFastifyInstance) => {
5
7
  const interactionLinkService = fastify.custom.interactionLinkService
@@ -21,7 +23,7 @@ export default (fastify: PluginFastifyInstance) => {
21
23
 
22
24
  return {
23
25
  handler,
24
- onRequest: [fastify.authenticate],
26
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
25
27
  config: {
26
28
  type: "dataRead",
27
29
  },
@@ -2,7 +2,8 @@ import type { Static } from "@sinclair/typebox"
2
2
  import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
- import { ForbiddenError } from "@/utils/errors"
5
+
6
+ const permissions = ["user.isAdmin"]
6
7
 
7
8
  const ParamsSchema = Type.Object({
8
9
  _id: Type.String(),
@@ -19,21 +20,15 @@ export default (fastify: PluginFastifyInstance) => {
19
20
  reply: FastifyReply,
20
21
  ) => {
21
22
  try {
22
- if (req.user.isAdmin) {
23
- const { _id } = req.params
24
-
25
- const payload = await interactionLinkService.hardDeleteInteractionLink(
26
- fastify,
27
- req.requestParams,
28
- _id,
29
- )
30
-
31
- return payload
32
- } else {
33
- throw new ForbiddenError(
34
- "Only admins can hard delete this core datatype",
35
- )
36
- }
23
+ const { _id } = req.params
24
+
25
+ const payload = await interactionLinkService.hardDeleteInteractionLink(
26
+ fastify,
27
+ req.requestParams,
28
+ _id,
29
+ )
30
+
31
+ return payload
37
32
  } catch (error: any) {
38
33
  fastify.log.error(error.message)
39
34
  return reply.internalServerError(error.message)
@@ -42,7 +37,7 @@ export default (fastify: PluginFastifyInstance) => {
42
37
 
43
38
  return {
44
39
  handler,
45
- onRequest: [fastify.authenticate],
40
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
46
41
  config: {
47
42
  type: "dataHardDelete",
48
43
  broadcastChannels: ["interactionLinkHardDeleted"],
@@ -5,6 +5,8 @@ import { PluginFastifyInstance } from "types"
5
5
  import { Type } from "@sinclair/typebox"
6
6
  import { interactionLinkUpdateSchema } from "../interactionLink.schema"
7
7
 
8
+ const permissions = ["user.isAdmin"]
9
+
8
10
  const ParamsSchema = Type.Object({
9
11
  _id: Type.String(),
10
12
  })
@@ -39,7 +41,7 @@ export default (fastify: PluginFastifyInstance) => {
39
41
 
40
42
  return {
41
43
  handler,
42
- onRequest: [fastify.authenticate],
44
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
43
45
  config: {
44
46
  type: "dataUpdate",
45
47
  broadcastChannels: ["interactionLinkUpdated"],
@@ -0,0 +1,62 @@
1
+ import type { InteractionLinkBody } from "../interactionLink.service"
2
+ import type { FastifyReply, FastifyRequest } from "fastify"
3
+ import type { PluginFastifyInstance } from "types"
4
+ import { interactionLinkCreateSchema } from "../interactionLink.schema"
5
+
6
+ const permissions = ["user.isAdmin"]
7
+
8
+ export default (fastify: PluginFastifyInstance) => {
9
+ const interactionLinkService = fastify.custom.interactionLinkService
10
+
11
+ const handler = async (
12
+ req: FastifyRequest<{
13
+ Body: InteractionLinkBody[]
14
+ }>,
15
+ reply: FastifyReply,
16
+ ) => {
17
+ try {
18
+ // Validate that body is an array
19
+ if (!Array.isArray(req.body)) {
20
+ return reply.badRequest(
21
+ "Request body must be an array of interactionLinks",
22
+ )
23
+ }
24
+
25
+ // Validate that array is not empty
26
+ if (req.body.length === 0) {
27
+ return reply.badRequest("Request body cannot be an empty array")
28
+ }
29
+
30
+ const payload = await interactionLinkService.createInteractionLinks(
31
+ fastify,
32
+ req.requestParams,
33
+ req.body,
34
+ req.user._id,
35
+ )
36
+
37
+ return payload
38
+ } catch (error: any) {
39
+ fastify.log.error(error.message)
40
+
41
+ return reply.internalServerError(error.message)
42
+ }
43
+ }
44
+
45
+ return {
46
+ handler,
47
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
48
+ config: {
49
+ type: "dataCreate",
50
+ broadcastChannels: ["interactionLinksCreated"],
51
+ },
52
+ schema: {
53
+ summary: "Create multiple interactionLinks in bulk",
54
+ tags: ["core/interactionLink"],
55
+ body: {
56
+ type: "array",
57
+ items: interactionLinkCreateSchema,
58
+ minItems: 1,
59
+ },
60
+ },
61
+ }
62
+ }
@@ -3,6 +3,8 @@ import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { interactionLinkCreateSchema } from "../interactionLink.schema"
5
5
 
6
+ const permissions = ["user.isAdmin"]
7
+
6
8
  export default (fastify: PluginFastifyInstance) => {
7
9
  const interactionLinkService = fastify.custom.interactionLinkService
8
10
 
@@ -30,7 +32,7 @@ export default (fastify: PluginFastifyInstance) => {
30
32
 
31
33
  return {
32
34
  handler,
33
- onRequest: [fastify.authenticate],
35
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
34
36
  config: {
35
37
  type: "dataCreate",
36
38
  broadcastChannels: ["interactionLinkCreated"],
@@ -3,6 +3,8 @@ import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
 
6
+ const permissions = ["user.isAdmin"]
7
+
6
8
  const ParamsSchema = Type.Object({
7
9
  _id: Type.String(),
8
10
  })
@@ -35,7 +37,7 @@ export default (fastify: PluginFastifyInstance) => {
35
37
 
36
38
  return {
37
39
  handler,
38
- onRequest: [fastify.authenticate],
40
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
39
41
  config: {
40
42
  type: "dataDelete",
41
43
  broadcastChannels: ["interactionLinkDeleted"],
@@ -2,7 +2,8 @@ import type { Static } from "@sinclair/typebox"
2
2
  import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
- import { ForbiddenError } from "@/utils/errors"
5
+
6
+ const permissions = ["user.isAdmin"]
6
7
 
7
8
  const ParamsSchema = Type.Object({
8
9
  _id: Type.String(),
@@ -17,21 +18,17 @@ export default (fastify: PluginFastifyInstance) => {
17
18
  reply: FastifyReply,
18
19
  ) => {
19
20
  try {
20
- if (req.user.isAdmin) {
21
- const { _id } = req.params
21
+ const { _id } = req.params
22
22
 
23
- const payload = await interactionLinkService.updateInteractionLink(
24
- fastify,
25
- req.requestParams,
26
- _id,
27
- { isDeleted: false },
28
- req.user._id,
29
- )
23
+ const payload = await interactionLinkService.updateInteractionLink(
24
+ fastify,
25
+ req.requestParams,
26
+ _id,
27
+ { isDeleted: false },
28
+ req.user._id,
29
+ )
30
30
 
31
- return payload
32
- } else {
33
- throw new ForbiddenError("Only admins can restore this core datatype")
34
- }
31
+ return payload
35
32
  } catch (error: any) {
36
33
  fastify.log.error(error.message)
37
34
  return reply.internalServerError(error.message)
@@ -40,7 +37,7 @@ export default (fastify: PluginFastifyInstance) => {
40
37
 
41
38
  return {
42
39
  handler,
43
- onRequest: [fastify.authenticate],
40
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
44
41
  config: {
45
42
  type: "dataRestore",
46
43
  broadcastChannels: ["interactionLinkRestored"],
@@ -87,6 +87,7 @@ export class ProjectService {
87
87
  options: QueryOptions = {},
88
88
  ): Promise<ProjectType[]> {
89
89
  try {
90
+ filter = { isDeleted: false, ...filter }
90
91
  // Start building the query
91
92
  let query = this.projectModel.find(filter)
92
93
 
@@ -3,6 +3,8 @@ import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
 
6
+ const permissions = ["user.isAdmin"]
7
+
6
8
  const ParamsSchema = Type.Object({
7
9
  _id: Type.String(),
8
10
  })
@@ -39,7 +41,7 @@ export default (fastify: PluginFastifyInstance) => {
39
41
 
40
42
  return {
41
43
  handler,
42
- onRequest: [fastify.authenticate],
44
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
43
45
  config: {
44
46
  type: "dataRead",
45
47
  },
@@ -1,5 +1,7 @@
1
1
  import type { FastifyReply, FastifyRequest } from "fastify"
2
- import { PluginFastifyInstance } from "types"
2
+ import type { PluginFastifyInstance } from "types"
3
+
4
+ const permissions = ["user.isAdmin"]
3
5
 
4
6
  export default (fastify: PluginFastifyInstance) => {
5
7
  const projectService = fastify.custom.projectService
@@ -24,7 +26,7 @@ export default (fastify: PluginFastifyInstance) => {
24
26
 
25
27
  return {
26
28
  handler,
27
- onRequest: [fastify.authenticate],
29
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
28
30
  config: {
29
31
  type: "dataRead",
30
32
  },
@@ -3,6 +3,8 @@ import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
 
6
+ const permissions = ["user.isAdmin"]
7
+
6
8
  const ParamsSchema = Type.Object({
7
9
  _id: Type.String(),
8
10
  })
@@ -35,7 +37,7 @@ export default (fastify: PluginFastifyInstance) => {
35
37
 
36
38
  return {
37
39
  handler,
38
- onRequest: [fastify.authenticate],
40
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
39
41
  config: {
40
42
  type: "dataHardDeleted",
41
43
  broadcastChannels: ["projectHardDeleted"],
@@ -5,6 +5,8 @@ import { PluginFastifyInstance } from "types"
5
5
  import { Type } from "@sinclair/typebox"
6
6
  import { projectSchema } from "../project.schema"
7
7
 
8
+ const permissions = ["user.isAdmin"]
9
+
8
10
  const ParamsSchema = Type.Object({
9
11
  _id: Type.String(),
10
12
  })
@@ -40,7 +42,7 @@ export default (fastify: PluginFastifyInstance) => {
40
42
 
41
43
  return {
42
44
  handler,
43
- onRequest: [fastify.authenticate],
45
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
44
46
  config: {
45
47
  type: "dataUpdate",
46
48
  broadcastChannels: ["projectUpdated"],
@@ -1,7 +1,9 @@
1
1
  import type { FastifyReply, FastifyRequest } from "fastify"
2
- import { PluginFastifyInstance } from "types"
2
+ import type { PluginFastifyInstance } from "types"
3
3
  import { projectCreateSchema, type ProjectCreate } from "../project.schema"
4
4
 
5
+ const permissions = ["user.isAdmin"]
6
+
5
7
  export default (fastify: PluginFastifyInstance) => {
6
8
  const projectService = fastify.custom.projectService
7
9
 
@@ -27,7 +29,7 @@ export default (fastify: PluginFastifyInstance) => {
27
29
 
28
30
  return {
29
31
  handler,
30
- // onRequest: [fastify.authenticate],
32
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
31
33
  config: {
32
34
  type: "dataCreate",
33
35
  broadcastChannels: ["projectCreated"],
@@ -3,6 +3,8 @@ import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
 
6
+ const permissions = ["user.isAdmin"]
7
+
6
8
  const ParamsSchema = Type.Object({
7
9
  _id: Type.String(),
8
10
  })
@@ -35,7 +37,7 @@ export default (fastify: PluginFastifyInstance) => {
35
37
 
36
38
  return {
37
39
  handler,
38
- onRequest: [fastify.authenticate],
40
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
39
41
  config: {
40
42
  type: "dataUpdate",
41
43
  broadcastChannels: ["projectDeleted"],
@@ -4,6 +4,7 @@ import getAll from "./route.tag.getAll"
4
4
  import hardDelete from "./route.tag.hardDelete"
5
5
  import patch from "./route.tag.patch"
6
6
  import post from "./route.tag.post"
7
+ import postBulk from "./route.tag.post.bulk"
7
8
  import remove from "./route.tag.remove"
8
9
  import restore from "./route.tag.restore"
9
10
 
@@ -13,6 +14,7 @@ const registerRoutes = async (fastify: PluginFastifyInstance) => {
13
14
  await fastify.patch("/tag/:_id", patch(fastify))
14
15
  await fastify.patch("/tag/:_id/restore", restore(fastify))
15
16
  await fastify.post("/tag/:project/:_id", post(fastify))
17
+ await fastify.post("/tag/bulk", postBulk(fastify))
16
18
  await fastify.delete("/tag/:_id", remove(fastify))
17
19
  await fastify.delete("/tag/:_id/hard", hardDelete(fastify))
18
20
  }
@@ -1,6 +1,7 @@
1
1
  import type { FastifyReply, FastifyRequest } from "fastify"
2
2
  import { PluginFastifyInstance } from "types"
3
3
  import { Type, type Static } from "@sinclair/typebox"
4
+ import { ForbiddenError } from "@/utils/errors"
4
5
 
5
6
  const ParamsSchema = Type.Object({
6
7
  _id: Type.Optional(Type.String()),
@@ -1,5 +1,6 @@
1
1
  import type { FastifyReply, FastifyRequest } from "fastify"
2
2
  import { PluginFastifyInstance } from "types"
3
+ import { ForbiddenError } from "@/utils/errors"
3
4
 
4
5
  export default (fastify: PluginFastifyInstance) => {
5
6
  const tagService = fastify.custom.tagService
@@ -2,7 +2,8 @@ import type { Static } from "@sinclair/typebox"
2
2
  import type { FastifyReply, FastifyRequest } from "fastify"
3
3
  import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
- import { ForbiddenError } from "@/utils/errors"
5
+
6
+ const permissions = ["user.isAdmin"]
6
7
 
7
8
  const ParamsSchema = Type.Object({
8
9
  _id: Type.String(),
@@ -17,21 +18,15 @@ export default (fastify: PluginFastifyInstance) => {
17
18
  reply: FastifyReply,
18
19
  ) => {
19
20
  try {
20
- if (req.user.isAdmin) {
21
- const { _id } = req.params
21
+ const { _id } = req.params
22
22
 
23
- const payloadWithTag = await tagService.hardDeleteTag(
24
- fastify,
25
- req.requestParams,
26
- _id,
27
- )
23
+ const payloadWithTag = await tagService.hardDeleteTag(
24
+ fastify,
25
+ req.requestParams,
26
+ _id,
27
+ )
28
28
 
29
- return payloadWithTag
30
- } else {
31
- throw new ForbiddenError(
32
- "Only admins can hard delete this core datatype",
33
- )
34
- }
29
+ return payloadWithTag
35
30
  } catch (error: any) {
36
31
  fastify.log.error(error.message)
37
32
  return reply.internalServerError(error.message)
@@ -40,7 +35,7 @@ export default (fastify: PluginFastifyInstance) => {
40
35
 
41
36
  return {
42
37
  handler,
43
- onRequest: [fastify.authenticate],
38
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
44
39
  config: {
45
40
  type: "dataHardDeleted",
46
41
  broadcastChannels: ["tagHardDeleted"],
@@ -4,6 +4,8 @@ import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
  import { tagUpdateSchema } from "../tag.schema"
6
6
 
7
+ const permissions = ["user.isAdmin"]
8
+
7
9
  const ParamsSchema = Type.Object({
8
10
  _id: Type.String(),
9
11
  })
@@ -40,7 +42,7 @@ export default (fastify: PluginFastifyInstance) => {
40
42
 
41
43
  return {
42
44
  handler,
43
- onRequest: [fastify.authenticate],
45
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
44
46
  config: {
45
47
  type: "dataUpdate",
46
48
  broadcastChannels: ["tagUpdated"],