@ossy/workspaces 1.17.2 → 1.17.3

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 (64) hide show
  1. package/package.json +8 -4
  2. package/src/CreateWorkspacePage.jsx +7 -16
  3. package/src/Definition.js +1 -0
  4. package/src/GeneralSettings.jsx +77 -19
  5. package/src/Invitations.jsx +7 -7
  6. package/src/Invite.jsx +13 -25
  7. package/src/SchemasReadBootstrap.jsx +20 -0
  8. package/src/SelectWorkspacePage.jsx +5 -8
  9. package/src/Users.jsx +7 -7
  10. package/src/Users.page.jsx +3 -3
  11. package/src/accept-invitation.action.js +1 -1
  12. package/src/accept-invitation.api.js +46 -0
  13. package/src/accept-invitation.task.js +6 -5
  14. package/src/create-api-token.action.js +1 -1
  15. package/src/create-api-token.task.js +1 -1
  16. package/src/create.action.js +1 -1
  17. package/src/create.task.js +1 -1
  18. package/src/disable-service.action.js +1 -1
  19. package/src/disable-service.task.js +3 -15
  20. package/src/en.translations.json +36 -30
  21. package/src/enable-service.action.js +1 -1
  22. package/src/enable-service.task.js +3 -15
  23. package/src/entitlements.js +199 -0
  24. package/src/entitlements.spec.js +88 -0
  25. package/src/get-api-tokens.action.js +1 -1
  26. package/src/get-api-tokens.task.js +1 -1
  27. package/src/get-invitations.action.js +1 -1
  28. package/src/get-invitations.task.js +1 -1
  29. package/src/get-schemas.action.js +1 -0
  30. package/src/get-schemas.task.js +14 -0
  31. package/src/get-users.action.js +1 -1
  32. package/src/get-users.task.js +1 -1
  33. package/src/get.action.js +1 -1
  34. package/src/get.task.js +1 -1
  35. package/src/import-schemas.action.js +1 -0
  36. package/src/import-schemas.task.js +26 -0
  37. package/src/index.js +3 -2
  38. package/src/invite-user.action.js +1 -1
  39. package/src/invite-user.task.js +4 -3
  40. package/src/list.action.js +1 -1
  41. package/src/list.task.js +1 -1
  42. package/src/merge-workspace-schemas.js +13 -0
  43. package/src/merge-workspace-schemas.spec.js +16 -0
  44. package/src/remove-member.action.js +1 -1
  45. package/src/remove-member.task.js +1 -1
  46. package/src/schema-ids.js +3 -0
  47. package/src/select-workspace.api.js +50 -0
  48. package/src/selectWorkspace.js +11 -0
  49. package/src/service-keys.js +1 -0
  50. package/src/stories/Users.stories.jsx +35 -0
  51. package/src/stories/decorators.jsx +59 -0
  52. package/src/sv.translations.json +36 -30
  53. package/src/sync-workspace-membership.task.js +7 -6
  54. package/src/workspace-invitation.email.jsx +1 -1
  55. package/src/workspace-users.component.jsx +3 -3
  56. package/src/workspace.aggregate.js +35 -47
  57. package/src/workspace.schema.js +9 -0
  58. package/src/workspaces.events.js +61 -155
  59. package/src/{workspaces.spec.js → workspaces.integration.spec.js} +40 -38
  60. package/src/workspaces.queries.js +27 -12
  61. package/src/get-resource-templates.action.js +0 -1
  62. package/src/get-resource-templates.task.js +0 -18
  63. package/src/import-resource-templates.action.js +0 -1
  64. package/src/import-resource-templates.task.js +0 -26
@@ -1,171 +1,77 @@
1
- /**
2
- * Field
3
- * @typedef {Object} Field
4
- * @property {string} type - field type
5
- * @property {string} name - name of field
6
- */
7
-
8
- /**
9
- * ResourceTemplate
10
- * @typedef {Object} ResourceTemplate
11
- * @property {string} name - Displayname of the resource template
12
- * @property {Field[]} fields - Allowed fields
13
- */
14
-
1
+ import { nanoid } from 'nanoid'
2
+ import { WorkspaceSchema } from './schema-ids.js'
15
3
 
16
4
  /**
17
- * @class
18
- */
5
+ * ADR 0008 workspace entity events.
6
+ */
19
7
  export class WorkspacesEvents {
20
8
 
21
- /**
22
- * Return type of WorkspacesEvents.Created
23
- * @typedef {Object} Created
24
- * @property {string} type - Created
25
- * @property {string} createdBy - userId of user who created the workspace
26
- * @property {CreatedPayload} payload - event payload
27
- */
9
+ static Created ({ resourceId, createdBy, name }) {
10
+ return {
11
+ type: WorkspaceSchema.workspace,
12
+ resourceId: resourceId ?? nanoid(),
13
+ event: 'Created',
14
+ createdBy,
15
+ payload: { name },
16
+ }
17
+ }
28
18
 
29
- /**
30
- * Payload of Workspace.Created event
31
- * @typedef {Object} CreatedPayload
32
- * @property {string} name - Name of workspace
33
- */
19
+ static SchemasImported ({ createdBy, schemas }) {
20
+ return {
21
+ event: 'SchemasImported',
22
+ createdBy,
23
+ payload: { schemas },
24
+ }
25
+ }
34
26
 
35
- /**
36
- * Input for WorkspacesEvents.Created
37
- * @typedef {Object} CreatedInput
38
- * @property {string} name - Name of workspace
39
- * @property {string} createdBy - userId of user who created the workspace
40
- */
27
+ static ApiTokenCreated ({ createdBy, description, token }) {
28
+ return {
29
+ event: 'ApiTokenCreated',
30
+ createdBy,
31
+ payload: { description, token },
32
+ }
33
+ }
41
34
 
42
- /**
43
- * Use this to indicate that a new workspace have been created
44
- *
45
- * @param {CreatedInput} input
46
- * @return {Created} - Workspace created event
47
- *
48
- * @example
49
- * const name = 'ossy.se'
50
- * const createdBy = 'fake-user-id-123'
51
- *
52
- * const event = WorkspacesEvents.Created({ name, createdBy })
53
- *
54
- * Aggregate.Of(Workspace, event)
55
- */
56
- static Created({ createdBy, name }) {
57
- return ({
58
- type: 'Created',
59
- createdBy: createdBy,
35
+ static UserInvited ({ createdBy, email, expiresAt }) {
36
+ return {
37
+ event: 'UserInvited',
38
+ createdBy,
60
39
  payload: {
61
- name: name
62
- }
63
- })
64
- }
65
-
66
- /**
67
- * Return type of WorkspacesEvents.ResourceTemplatesImported
68
- * @typedef {Object} ResourceTemplatesImported
69
- * @property {string} type - ResourceTemplatesImported
70
- * @property {string} createdBy - userId of user who created the workspace
71
- * @property {ResourceTemplate[]} payload - event payload
72
- */
73
-
74
- /**
75
- * Input for WorkspacesEvents.Created
76
- * @typedef {Object} ResourceTemplatesImportedInput
77
- * @property {ResourceTemplate[]} templates - List of resource templates
78
- * @property {string} createdBy - userId of user who created the workspace
79
- */
80
-
81
- /**
82
- * Use this to save imported resource templates
83
- *
84
- * @param {ResourceTemplatesImportedInput} input
85
- * @return {ResourceTemplatesImported} - Resource templates imported event
86
- *
87
- * @example
88
- * const templates = []
89
- * const createdBy = 'fake-user-123'
90
- *
91
- * const event = WorkspacesEvents.Created({ templates, createdBy })
92
- *
93
- * Aggregate.Of(Workspace, userId)
94
- * .then(Aggregate.Add(event))
95
- */
96
- static ResourceTemplatesImported({ createdBy, templates }) {
97
- return ({
98
- type: 'ResourceTemplatesImported',
99
- createdBy: createdBy,
100
- payload: {
101
- templates: templates
102
- }
103
- })
104
- }
105
-
106
- // Not in use atm, use API TOKENS in the user aggregate instead.
107
- // Caller is responsible for generating the token value.
108
- static ApiTokenCreated({ createdBy, description, token }) {
109
- return ({
110
- type: 'ApiTokenCreated',
111
- createdBy: createdBy,
112
- payload: {
113
- description: description,
114
- token: token
115
- }
116
- })
117
- }
118
-
119
-
120
- static UserInvited({ createdBy, email, expiresAt }) {
121
- return ({
122
- type: 'UserInvited',
123
- createdBy: createdBy,
124
- payload: {
125
- email: email,
126
- expiresAt: new Date().getTime() + 1000 * 60 * 60 * 24 * 7, // One week
127
- }
128
- })
129
- }
40
+ email,
41
+ expiresAt: expiresAt ?? Date.now() + 1000 * 60 * 60 * 24 * 7,
42
+ },
43
+ }
44
+ }
130
45
 
131
- static UserInvitationAccepted({ createdBy, email }) {
132
- return ({
133
- type: 'UserInvitationAccepted',
134
- createdBy: createdBy,
135
- payload: {
136
- email: email
137
- }
138
- })
139
- }
140
-
141
- static ServiceEnabled({ createdBy, service }) {
142
- return ({
143
- type: 'ServiceEnabled',
144
- createdBy: createdBy,
145
- payload: {
146
- service: service
147
- }
148
- })
46
+ static UserInvitationAccepted ({ createdBy, email }) {
47
+ return {
48
+ event: 'UserInvitationAccepted',
49
+ createdBy,
50
+ payload: { email },
51
+ }
149
52
  }
150
53
 
151
- static ServiceDisabled({ createdBy, service }) {
152
- return ({
153
- type: 'ServiceDisabled',
154
- createdBy: createdBy,
155
- payload: {
156
- service: service
157
- }
158
- })
54
+ static ServiceEnabled ({ createdBy, service }) {
55
+ return {
56
+ event: 'ServiceEnabled',
57
+ createdBy,
58
+ payload: { service },
59
+ }
159
60
  }
160
61
 
161
- static UserRemoved({ createdBy, userId }) {
162
- return ({
163
- type: 'UserRemoved',
164
- createdBy: createdBy,
165
- payload: {
166
- userId: userId
167
- }
168
- })
62
+ static ServiceDisabled ({ createdBy, service }) {
63
+ return {
64
+ event: 'ServiceDisabled',
65
+ createdBy,
66
+ payload: { service },
67
+ }
169
68
  }
170
69
 
70
+ static UserRemoved ({ createdBy, userId }) {
71
+ return {
72
+ event: 'UserRemoved',
73
+ createdBy,
74
+ payload: { userId },
75
+ }
76
+ }
171
77
  }
@@ -1,6 +1,8 @@
1
1
  import casual from 'casual'
2
2
  import { TestUtil } from '@ossy/platform/test'
3
3
 
4
+ const WORKSPACE_SCHEMA = '@ossy/workspaces/schema/workspace'
5
+
4
6
  function authHeaders(token) {
5
7
  return {
6
8
  'Content-Type': 'application/json',
@@ -16,10 +18,10 @@ function workspaceHeaders(userToken, workspaceId) {
16
18
  }
17
19
  }
18
20
 
19
- describe('[workspaces/create]', () => {
21
+ describe('[workspaces/actions/create]', () => {
20
22
 
21
23
  TestUtil.AssertActionAuthenticationNeeded({
22
- actionId: 'workspaces/create',
24
+ actionId: '@ossy/workspaces/actions/create',
23
25
  })
24
26
 
25
27
  describe('given a workspace name', () => {
@@ -28,7 +30,7 @@ describe('[workspaces/create]', () => {
28
30
  const workspaceName = casual.word
29
31
 
30
32
  const response = await TestUtil.InvokeAction({
31
- actionId: 'workspaces/create',
33
+ actionId: '@ossy/workspaces/actions/create',
32
34
  headers: authHeaders(user.token),
33
35
  payload: { name: workspaceName },
34
36
  })
@@ -36,8 +38,8 @@ describe('[workspaces/create]', () => {
36
38
  const body = await response.json()
37
39
 
38
40
  const workspaceCreatedEvent = await TestUtil.GetEvent({
39
- aggregateType: 'Workspace',
40
- type: 'Created',
41
+ type: WORKSPACE_SCHEMA,
42
+ event: 'Created',
41
43
  createdBy: user.id,
42
44
  'payload.name': workspaceName
43
45
  })
@@ -45,35 +47,35 @@ describe('[workspaces/create]', () => {
45
47
  expect(!!workspaceCreatedEvent).toEqual(true)
46
48
  expect(response.status).toEqual(200)
47
49
  expect(response.headers.get('Content-Type').includes('application/json')).toEqual(true)
48
- expect(body.id).toEqual(workspaceCreatedEvent.aggregateId)
50
+ expect(body.id).toEqual(workspaceCreatedEvent.resourceId)
49
51
  expect(body.name).toEqual(workspaceName)
50
52
  expect(body.createdBy).toEqual(user.id)
51
53
  expect(body.created).toEqual(workspaceCreatedEvent.created)
52
54
  expect(body.apiTokens).toEqual([])
53
- expect(Array.isArray(body.resourceTemplates)).toBe(true)
54
- expect(body.resourceTemplates.length).toEqual(0)
55
+ expect(Array.isArray(body.schemas)).toBe(true)
56
+ expect(body.schemas.length).toEqual(0)
55
57
  })
56
58
  })
57
59
 
58
60
  })
59
61
 
60
- describe('[workspaces/list]', () => {
62
+ describe('[workspaces/actions/list]', () => {
61
63
 
62
64
  TestUtil.AssertActionAuthenticationNeeded({
63
- actionId: 'workspaces/list',
65
+ actionId: '@ossy/workspaces/actions/list',
64
66
  })
65
67
 
66
68
  it('must return a minified list of workspaces the user have created', async () => {
67
69
  const user = await TestUtil.GetAuthenticatedTestUser()
68
70
 
69
71
  const workspace = await TestUtil.InvokeAction({
70
- actionId: 'workspaces/create',
72
+ actionId: '@ossy/workspaces/actions/create',
71
73
  headers: authHeaders(user.token),
72
74
  payload: { name: casual.word },
73
75
  }).then(response => response.json())
74
76
 
75
77
  const response = await TestUtil.InvokeAction({
76
- actionId: 'workspaces/list',
78
+ actionId: '@ossy/workspaces/actions/list',
77
79
  headers: authHeaders(user.token),
78
80
  })
79
81
 
@@ -89,10 +91,10 @@ describe('[workspaces/list]', () => {
89
91
 
90
92
  })
91
93
 
92
- describe('[workspaces/get]', () => {
94
+ describe('[workspaces/actions/get]', () => {
93
95
 
94
96
  TestUtil.AssertWorkspaceActionAuthenticationNeeded({
95
- actionId: 'workspaces/get',
97
+ actionId: '@ossy/workspaces/actions/get',
96
98
  payload: { workspaceId: '123' },
97
99
  })
98
100
 
@@ -100,13 +102,13 @@ describe('[workspaces/get]', () => {
100
102
  const user = await TestUtil.GetAuthenticatedTestUser()
101
103
 
102
104
  const workspace = await TestUtil.InvokeAction({
103
- actionId: 'workspaces/create',
105
+ actionId: '@ossy/workspaces/actions/create',
104
106
  headers: authHeaders(user.token),
105
107
  payload: { name: casual.word },
106
108
  }).then(response => response.json())
107
109
 
108
110
  const response = await TestUtil.InvokeAction({
109
- actionId: 'workspaces/get',
111
+ actionId: '@ossy/workspaces/actions/get',
110
112
  headers: workspaceHeaders(user.token, workspace.id),
111
113
  payload: { workspaceId: workspace.id },
112
114
  })
@@ -120,19 +122,19 @@ describe('[workspaces/get]', () => {
120
122
 
121
123
  })
122
124
 
123
- describe('[workspaces/import-resource-templates]', () => {
125
+ describe('[workspaces/actions/import-schemas]', () => {
124
126
 
125
127
  TestUtil.AssertWorkspaceActionAuthenticationNeeded({
126
- actionId: 'workspaces/import-resource-templates',
127
- payload: { templates: [] },
128
+ actionId: '@ossy/workspaces/actions/import-schemas',
129
+ payload: { schemas: [] },
128
130
  headers: { workspaceId: 'ws-test' },
129
131
  })
130
132
 
131
- it('must return the saved templates and create a ResourceTemplatesImported event', async () => {
133
+ it('must return the saved schemas and create a SchemasImported event', async () => {
132
134
  const user = await TestUtil.GetAuthenticatedTestUser()
133
135
 
134
136
  const workspace = await TestUtil.InvokeAction({
135
- actionId: 'workspaces/create',
137
+ actionId: '@ossy/workspaces/actions/create',
136
138
  headers: authHeaders(user.token),
137
139
  payload: { name: casual.word },
138
140
  }).then(response => response.json())
@@ -146,40 +148,40 @@ describe('[workspaces/import-resource-templates]', () => {
146
148
  ]
147
149
 
148
150
  const response = await TestUtil.InvokeAction({
149
- actionId: 'workspaces/import-resource-templates',
151
+ actionId: '@ossy/workspaces/actions/import-schemas',
150
152
  headers: workspaceHeaders(user.token, workspace.id),
151
- payload: { templates: imported },
153
+ payload: { schemas: imported },
152
154
  })
153
155
 
154
156
  const responseBody = await response.json()
155
157
 
156
- const resourceTemplatesImportedEvent = await TestUtil.GetEvent({
157
- aggregateType: 'Workspace',
158
- type: 'ResourceTemplatesImported',
158
+ const schemasImportedEvent = await TestUtil.GetEvent({
159
+ type: WORKSPACE_SCHEMA,
160
+ event: 'SchemasImported',
159
161
  createdBy: user.id,
160
- 'payload.templates': imported
162
+ 'payload.schemas': imported
161
163
  })
162
164
 
163
165
  expect(response.status).toEqual(200)
164
166
  expect(responseBody).toEqual(imported)
165
- expect(!!resourceTemplatesImportedEvent).toEqual(true)
167
+ expect(!!schemasImportedEvent).toEqual(true)
166
168
 
167
169
  })
168
170
 
169
171
  })
170
172
 
171
- describe('[workspaces/get-resource-templates]', () => {
173
+ describe('[workspaces/actions/get-schemas]', () => {
172
174
 
173
175
  TestUtil.AssertWorkspaceActionAuthenticationNeeded({
174
- actionId: 'workspaces/get-resource-templates',
176
+ actionId: '@ossy/workspaces/actions/get-schemas',
175
177
  headers: { workspaceId: 'ws-test' },
176
178
  })
177
179
 
178
- it('must return the saved templates event', async () => {
180
+ it('must return the saved schemas', async () => {
179
181
  const user = await TestUtil.GetAuthenticatedTestUser()
180
182
 
181
183
  const workspace = await TestUtil.InvokeAction({
182
- actionId: 'workspaces/create',
184
+ actionId: '@ossy/workspaces/actions/create',
183
185
  headers: authHeaders(user.token),
184
186
  payload: { name: casual.word },
185
187
  }).then(response => response.json())
@@ -193,9 +195,9 @@ describe('[workspaces/get-resource-templates]', () => {
193
195
  ]
194
196
 
195
197
  const response = await TestUtil.InvokeAction({
196
- actionId: 'workspaces/import-resource-templates',
198
+ actionId: '@ossy/workspaces/actions/import-schemas',
197
199
  headers: workspaceHeaders(user.token, workspace.id),
198
- payload: { templates: imported },
200
+ payload: { schemas: imported },
199
201
  })
200
202
 
201
203
  const responseBody = await response.json()
@@ -207,10 +209,10 @@ describe('[workspaces/get-resource-templates]', () => {
207
209
 
208
210
  })
209
211
 
210
- describe('[workspaces/create-api-token]', () => {
212
+ describe('[workspaces/actions/create-api-token]', () => {
211
213
 
212
214
  TestUtil.AssertWorkspaceActionAuthenticationNeeded({
213
- actionId: 'workspaces/create-api-token',
215
+ actionId: '@ossy/workspaces/actions/create-api-token',
214
216
  payload: { description: 'Api token for GitHub Actions' },
215
217
  headers: { workspaceId: 'ws-test' },
216
218
  })
@@ -219,13 +221,13 @@ describe('[workspaces/create-api-token]', () => {
219
221
  const user = await TestUtil.GetAuthenticatedTestUser()
220
222
 
221
223
  const workspace = await TestUtil.InvokeAction({
222
- actionId: 'workspaces/create',
224
+ actionId: '@ossy/workspaces/actions/create',
223
225
  headers: authHeaders(user.token),
224
226
  payload: { name: casual.word },
225
227
  }).then(response => response.json())
226
228
 
227
229
  const response = await TestUtil.InvokeAction({
228
- actionId: 'workspaces/create-api-token',
230
+ actionId: '@ossy/workspaces/actions/create-api-token',
229
231
  headers: workspaceHeaders(user.token, workspace.id),
230
232
  payload: { description: 'Api token for GitHub Actions' },
231
233
  })
@@ -1,33 +1,48 @@
1
1
  import { EventStore } from '@ossy/event-store'
2
2
  import { createLogger } from '@ossy/observability'
3
+ import { WorkspaceSchema } from './schema-ids.js'
3
4
 
4
5
  const log = createLogger('workspaces')
5
6
 
6
7
  export class WorkspacesQueries {
7
- static getAllByUserIncluded(userId) {
8
+ static getAllByUserIncluded (userId) {
8
9
  log.info('[WorkspacesQueries] getAllByUserIncluded()')
9
10
  return EventStore.Aggregate([
10
- { $group: { _id: { aggregateId: '$aggregateId', aggregateType: '$aggregateType' }, events: { $push: '$$ROOT' } } },
11
+ { $match: { type: WorkspaceSchema.workspace, resourceId: { $exists: true } } },
12
+ { $group: { _id: '$resourceId', events: { $push: '$$ROOT' } } },
11
13
  {
12
14
  $match: {
13
- '_id.aggregateType': 'Workspace',
14
- 'events.createdBy': userId,
15
- 'events.type': { $nin: ['Deleted'], $in: ['Created', 'UserInvitationAccepted'] },
15
+ $or: [
16
+ { 'events.createdBy': userId },
17
+ { 'events.event': 'UserInvitationAccepted', 'events.createdBy': userId },
18
+ ],
19
+ 'events.event': { $in: ['Created', 'UserInvitationAccepted'] },
16
20
  },
17
21
  },
18
22
  {
19
23
  $project: {
20
- events: '$events',
21
- currentState: {
22
- $reduce: {
23
- input: '$events',
24
- initialValue: {},
25
- in: { id: '$_id.aggregateId', name: { $ifNull: ['$$this.payload.name', '$$value.name'] } },
24
+ id: '$_id',
25
+ name: {
26
+ $let: {
27
+ vars: {
28
+ created: {
29
+ $arrayElemAt: [
30
+ {
31
+ $filter: {
32
+ input: '$events',
33
+ as: 'e',
34
+ cond: { $eq: ['$$e.event', 'Created'] },
35
+ },
36
+ },
37
+ 0,
38
+ ],
39
+ },
40
+ },
41
+ in: '$$created.payload.name',
26
42
  },
27
43
  },
28
44
  },
29
45
  },
30
- { $project: { _id: 0, id: '$currentState.id', name: '$currentState.name' } },
31
46
  ]).catch(() => [])
32
47
  }
33
48
  }
@@ -1 +0,0 @@
1
- export const metadata = { id: 'workspaces/get-resource-templates', access: 'workspace' }
@@ -1,18 +0,0 @@
1
- import { Aggregate } from '@ossy/event-store'
2
- import { Workspace } from '@ossy/workspaces/server'
3
- import { getSystemResourceTemplates } from '@ossy/platform'
4
-
5
- export const metadata = { id: 'workspaces/get-resource-templates' }
6
-
7
- export async function run({ payload, req }) {
8
- const workspaceId = payload?.workspaceId ?? req?.workspaceId
9
-
10
- const workspace = await Aggregate.Of(Workspace, workspaceId).then(Aggregate.View())
11
- const systemTemplates = getSystemResourceTemplates()
12
- const workspaceTemplates = workspace.resourceTemplates || []
13
- const workspaceIds = new Set(workspaceTemplates.map(t => t.id))
14
- return [
15
- ...systemTemplates.filter(t => !workspaceIds.has(t.id)),
16
- ...workspaceTemplates,
17
- ]
18
- }
@@ -1 +0,0 @@
1
- export const metadata = { id: 'workspaces/import-resource-templates', access: 'workspace' }
@@ -1,26 +0,0 @@
1
- import { Aggregate } from '@ossy/event-store'
2
- import { Workspace, WorkspacesEvents } from '@ossy/workspaces/server'
3
- import { validateResourceTemplatesForImport } from '@ossy/platform'
4
-
5
- export const metadata = { id: 'workspaces/import-resource-templates' }
6
-
7
- export async function run({ payload, req }) {
8
- const userId = payload?.userId ?? req?.userId
9
- const workspaceId = payload?.workspaceId ?? req?.workspaceId
10
- const templates = payload?.templates ?? payload
11
-
12
- if (!Array.isArray(templates)) {
13
- throw Object.assign(new Error('templates must be an array'), { status: 400 })
14
- }
15
-
16
- const reservedIds = new Set([])
17
- const validation = validateResourceTemplatesForImport(templates, reservedIds)
18
- if (!validation.ok) {
19
- throw Object.assign(new Error(validation.message), { status: 400, type: validation.code })
20
- }
21
-
22
- const event = WorkspacesEvents.ResourceTemplatesImported({ createdBy: userId, templates })
23
-
24
- await Aggregate.Of(Workspace, workspaceId).then(Aggregate.Add(event))
25
- return event.payload.templates
26
- }