Skip to content

Commit 4bd155a

Browse files
committed
Add .put method on path.
Closes #60
1 parent 1bd6fc5 commit 4bd155a

5 files changed

Lines changed: 439 additions & 0 deletions

File tree

src/RootPath.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { PathFactory, defaultHandlers } from 'ldflex';
22
import context from '@solid/context';
3+
import PutHandler from './handlers/PutHandler';
34
import SolidDeleteFunctionHandler from './handlers/SolidDeleteFunctionHandler';
45
import FindActivityHandler from './handlers/FindActivityHandler';
56
import CreateActivityHandler from './handlers/CreateActivityHandler';
@@ -16,6 +17,9 @@ const contextResolver = new ContextResolver(context);
1617
const subjectHandlers = {
1718
...defaultHandlers,
1819

20+
// HTTP PUT handler
21+
put: new PutHandler(),
22+
1923
// Custom delete handler to match node-solid-server behavior
2024
delete: new SolidDeleteFunctionHandler(),
2125

src/handlers/PutHandler.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { toIterablePromise } from 'ldflex';
2+
import auth from 'solid-auth-client';
3+
4+
/**
5+
* Creates a document for every result with the given contents.
6+
* Requires:
7+
* - the `root[...]` resolver
8+
*/
9+
export default class PutHandler {
10+
handle(pathData, path) {
11+
const { root } = path;
12+
13+
// Return an iterator over the created documents
14+
return (body = '', contentType = 'text/turtle') =>
15+
toIterablePromise(async function* () {
16+
// Collect all unique URLs from the path
17+
const urls = new Set();
18+
for await (const result of path) {
19+
const match = /^https?:\/\/[^#]+/.exec(result ? result.value : '');
20+
if (match)
21+
urls.add(match[0]);
22+
}
23+
24+
// Create and execute HTTP requests for every URL
25+
const requests = [...urls].map(url => auth.fetch(url, {
26+
method: 'PUT',
27+
headers: { 'Content-Type': contentType },
28+
body,
29+
}));
30+
await Promise.all(requests);
31+
32+
// Return paths to the created documents
33+
for (const url of urls)
34+
yield root[url];
35+
});
36+
}
37+
}
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
{
2+
"log": {
3+
"_recordingName": "System test: PUT/PUTting a Turtle document",
4+
"creator": {
5+
"comment": "persister:fs",
6+
"name": "Polly.JS",
7+
"version": "4.3.0"
8+
},
9+
"entries": [
10+
{
11+
"_id": "78931cfd34cc6dbe7dea87154278b303",
12+
"_order": 0,
13+
"cache": {},
14+
"request": {
15+
"bodySize": 18,
16+
"cookies": [],
17+
"headers": [
18+
{
19+
"_fromType": "array",
20+
"name": "content-type",
21+
"value": "text/turtle"
22+
},
23+
{
24+
"_fromType": "array",
25+
"name": "accept-encoding",
26+
"value": "gzip,deflate"
27+
},
28+
{
29+
"_fromType": "array",
30+
"name": "user-agent",
31+
"value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
32+
},
33+
{
34+
"_fromType": "array",
35+
"name": "connection",
36+
"value": "close"
37+
},
38+
{
39+
"_fromType": "array",
40+
"name": "accept",
41+
"value": "*/*"
42+
},
43+
{
44+
"_fromType": "array",
45+
"name": "content-length",
46+
"value": 18
47+
},
48+
{
49+
"name": "host",
50+
"value": "drive.verborgh.org"
51+
}
52+
],
53+
"headersSize": 266,
54+
"httpVersion": "HTTP/1.1",
55+
"method": "PUT",
56+
"postData": {
57+
"mimeType": "text/turtle",
58+
"params": [],
59+
"text": "# Turtle document\n"
60+
},
61+
"queryString": [],
62+
"url": "https://drive.verborgh.org/public/destination"
63+
},
64+
"response": {
65+
"bodySize": 7,
66+
"content": {
67+
"mimeType": "text/plain; charset=utf-8",
68+
"size": 7,
69+
"text": "Created"
70+
},
71+
"cookies": [],
72+
"headers": [
73+
{
74+
"name": "date",
75+
"value": "Mon, 01 Jun 2020 15:37:49 GMT"
76+
},
77+
{
78+
"name": "content-type",
79+
"value": "text/plain; charset=utf-8"
80+
},
81+
{
82+
"name": "content-length",
83+
"value": "7"
84+
},
85+
{
86+
"name": "connection",
87+
"value": "close"
88+
},
89+
{
90+
"name": "x-powered-by",
91+
"value": "solid-server"
92+
},
93+
{
94+
"name": "vary",
95+
"value": "Accept, Authorization, Origin"
96+
},
97+
{
98+
"name": "access-control-allow-credentials",
99+
"value": "true"
100+
},
101+
{
102+
"name": "access-control-expose-headers",
103+
"value": "Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate"
104+
},
105+
{
106+
"name": "allow",
107+
"value": "OPTIONS, HEAD, GET, PATCH, POST, PUT, DELETE"
108+
},
109+
{
110+
"name": "link",
111+
"value": "<destination.acl>; rel=\"acl\", <destination.meta>; rel=\"describedBy\", <http://www.w3.org/ns/ldp#Resource>; rel=\"type\""
112+
},
113+
{
114+
"name": "ms-author-via",
115+
"value": "SPARQL"
116+
},
117+
{
118+
"name": "etag",
119+
"value": "W/\"7-rM9AyJuqT6iOan/xHh+AW+7K/T8\""
120+
},
121+
{
122+
"name": "strict-transport-security",
123+
"value": "max-age=15768000"
124+
}
125+
],
126+
"headersSize": 696,
127+
"httpVersion": "HTTP/1.1",
128+
"redirectURL": "",
129+
"status": 201,
130+
"statusText": "Created"
131+
},
132+
"startedDateTime": "2020-06-01T15:37:48.871Z",
133+
"time": 237,
134+
"timings": {
135+
"blocked": -1,
136+
"connect": -1,
137+
"dns": -1,
138+
"receive": 0,
139+
"send": 0,
140+
"ssl": -1,
141+
"wait": 237
142+
}
143+
},
144+
{
145+
"_id": "573cbe5fa9b204bbcf4cae575188ef7d",
146+
"_order": 0,
147+
"cache": {},
148+
"request": {
149+
"bodySize": 0,
150+
"cookies": [],
151+
"headers": [
152+
{
153+
"_fromType": "array",
154+
"name": "accept-encoding",
155+
"value": "gzip,deflate"
156+
},
157+
{
158+
"_fromType": "array",
159+
"name": "user-agent",
160+
"value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
161+
},
162+
{
163+
"_fromType": "array",
164+
"name": "connection",
165+
"value": "close"
166+
},
167+
{
168+
"_fromType": "array",
169+
"name": "accept",
170+
"value": "*/*"
171+
},
172+
{
173+
"name": "host",
174+
"value": "drive.verborgh.org"
175+
}
176+
],
177+
"headersSize": 219,
178+
"httpVersion": "HTTP/1.1",
179+
"method": "GET",
180+
"queryString": [],
181+
"url": "https://drive.verborgh.org/public/destination"
182+
},
183+
"response": {
184+
"bodySize": 80,
185+
"content": {
186+
"_isBinary": true,
187+
"mimeType": "text/turtle",
188+
"size": 80,
189+
"text": "[\"1f8b0800000000000003535608292d2ac9495548c94f2ecd4dcd2be1020046ae618812000000\"]"
190+
},
191+
"cookies": [],
192+
"headers": [
193+
{
194+
"name": "date",
195+
"value": "Mon, 01 Jun 2020 15:37:49 GMT"
196+
},
197+
{
198+
"name": "content-type",
199+
"value": "text/turtle"
200+
},
201+
{
202+
"name": "transfer-encoding",
203+
"value": "chunked"
204+
},
205+
{
206+
"name": "connection",
207+
"value": "close"
208+
},
209+
{
210+
"name": "vary",
211+
"value": "Accept-Encoding, Accept, Authorization, Origin"
212+
},
213+
{
214+
"name": "x-powered-by",
215+
"value": "solid-server"
216+
},
217+
{
218+
"name": "access-control-allow-credentials",
219+
"value": "true"
220+
},
221+
{
222+
"name": "access-control-expose-headers",
223+
"value": "Authorization, User, Location, Link, Vary, Last-Modified, ETag, Accept-Patch, Accept-Post, Updates-Via, Allow, WAC-Allow, Content-Length, WWW-Authenticate"
224+
},
225+
{
226+
"name": "allow",
227+
"value": "OPTIONS, HEAD, GET, PATCH, POST, PUT, DELETE"
228+
},
229+
{
230+
"name": "link",
231+
"value": "<destination.acl>; rel=\"acl\", <destination.meta>; rel=\"describedBy\", <http://www.w3.org/ns/ldp#Resource>; rel=\"type\""
232+
},
233+
{
234+
"name": "wac-allow",
235+
"value": "user=\"read write append\",public=\"read write append\""
236+
},
237+
{
238+
"name": "ms-author-via",
239+
"value": "SPARQL"
240+
},
241+
{
242+
"name": "updates-via",
243+
"value": "wss://drive.verborgh.org"
244+
},
245+
{
246+
"name": "strict-transport-security",
247+
"value": "max-age=15768000"
248+
},
249+
{
250+
"name": "content-encoding",
251+
"value": "gzip"
252+
}
253+
],
254+
"headersSize": 794,
255+
"httpVersion": "HTTP/1.1",
256+
"redirectURL": "",
257+
"status": 200,
258+
"statusText": "OK"
259+
},
260+
"startedDateTime": "2020-06-01T15:37:49.115Z",
261+
"time": 145,
262+
"timings": {
263+
"blocked": -1,
264+
"connect": -1,
265+
"dns": -1,
266+
"receive": 0,
267+
"send": 0,
268+
"ssl": -1,
269+
"wait": 145
270+
}
271+
}
272+
],
273+
"pages": [],
274+
"version": "1.2"
275+
}
276+
}

test/system/put-test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import data from '../../src/exports/comunica.js';
2+
import auth from 'solid-auth-client';
3+
4+
jest.unmock('solid-auth-client');
5+
import { mockHttp } from '../util';
6+
7+
describe('System test: PUT', () => {
8+
mockHttp();
9+
10+
test('PUTting a Turtle document', async () => {
11+
// Write document
12+
const document = 'https://drive.verborgh.org/public/destination';
13+
const contents = '# Turtle document\n';
14+
const result = await data[document].put(contents);
15+
16+
// Verify successful write
17+
const response = await auth.fetch(document);
18+
expect(await response.text()).toBe(contents);
19+
20+
// Verify result
21+
expect(result).toHaveProperty('value', document);
22+
expect(result).toHaveProperty('termType', 'NamedNode');
23+
});
24+
});

0 commit comments

Comments
 (0)