@ossy/workspaces 1.4.1 → 1.5.0
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/package.json +2 -2
- package/src/index.js +2 -0
- package/src/workspace.aggregate.js +116 -0
- package/src/workspaces.events.js +171 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/workspaces",
|
|
3
3
|
"description": "Workspaces feature package — create, select, and manage workspaces, users, and invitations",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"module": "./src/index.js",
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"/src",
|
|
28
28
|
"README.md"
|
|
29
29
|
],
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "5f1feadf3b630aa96ec61f1d48c11e0e1aa4b095"
|
|
31
31
|
}
|
package/src/index.js
CHANGED
|
@@ -7,3 +7,5 @@ export { Users } from './Users.jsx'
|
|
|
7
7
|
export { AuthenticationGuard } from './AuthenticationGuard.jsx'
|
|
8
8
|
export { patchUserWorkspaceId } from './patchUserWorkspaceId.js'
|
|
9
9
|
export { Definition } from './Definition.js'
|
|
10
|
+
export { Workspace } from './workspace.aggregate.js'
|
|
11
|
+
export { WorkspacesEvents } from './workspaces.events.js'
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export class Workspace {
|
|
2
|
+
|
|
3
|
+
static AggregateType = 'Workspace'
|
|
4
|
+
|
|
5
|
+
static View(events, state = {}) {
|
|
6
|
+
return events
|
|
7
|
+
.reduce((workspace, event) => {
|
|
8
|
+
|
|
9
|
+
switch (event.type) {
|
|
10
|
+
|
|
11
|
+
case 'Created':
|
|
12
|
+
return {
|
|
13
|
+
...workspace,
|
|
14
|
+
id: event.aggregateId,
|
|
15
|
+
name: event.payload.name,
|
|
16
|
+
createdBy: event.createdBy,
|
|
17
|
+
created: event.created,
|
|
18
|
+
apiTokens: [],
|
|
19
|
+
users: [event.createdBy],
|
|
20
|
+
invitations: [],
|
|
21
|
+
resourceTemplates: [],
|
|
22
|
+
services: {
|
|
23
|
+
// '@ossy/visual-content-classifiers': true,
|
|
24
|
+
'@ossy/tasks/resize-common-web': true,
|
|
25
|
+
'@ossy/apps': true,
|
|
26
|
+
'@ossy/domains': true,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
case 'ResourceTemplatesImported':
|
|
31
|
+
return {
|
|
32
|
+
...workspace,
|
|
33
|
+
resourceTemplates: [
|
|
34
|
+
...(event.payload.templates || []),
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
case 'UserInvited': {
|
|
39
|
+
const oneWeek = 1000 * 60 * 60 * 24 * 7
|
|
40
|
+
const expired = event.payload.expiresAt < Date.now()
|
|
41
|
+
// show expired workspace invitations for 7 days
|
|
42
|
+
const showInvitation = (event.payload.expiresAt + oneWeek) > Date.now()
|
|
43
|
+
|
|
44
|
+
if (!showInvitation) {
|
|
45
|
+
return workspace
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
...workspace,
|
|
50
|
+
invitations: [
|
|
51
|
+
...(workspace.invitations || []),
|
|
52
|
+
{
|
|
53
|
+
email: event.payload.email,
|
|
54
|
+
invitedAt: event.created,
|
|
55
|
+
expiresAt: event.payload.expiresAt,
|
|
56
|
+
expired: expired
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
case 'UserInvitationAccepted': {
|
|
63
|
+
return {
|
|
64
|
+
...workspace,
|
|
65
|
+
users: [
|
|
66
|
+
...workspace.users,
|
|
67
|
+
event.createdBy
|
|
68
|
+
],
|
|
69
|
+
invitations: workspace.invitations.filter(invitation => invitation.email !== event.payload.email)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
case 'ApiTokenCreated':
|
|
74
|
+
return {
|
|
75
|
+
...workspace,
|
|
76
|
+
apiTokens: [
|
|
77
|
+
...(apiTokens || []),
|
|
78
|
+
{
|
|
79
|
+
id: event.id,
|
|
80
|
+
description: event.payload.description
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
case 'ServiceEnabled':
|
|
86
|
+
return {
|
|
87
|
+
...workspace,
|
|
88
|
+
services: {
|
|
89
|
+
...(workspace.services || {}),
|
|
90
|
+
[event.payload.service]: true
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
case 'ServiceDisabled':
|
|
95
|
+
return {
|
|
96
|
+
...workspace,
|
|
97
|
+
services: {
|
|
98
|
+
...(workspace.services || {}),
|
|
99
|
+
[event.payload.service]: false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
case 'UserRemoved':
|
|
104
|
+
return {
|
|
105
|
+
...workspace,
|
|
106
|
+
users: (workspace.users || []).filter(id => id !== event.payload.userId)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
default:
|
|
110
|
+
return workspace
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
}, state)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
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
|
+
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @class
|
|
18
|
+
*/
|
|
19
|
+
export class WorkspacesEvents {
|
|
20
|
+
|
|
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
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Payload of Workspace.Created event
|
|
31
|
+
* @typedef {Object} CreatedPayload
|
|
32
|
+
* @property {string} name - Name of workspace
|
|
33
|
+
*/
|
|
34
|
+
|
|
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
|
+
*/
|
|
41
|
+
|
|
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,
|
|
60
|
+
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
|
+
}
|
|
130
|
+
|
|
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
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static ServiceDisabled({ createdBy, service }) {
|
|
152
|
+
return ({
|
|
153
|
+
type: 'ServiceDisabled',
|
|
154
|
+
createdBy: createdBy,
|
|
155
|
+
payload: {
|
|
156
|
+
service: service
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static UserRemoved({ createdBy, userId }) {
|
|
162
|
+
return ({
|
|
163
|
+
type: 'UserRemoved',
|
|
164
|
+
createdBy: createdBy,
|
|
165
|
+
payload: {
|
|
166
|
+
userId: userId
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
}
|