@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
@@ -0,0 +1,60 @@
1
+ import type { TagBody } from "../tag.service"
2
+ import type { FastifyReply, FastifyRequest } from "fastify"
3
+ import type { PluginFastifyInstance } from "types"
4
+ import { tagCreateSchema } from "../tag.schema"
5
+
6
+ const permissions = ["user.isAdmin"]
7
+
8
+ export default (fastify: PluginFastifyInstance) => {
9
+ const tagService = fastify.custom.tagService
10
+
11
+ const handler = async (
12
+ req: FastifyRequest<{
13
+ Body: TagBody[]
14
+ }>,
15
+ reply: FastifyReply,
16
+ ) => {
17
+ try {
18
+ // Validate that body is an array
19
+ if (!Array.isArray(req.body)) {
20
+ return reply.badRequest("Request body must be an array of tags")
21
+ }
22
+
23
+ // Validate that array is not empty
24
+ if (req.body.length === 0) {
25
+ return reply.badRequest("Request body cannot be an empty array")
26
+ }
27
+
28
+ const payload = await tagService.createTags(
29
+ fastify,
30
+ req.requestParams,
31
+ req.body,
32
+ req.user._id,
33
+ )
34
+
35
+ return payload
36
+ } catch (error: any) {
37
+ fastify.log.error(error.message)
38
+
39
+ return reply.internalServerError(error.message)
40
+ }
41
+ }
42
+
43
+ return {
44
+ handler,
45
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
46
+ config: {
47
+ type: "dataCreate",
48
+ broadcastChannels: ["tagsCreated"],
49
+ },
50
+ schema: {
51
+ summary: "Create multiple tags in bulk",
52
+ tags: ["core/tag"],
53
+ body: {
54
+ type: "array",
55
+ items: tagCreateSchema,
56
+ minItems: 1,
57
+ },
58
+ },
59
+ }
60
+ }
@@ -4,6 +4,8 @@ import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
  import { tagCreateSchema, type TagCreate } from "../tag.schema"
6
6
 
7
+ const permissions = ["user.isAdmin"]
8
+
7
9
  const ParamsSchema = Type.Object({
8
10
  _id: Type.String(),
9
11
  project: Type.String(),
@@ -38,7 +40,7 @@ export default (fastify: PluginFastifyInstance) => {
38
40
 
39
41
  return {
40
42
  handler,
41
- onRequest: [fastify.authenticate],
43
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
42
44
  config: {
43
45
  type: "dataCreate",
44
46
  broadcastChannels: ["tagCreated"],
@@ -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
  })
@@ -33,7 +35,7 @@ export default (fastify: PluginFastifyInstance) => {
33
35
 
34
36
  return {
35
37
  handler,
36
- onRequest: [fastify.authenticate],
38
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
37
39
  config: {
38
40
  type: "dataUpdate",
39
41
  broadcastChannels: ["tagDeleted"],
@@ -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 tagService.updateTag(
24
- fastify,
25
- req.requestParams,
26
- _id,
27
- { isDeleted: false },
28
- req.user._id,
29
- )
23
+ const payload = await tagService.updateTag(
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: ["tagRestored"],
@@ -8,7 +8,9 @@ import type { PluginFastifyInstance } from "types"
8
8
  import { v4 as uuidv4, validate } from "uuid"
9
9
  import { createTagPayload } from "./helpers/payload"
10
10
  import type { Model } from "mongoose"
11
-
11
+ export type TagBody = Partial<Omit<TagType, "_id">> & {
12
+ _id?: string
13
+ }
12
14
  export class TagService {
13
15
  private tagModel: Model<TagType>
14
16
 
@@ -131,8 +133,7 @@ export class TagService {
131
133
  options: QueryOptions = {},
132
134
  ): Promise<TagType[]> {
133
135
  try {
134
- if (filter.isDeleted !== true && filter.isDeleted !== "true")
135
- filter.isDeleted = false
136
+ filter = { isDeleted: false, ...filter }
136
137
  // Start building the query
137
138
  let query = this.tagModel.find(filter)
138
139
 
@@ -369,6 +370,75 @@ export class TagService {
369
370
 
370
371
  fastify.emit("tagHardDeleted", payload)
371
372
 
373
+ return payload
374
+ }
375
+ /**
376
+ * Core function to create multiple tags (returns raw data)
377
+ */
378
+ async _createTags(
379
+ fastify: PluginFastifyInstance,
380
+ tagBodies: TagBody[],
381
+ userId: string,
382
+ ): Promise<TagType[]> {
383
+ try {
384
+ const tagsToCreate: TagBody[] = []
385
+
386
+ // Validate and prepare all tags
387
+ for (const tagBody of tagBodies) {
388
+ if (tagBody._id) {
389
+ const uuidValid = validate(tagBody._id)
390
+
391
+ if (!uuidValid) {
392
+ throw new Error(`Invalid ID - not a valid uuid v4: ${tagBody._id}`)
393
+ }
394
+
395
+ const duplicate = await this.tagModel.findOne({
396
+ _id: tagBody._id,
397
+ })
398
+
399
+ if (duplicate) {
400
+ throw new Error(
401
+ `An entry with this id already exists: ${tagBody._id}`,
402
+ )
403
+ }
404
+ } else {
405
+ tagBody._id = uuidv4()
406
+ }
407
+
408
+ tagsToCreate.push({
409
+ ...tagBody,
410
+ author: userId,
411
+ lastEditor: userId,
412
+ })
413
+ }
414
+
415
+ // Bulk insert
416
+ const tags = await this.tagModel.insertMany(tagsToCreate)
417
+
418
+ fastify.log.info(`[API] Created ${tags.length} tags in bulk`)
419
+
420
+ return tags.map((comp) => (comp.toObject ? comp.toObject() : comp))
421
+ } catch (error: any) {
422
+ fastify.log.error(error.message)
423
+ throw error
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Create multiple tags with payload wrapping and event emission
429
+ */
430
+ async createTags(
431
+ fastify: PluginFastifyInstance,
432
+ requestData: FrontendPayloadRequestData,
433
+ tagBodies: TagBody[],
434
+ userId: string,
435
+ ): Promise<FrontendPayload<TagType[]>> {
436
+ const tags = await this._createTags(fastify, tagBodies, userId)
437
+
438
+ const payload = await createTagPayload(fastify, tags, requestData)
439
+
440
+ fastify.emit("tagsCreated", payload)
441
+
372
442
  return payload
373
443
  }
374
444
  }
@@ -2,6 +2,7 @@ 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
 
6
7
  const ParamsSchema = Type.Object({
7
8
  _id: Type.String(),
@@ -2,6 +2,7 @@ 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
 
6
7
  const QuerySchema = Type.Object({
7
8
  account: Type.Optional(Type.String()),
@@ -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 payloadWithUser = await userService.hardDeleteUser(
24
- fastify,
25
- req.requestParams,
26
- _id,
27
- )
23
+ const payloadWithUser = await userService.hardDeleteUser(
24
+ fastify,
25
+ req.requestParams,
26
+ _id,
27
+ )
28
28
 
29
- return payloadWithUser
30
- } else {
31
- throw new ForbiddenError(
32
- "Only admins can hard delete this core datatype",
33
- )
34
- }
29
+ return payloadWithUser
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: ["userHardDeleted"],
@@ -4,6 +4,8 @@ import type { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
  import { userUpdateSchema } from "../user.schema"
6
6
 
7
+ const permissions = ["user.isAdmin"]
8
+
7
9
  const ParamsSchema = Type.Object({
8
10
  _id: Type.String(),
9
11
  })
@@ -22,15 +24,11 @@ export default (fastify: PluginFastifyInstance) => {
22
24
  reply: FastifyReply,
23
25
  ) => {
24
26
  try {
25
- let cleanBody = req.body
26
- if (!req.user.isAdmin) {
27
- delete cleanBody.tags
28
- }
29
27
  const payloadWithUser = await userService.updateUser(
30
28
  fastify,
31
29
  req.requestParams,
32
30
  req.params._id,
33
- cleanBody,
31
+ req.body,
34
32
  )
35
33
 
36
34
  return payloadWithUser
@@ -42,7 +40,7 @@ export default (fastify: PluginFastifyInstance) => {
42
40
 
43
41
  return {
44
42
  handler,
45
- onRequest: [fastify.authenticate],
43
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
46
44
  config: {
47
45
  type: "dataUpdate",
48
46
  broadcastChannels: ["userUpdated"],
@@ -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 { Type } from "@sinclair/typebox"
4
4
 
5
+ const permissions = ["user.isAdmin"]
6
+
5
7
  export default (fastify: PluginFastifyInstance) => {
6
8
  const userService = fastify.custom.userService
7
9
 
@@ -26,7 +28,7 @@ export default (fastify: PluginFastifyInstance) => {
26
28
 
27
29
  return {
28
30
  handler,
29
- onRequest: [fastify.authenticate],
31
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
30
32
  config: {
31
33
  type: "dataUpdate",
32
34
  broadcastChannels: ["userUpdated"],
@@ -2,6 +2,8 @@ import type { FastifyReply, FastifyRequest } from "fastify"
2
2
  import { PluginFastifyInstance } from "types"
3
3
  import { userCreateSchema, type UserCreate } from "../user.schema"
4
4
 
5
+ const permissions = ["user.isAdmin"]
6
+
5
7
  export default (fastify: PluginFastifyInstance) => {
6
8
  const userService = fastify.custom.userService
7
9
 
@@ -25,7 +27,7 @@ export default (fastify: PluginFastifyInstance) => {
25
27
 
26
28
  return {
27
29
  handler,
28
- onRequest: [fastify.authenticate],
30
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
29
31
  config: {
30
32
  type: "dataCreate",
31
33
  broadcastChannels: ["userCreated"],
@@ -4,6 +4,8 @@ import { PluginFastifyInstance } from "types"
4
4
  import { Type } from "@sinclair/typebox"
5
5
  import { ForbiddenError } from "@/utils/errors"
6
6
 
7
+ const permissions = ["user.isAdmin"]
8
+
7
9
  const ParamsSchema = Type.Object({
8
10
  _id: Type.String(),
9
11
  })
@@ -19,9 +21,6 @@ export default (fastify: PluginFastifyInstance) => {
19
21
  reply: FastifyReply,
20
22
  ) => {
21
23
  try {
22
- if (!req.user.isAdmin) {
23
- throw new ForbiddenError("Only Admins can use this feature")
24
- }
25
24
  if (req.user._id === req.params._id) {
26
25
  throw new ForbiddenError("A user cannot remove itself")
27
26
  }
@@ -41,7 +40,7 @@ export default (fastify: PluginFastifyInstance) => {
41
40
 
42
41
  return {
43
42
  handler,
44
- onRequest: [fastify.authenticate],
43
+ onRequest: [fastify.authenticate, fastify.checkPermissions(permissions)],
45
44
  config: {
46
45
  type: "dataDelete",
47
46
  broadcastChannels: ["userDeleted"],
@@ -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 userService.updateUser(
24
- fastify,
25
- req.requestParams,
26
- _id,
27
- { isDeleted: false },
28
- req.user._id,
29
- )
23
+ const payload = await userService.updateUser(
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: ["userRestored"],
@@ -0,0 +1,45 @@
1
+ import type { AnyWorkSession } from "../workSession.schema"
2
+ import type { FrontendPayload } from "@c/payload/payloadTypes"
3
+ import { PluginFastifyInstance } from "types"
4
+
5
+ const registerEvents = (fastify: PluginFastifyInstance) => {
6
+ /**
7
+ * WorkSession created
8
+ */
9
+ const created = async (payload: FrontendPayload<AnyWorkSession>) => {
10
+ fastify.eventbus.emit("broadcastDataUpdated", payload)
11
+ fastify.eventbus.emit("broadcastWorkSessionCreated", payload)
12
+ fastify.log.info(
13
+ `[eventbus] workSession broadcast created ${payload.body.item._id}`,
14
+ )
15
+ }
16
+
17
+ /**
18
+ * WorkSession updated
19
+ */
20
+ const updated = async (payload: FrontendPayload<AnyWorkSession>) => {
21
+ fastify.eventbus.emit("broadcastDataUpdated", payload)
22
+ fastify.log.info(
23
+ `[eventbus] workSession broadcast updated ${payload.body.item._id}`,
24
+ )
25
+ }
26
+
27
+ /**
28
+ * WorkSession deleted
29
+ */
30
+ const deleted = async (payload: FrontendPayload<AnyWorkSession>) => {
31
+ fastify.eventbus.emit("broadcastWorkSessionDeleted", payload)
32
+ fastify.log.info(
33
+ `[eventbus] workSession broadcast deleted ${payload.body.item._id}`,
34
+ )
35
+ }
36
+
37
+ /**
38
+ * Register event handlers
39
+ */
40
+ fastify.eventbus.on("coreWorkSessionCreated", created)
41
+ fastify.eventbus.on("coreWorkSessionUpdated", updated)
42
+ fastify.eventbus.on("coreWorkSessionDeleted", deleted)
43
+ }
44
+
45
+ export default registerEvents
@@ -0,0 +1,12 @@
1
+ import type { PluginFastifyInstance } from "@raclettejs/core"
2
+
3
+ export const registerCrud = (fastify: PluginFastifyInstance) => {
4
+ const workSessionService = fastify.custom.workSessionService
5
+
6
+ fastify.registerCrudHandlers("workSession", {
7
+ create: workSessionService.createWorkSession,
8
+ read: workSessionService.readWorkSession,
9
+ update: workSessionService.updateWorkSession,
10
+ delete: workSessionService.removeWorkSession,
11
+ })
12
+ }
@@ -0,0 +1,21 @@
1
+ import type { WorkSession } from "../workSession.schema"
2
+ import type { FrontendPayloadRequestData, PluginFastifyInstance } from "types"
3
+
4
+ export const registerPayload = (fastify: PluginFastifyInstance) => {
5
+ fastify.registerPayloadHandler<WorkSession>("workSession", {
6
+ type: "workSession",
7
+ displayName: (workSession: WorkSession) => workSession._id || "",
8
+ completion: (workSession: WorkSession) => workSession._id || "",
9
+ fields: () => ({
10
+ owner: "NONE",
11
+ }),
12
+ })
13
+ }
14
+
15
+ export const createWorkSessionPayload = async (
16
+ fastify: PluginFastifyInstance,
17
+ items: WorkSession[],
18
+ requestData: FrontendPayloadRequestData,
19
+ ) => {
20
+ return await fastify.createPayload("workSession", items, requestData)
21
+ }
@@ -0,0 +1,55 @@
1
+ import { PluginFastifyInstance } from "types"
2
+ import registerRoutes from "./routes"
3
+ import { createModels } from "./workSession.model"
4
+ import { createWorkSessionService } from "./workSession.service"
5
+ import { registerPayload } from "./helpers/payload"
6
+ import { registerCrud } from "./helpers/crud"
7
+ import { registerSchemas } from "./workSession.schema"
8
+
9
+ const registerWorkSession = async (fastify: PluginFastifyInstance) => {
10
+ /*
11
+ * ---------------------------------------------------------------------
12
+ * CREATE AND REGISTER ALL YOUR MODELS
13
+ * ---------------------------------------------------------------------
14
+ */
15
+ const workSessionModel = createModels(fastify)
16
+
17
+ // create and pass in the model to your service
18
+ const workSessionService = createWorkSessionService(workSessionModel)
19
+
20
+ // decorate the service to the instance, so we can easily call it everywhere
21
+ fastify.custom.workSessionService = workSessionService
22
+
23
+ /*
24
+ * ---------------------------------------------------------------------
25
+ * REGISTER ALL YOUR ROUTES
26
+ * ---------------------------------------------------------------------
27
+ */
28
+ try {
29
+ await fastify.register((instance) => registerRoutes(instance))
30
+ } catch (error) {
31
+ fastify.log.error(`Failed to register routes.`, error)
32
+ throw error // Let the application handle the error
33
+ }
34
+
35
+ registerPayload(fastify)
36
+ registerCrud(fastify)
37
+ registerSchemas(fastify)
38
+
39
+ return {
40
+ workSession: {
41
+ operations: {
42
+ read: workSessionService._readWorkSession.bind(workSessionService),
43
+ readAll: workSessionService._readWorkSessions.bind(workSessionService),
44
+ create: workSessionService._createWorkSession.bind(workSessionService),
45
+ update: workSessionService._updateWorkSession.bind(workSessionService),
46
+ },
47
+ keywords: ["workSession", "session"],
48
+ metadata: {
49
+ description: "A work session for user interactions.",
50
+ },
51
+ },
52
+ }
53
+ }
54
+
55
+ export default registerWorkSession
@@ -0,0 +1,19 @@
1
+ import { PluginFastifyInstance } from "types"
2
+ import get from "./route.workSession.get"
3
+ import getAll from "./route.workSession.getAll"
4
+ import patch from "./route.workSession.patch"
5
+ import post from "./route.workSession.post"
6
+ import hardDelete from "./route.workSession.hardDelete"
7
+ import remove from "./route.workSession.remove"
8
+
9
+ const registerRoutes = async (fastify: PluginFastifyInstance) => {
10
+ await fastify.get("/workSession/all", getAll(fastify))
11
+ await fastify.get("/workSession/:_id", get(fastify))
12
+
13
+ await fastify.post("/workSession", post(fastify))
14
+ await fastify.patch("/workSession/:_id", patch(fastify))
15
+ await fastify.delete("/workSession/:_id", remove(fastify))
16
+ await fastify.delete("/workSession/:_id/hard", hardDelete(fastify))
17
+ }
18
+
19
+ export default registerRoutes
@@ -0,0 +1,53 @@
1
+ import type { Static } from "@sinclair/typebox"
2
+ import type { FastifyReply, FastifyRequest } from "fastify"
3
+ import { PluginFastifyInstance } from "types"
4
+ import { Type } from "@sinclair/typebox"
5
+
6
+ const ParamsSchema = Type.Object({
7
+ _id: Type.String(),
8
+ })
9
+ type Params = Static<typeof ParamsSchema>
10
+
11
+ export default (fastify: PluginFastifyInstance) => {
12
+ const workSessionService = fastify.custom.workSessionService
13
+
14
+ const handler = async (
15
+ req: FastifyRequest<{
16
+ Params: Params
17
+ }>,
18
+ reply: FastifyReply,
19
+ ) => {
20
+ try {
21
+ const { _id } = req.params
22
+
23
+ const payload = await workSessionService.readWorkSession(
24
+ fastify,
25
+ req.requestParams,
26
+ _id,
27
+ )
28
+
29
+ if (!payload) {
30
+ return reply.notFound("WorkSession not found")
31
+ }
32
+
33
+ return payload
34
+ } catch (error: any) {
35
+ fastify.log.error(error.message)
36
+ return reply.internalServerError(error.message)
37
+ }
38
+ }
39
+
40
+ return {
41
+ handler,
42
+ onRequest: [fastify.authenticate],
43
+ config: {
44
+ type: "dataRead",
45
+ },
46
+ schema: {
47
+ summary: "Get a workSession by id",
48
+ tags: ["core/workSession"],
49
+
50
+ params: ParamsSchema,
51
+ },
52
+ }
53
+ }