@ossy/resources 1.12.0 → 1.12.2
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 +10 -4
- package/src/AudioResource.jsx +4 -2
- package/src/CreateDirectory.jsx +4 -3
- package/src/CreateDocument.jsx +4 -3
- package/src/DocumentEdit.jsx +9 -6
- package/src/DocumentView.jsx +8 -4
- package/src/GenericResourceCard.jsx +4 -2
- package/src/GenericResourceDetail.jsx +9 -4
- package/src/GenericResourceForm.jsx +5 -2
- package/src/ImageResource.jsx +4 -2
- package/src/PDFResource.jsx +4 -2
- package/src/ResourceContentPage.jsx +4 -2
- package/src/ResourceDescription.jsx +4 -3
- package/src/ResourceDetails.jsx +9 -4
- package/src/ResourceDialogMove.jsx +4 -3
- package/src/ResourceFactory.jsx +6 -3
- package/src/ResourceGenericView.jsx +4 -2
- package/src/ResourceList.jsx +4 -2
- package/src/ResourcePanel.jsx +9 -12
- package/src/ResourceTags.jsx +4 -3
- package/src/ResourcesPage.jsx +4 -2
- package/src/UploadResources.jsx +4 -3
- package/src/VideoResource.jsx +4 -2
- package/src/create-page-view.action.js +1 -38
- package/src/create-page-view.task.js +38 -0
- package/src/create.action.js +1 -98
- package/src/create.task.js +100 -0
- package/src/delete.action.js +1 -31
- package/src/delete.task.js +31 -0
- package/src/en.translations.json +5 -5
- package/src/get-page-view-stats.action.js +1 -65
- package/src/get-page-view-stats.task.js +64 -0
- package/src/get.action.js +1 -14
- package/src/get.task.js +14 -0
- package/src/index.js +13 -4
- package/src/list.action.js +1 -19
- package/src/list.task.js +20 -0
- package/src/resource-create.page.jsx +4 -3
- package/src/resource.helpers.js +83 -0
- package/src/resources.action-media.js +18 -0
- package/src/resources.attach-media-urls.js +1 -1
- package/src/resources.events.js +1 -0
- package/src/resources.spec.js +54 -55
- package/src/search.action.js +1 -19
- package/src/search.task.js +20 -0
- package/src/server.js +4 -0
- package/src/sv.translations.json +5 -5
- package/src/update-access.action.js +1 -20
- package/src/update-access.task.js +22 -0
- package/src/update-content.action.js +1 -39
- package/src/update-content.task.js +41 -0
- package/src/update-location.action.js +1 -18
- package/src/update-location.task.js +20 -0
- package/src/update-name.action.js +1 -18
- package/src/update-name.task.js +20 -0
- package/src/upload-named-version.action.js +1 -42
- package/src/upload-named-version.task.js +46 -0
- package/src/item-access.api.js +0 -34
- package/src/item-content.api.js +0 -35
- package/src/item-location.api.js +0 -34
- package/src/item-name.api.js +0 -34
- package/src/item-version.api.js +0 -48
- package/src/item.api.js +0 -58
- package/src/list.api.js +0 -43
- package/src/page-views-stats.api.js +0 -23
- package/src/page-views.api.js +0 -23
- package/src/search.api.js +0 -27
package/src/resources.spec.js
CHANGED
|
@@ -9,72 +9,70 @@ function workspaceHeaders(userToken, workspaceId) {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
describe('[/
|
|
12
|
+
describe('[resources/create]', () => {
|
|
13
13
|
|
|
14
|
-
TestUtil.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
headers: {
|
|
14
|
+
TestUtil.AssertWorkspaceActionAuthenticationNeeded({
|
|
15
|
+
actionId: 'resources/create',
|
|
16
|
+
payload: { type: 'directory', location: '/', name: 'test' },
|
|
17
|
+
headers: { workspaceId: 'ws-test' },
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
-
describe('[/
|
|
23
|
-
TestUtil.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
headers: { 'Content-Type': 'application/json', 'workspaceId': 'ws-test' },
|
|
22
|
+
describe('[resources/list]', () => {
|
|
23
|
+
TestUtil.AssertWorkspaceActionAuthenticationNeeded({
|
|
24
|
+
actionId: 'resources/list',
|
|
25
|
+
headers: { workspaceId: 'ws-test' },
|
|
27
26
|
})
|
|
28
27
|
})
|
|
29
28
|
|
|
30
|
-
describe('[/
|
|
31
|
-
TestUtil.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
headers: {
|
|
29
|
+
describe('[resources/get]', () => {
|
|
30
|
+
TestUtil.AssertWorkspaceActionAuthenticationNeeded({
|
|
31
|
+
actionId: 'resources/get',
|
|
32
|
+
payload: { resourceId: 'r1' },
|
|
33
|
+
headers: { workspaceId: 'ws-test' },
|
|
35
34
|
})
|
|
36
35
|
})
|
|
37
36
|
|
|
38
|
-
describe('[
|
|
39
|
-
TestUtil.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
headers: {
|
|
37
|
+
describe('[resources/update-name]', () => {
|
|
38
|
+
TestUtil.AssertWorkspaceActionAuthenticationNeeded({
|
|
39
|
+
actionId: 'resources/update-name',
|
|
40
|
+
payload: { resourceId: 'r1', name: 'x' },
|
|
41
|
+
headers: { workspaceId: 'ws-test' },
|
|
43
42
|
})
|
|
44
43
|
})
|
|
45
44
|
|
|
46
|
-
describe('[
|
|
47
|
-
TestUtil.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
headers: {
|
|
45
|
+
describe('[resources/update-location]', () => {
|
|
46
|
+
TestUtil.AssertWorkspaceActionAuthenticationNeeded({
|
|
47
|
+
actionId: 'resources/update-location',
|
|
48
|
+
payload: { resourceId: 'r1', target: '/other/' },
|
|
49
|
+
headers: { workspaceId: 'ws-test' },
|
|
51
50
|
})
|
|
52
51
|
})
|
|
53
52
|
|
|
54
|
-
describe('[
|
|
55
|
-
TestUtil.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
headers: {
|
|
53
|
+
describe('[resources/update-content]', () => {
|
|
54
|
+
TestUtil.AssertWorkspaceActionAuthenticationNeeded({
|
|
55
|
+
actionId: 'resources/update-content',
|
|
56
|
+
payload: { resourceId: 'r1', content: {} },
|
|
57
|
+
headers: { workspaceId: 'ws-test' },
|
|
59
58
|
})
|
|
60
59
|
})
|
|
61
60
|
|
|
62
|
-
describe('[/
|
|
63
|
-
TestUtil.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
headers: {
|
|
61
|
+
describe('[resources/delete]', () => {
|
|
62
|
+
TestUtil.AssertWorkspaceActionAuthenticationNeeded({
|
|
63
|
+
actionId: 'resources/delete',
|
|
64
|
+
payload: { resourceId: 'r1' },
|
|
65
|
+
headers: { workspaceId: 'ws-test' },
|
|
67
66
|
})
|
|
68
67
|
})
|
|
69
68
|
|
|
70
69
|
describe('E2E: template-backed resource (workspaceId header)', () => {
|
|
71
70
|
it('create → update content → delete', async () => {
|
|
72
71
|
const user = await TestUtil.GetAuthenticatedTestUser()
|
|
73
|
-
const workspace = await TestUtil.
|
|
74
|
-
|
|
75
|
-
method: 'POST',
|
|
72
|
+
const workspace = await TestUtil.InvokeAction({
|
|
73
|
+
actionId: 'workspaces/create',
|
|
76
74
|
headers: { 'Content-Type': 'application/json', Authorization: user.token },
|
|
77
|
-
|
|
75
|
+
payload: { name: casual.word },
|
|
78
76
|
}).then(r => r.json())
|
|
79
77
|
|
|
80
78
|
const templateType = '@ossy/web/page'
|
|
@@ -89,11 +87,10 @@ describe('E2E: template-backed resource (workspaceId header)', () => {
|
|
|
89
87
|
},
|
|
90
88
|
}
|
|
91
89
|
|
|
92
|
-
const createRes = await TestUtil.
|
|
93
|
-
|
|
94
|
-
method: 'POST',
|
|
90
|
+
const createRes = await TestUtil.InvokeAction({
|
|
91
|
+
actionId: 'resources/create',
|
|
95
92
|
headers: workspaceHeaders(user.token, workspace.id),
|
|
96
|
-
|
|
93
|
+
payload: createBody,
|
|
97
94
|
})
|
|
98
95
|
|
|
99
96
|
expect(createRes.status).toEqual(200)
|
|
@@ -105,17 +102,17 @@ describe('E2E: template-backed resource (workspaceId header)', () => {
|
|
|
105
102
|
body: '<p>initial</p>',
|
|
106
103
|
})
|
|
107
104
|
|
|
108
|
-
const updateRes = await TestUtil.
|
|
109
|
-
|
|
110
|
-
method: 'PUT',
|
|
105
|
+
const updateRes = await TestUtil.InvokeAction({
|
|
106
|
+
actionId: 'resources/update-content',
|
|
111
107
|
headers: workspaceHeaders(user.token, workspace.id),
|
|
112
|
-
|
|
108
|
+
payload: {
|
|
109
|
+
resourceId: created.id,
|
|
113
110
|
content: {
|
|
114
111
|
title: 'Updated',
|
|
115
112
|
description: 'D2',
|
|
116
113
|
body: '<p>revised</p>',
|
|
117
114
|
},
|
|
118
|
-
}
|
|
115
|
+
},
|
|
119
116
|
})
|
|
120
117
|
|
|
121
118
|
expect(updateRes.status).toEqual(200)
|
|
@@ -126,18 +123,20 @@ describe('E2E: template-backed resource (workspaceId header)', () => {
|
|
|
126
123
|
body: '<p>revised</p>',
|
|
127
124
|
})
|
|
128
125
|
|
|
129
|
-
const deleteRes = await TestUtil.
|
|
130
|
-
|
|
131
|
-
method: 'DELETE',
|
|
126
|
+
const deleteRes = await TestUtil.InvokeAction({
|
|
127
|
+
actionId: 'resources/delete',
|
|
132
128
|
headers: workspaceHeaders(user.token, workspace.id),
|
|
129
|
+
payload: { resourceId: created.id },
|
|
133
130
|
})
|
|
134
131
|
|
|
135
|
-
expect(deleteRes.status).toEqual(
|
|
132
|
+
expect(deleteRes.status).toEqual(200)
|
|
133
|
+
const deleteBody = await deleteRes.json()
|
|
134
|
+
expect(deleteBody).toEqual({ ok: true })
|
|
136
135
|
|
|
137
|
-
const listRes = await TestUtil.
|
|
138
|
-
|
|
139
|
-
method: 'GET',
|
|
136
|
+
const listRes = await TestUtil.InvokeAction({
|
|
137
|
+
actionId: 'resources/list',
|
|
140
138
|
headers: workspaceHeaders(user.token, workspace.id),
|
|
139
|
+
payload: { query: { location: '/' } },
|
|
141
140
|
})
|
|
142
141
|
|
|
143
142
|
expect(listRes.status).toEqual(200)
|
package/src/search.action.js
CHANGED
|
@@ -1,19 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const id = 'resources/search'
|
|
4
|
-
export const access = 'workspace'
|
|
5
|
-
|
|
6
|
-
export async function run({ payload, req }) {
|
|
7
|
-
const query = { ...(payload ?? {}) }
|
|
8
|
-
const workspaceId = payload?.workspaceId ?? req?.workspaceId
|
|
9
|
-
const user = payload?.user ?? req?.user
|
|
10
|
-
let location = query.location
|
|
11
|
-
|
|
12
|
-
if (location && !location.endsWith('/')) location += '/'
|
|
13
|
-
if (location && !location.startsWith('/')) location = '/' + location
|
|
14
|
-
if (location) query.location = location
|
|
15
|
-
|
|
16
|
-
if (workspaceId) query.belongsTo = workspaceId
|
|
17
|
-
|
|
18
|
-
return ResourcesQueries.GetResources(query, user)
|
|
19
|
-
}
|
|
1
|
+
export const metadata = { id: 'resources/search', access: 'workspace' }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ResourcesQueries } from './resources.queries.js'
|
|
2
|
+
import { mediaContextFromRun, withResourceMedia } from './resources.action-media.js'
|
|
3
|
+
|
|
4
|
+
export const metadata = { id: 'resources/search' }
|
|
5
|
+
|
|
6
|
+
export async function run({ payload, req }) {
|
|
7
|
+
const query = { ...(payload ?? {}) }
|
|
8
|
+
const workspaceId = payload?.workspaceId ?? req?.workspaceId
|
|
9
|
+
const user = payload?.user ?? req?.user
|
|
10
|
+
let location = query.location
|
|
11
|
+
|
|
12
|
+
if (location && !location.endsWith('/')) location += '/'
|
|
13
|
+
if (location && !location.startsWith('/')) location = '/' + location
|
|
14
|
+
if (location) query.location = location
|
|
15
|
+
|
|
16
|
+
if (workspaceId) query.belongsTo = workspaceId
|
|
17
|
+
|
|
18
|
+
const resources = await ResourcesQueries.GetResources(query, user)
|
|
19
|
+
return withResourceMedia(resources, mediaContextFromRun({ payload, req }))
|
|
20
|
+
}
|
package/src/server.js
ADDED
package/src/sv.translations.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"resources
|
|
2
|
+
"resources/home.documentTitle": "Gratis resurser",
|
|
3
3
|
"resources.home.title": "Gratis resurser",
|
|
4
4
|
"resources.home.description": "Vi tror på att leverera värde i varje steg av din resa med oss. Därför har vi samlat gratis resurser. Oavsett om du vill förbättra dina kreativa projekt eller bara söker inspiration kan du utforska galleriet nedan. Vi hoppas att du hittar något användbart — hör av dig om du har frågor!",
|
|
5
5
|
"resources.form.nameRequired": "Namn krävs",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"resources/create-page-view.description": "Registrera en sidvisningshändelse för analys",
|
|
32
32
|
"resources/get-page-view-stats.label": "Hämta sidvisningsstatistik",
|
|
33
33
|
"resources/get-page-view-stats.description": "Hämta aggregerad statistik för sidvisningar",
|
|
34
|
-
"resources
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
34
|
+
"resources/create/generic.documentTitle": "Skapa resurs",
|
|
35
|
+
"create-directory.documentTitle": "Skapa mapp",
|
|
36
|
+
"create-document.documentTitle": "Skapa dokument",
|
|
37
|
+
"upload-media.documentTitle": "Ladda upp",
|
|
38
38
|
"@resource.documentTitle": "Resurs",
|
|
39
39
|
"resources.upload.title": "Ladda upp",
|
|
40
40
|
"resources.upload.location": "Plats: {location}",
|
|
@@ -1,20 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Resource, ResourcesEvents } from '@ossy/resources'
|
|
3
|
-
|
|
4
|
-
export const id = 'resources/update-access'
|
|
5
|
-
export const access = 'workspace'
|
|
6
|
-
|
|
7
|
-
export async function run({ payload, req }) {
|
|
8
|
-
const createdBy = payload?.userId ?? req?.userId
|
|
9
|
-
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
10
|
-
const resourceAccess = payload?.access
|
|
11
|
-
|
|
12
|
-
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
13
|
-
if (!['public', 'restricted'].includes(resourceAccess)) {
|
|
14
|
-
throw Object.assign(new Error(`Invalid access value: ${resourceAccess}`), { status: 400 })
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return Aggregate.Of(Resource, resourceId)
|
|
18
|
-
.then(Aggregate.Add(ResourcesEvents.AccessUpdated({ createdBy, access: resourceAccess })))
|
|
19
|
-
.then(Aggregate.View())
|
|
20
|
-
}
|
|
1
|
+
export const metadata = { id: 'resources/update-access', access: 'workspace' }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Aggregate } from '@ossy/event-store'
|
|
2
|
+
import { Resource } from './resource.aggregate.js'
|
|
3
|
+
import { ResourcesEvents } from './resources.events.js'
|
|
4
|
+
import { mediaContextFromRun, withResourceMedia } from './resources.action-media.js'
|
|
5
|
+
|
|
6
|
+
export const metadata = { id: 'resources/update-access' }
|
|
7
|
+
|
|
8
|
+
export async function run({ payload, req }) {
|
|
9
|
+
const createdBy = payload?.userId ?? req?.userId
|
|
10
|
+
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
11
|
+
const resourceAccess = payload?.access
|
|
12
|
+
|
|
13
|
+
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
14
|
+
if (!['public', 'restricted'].includes(resourceAccess)) {
|
|
15
|
+
throw Object.assign(new Error(`Invalid access value: ${resourceAccess}`), { status: 400 })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const resource = await Aggregate.Of(Resource, resourceId)
|
|
19
|
+
.then(Aggregate.Add(ResourcesEvents.AccessUpdated({ createdBy, access: resourceAccess })))
|
|
20
|
+
.then(Aggregate.View())
|
|
21
|
+
return withResourceMedia(resource, mediaContextFromRun({ payload, req }))
|
|
22
|
+
}
|
|
@@ -1,39 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Resource, ResourcesEvents } from '@ossy/resources'
|
|
3
|
-
import { Workspace } from '@ossy/workspaces'
|
|
4
|
-
import { getSystemResourceTemplates, normalizeAndValidateDocumentContent } from '@ossy/platform'
|
|
5
|
-
|
|
6
|
-
export const id = 'resources/update-content'
|
|
7
|
-
export const access = 'workspace'
|
|
8
|
-
|
|
9
|
-
export async function run({ payload, req }) {
|
|
10
|
-
const createdBy = payload?.userId ?? req?.userId
|
|
11
|
-
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
12
|
-
const content = payload?.content
|
|
13
|
-
const workspaceId = payload?.workspaceId ?? req?.workspaceId
|
|
14
|
-
|
|
15
|
-
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
16
|
-
|
|
17
|
-
const workspace = await Aggregate.Of(Workspace, workspaceId).then(Aggregate.View())
|
|
18
|
-
|
|
19
|
-
return Aggregate.Of(Resource, resourceId)
|
|
20
|
-
.then(aggregate => {
|
|
21
|
-
const resource = Aggregate.View()(aggregate)
|
|
22
|
-
const systemTemplates = getSystemResourceTemplates()
|
|
23
|
-
const allTemplates = [
|
|
24
|
-
...systemTemplates,
|
|
25
|
-
...(workspace.resourceTemplates || []).filter(t => !systemTemplates.find(s => s.id === t.id)),
|
|
26
|
-
]
|
|
27
|
-
const template = allTemplates.find(t => t.id === resource.type)
|
|
28
|
-
let finalContent = content
|
|
29
|
-
if (template) {
|
|
30
|
-
const normalized = normalizeAndValidateDocumentContent(content, template)
|
|
31
|
-
if (!normalized.ok) {
|
|
32
|
-
throw Object.assign(new Error(normalized.message), { status: 400, type: normalized.code })
|
|
33
|
-
}
|
|
34
|
-
finalContent = normalized.content
|
|
35
|
-
}
|
|
36
|
-
return Aggregate.Add(ResourcesEvents.ContentUpdated({ createdBy, content: finalContent }))(aggregate)
|
|
37
|
-
})
|
|
38
|
-
.then(Aggregate.View())
|
|
39
|
-
}
|
|
1
|
+
export const metadata = { id: 'resources/update-content', access: 'workspace' }
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Aggregate } from '@ossy/event-store'
|
|
2
|
+
import { Resource } from './resource.aggregate.js'
|
|
3
|
+
import { ResourcesEvents } from './resources.events.js'
|
|
4
|
+
import { Workspace } from '@ossy/workspaces/server'
|
|
5
|
+
import { getSystemResourceTemplates, normalizeAndValidateDocumentContent } from '@ossy/platform'
|
|
6
|
+
import { mediaContextFromRun, withResourceMedia } from './resources.action-media.js'
|
|
7
|
+
|
|
8
|
+
export const metadata = { id: 'resources/update-content' }
|
|
9
|
+
|
|
10
|
+
export async function run({ payload, req }) {
|
|
11
|
+
const createdBy = payload?.userId ?? req?.userId
|
|
12
|
+
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
13
|
+
const content = payload?.content
|
|
14
|
+
const workspaceId = payload?.workspaceId ?? req?.workspaceId
|
|
15
|
+
|
|
16
|
+
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
17
|
+
|
|
18
|
+
const workspace = await Aggregate.Of(Workspace, workspaceId).then(Aggregate.View())
|
|
19
|
+
|
|
20
|
+
return Aggregate.Of(Resource, resourceId)
|
|
21
|
+
.then(aggregate => {
|
|
22
|
+
const resource = Aggregate.View()(aggregate)
|
|
23
|
+
const systemTemplates = getSystemResourceTemplates()
|
|
24
|
+
const allTemplates = [
|
|
25
|
+
...systemTemplates,
|
|
26
|
+
...(workspace.resourceTemplates || []).filter(t => !systemTemplates.find(s => s.id === t.id)),
|
|
27
|
+
]
|
|
28
|
+
const template = allTemplates.find(t => t.id === resource.type)
|
|
29
|
+
let finalContent = content
|
|
30
|
+
if (template) {
|
|
31
|
+
const normalized = normalizeAndValidateDocumentContent(content, template)
|
|
32
|
+
if (!normalized.ok) {
|
|
33
|
+
throw Object.assign(new Error(normalized.message), { status: 400, type: normalized.code })
|
|
34
|
+
}
|
|
35
|
+
finalContent = normalized.content
|
|
36
|
+
}
|
|
37
|
+
return Aggregate.Add(ResourcesEvents.ContentUpdated({ createdBy, content: finalContent }))(aggregate)
|
|
38
|
+
})
|
|
39
|
+
.then(Aggregate.View())
|
|
40
|
+
.then(resource => withResourceMedia(resource, mediaContextFromRun({ payload, req })))
|
|
41
|
+
}
|
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Resource, ResourcesEvents } from '@ossy/resources'
|
|
3
|
-
|
|
4
|
-
export const id = 'resources/update-location'
|
|
5
|
-
export const access = 'workspace'
|
|
6
|
-
|
|
7
|
-
export async function run({ payload, req }) {
|
|
8
|
-
const createdBy = payload?.userId ?? req?.userId
|
|
9
|
-
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
10
|
-
const location = payload?.target ?? payload?.location
|
|
11
|
-
|
|
12
|
-
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
13
|
-
if (!location) throw Object.assign(new Error('target location is required'), { status: 400 })
|
|
14
|
-
|
|
15
|
-
return Aggregate.Of(Resource, resourceId)
|
|
16
|
-
.then(Aggregate.Add(ResourcesEvents.LocationUpdated({ createdBy, location })))
|
|
17
|
-
.then(Aggregate.View())
|
|
18
|
-
}
|
|
1
|
+
export const metadata = { id: 'resources/update-location', access: 'workspace' }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Aggregate } from '@ossy/event-store'
|
|
2
|
+
import { Resource } from './resource.aggregate.js'
|
|
3
|
+
import { ResourcesEvents } from './resources.events.js'
|
|
4
|
+
import { mediaContextFromRun, withResourceMedia } from './resources.action-media.js'
|
|
5
|
+
|
|
6
|
+
export const metadata = { id: 'resources/update-location' }
|
|
7
|
+
|
|
8
|
+
export async function run({ payload, req }) {
|
|
9
|
+
const createdBy = payload?.userId ?? req?.userId
|
|
10
|
+
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
11
|
+
const location = payload?.target ?? payload?.location
|
|
12
|
+
|
|
13
|
+
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
14
|
+
if (!location) throw Object.assign(new Error('target location is required'), { status: 400 })
|
|
15
|
+
|
|
16
|
+
const resource = await Aggregate.Of(Resource, resourceId)
|
|
17
|
+
.then(Aggregate.Add(ResourcesEvents.LocationUpdated({ createdBy, location })))
|
|
18
|
+
.then(Aggregate.View())
|
|
19
|
+
return withResourceMedia(resource, mediaContextFromRun({ payload, req }))
|
|
20
|
+
}
|
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Resource, ResourcesEvents } from '@ossy/resources'
|
|
3
|
-
|
|
4
|
-
export const id = 'resources/update-name'
|
|
5
|
-
export const access = 'workspace'
|
|
6
|
-
|
|
7
|
-
export async function run({ payload, req }) {
|
|
8
|
-
const createdBy = payload?.userId ?? req?.userId
|
|
9
|
-
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
10
|
-
const name = payload?.name
|
|
11
|
-
|
|
12
|
-
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
13
|
-
if (!name) throw Object.assign(new Error('name is required'), { status: 400 })
|
|
14
|
-
|
|
15
|
-
return Aggregate.Of(Resource, resourceId)
|
|
16
|
-
.then(Aggregate.Add(ResourcesEvents.NameUpdated({ createdBy, name })))
|
|
17
|
-
.then(Aggregate.View())
|
|
18
|
-
}
|
|
1
|
+
export const metadata = { id: 'resources/update-name', access: 'workspace' }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Aggregate } from '@ossy/event-store'
|
|
2
|
+
import { Resource } from './resource.aggregate.js'
|
|
3
|
+
import { ResourcesEvents } from './resources.events.js'
|
|
4
|
+
import { mediaContextFromRun, withResourceMedia } from './resources.action-media.js'
|
|
5
|
+
|
|
6
|
+
export const metadata = { id: 'resources/update-name' }
|
|
7
|
+
|
|
8
|
+
export async function run({ payload, req }) {
|
|
9
|
+
const createdBy = payload?.userId ?? req?.userId
|
|
10
|
+
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
11
|
+
const name = payload?.name
|
|
12
|
+
|
|
13
|
+
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
14
|
+
if (!name) throw Object.assign(new Error('name is required'), { status: 400 })
|
|
15
|
+
|
|
16
|
+
const resource = await Aggregate.Of(Resource, resourceId)
|
|
17
|
+
.then(Aggregate.Add(ResourcesEvents.NameUpdated({ createdBy, name })))
|
|
18
|
+
.then(Aggregate.View())
|
|
19
|
+
return withResourceMedia(resource, mediaContextFromRun({ payload, req }))
|
|
20
|
+
}
|
|
@@ -1,42 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Resource, ResourcesEvents } from '@ossy/resources'
|
|
3
|
-
import { Workspace } from '@ossy/workspaces'
|
|
4
|
-
|
|
5
|
-
export const id = 'resources/upload-named-version'
|
|
6
|
-
export const access = 'workspace'
|
|
7
|
-
|
|
8
|
-
export async function run({ payload, integrations, req }) {
|
|
9
|
-
const createdBy = payload?.userId ?? req?.userId
|
|
10
|
-
const workspaceId = payload?.workspaceId ?? req?.workspaceId
|
|
11
|
-
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
12
|
-
const namedVersion = payload?.namedVersion ?? req?.params?.namedVersion
|
|
13
|
-
const type = payload?.type
|
|
14
|
-
const size = payload?.size
|
|
15
|
-
|
|
16
|
-
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
17
|
-
if (!namedVersion) throw Object.assign(new Error('namedVersion is required'), { status: 400 })
|
|
18
|
-
|
|
19
|
-
const workspace = await Aggregate.Of(Workspace, workspaceId).then(Aggregate.View())
|
|
20
|
-
|
|
21
|
-
const event = ResourcesEvents.NamedVersionUploaded({
|
|
22
|
-
createdBy,
|
|
23
|
-
namedVersion,
|
|
24
|
-
Key: `media/${workspace.id}/${resourceId}/${namedVersion}.${type.replace('image/', '')}`,
|
|
25
|
-
ContentLength: size,
|
|
26
|
-
ContentType: type,
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
const storageClient = integrations?.get?.('storage')
|
|
30
|
-
const uploadHeaders = {
|
|
31
|
-
ContentLength: event.payload.ContentLength,
|
|
32
|
-
ContentType: event.payload.ContentType,
|
|
33
|
-
Key: event.payload.Key,
|
|
34
|
-
}
|
|
35
|
-
const uploadUrl = storageClient ? await storageClient.createUploadUrl(uploadHeaders) : null
|
|
36
|
-
const resource = await Aggregate.Of(Resource, resourceId)
|
|
37
|
-
.then(Aggregate.Add(event))
|
|
38
|
-
.then(Aggregate.View())
|
|
39
|
-
return uploadUrl
|
|
40
|
-
? { ...resource, content: { ...resource.content, uploadUrl } }
|
|
41
|
-
: resource
|
|
42
|
-
}
|
|
1
|
+
export const metadata = { id: 'resources/upload-named-version', access: 'workspace' }
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Aggregate } from '@ossy/event-store'
|
|
2
|
+
import { Resource } from './resource.aggregate.js'
|
|
3
|
+
import { ResourcesEvents } from './resources.events.js'
|
|
4
|
+
import { Workspace } from '@ossy/workspaces/server'
|
|
5
|
+
import { mediaContextFromRun, withResourceMedia } from './resources.action-media.js'
|
|
6
|
+
|
|
7
|
+
export const metadata = { id: 'resources/upload-named-version' }
|
|
8
|
+
|
|
9
|
+
// TODO: remove named version concept
|
|
10
|
+
|
|
11
|
+
export async function run({ payload, integrations, req }) {
|
|
12
|
+
const createdBy = payload?.userId ?? req?.userId
|
|
13
|
+
const workspaceId = payload?.workspaceId ?? req?.workspaceId
|
|
14
|
+
const resourceId = payload?.resourceId ?? req?.params?.resourceId
|
|
15
|
+
const namedVersion = payload?.namedVersion ?? req?.params?.namedVersion
|
|
16
|
+
const type = payload?.type
|
|
17
|
+
const size = payload?.size
|
|
18
|
+
|
|
19
|
+
if (!resourceId) throw Object.assign(new Error('resourceId is required'), { status: 400 })
|
|
20
|
+
if (!namedVersion) throw Object.assign(new Error('namedVersion is required'), { status: 400 })
|
|
21
|
+
|
|
22
|
+
const workspace = await Aggregate.Of(Workspace, workspaceId).then(Aggregate.View())
|
|
23
|
+
|
|
24
|
+
const event = ResourcesEvents.NamedVersionUploaded({
|
|
25
|
+
createdBy,
|
|
26
|
+
namedVersion,
|
|
27
|
+
Key: `media/${workspace.id}/${resourceId}/${namedVersion}.${type.replace('image/', '')}`,
|
|
28
|
+
ContentLength: size,
|
|
29
|
+
ContentType: type,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const storageClient = integrations?.get?.('storage')
|
|
33
|
+
const uploadHeaders = {
|
|
34
|
+
ContentLength: event.payload.ContentLength,
|
|
35
|
+
ContentType: event.payload.ContentType,
|
|
36
|
+
Key: event.payload.Key,
|
|
37
|
+
}
|
|
38
|
+
const uploadUrl = storageClient ? await storageClient.createUploadUrl(uploadHeaders) : null
|
|
39
|
+
const resource = await Aggregate.Of(Resource, resourceId)
|
|
40
|
+
.then(Aggregate.Add(event))
|
|
41
|
+
.then(Aggregate.View())
|
|
42
|
+
const withUpload = uploadUrl
|
|
43
|
+
? { ...resource, content: { ...resource.content, uploadUrl } }
|
|
44
|
+
: resource
|
|
45
|
+
return withResourceMedia(withUpload, mediaContextFromRun({ payload, req }))
|
|
46
|
+
}
|
package/src/item-access.api.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { ActionService } from '@ossy/platform'
|
|
2
|
-
import { attachResourceMediaUrls } from './resources.attach-media-urls.js'
|
|
3
|
-
|
|
4
|
-
const pathRe = /^\/api\/v0\/resources\/([^/]+)\/access$/
|
|
5
|
-
|
|
6
|
-
export const metadata = {
|
|
7
|
-
id: 'resources.item.access',
|
|
8
|
-
path: '/api/v0/resources/:resourceId/access',
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default async function handle(req, res) {
|
|
12
|
-
if (req.method !== 'PUT') {
|
|
13
|
-
res.setHeader('Allow', 'PUT')
|
|
14
|
-
res.status(405).json({ error: 'Method Not Allowed' })
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
const pathname = (req.path || new URL(req.originalUrl, 'http://localhost').pathname).replace(/\/+$/, '')
|
|
18
|
-
const m = pathname.match(pathRe)
|
|
19
|
-
if (!m) {
|
|
20
|
-
res.status(404).json('')
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
const resourceId = decodeURIComponent(m[1])
|
|
24
|
-
try {
|
|
25
|
-
const resource = await ActionService.invoke('resources/update-access', {
|
|
26
|
-
payload: { resourceId, access: req.body?.access, userId: req.userId },
|
|
27
|
-
req,
|
|
28
|
-
})
|
|
29
|
-
const withUrls = await attachResourceMediaUrls(resource, { userId: req.userId, workspaceId: req.workspaceId })
|
|
30
|
-
res.json(withUrls)
|
|
31
|
-
} catch (err) {
|
|
32
|
-
res.status(err?.status ?? 500).json({ error: err?.message })
|
|
33
|
-
}
|
|
34
|
-
}
|
package/src/item-content.api.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { ActionService } from '@ossy/platform'
|
|
2
|
-
import { attachResourceMediaUrls } from './resources.attach-media-urls.js'
|
|
3
|
-
|
|
4
|
-
const pathRe = /^\/api\/v0\/resources\/([^/]+)\/content$/
|
|
5
|
-
|
|
6
|
-
export const metadata = {
|
|
7
|
-
id: 'resources.item.content',
|
|
8
|
-
path: '/api/v0/resources/:resourceId/content',
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default async function handle(req, res) {
|
|
12
|
-
if (req.method !== 'PUT') {
|
|
13
|
-
res.setHeader('Allow', 'PUT')
|
|
14
|
-
res.status(405).json({ error: 'Method Not Allowed' })
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
const pathname = (req.path || new URL(req.originalUrl, 'http://localhost').pathname).replace(/\/+$/, '')
|
|
18
|
-
const m = pathname.match(pathRe)
|
|
19
|
-
if (!m) {
|
|
20
|
-
res.status(404).json('')
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
const resourceId = decodeURIComponent(m[1])
|
|
24
|
-
try {
|
|
25
|
-
const resource = await ActionService.invoke('resources/update-content', {
|
|
26
|
-
payload: { resourceId, content: req.body?.content, userId: req.userId, workspaceId: req.workspaceId },
|
|
27
|
-
req,
|
|
28
|
-
})
|
|
29
|
-
if (resource === null || resource === undefined) return
|
|
30
|
-
const withUrls = await attachResourceMediaUrls(resource, { userId: req.userId, workspaceId: req.workspaceId })
|
|
31
|
-
res.json(withUrls)
|
|
32
|
-
} catch (err) {
|
|
33
|
-
res.status(err?.status ?? 400).json({ type: err?.type, message: err?.message })
|
|
34
|
-
}
|
|
35
|
-
}
|