solid-client-js
solid-client-js copied to clipboard
Support appending to file without read/write access
Search terms you've used
I've searched for "patch" and "append"
Feature suggestion
The Solid rest-api describes that we can use a PATCH request to append data with SPARQL. I would like to see an implementation of this, which allows appending a Thing to a specific file with only append access.
Expected functionality/enhancement
Something along await appendToFile(url, thing). I'm not very familiar to the solid-client API, so there may be a better solution.
Actual functionality/enhancement
Currently it seems possible to update a file only if one has read and write access.
Use Cases
I would use it to let people append themself to secret groups.
Indirectly this allows granting access to a file shareMe.txt via a link:
- create file
myGroupwhere everbody can append, but not read (so the content is secret) - give a group with a cryptographically random name (
asdfasdf) access toshareMe.txt - create a Link which contains the random name (
https://example-sharer.com/#key=asdfasdf) - anybody with this link can append themself to group
asdfasdfand thus has access toshareMe.txt
Additional information
solid-client already sends PATCH requests when you build on top of a previously fetched SolidDataset. So if you first fetch the SolidDataset that contains the group, then add people to the group's Thing, then save that SolidDataset again, that should do what you want.
Hi Vinnl, thanks for the fast response.
From my testing, saveSolidDatasetAt requires WRITE permissions to the file (and APPEND does not suffice, even if only adding to the file).
I've tested it with the script below which resulted in this output:
success: https://sheep.solidcommunity.net/private/editors.ttl
error: https://sheep.solidcommunity.net/private/posters.ttl - 401
error: https://sheep.solidcommunity.net/private/submitters.ttl - 401
The files are initially empty and have public access to WRITE (editors), READ (posters) and APPEND (posters, subbmitters).
This is the testing script:
const { saveSolidDatasetAt, createSolidDataset, createThing, buildThing, setThing } = require("@inrupt/solid-client")
const { RDF, SCHEMA_INRUPT } = require('@inrupt/vocab-common-rdf')
const main = async () => {
let courseSolidDataset = createSolidDataset();
const newBookThing1 = buildThing(createThing({ name: "book2" }))
.addStringNoLocale(SCHEMA_INRUPT.name, "ABC123 of Example Literature")
.addUrl(RDF.type, "https://schema.org/Book")
.build();
courseSolidDataset = setThing(courseSolidDataset, newBookThing1);
await testSaving('https://sheep.solidcommunity.net/private/editors.ttl', courseSolidDataset)
await testSaving('https://sheep.solidcommunity.net/private/posters.ttl', courseSolidDataset)
await testSaving('https://sheep.solidcommunity.net/private/submitters.ttl', courseSolidDataset)
}
const testSaving = async(url, dataset) => {
try {
const savedSolidDataset = await saveSolidDatasetAt(url, dataset);
console.log(`success: ${url}`)
} catch (err) {
console.log(`error: ${url} - ${err.response?.status ?? err.message}`)
}
}
main()
@Otto-AA Yes, that's why I said "when you build on top of a previously fetched SolidDataset". You are creating a new SolidDataset every time (createSolidDataset()), so solid-client will attempt to overwrite whatever is already at that location (hence requiring Write permissions). Off the top of my head (i.e. I didn't run this to test), if I change your code to the following, it should only require Append access:
const { saveSolidDatasetAt, createSolidDataset, createThing, buildThing, setThing } = require("@inrupt/solid-client")
const { RDF, SCHEMA_INRUPT } = require('@inrupt/vocab-common-rdf')
const main = async () => {
let editorsSolidDataset = await getSolidDataset("https://sheep.solidcommunity.net/private/editors.ttl");
const newBookThing1 = buildThing(createThing({ name: "book2" }))
.addStringNoLocale(SCHEMA_INRUPT.name, "ABC123 of Example Literature")
.addUrl(RDF.type, "https://schema.org/Book")
.build();
editorsSolidDataset = setThing(editorsSolidDataset, newBookThing1);
await testSaving('https://sheep.solidcommunity.net/private/editors.ttl', editorsSolidDataset);
}
const testSaving = async(url, dataset) => {
try {
const savedSolidDataset = await saveSolidDatasetAt(url, dataset);
console.log(`success: ${url}`)
} catch (err) {
console.log(`error: ${url} - ${err.response?.status ?? err.message}`)
}
}
main()
Sorry if I was not clear enough, or I'm still not getting your point.
As far as I understand your example requires READ access (getSolidDataset fails without READ access). The spec and at least NSS support appending with only APPEND access (even without READ and WRITE). This can be done with a INSERT SPARQL statement I think (but I don't know if this is defined in the spec, or only implemented this way by NSS).
This is what I try to achieve: appending without being able to read or modify existing contents.
Ah yes, if you want to append without read access, that would indeed need an addition to the API, e.g. something like saveSolidDatasetAt("https://example.com", { forceAppend: true }). (Also note that I don't work on solid-client/at Inrupt any more, so someone else will have to do that :slightly_smiling_face: )