Skip to content

Commit 96ce2f0

Browse files
authored
Merge pull request #1801 from nodeSolidServer/basic-prep-fix-1
Basic prep fix 1
2 parents 41a2ba3 + d86d150 commit 96ce2f0

File tree

10 files changed

+224
-74
lines changed

10 files changed

+224
-74
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717

1818
strategy:
1919
matrix:
20-
node-version: [ '>=20.17.0' ]
20+
node-version: [ '^20.17.0' ]
2121
os: [ubuntu-latest]
2222

2323
steps:

lib/handlers/delete.js

-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ async function handler (req, res, next) {
66
debug('DELETE -- Request on' + req.originalUrl)
77

88
const ldp = req.app.locals.ldp
9-
const prep = req.app.locals.prep
109
try {
1110
await ldp.delete(req)
1211
debug('DELETE -- Ok.')
13-
// Add event-id for notifications
14-
prep && res.setHeader('Event-ID', res.setEventID())
1512
res.sendStatus(200)
1613
next()
1714
} catch (err) {

lib/handlers/notify.js

+30-12
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,32 @@ function getParentActivity (method, status) {
3838
return 'Update'
3939
}
4040

41+
function filterMillseconds (isoDate) {
42+
return `${isoDate.substring(0, 19)}${isoDate.substring(23)}`
43+
}
44+
45+
function getDate (date) {
46+
if (date) {
47+
const eventDate = new Date(date)
48+
if (!isNaN(eventDate.valueOf())) {
49+
return filterMillseconds(eventDate.toISOString())
50+
}
51+
}
52+
const now = new Date()
53+
return filterMillseconds(now.toISOString())
54+
}
55+
4156
function handler (req, res, next) {
4257
const { trigger, defaultNotification } = res.events.prep
4358

4459
const { method, path } = req
4560
const { statusCode } = res
46-
const eventID = res.getHeader('event-id')
61+
const eventID = res.setEventID()
4762
const fullUrl = new URL(path, `${req.protocol}://${req.hostname}/`)
4863

4964
// Date is a hack since node does not seem to provide access to send date.
5065
// Date needs to be shared with parent notification
51-
const eventDate = res._header.match(/^Date: (.*?)$/m)?.[1] ||
52-
new Date().toUTCString()
66+
const eventDate = getDate(res._header.match(/^Date: (.*?)$/m)?.[1])
5367

5468
// If the resource itself newly created,
5569
// it could not have been subscribed for notifications already
@@ -61,18 +75,19 @@ function handler (req, res, next) {
6175
) {
6276
const mediaType = negotiatedFields['content-type']
6377
const activity = getActivity(method, path)
64-
const target = activity === 'Add'
78+
const object = activity === 'Add'
6579
? res.getHeader('location')
80+
: String(fullUrl)
81+
const target = activity === 'Add'
82+
? String(fullUrl)
6683
: undefined
6784
if (ALLOWED_RDF_MIME_TYPES.includes(mediaType?.[0])) {
6885
return `${headerTemplate(negotiatedFields)}\r\n${solidRDFTemplate({
6986
activity,
7087
eventID,
71-
object: String(fullUrl),
88+
object,
7289
target,
7390
date: eventDate,
74-
// We use eTag as a proxy for state for now
75-
state: res.getHeader('ETag'),
7691
mediaType
7792
})}`
7893
} else {
@@ -93,7 +108,10 @@ function handler (req, res, next) {
93108
// POST in Solid creates a child resource
94109
const parent = getParent(path)
95110
if (parent && method !== 'POST') {
96-
const parentID = res.setEventID(parent)
111+
res.setEventID({
112+
path: parent,
113+
id: eventID
114+
})
97115
const parentUrl = new URL(parent, fullUrl)
98116
try {
99117
trigger({
@@ -103,15 +121,15 @@ function handler (req, res, next) {
103121
) {
104122
const mediaType = negotiatedFields['content-type']
105123
const activity = getParentActivity(method, statusCode)
106-
const target = activity !== 'Update' ? String(fullUrl) : undefined
124+
const object = activity === 'Update' ? String(parentUrl) : String(fullUrl)
125+
const target = activity === 'Update' ? undefined : String(parentUrl)
107126
if (ALLOWED_RDF_MIME_TYPES.includes(mediaType?.[0])) {
108127
return `${headerTemplate(negotiatedFields)}\r\n${solidRDFTemplate({
109128
activity,
110-
eventID: parentID,
129+
eventID,
111130
date: eventDate,
112-
object: String(parentUrl),
131+
object,
113132
target,
114-
eTag: undefined,
115133
mediaType
116134
})}`
117135
}

lib/handlers/patch.js

-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ function contentForNew (contentType) {
3939
// Handles a PATCH request
4040
async function patchHandler (req, res, next) {
4141
debug(`PATCH -- ${req.originalUrl}`)
42-
const prep = req.app.locals.prep
4342
try {
4443
// Obtain details of the target resource
4544
const ldp = req.app.locals.ldp
@@ -91,9 +90,6 @@ async function patchHandler (req, res, next) {
9190
await applyPatch(patchObject, graph, url)
9291
return writeGraph(graph, resource, ldp.resourceMapper.resolveFilePath(req.hostname), ldp.serverUri)
9392
})
94-
95-
// Add event-id for notifications
96-
prep && res.setHeader('Event-ID', res.setEventID())
9793
// Send the status and result to the client
9894
res.status(resourceExists ? 200 : 201)
9995
res.send(result)

lib/handlers/post.js

-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const getContentType = require('../utils').getContentType
1111

1212
async function handler (req, res, next) {
1313
const ldp = req.app.locals.ldp
14-
const prep = req.app.locals.prep
1514
const contentType = getContentType(req.headers)
1615
debug('content-type is ', contentType)
1716
// Handle SPARQL(-update?) query
@@ -73,8 +72,6 @@ async function handler (req, res, next) {
7372
// Handled by backpressure of streams!
7473
busboy.on('finish', function () {
7574
debug('Done storing files')
76-
// Add event-id for notifications
77-
prep && res.setHeader('Event-ID', res.setEventID())
7875
res.sendStatus(200)
7976
next()
8077
})
@@ -94,8 +91,6 @@ async function handler (req, res, next) {
9491
debug('File stored in ' + resourcePath)
9592
header.addLinks(res, links)
9693
res.set('Location', resourcePath)
97-
// Add event-id for notifications
98-
prep && res.setHeader('Event-ID', res.setEventID())
9994
res.sendStatus(201)
10095
next()
10196
},

lib/handlers/put.js

-3
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ async function checkPermission (request, resourceExists) {
5959
// TODO could be renamed as putResource (it now covers container and non-container)
6060
async function putStream (req, res, next, stream = req) {
6161
const ldp = req.app.locals.ldp
62-
const prep = req.app.locals.prep
6362
// try {
6463
// Obtain details of the target resource
6564
let resourceExists = true
@@ -78,8 +77,6 @@ async function putStream (req, res, next, stream = req) {
7877
// Fails with Append on existing resource
7978
if (!req.originalUrl.endsWith('.acl')) await checkPermission(req, resourceExists)
8079
await ldp.put(req, stream, getContentType(req.headers))
81-
// Add event-id for notifications
82-
prep && res.setHeader('Event-ID', res.setEventID())
8380
res.sendStatus(resourceExists ? 204 : 201)
8481
return next()
8582
} catch (err) {

lib/rdf-notification-template.js

+22-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
const uuid = require('uuid')
2+
13
const CONTEXT_ACTIVITYSTREAMS = 'https://www.w3.org/ns/activitystreams'
24
const CONTEXT_NOTIFICATION = 'https://www.w3.org/ns/solid/notification/v1'
35
const CONTEXT_XML_SCHEMA = 'http://www.w3.org/2001/XMLSchema'
46

57
function generateJSONNotification ({
68
activity: type,
7-
eventId: id,
9+
eventID,
810
date: published,
911
object,
1012
target,
@@ -13,30 +15,40 @@ function generateJSONNotification ({
1315
return {
1416
published,
1517
type,
16-
id,
18+
id: `urn:uuid:${uuid.v4()}`,
19+
...(eventID) && { state: eventID },
1720
object,
1821
...(type === 'Add') && { target },
19-
...(type === 'Remove') && { origin: target },
20-
...(state) && { state }
22+
...(type === 'Remove') && { origin: target }
2123
}
2224
}
2325

2426
function generateTurtleNotification ({
2527
activity,
26-
eventId,
28+
eventID,
2729
date,
2830
object,
29-
target,
30-
state = undefined
31+
target
3132
}) {
32-
const stateLine = `\n notify:state "${state}" ;`
33+
let targetLine = ''
34+
let stateLine = ''
35+
36+
if (activity === 'Add') {
37+
targetLine = `\n as:target <${target}> ;`
38+
}
39+
if (activity === 'Remove') {
40+
targetLine = `\n as:origin <${target}> ;`
41+
}
42+
if (eventID) {
43+
stateLine = `\n notify:state "${eventID}" ;`
44+
}
3345

3446
return `@prefix as: <${CONTEXT_ACTIVITYSTREAMS}#> .
3547
@prefix notify: <${CONTEXT_NOTIFICATION}#> .
3648
@prefix xsd: <${CONTEXT_XML_SCHEMA}#> .
3749
38-
<${eventId}> a as:${activity} ;${state && stateLine}
39-
as:object ${object} ;
50+
<urn:uuid:${uuid.v4()}> a as:${activity} ;
51+
as:object <${object}> ;${targetLine}${stateLine}
4052
as:published "${date}"^^xsd:dateTime .`.replaceAll('\n', '\r\n')
4153
}
4254

0 commit comments

Comments
 (0)