Skip to content

Commit

Permalink
Merge pull request #17 from NoelDeMartin/clean-up
Browse files Browse the repository at this point in the history
Clean up
  • Loading branch information
NoelDeMartin authored Dec 19, 2021
2 parents f262357 + 46e913f commit eb8b3db
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 48 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <h1>0data Hello World</h1>
<ul>
<li><a href="./fission/">Fission</a></li>
<li><a href="./remotestorage/">remoteStorage</a></li>
<li><a href="./solid/">Solid</a></li>
<li><a href="./solid/solid-file-client/">Solid</a></li>
</ul>

<p>This project came out of <a href="https://chat.0data.app/t/51">Zero Data Swap #4</a>.</p>
Expand Down
9 changes: 6 additions & 3 deletions solid/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Solid Hello World

This is a simple application illustrating how to get started with [Solid](https://solidproject.org/).
This folder contains some simple applications illustrating how to get started with [Solid](https://solidproject.org/) using different libraries.

It only has two dependencies: [an authentication library](https://github.com/inrupt/solid-client-authn-js) and [an RDF parsing library](https://github.com/rdfjs/N3.js). Everything else is plain HTML, CSS and JavaScript. All the functionality related with Solid is contained in a single file; `solid.js`.
- [solid-file-client](./solid-file-client): This example uses a higher-level library called [solid-file-client](https://github.com/jeff-zucker/solid-file-client). It's pretty minimal library, but makes some basic operations easier.
- [solid-rest-api](./solid-rest-api): This example is the most minimal, it only uses the authentication library and a Turtle parser. All the interaction with the POD is implemented using the native `fetch` function.

## Understanding the code

If you're not familiar with the basics of Solid, we strongly suggest that you check out [the glossary](Glossary.md). You can find more specific documentation about the code in this app within the [solid.js](./solid.js) file.
If you're not familiar with the basics of Solid, we strongly suggest that you check out [the glossary](Glossary.md). You can find more documentation about each code sample in the source files, they contain inline comments specific to each implementation.

The `index.html` and `main.js` files are not documented, but they should be fairly easy to understand if you're already familiar with HTML and JavaScript. The application doesn't have any custom CSS because it uses a classless CSS framework called [Simple.css](https://simplecss.org).

Expand Down Expand Up @@ -49,3 +50,5 @@ There are already some existing examples using more libraries:
- [Solid To-Do App Tutorial](https://www.virginiabalseiro.com/blog/tutorial) ([React](https://reactjs.org/) + [solid-client](https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/read-write-data/)): A tutorial of how to build a To-Do app using [Inrupt](https://inrupt.com/)'s libraries.
- [Ramen](https://github.com/noeldemartin/ramen) ([Vue](https://vuejs.org/) + [soukai-solid](https://github.com/noeldemartin/soukai-solid)): A simple application that adds a recipe for Ramen to your POD. This application can also serve as an example to use the type index.
- [Hello Solid](https://wkokgit.github.io/hellosolid/) ([JQuery](https://jquery.com/) + [rdflib](https://github.com/linkeddata/rdflib.js)/[LDFlex](https://github.com/LDflex/LDflex)): A Solid Client application to explain the basics of Solid. Keep in mind that this library uses the deprecated [solid-auth-client](https://github.com/solid/solid-auth-client) for authentication, and will not work with newer Solid PODs.

You can also check out [this list](https://timea.solidcommunity.net/HelloWorld/index.html).
4 changes: 2 additions & 2 deletions solid/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ <h1>Solid Hello World Examples</h1>
<p>Here you can find more examples following the same simple structure, but using some advanced libraries:</p>

<ul>
<li><a href="solid-rest-api/">solid-rest-api</a></li>
<li><a href="solid-file-client/">solid-file-client</a></li>
<li><a href="solid-file-client/">solid-file-client library</a></li>
<li><a href="solid-rest-api/">REST API</a></li>
</ul>

<p>If you would like to see even more advanced examples, you can find them in the <a href="https://github.com/0dataapp/hello/tree/main/solid#this-example-is-too-simple-can-you-make-one-using-more-libraries">FAQs</a>.</p>
Expand Down
4 changes: 2 additions & 2 deletions solid/solid-file-client/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Solid Hello World
# Solid Hello World (solid-file-client)

This is a simple application illustrating how to get started with [Solid](https://solidproject.org/) using the [solid-file-client](https://github.com/jeff-zucker/solid-file-client) library.

It only has two dependencies: [an authentication library](https://github.com/inrupt/solid-client-authn-js) and [solid-file-client](https://github.com/jeff-zucker/solid-file-client). Everything else is plain HTML, CSS and JavaScript. All the functionality related to Solid is contained in a single file; `solid.js`.

## Understanding the code & Usage instructions

This example follows the same structure as the other examples, so you follow the [same instructions](../).
This example follows the same structure as other examples in this repository, so you can follow these [general instructions](../).
8 changes: 5 additions & 3 deletions solid/solid-file-client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>Solid Hello World</title>
<title>Solid Hello World (solid-file-client)</title>
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
</head>

<body>
<h1>Solid-File-Client Hello World</h1>
<h1>Solid Hello World<br><small>(solid-file-client)</small></h1>

<div id="loading">
<p>Loading...</p>
Expand All @@ -19,10 +19,12 @@ <h1>Solid-File-Client Hello World</h1>
<p>Hi there!</p>
<p>
This page is a showcase of a simple <a href="https://solidproject.org/" target="_blank">Solid application</a>
built using the <a href="https://github.com/jeff-zucker/solid-file-client">solid-file-client</a> library. You can look at the source code and learn how to use it in
built using the <a href="https://github.com/jeff-zucker/solid-file-client" target="_blank">solid-file-client</a> library. You can look at the source code and learn how to use it in
<a href="https://github.com/0dataapp/hello/tree/main/solid/solid-file-client" target="_blank">the repository</a>.
</p>

<p>If you want to see other examples, you can find them here: <a href="../">Solid Hello World Examples</a>.</p>

<button id="login-button" type="button" onclick="login()">Log in with Solid</button>
</div>

Expand Down
60 changes: 34 additions & 26 deletions solid/solid-file-client/solid.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
let user, tasksContainerUrl;
const solidFileClient = new SolidFileClient(solidClientAuthentication);

solidFileClient.rdf.setPrefix('schemaorg', 'https://schema.org/');

async function restoreSession() {
// This function uses Inrupt's authentication library to restore a previous session. If you were
// already logged into the application last time that you used it, this will trigger a redirect that
Expand Down Expand Up @@ -76,11 +78,8 @@ async function performTaskCreation(description) {
// - SAI, or Solid App Interoperability. This one is still being defined:
// https://solid.github.io/data-interoperability-panel/specification/

if (!tasksContainerUrl) {
await createSolidContainer(`${user.storageUrl}tasks/`);

tasksContainerUrl = `${user.storageUrl}tasks/`;
}
if (!tasksContainerUrl)
tasksContainerUrl = await createSolidContainer(`${user.storageUrl}tasks/`);

const documentUrl = await createSolidDocument(tasksContainerUrl, `
@prefix schema: <https://schema.org/> .
Expand Down Expand Up @@ -122,17 +121,17 @@ async function loadTasks() {
// In a real application, you shouldn't hard-code the path to the container like we're doing here.
// Read more about this in the comments on the performTaskCreation function.

const tasks = [];
const containmentQuads = await readSolidDocument(`${user.storageUrl}tasks/`, null, { ldp: 'contains' })
const containerUrl = `${user.storageUrl}tasks/`;
const containmentQuads = await readSolidDocument(containerUrl, null, { ldp: 'contains' });

if (!containmentQuads) {
if (!containmentQuads)
return [];

}
tasksContainerUrl = `${user.storageUrl}tasks/`;
tasksContainerUrl = containerUrl;

const tasks = [];
for (const containmentQuad of containmentQuads) {
const [typeQuad] = await readSolidDocument(containmentQuad.object.value, null, { rdf: 'type' }, '<https://schema.org/Action>');
const [typeQuad] = await readSolidDocument(containmentQuad.object.value, null, { rdf: 'type' }, { schemaorg: 'Action' });

if (!typeQuad) {
// Not a Task, we can ignore this document.
Expand All @@ -141,8 +140,8 @@ async function loadTasks() {
}

const taskUrl = typeQuad.subject.value;
const [descriptionQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, '<https://schema.org/description>');
const [statusQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, '<https://schema.org/actionStatus>');
const [descriptionQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, { schemaorg: 'description' });
const [statusQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, { schemaorg: 'actionStatus' });

tasks.push({
url: taskUrl,
Expand All @@ -156,7 +155,8 @@ async function loadTasks() {

async function readSolidDocument(url, source, predicate, object, graph) {
try {
// rdf.query return an array of statements matching terms (load and cache url content)
// solidFileClient.rdf.query returns an array of statements with matching terms.
// (load and cache url content)
return await solidFileClient.rdf.query(url, source, predicate, object, graph);
} catch (error) {
return null;
Expand Down Expand Up @@ -192,10 +192,12 @@ async function deleteSolidDocument(url) {
}

async function createSolidContainer(url) {
const response = await solidFileClient.createFolder(url)
const response = await solidFileClient.createFolder(url);

if (!isSuccessfulStatusCode(response.status))
throw new Error(`Failed creating container at ${url}, returned status ${response.status}`);

return url;
}

function isSuccessfulStatusCode(statusCode) {
Expand All @@ -211,30 +213,36 @@ function getSolidDocumentUrl(resourceUrl) {
}

async function fetchUserProfile(webId) {
const [nameQuad] = await readSolidDocument(webId, null, { foaf: 'name' })
const [nameQuad] = await readSolidDocument(webId, null, { foaf: 'name' });
const [storageQuad] = await readSolidDocument(webId, null, { space: 'storage' });

return {
url: webId,
name: nameQuad?.object.value || 'Anonymous',
storageUrl: await findeUserStorage(webId),

// WebIds may declare more than one storage url, so in a real application you should
// ask which one to use if that happens. In this app, in order to keep it simple, we'll
// just use the first one. If none is declared in the profile, we'll search for it.
storageUrl: storageQuad?.object.value || await findUserStorage(webId),
};
}

async function findeUserStorage(url) {
// See https://solidproject.org/TR/protocol#storage.
async function findUserStorage(url) {
url = url.replace(/#.*$/, '');
url = url.endsWith('/') ? url + '../' : url + '/../';
url = new URL(url);

// following solid/protocol used by NSS and CSS
const response = await solidFileClient.head(url.href)
const response = await solidFileClient.head(url.href);

if (response.headers.get('Link')?.includes('<http://www.w3.org/ns/pim/space#Storage>; rel="type"')) {
return url.href
}
if (response.headers.get('Link')?.includes('<http://www.w3.org/ns/pim/space#Storage>; rel="type"'))
return url.href;

// for providers that don't advertise storage properly
if (url.pathname === '/') return url.href
// Fallback for providers that don't advertise storage properly.
if (url.pathname === '/')
return url.href;

return findeUserStorage(url.href);
return findUserStorage(url.href);
}

function escapeText(text) {
Expand Down
9 changes: 9 additions & 0 deletions solid/solid-rest-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Solid Hello World (REST API)

This is a simple application illustrating how to get started with [Solid](https://solidproject.org/).

It only has two dependencies: [an authentication library](https://github.com/inrupt/solid-client-authn-js) and [an RDF parsing library](https://github.com/rdfjs/N3.js). Everything else is plain HTML, CSS and JavaScript. All the functionality related with Solid is contained in a single file; `solid.js`.

## Understanding the code & Usage instructions

This example follows the same structure as other examples in this repository, so you can follow these [general instructions](../).
12 changes: 6 additions & 6 deletions solid/solid-rest-api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>Solid Hello World</title>
<title>Solid Hello World (REST API)</title>
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
</head>

<body>
<h1>Solid-Rest-Api Hello World</h1>
<h1>Solid Hello World<br><small>(REST API)</small></h1>

<div id="loading">
<p>Loading...</p>
Expand All @@ -19,11 +19,11 @@ <h1>Solid-Rest-Api Hello World</h1>
<p>Hi there!</p>
<p>
This page is a showcase of a simple <a href="https://solidproject.org/" target="_blank">Solid application</a>
built using JavaScript, CSS and HTML. You can look at the source code and learn how to use it in the
<a href="https://github.com/0dataapp/hello/tree/main/solid/solid-rest-api" target="_blank">solid-rest-api repository</a>.
built using JavaScript, CSS and HTML. You can look at the source code and learn how to use it in
<a href="https://github.com/0dataapp/hello/tree/main/solid/solid-rest-api" target="_blank">the repository</a>.
</p>

<p>If you want to see other examples, you can find them here: <a href="../index.html">Solid Hello World Examples</a>.</p>
<p>If you want to see other examples, you can find them here: <a href="../">Solid Hello World Examples</a>.</p>

<button id="login-button" type="button" onclick="login()">Log in with Solid</button>
</div>
Expand All @@ -37,7 +37,7 @@ <h2>Your tasks</h2>
<button type="button" onclick="createTask()">Create new task</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/n3-browserify@1.11.1"></script>
<script src="https://cdn.jsdelivr.net/npm/n3@1.12.1/browser/n3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@inrupt/[email protected]/dist/solid-client-authn.bundle.js"></script>
<script src="solid.js"></script>
<script src="main.js"></script>
Expand Down
15 changes: 10 additions & 5 deletions solid/solid-rest-api/solid.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,8 @@ async function performTaskCreation(description) {
// - SAI, or Solid App Interoperability. This one is still being defined:
// https://solid.github.io/data-interoperability-panel/specification/

if (!tasksContainerUrl) {
await createSolidContainer(user.storageUrl, 'tasks');

tasksContainerUrl = `${user.storageUrl}tasks/`;
}
if (!tasksContainerUrl)
tasksContainerUrl = await createSolidContainer(user.storageUrl, 'tasks');

const documentUrl = await createSolidDocument(tasksContainerUrl, `
@prefix schema: <https://schema.org/> .
Expand Down Expand Up @@ -228,6 +225,10 @@ async function createSolidContainer(url, name) {

if (!isSuccessfulStatusCode(response.status))
throw new Error(`Failed creating container at ${url}, returned status ${response.status}`);

const location = response.headers.get('Location');

return new URL(location, url).href;
}

function isSuccessfulStatusCode(statusCode) {
Expand All @@ -250,6 +251,10 @@ async function fetchUserProfile(webId) {
return {
url: webId,
name: nameQuad?.object.value || 'Anonymous',

// WebIds may declare more than one storage url, so in a real application you should
// ask which one to use if that happens. In this app, in order to keep it simple, we'll
// just use the first one. If none is declared in the profile, we'll search for it.
storageUrl: storageQuad?.object.value || await findUserStorage(webId),
};
}
Expand Down

0 comments on commit eb8b3db

Please sign in to comment.