commit
78cadc3eb8
@ -1,4 +1,4 @@ |
||||
{ |
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json", |
||||
"version": "0.0.1-alpha.19" |
||||
"version": "0.0.1-alpha.23" |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@ |
||||
{ |
||||
"extends": ["../../.eslintrc"] |
||||
} |
@ -1,23 +0,0 @@ |
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. |
||||
|
||||
# dependencies |
||||
/node_modules |
||||
/.pnp |
||||
.pnp.js |
||||
|
||||
# testing |
||||
/coverage |
||||
|
||||
# production |
||||
/build |
||||
|
||||
# misc |
||||
.DS_Store |
||||
.env.local |
||||
.env.development.local |
||||
.env.test.local |
||||
.env.production.local |
||||
|
||||
npm-debug.log* |
||||
yarn-debug.log* |
||||
yarn-error.log* |
@ -1,21 +0,0 @@ |
||||
MIT License |
||||
|
||||
Copyright (c) 2023 Jackson Morgan |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -1,12 +0,0 @@ |
||||
# LDO Demo-React |
||||
|
||||
A demo app to show off the use of LDO. |
||||
|
||||
## Sponsorship |
||||
This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn more on the [NLnet project page](https://nlnet.nl/project/SolidUsableApps/). |
||||
|
||||
[<img src="https://nlnet.nl/logo/banner.png" alt="nlnet foundation logo" width="300" />](https://nlnet.nl/) |
||||
[<img src="https://nlnet.nl/image/logos/NGI0Entrust_tag.svg" alt="NGI Zero Entrust Logo" width="300" />](https://nlnet.nl/) |
||||
|
||||
## Liscense |
||||
MIT |
@ -1,28 +0,0 @@ |
||||
// this file overrides the default CRA configurations (webpack, eslint, babel, etc)
|
||||
// Ingnore because config scripts can't use the import variable
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); |
||||
|
||||
module.exports = { |
||||
webpack: { |
||||
configure: (config) => { |
||||
// Remove ModuleScopePlugin which throws when we try to import something
|
||||
// outside of src/.
|
||||
config.resolve.plugins.pop(); |
||||
|
||||
// Resolve the path aliases.
|
||||
config.resolve.plugins.push(new TsconfigPathsPlugin()); |
||||
|
||||
// Let Babel compile outside of src/.
|
||||
const oneOfRule = config.module.rules.find((rule) => rule.oneOf); |
||||
const tsRule = oneOfRule.oneOf.find((rule) => |
||||
rule.test.toString().includes("ts|tsx"), |
||||
); |
||||
|
||||
tsRule.include = undefined; |
||||
tsRule.exclude = /node_modules/; |
||||
|
||||
return config; |
||||
}, |
||||
}, |
||||
}; |
@ -1,50 +0,0 @@ |
||||
{ |
||||
"name": "@ldo/demo-react", |
||||
"version": "0.0.1-alpha.19", |
||||
"dependencies": { |
||||
"@inrupt/solid-client-authn-browser": "^2.0.0", |
||||
"@ldo/solid-react": "^0.0.1-alpha.19", |
||||
"react": "^18.2.0", |
||||
"react-dom": "^18.2.0", |
||||
"react-router-dom": "^6.15.0", |
||||
"react-scripts": "5.0.1", |
||||
"uuid": "^9.0.1" |
||||
}, |
||||
"scripts": { |
||||
"start": "craco start", |
||||
"build": "craco build", |
||||
"eject": "react-scripts eject", |
||||
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern", |
||||
"build:ldo": "ldo build --input src/.shapes --output src/.ldo" |
||||
}, |
||||
"eslintConfig": { |
||||
"extends": [ |
||||
"react-app", |
||||
"react-app/jest" |
||||
] |
||||
}, |
||||
"browserslist": { |
||||
"production": [ |
||||
">0.2%", |
||||
"not dead", |
||||
"not op_mini all" |
||||
], |
||||
"development": [ |
||||
"last 1 firefox version", |
||||
"last 1 chrome version", |
||||
"last 1 safari version" |
||||
] |
||||
}, |
||||
"devDependencies": { |
||||
"@craco/craco": "^7.1.0", |
||||
"@ldo/cli": "^0.0.1-alpha.19", |
||||
"@types/jsonld": "^1.5.9", |
||||
"@types/react": "^18.2.21", |
||||
"@types/shexj": "^2.1.4", |
||||
"tsconfig-paths-webpack-plugin": "^4.1.0" |
||||
}, |
||||
"gitHead": "4548985c0de9b0ec83cf5ee93f2d7c1ca2c1b8d8", |
||||
"publishConfig": { |
||||
"access": "public" |
||||
} |
||||
} |
@ -1,41 +0,0 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="utf-8" /> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
||||
<meta name="theme-color" content="#000000" /> |
||||
<meta |
||||
name="description" |
||||
content="Web site created using create-react-app" |
||||
/> |
||||
<!-- |
||||
manifest.json provides metadata used when your web app is installed on a |
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ |
||||
--> |
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> |
||||
<!-- |
||||
Notice the use of %PUBLIC_URL% in the tags above. |
||||
It will be replaced with the URL of the `public` folder during the build. |
||||
Only files inside the `public` folder can be referenced from the HTML. |
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will |
||||
work correctly both with client-side routing and a non-root public URL. |
||||
Learn how to configure a non-root public URL by running `npm run build`. |
||||
--> |
||||
<title>React App</title> |
||||
</head> |
||||
<body> |
||||
<noscript>You need to enable JavaScript to run this app.</noscript> |
||||
<div id="root"></div> |
||||
<!-- |
||||
This HTML file is a template. |
||||
If you open it directly in the browser, you will see an empty page. |
||||
|
||||
You can add webfonts, meta tags, or analytics to this file. |
||||
The build step will place the bundled scripts into the <body> tag. |
||||
|
||||
To begin the development, run `npm start` or `yarn start`. |
||||
To create a production bundle, use `npm run build` or `yarn build`. |
||||
--> |
||||
</body> |
||||
</html> |
@ -1,25 +0,0 @@ |
||||
{ |
||||
"short_name": "React App", |
||||
"name": "Create React App Sample", |
||||
"icons": [ |
||||
{ |
||||
"src": "favicon.ico", |
||||
"sizes": "64x64 32x32 24x24 16x16", |
||||
"type": "image/x-icon" |
||||
}, |
||||
{ |
||||
"src": "logo192.png", |
||||
"type": "image/png", |
||||
"sizes": "192x192" |
||||
}, |
||||
{ |
||||
"src": "logo512.png", |
||||
"type": "image/png", |
||||
"sizes": "512x512" |
||||
} |
||||
], |
||||
"start_url": ".", |
||||
"display": "standalone", |
||||
"theme_color": "#000000", |
||||
"background_color": "#ffffff" |
||||
} |
@ -1,3 +0,0 @@ |
||||
# https://www.robotstxt.org/robotstxt.html |
||||
User-agent: * |
||||
Disallow: |
@ -1,31 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* postContext: JSONLD Context for post |
||||
* ============================================================================= |
||||
*/ |
||||
export const postContext: ContextDefinition = { |
||||
type: { |
||||
"@id": "@type", |
||||
}, |
||||
SocialMediaPosting: "http://schema.org/SocialMediaPosting", |
||||
CreativeWork: "http://schema.org/CreativeWork", |
||||
Thing: "http://schema.org/Thing", |
||||
articleBody: { |
||||
"@id": "http://schema.org/articleBody", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
uploadDate: { |
||||
"@id": "http://schema.org/uploadDate", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#date", |
||||
}, |
||||
image: { |
||||
"@id": "http://schema.org/image", |
||||
"@type": "@id", |
||||
}, |
||||
publisher: { |
||||
"@id": "http://schema.org/publisher", |
||||
"@type": "@id", |
||||
}, |
||||
}; |
@ -1,19 +0,0 @@ |
||||
import { ShapeType } from "@ldo/ldo"; |
||||
import { postSchema } from "./post.schema"; |
||||
import { postContext } from "./post.context"; |
||||
import { PostSh } from "./post.typings"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* LDO ShapeTypes post |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* PostSh ShapeType |
||||
*/ |
||||
export const PostShShapeType: ShapeType<PostSh> = { |
||||
schema: postSchema, |
||||
shape: "https://example.com/PostSh", |
||||
context: postContext, |
||||
}; |
@ -1,45 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* Typescript Typings for post |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* PostSh Type |
||||
*/ |
||||
export interface PostSh { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
type: |
||||
| { |
||||
"@id": "SocialMediaPosting"; |
||||
} |
||||
| { |
||||
"@id": "CreativeWork"; |
||||
} |
||||
| { |
||||
"@id": "Thing"; |
||||
}; |
||||
/** |
||||
* The actual body of the article. |
||||
*/ |
||||
articleBody?: string; |
||||
/** |
||||
* Date when this media object was uploaded to this site. |
||||
*/ |
||||
uploadDate: string; |
||||
/** |
||||
* A media object that encodes this CreativeWork. This property is a synonym for encoding. |
||||
*/ |
||||
image?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* The publisher of the creative work. |
||||
*/ |
||||
publisher: { |
||||
"@id": string; |
||||
}; |
||||
} |
@ -1,154 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* solidProfileContext: JSONLD Context for solidProfile |
||||
* ============================================================================= |
||||
*/ |
||||
export const solidProfileContext: ContextDefinition = { |
||||
type: { |
||||
"@id": "@type", |
||||
}, |
||||
Person: "http://schema.org/Person", |
||||
Person2: "http://xmlns.com/foaf/0.1/Person", |
||||
fn: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#fn", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
name: { |
||||
"@id": "http://xmlns.com/foaf/0.1/name", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
hasAddress: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#hasAddress", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
countryName: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#country-name", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
locality: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#locality", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
postalCode: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#postal-code", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
region: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#region", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
streetAddress: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#street-address", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
hasEmail: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
Dom: "http://www.w3.org/2006/vcard/ns#Dom", |
||||
Home: "http://www.w3.org/2006/vcard/ns#Home", |
||||
ISDN: "http://www.w3.org/2006/vcard/ns#ISDN", |
||||
Internet: "http://www.w3.org/2006/vcard/ns#Internet", |
||||
Intl: "http://www.w3.org/2006/vcard/ns#Intl", |
||||
Label: "http://www.w3.org/2006/vcard/ns#Label", |
||||
Parcel: "http://www.w3.org/2006/vcard/ns#Parcel", |
||||
Postal: "http://www.w3.org/2006/vcard/ns#Postal", |
||||
Pref: "http://www.w3.org/2006/vcard/ns#Pref", |
||||
Work: "http://www.w3.org/2006/vcard/ns#Work", |
||||
X400: "http://www.w3.org/2006/vcard/ns#X400", |
||||
value: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#value", |
||||
"@type": "@id", |
||||
}, |
||||
hasPhoto: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#hasPhoto", |
||||
"@type": "@id", |
||||
}, |
||||
img: { |
||||
"@id": "http://xmlns.com/foaf/0.1/img", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
hasTelephone: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#hasTelephone", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
phone: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#phone", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
organizationName: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#organization-name", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
role: { |
||||
"@id": "http://www.w3.org/2006/vcard/ns#role", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
trustedApp: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#trustedApp", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
mode: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#mode", |
||||
"@container": "@set", |
||||
}, |
||||
Append: "http://www.w3.org/ns/auth/acl#Append", |
||||
Control: "http://www.w3.org/ns/auth/acl#Control", |
||||
Read: "http://www.w3.org/ns/auth/acl#Read", |
||||
Write: "http://www.w3.org/ns/auth/acl#Write", |
||||
origin: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#origin", |
||||
"@type": "@id", |
||||
}, |
||||
key: { |
||||
"@id": "http://www.w3.org/ns/auth/cert#key", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
modulus: { |
||||
"@id": "http://www.w3.org/ns/auth/cert#modulus", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
exponent: { |
||||
"@id": "http://www.w3.org/ns/auth/cert#exponent", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#integer", |
||||
}, |
||||
inbox: { |
||||
"@id": "http://www.w3.org/ns/ldp#inbox", |
||||
"@type": "@id", |
||||
}, |
||||
preferencesFile: { |
||||
"@id": "http://www.w3.org/ns/pim/space#preferencesFile", |
||||
"@type": "@id", |
||||
}, |
||||
storage: { |
||||
"@id": "http://www.w3.org/ns/pim/space#storage", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
account: { |
||||
"@id": "http://www.w3.org/ns/solid/terms#account", |
||||
"@type": "@id", |
||||
}, |
||||
privateTypeIndex: { |
||||
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
publicTypeIndex: { |
||||
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
knows: { |
||||
"@id": "http://xmlns.com/foaf/0.1/knows", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
}; |
@ -1,749 +0,0 @@ |
||||
import { Schema } from "shexj"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* solidProfileSchema: ShexJ Schema for solidProfile |
||||
* ============================================================================= |
||||
*/ |
||||
export const solidProfileSchema: Schema = { |
||||
type: "Schema", |
||||
shapes: [ |
||||
{ |
||||
id: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape", |
||||
type: "ShapeDecl", |
||||
shapeExpr: { |
||||
type: "Shape", |
||||
expression: { |
||||
type: "EachOf", |
||||
expressions: [ |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
values: ["http://schema.org/Person"], |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "Defines the node as a Person (from Schema.org)", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
values: ["http://xmlns.com/foaf/0.1/Person"], |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "Defines the node as a Person (from foaf)", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#fn", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The formatted name of a person. Example: John Smith", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://xmlns.com/foaf/0.1/name", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "An alternate way to define a person's name.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#hasAddress", |
||||
valueExpr: |
||||
"https://shaperepo.com/schemas/solidProfile#AddressShape", |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The person's street address.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#hasEmail", |
||||
valueExpr: |
||||
"https://shaperepo.com/schemas/solidProfile#EmailShape", |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The person's email.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#hasPhoto", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "A link to the person's photo", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://xmlns.com/foaf/0.1/img", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "Photo link but in string form", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#hasTelephone", |
||||
valueExpr: |
||||
"https://shaperepo.com/schemas/solidProfile#PhoneNumberShape", |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "Person's telephone number", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#phone", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"An alternative way to define a person's telephone number using a string", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#organization-name", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The name of the organization with which the person is affiliated", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#role", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The name of the person's role in their organization", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/auth/acl#trustedApp", |
||||
valueExpr: |
||||
"https://shaperepo.com/schemas/solidProfile#TrustedAppShape", |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"A list of app origins that are trusted by this user", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/auth/cert#key", |
||||
valueExpr: |
||||
"https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape", |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"A list of RSA public keys that are associated with private keys the user holds.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/ldp#inbox", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The user's LDP inbox to which apps can post notifications", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/pim/space#preferencesFile", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The user's preferences", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/pim/space#storage", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The location of a Solid storage server related to this WebId", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/solid/terms#account", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The user's account", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/solid/terms#privateTypeIndex", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"A registry of all types used on the user's Pod (for private access only)", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/solid/terms#publicTypeIndex", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"A registry of all types used on the user's Pod (for public access)", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://xmlns.com/foaf/0.1/knows", |
||||
valueExpr: |
||||
"https://shaperepo.com/schemas/solidProfile#SolidProfileShape", |
||||
min: 0, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"A list of WebIds for all the people this user knows.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"], |
||||
}, |
||||
}, |
||||
{ |
||||
id: "https://shaperepo.com/schemas/solidProfile#AddressShape", |
||||
type: "ShapeDecl", |
||||
shapeExpr: { |
||||
type: "Shape", |
||||
expression: { |
||||
type: "EachOf", |
||||
expressions: [ |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#country-name", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The name of the user's country of residence", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#locality", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The name of the user's locality (City, Town etc.) of residence", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#postal-code", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The user's postal code", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#region", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The name of the user's region (State, Province etc.) of residence", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#street-address", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The user's street address", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
id: "https://shaperepo.com/schemas/solidProfile#EmailShape", |
||||
type: "ShapeDecl", |
||||
shapeExpr: { |
||||
type: "Shape", |
||||
expression: { |
||||
type: "EachOf", |
||||
expressions: [ |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
values: [ |
||||
"http://www.w3.org/2006/vcard/ns#Dom", |
||||
"http://www.w3.org/2006/vcard/ns#Home", |
||||
"http://www.w3.org/2006/vcard/ns#ISDN", |
||||
"http://www.w3.org/2006/vcard/ns#Internet", |
||||
"http://www.w3.org/2006/vcard/ns#Intl", |
||||
"http://www.w3.org/2006/vcard/ns#Label", |
||||
"http://www.w3.org/2006/vcard/ns#Parcel", |
||||
"http://www.w3.org/2006/vcard/ns#Postal", |
||||
"http://www.w3.org/2006/vcard/ns#Pref", |
||||
"http://www.w3.org/2006/vcard/ns#Work", |
||||
"http://www.w3.org/2006/vcard/ns#X400", |
||||
], |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The type of email.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#value", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The value of an email as a mailto link (Example <mailto:jane@example.com>)", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"], |
||||
}, |
||||
}, |
||||
{ |
||||
id: "https://shaperepo.com/schemas/solidProfile#PhoneNumberShape", |
||||
type: "ShapeDecl", |
||||
shapeExpr: { |
||||
type: "Shape", |
||||
expression: { |
||||
type: "EachOf", |
||||
expressions: [ |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
values: [ |
||||
"http://www.w3.org/2006/vcard/ns#Dom", |
||||
"http://www.w3.org/2006/vcard/ns#Home", |
||||
"http://www.w3.org/2006/vcard/ns#ISDN", |
||||
"http://www.w3.org/2006/vcard/ns#Internet", |
||||
"http://www.w3.org/2006/vcard/ns#Intl", |
||||
"http://www.w3.org/2006/vcard/ns#Label", |
||||
"http://www.w3.org/2006/vcard/ns#Parcel", |
||||
"http://www.w3.org/2006/vcard/ns#Postal", |
||||
"http://www.w3.org/2006/vcard/ns#Pref", |
||||
"http://www.w3.org/2006/vcard/ns#Work", |
||||
"http://www.w3.org/2006/vcard/ns#X400", |
||||
], |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "They type of Phone Number", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/2006/vcard/ns#value", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"The value of a phone number as a tel link (Example <tel:555-555-5555>)", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"], |
||||
}, |
||||
}, |
||||
{ |
||||
id: "https://shaperepo.com/schemas/solidProfile#TrustedAppShape", |
||||
type: "ShapeDecl", |
||||
shapeExpr: { |
||||
type: "Shape", |
||||
expression: { |
||||
type: "EachOf", |
||||
expressions: [ |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/auth/acl#mode", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
values: [ |
||||
"http://www.w3.org/ns/auth/acl#Append", |
||||
"http://www.w3.org/ns/auth/acl#Control", |
||||
"http://www.w3.org/ns/auth/acl#Read", |
||||
"http://www.w3.org/ns/auth/acl#Write", |
||||
], |
||||
}, |
||||
min: 1, |
||||
max: -1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The level of access provided to this origin", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/auth/acl#origin", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The app origin the user trusts", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
id: "https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape", |
||||
type: "ShapeDecl", |
||||
shapeExpr: { |
||||
type: "Shape", |
||||
expression: { |
||||
type: "EachOf", |
||||
expressions: [ |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/auth/cert#modulus", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "RSA Modulus", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/ns/auth/cert#exponent", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#integer", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "RSA Exponent", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
], |
||||
}; |
@ -1,71 +0,0 @@ |
||||
import { ShapeType } from "@ldo/ldo"; |
||||
import { solidProfileSchema } from "./solidProfile.schema"; |
||||
import { solidProfileContext } from "./solidProfile.context"; |
||||
import { |
||||
SolidProfileShape, |
||||
AddressShape, |
||||
EmailShape, |
||||
PhoneNumberShape, |
||||
TrustedAppShape, |
||||
RSAPublicKeyShape, |
||||
} from "./solidProfile.typings"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* LDO ShapeTypes solidProfile |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* SolidProfileShape ShapeType |
||||
*/ |
||||
export const SolidProfileShapeShapeType: ShapeType<SolidProfileShape> = { |
||||
schema: solidProfileSchema, |
||||
shape: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape", |
||||
context: solidProfileContext, |
||||
}; |
||||
|
||||
/** |
||||
* AddressShape ShapeType |
||||
*/ |
||||
export const AddressShapeShapeType: ShapeType<AddressShape> = { |
||||
schema: solidProfileSchema, |
||||
shape: "https://shaperepo.com/schemas/solidProfile#AddressShape", |
||||
context: solidProfileContext, |
||||
}; |
||||
|
||||
/** |
||||
* EmailShape ShapeType |
||||
*/ |
||||
export const EmailShapeShapeType: ShapeType<EmailShape> = { |
||||
schema: solidProfileSchema, |
||||
shape: "https://shaperepo.com/schemas/solidProfile#EmailShape", |
||||
context: solidProfileContext, |
||||
}; |
||||
|
||||
/** |
||||
* PhoneNumberShape ShapeType |
||||
*/ |
||||
export const PhoneNumberShapeShapeType: ShapeType<PhoneNumberShape> = { |
||||
schema: solidProfileSchema, |
||||
shape: "https://shaperepo.com/schemas/solidProfile#PhoneNumberShape", |
||||
context: solidProfileContext, |
||||
}; |
||||
|
||||
/** |
||||
* TrustedAppShape ShapeType |
||||
*/ |
||||
export const TrustedAppShapeShapeType: ShapeType<TrustedAppShape> = { |
||||
schema: solidProfileSchema, |
||||
shape: "https://shaperepo.com/schemas/solidProfile#TrustedAppShape", |
||||
context: solidProfileContext, |
||||
}; |
||||
|
||||
/** |
||||
* RSAPublicKeyShape ShapeType |
||||
*/ |
||||
export const RSAPublicKeyShapeShapeType: ShapeType<RSAPublicKeyShape> = { |
||||
schema: solidProfileSchema, |
||||
shape: "https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape", |
||||
context: solidProfileContext, |
||||
}; |
@ -1,293 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* Typescript Typings for solidProfile |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* SolidProfileShape Type |
||||
*/ |
||||
export interface SolidProfileShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* Defines the node as a Person (from Schema.org) | Defines the node as a Person (from foaf) |
||||
*/ |
||||
type: ( |
||||
| { |
||||
"@id": "Person"; |
||||
} |
||||
| { |
||||
"@id": "Person2"; |
||||
} |
||||
)[]; |
||||
/** |
||||
* The formatted name of a person. Example: John Smith |
||||
*/ |
||||
fn?: string; |
||||
/** |
||||
* An alternate way to define a person's name. |
||||
*/ |
||||
name?: string; |
||||
/** |
||||
* The person's street address. |
||||
*/ |
||||
hasAddress?: AddressShape[]; |
||||
/** |
||||
* The person's email. |
||||
*/ |
||||
hasEmail?: EmailShape[]; |
||||
/** |
||||
* A link to the person's photo |
||||
*/ |
||||
hasPhoto?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* Photo link but in string form |
||||
*/ |
||||
img?: string; |
||||
/** |
||||
* Person's telephone number |
||||
*/ |
||||
hasTelephone?: PhoneNumberShape[]; |
||||
/** |
||||
* An alternative way to define a person's telephone number using a string |
||||
*/ |
||||
phone?: string; |
||||
/** |
||||
* The name of the organization with which the person is affiliated |
||||
*/ |
||||
organizationName?: string; |
||||
/** |
||||
* The name of the person's role in their organization |
||||
*/ |
||||
role?: string; |
||||
/** |
||||
* A list of app origins that are trusted by this user |
||||
*/ |
||||
trustedApp?: TrustedAppShape[]; |
||||
/** |
||||
* A list of RSA public keys that are associated with private keys the user holds. |
||||
*/ |
||||
key?: RSAPublicKeyShape[]; |
||||
/** |
||||
* The user's LDP inbox to which apps can post notifications |
||||
*/ |
||||
inbox: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* The user's preferences |
||||
*/ |
||||
preferencesFile?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* The location of a Solid storage server related to this WebId |
||||
*/ |
||||
storage?: { |
||||
"@id": string; |
||||
}[]; |
||||
/** |
||||
* The user's account |
||||
*/ |
||||
account?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* A registry of all types used on the user's Pod (for private access only) |
||||
*/ |
||||
privateTypeIndex?: { |
||||
"@id": string; |
||||
}[]; |
||||
/** |
||||
* A registry of all types used on the user's Pod (for public access) |
||||
*/ |
||||
publicTypeIndex?: { |
||||
"@id": string; |
||||
}[]; |
||||
/** |
||||
* A list of WebIds for all the people this user knows. |
||||
*/ |
||||
knows?: SolidProfileShape[]; |
||||
} |
||||
|
||||
/** |
||||
* AddressShape Type |
||||
*/ |
||||
export interface AddressShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* The name of the user's country of residence |
||||
*/ |
||||
countryName?: string; |
||||
/** |
||||
* The name of the user's locality (City, Town etc.) of residence |
||||
*/ |
||||
locality?: string; |
||||
/** |
||||
* The user's postal code |
||||
*/ |
||||
postalCode?: string; |
||||
/** |
||||
* The name of the user's region (State, Province etc.) of residence |
||||
*/ |
||||
region?: string; |
||||
/** |
||||
* The user's street address |
||||
*/ |
||||
streetAddress?: string; |
||||
} |
||||
|
||||
/** |
||||
* EmailShape Type |
||||
*/ |
||||
export interface EmailShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* The type of email. |
||||
*/ |
||||
type?: |
||||
| { |
||||
"@id": "Dom"; |
||||
} |
||||
| { |
||||
"@id": "Home"; |
||||
} |
||||
| { |
||||
"@id": "ISDN"; |
||||
} |
||||
| { |
||||
"@id": "Internet"; |
||||
} |
||||
| { |
||||
"@id": "Intl"; |
||||
} |
||||
| { |
||||
"@id": "Label"; |
||||
} |
||||
| { |
||||
"@id": "Parcel"; |
||||
} |
||||
| { |
||||
"@id": "Postal"; |
||||
} |
||||
| { |
||||
"@id": "Pref"; |
||||
} |
||||
| { |
||||
"@id": "Work"; |
||||
} |
||||
| { |
||||
"@id": "X400"; |
||||
}; |
||||
/** |
||||
* The value of an email as a mailto link (Example <mailto:jane@example.com>) |
||||
*/ |
||||
value: { |
||||
"@id": string; |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* PhoneNumberShape Type |
||||
*/ |
||||
export interface PhoneNumberShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* They type of Phone Number |
||||
*/ |
||||
type?: |
||||
| { |
||||
"@id": "Dom"; |
||||
} |
||||
| { |
||||
"@id": "Home"; |
||||
} |
||||
| { |
||||
"@id": "ISDN"; |
||||
} |
||||
| { |
||||
"@id": "Internet"; |
||||
} |
||||
| { |
||||
"@id": "Intl"; |
||||
} |
||||
| { |
||||
"@id": "Label"; |
||||
} |
||||
| { |
||||
"@id": "Parcel"; |
||||
} |
||||
| { |
||||
"@id": "Postal"; |
||||
} |
||||
| { |
||||
"@id": "Pref"; |
||||
} |
||||
| { |
||||
"@id": "Work"; |
||||
} |
||||
| { |
||||
"@id": "X400"; |
||||
}; |
||||
/** |
||||
* The value of a phone number as a tel link (Example <tel:555-555-5555>) |
||||
*/ |
||||
value: { |
||||
"@id": string; |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* TrustedAppShape Type |
||||
*/ |
||||
export interface TrustedAppShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* The level of access provided to this origin |
||||
*/ |
||||
mode: ( |
||||
| { |
||||
"@id": "Append"; |
||||
} |
||||
| { |
||||
"@id": "Control"; |
||||
} |
||||
| { |
||||
"@id": "Read"; |
||||
} |
||||
| { |
||||
"@id": "Write"; |
||||
} |
||||
)[]; |
||||
/** |
||||
* The app origin the user trusts |
||||
*/ |
||||
origin: { |
||||
"@id": string; |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* RSAPublicKeyShape Type |
||||
*/ |
||||
export interface RSAPublicKeyShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* RSA Modulus |
||||
*/ |
||||
modulus: string; |
||||
/** |
||||
* RSA Exponent |
||||
*/ |
||||
exponent: number; |
||||
} |
@ -1,23 +0,0 @@ |
||||
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> |
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> |
||||
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> |
||||
PREFIX ex: <https://example.com/> |
||||
BASE <http://schema.org/> |
||||
|
||||
ex:PostSh { |
||||
a [<SocialMediaPosting> <CreativeWork> <Thing>] ; |
||||
<articleBody> xsd:string? |
||||
// rdfs:label '''articleBody''' |
||||
// rdfs:comment '''The actual body of the article. ''' ; |
||||
<uploadDate> xsd:date |
||||
// rdfs:label '''uploadDate''' |
||||
// rdfs:comment '''Date when this media object was uploaded to this site.''' ; |
||||
<image> IRI ? |
||||
// rdfs:label '''image''' |
||||
// rdfs:comment '''A media object that encodes this CreativeWork. This property is a synonym for encoding.''' ; |
||||
<publisher> IRI |
||||
// rdfs:label '''publisher''' |
||||
// rdfs:comment '''The publisher of the creative work.''' ; |
||||
} |
||||
// rdfs:label '''SocialMediaPost''' |
||||
// rdfs:comment '''A post to a social media platform, including blog posts, tweets, Facebook posts, etc.''' |
@ -1,121 +0,0 @@ |
||||
PREFIX srs: <https://shaperepo.com/schemas/solidProfile#> |
||||
PREFIX foaf: <http://xmlns.com/foaf/0.1/> |
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> |
||||
PREFIX schem: <http://schema.org/> |
||||
PREFIX vcard: <http://www.w3.org/2006/vcard/ns#> |
||||
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> |
||||
PREFIX acl: <http://www.w3.org/ns/auth/acl#> |
||||
PREFIX cert: <http://www.w3.org/ns/auth/cert#> |
||||
PREFIX ldp: <http://www.w3.org/ns/ldp#> |
||||
PREFIX sp: <http://www.w3.org/ns/pim/space#> |
||||
PREFIX solid: <http://www.w3.org/ns/solid/terms#> |
||||
|
||||
srs:SolidProfileShape EXTRA a { |
||||
a [ schem:Person ] |
||||
// rdfs:comment "Defines the node as a Person (from Schema.org)" ; |
||||
a [ foaf:Person ] |
||||
// rdfs:comment "Defines the node as a Person (from foaf)" ; |
||||
vcard:fn xsd:string ? |
||||
// rdfs:comment "The formatted name of a person. Example: John Smith" ; |
||||
foaf:name xsd:string ? |
||||
// rdfs:comment "An alternate way to define a person's name." ; |
||||
vcard:hasAddress @srs:AddressShape * |
||||
// rdfs:comment "The person's street address." ; |
||||
vcard:hasEmail @srs:EmailShape * |
||||
// rdfs:comment "The person's email." ; |
||||
vcard:hasPhoto IRI ? |
||||
// rdfs:comment "A link to the person's photo" ; |
||||
foaf:img xsd:string ? |
||||
// rdfs:comment "Photo link but in string form" ; |
||||
vcard:hasTelephone @srs:PhoneNumberShape * |
||||
// rdfs:comment "Person's telephone number" ; |
||||
vcard:phone xsd:string ? |
||||
// rdfs:comment "An alternative way to define a person's telephone number using a string" ; |
||||
vcard:organization-name xsd:string ? |
||||
// rdfs:comment "The name of the organization with which the person is affiliated" ; |
||||
vcard:role xsd:string ? |
||||
// rdfs:comment "The name of the person's role in their organization" ; |
||||
acl:trustedApp @srs:TrustedAppShape * |
||||
// rdfs:comment "A list of app origins that are trusted by this user" ; |
||||
cert:key @srs:RSAPublicKeyShape * |
||||
// rdfs:comment "A list of RSA public keys that are associated with private keys the user holds." ; |
||||
ldp:inbox IRI |
||||
// rdfs:comment "The user's LDP inbox to which apps can post notifications" ; |
||||
sp:preferencesFile IRI ? |
||||
// rdfs:comment "The user's preferences" ; |
||||
sp:storage IRI * |
||||
// rdfs:comment "The location of a Solid storage server related to this WebId" ; |
||||
solid:account IRI ? |
||||
// rdfs:comment "The user's account" ; |
||||
solid:privateTypeIndex IRI * |
||||
// rdfs:comment "A registry of all types used on the user's Pod (for private access only)" ; |
||||
solid:publicTypeIndex IRI * |
||||
// rdfs:comment "A registry of all types used on the user's Pod (for public access)" ; |
||||
foaf:knows @srs:SolidProfileShape * |
||||
// rdfs:comment "A list of WebIds for all the people this user knows." ; |
||||
} |
||||
|
||||
srs:AddressShape { |
||||
vcard:country-name xsd:string ? |
||||
// rdfs:comment "The name of the user's country of residence" ; |
||||
vcard:locality xsd:string ? |
||||
// rdfs:comment "The name of the user's locality (City, Town etc.) of residence" ; |
||||
vcard:postal-code xsd:string ? |
||||
// rdfs:comment "The user's postal code" ; |
||||
vcard:region xsd:string ? |
||||
// rdfs:comment "The name of the user's region (State, Province etc.) of residence" ; |
||||
vcard:street-address xsd:string ? |
||||
// rdfs:comment "The user's street address" ; |
||||
} |
||||
|
||||
srs:EmailShape EXTRA a { |
||||
a [ |
||||
vcard:Dom |
||||
vcard:Home |
||||
vcard:ISDN |
||||
vcard:Internet |
||||
vcard:Intl |
||||
vcard:Label |
||||
vcard:Parcel |
||||
vcard:Postal |
||||
vcard:Pref |
||||
vcard:Work |
||||
vcard:X400 |
||||
] ? |
||||
// rdfs:comment "The type of email." ; |
||||
vcard:value IRI |
||||
// rdfs:comment "The value of an email as a mailto link (Example <mailto:jane@example.com>)" ; |
||||
} |
||||
|
||||
srs:PhoneNumberShape EXTRA a { |
||||
a [ |
||||
vcard:Dom |
||||
vcard:Home |
||||
vcard:ISDN |
||||
vcard:Internet |
||||
vcard:Intl |
||||
vcard:Label |
||||
vcard:Parcel |
||||
vcard:Postal |
||||
vcard:Pref |
||||
vcard:Work |
||||
vcard:X400 |
||||
] ? |
||||
// rdfs:comment "They type of Phone Number" ; |
||||
vcard:value IRI |
||||
// rdfs:comment "The value of a phone number as a tel link (Example <tel:555-555-5555>)" ; |
||||
} |
||||
|
||||
srs:TrustedAppShape { |
||||
acl:mode [acl:Append acl:Control acl:Read acl:Write] + |
||||
// rdfs:comment "The level of access provided to this origin" ; |
||||
acl:origin IRI |
||||
// rdfs:comment "The app origin the user trusts" |
||||
} |
||||
|
||||
srs:RSAPublicKeyShape { |
||||
cert:modulus xsd:string |
||||
// rdfs:comment "RSA Modulus" ; |
||||
cert:exponent xsd:integer |
||||
// rdfs:comment "RSA Exponent" ; |
||||
} |
@ -1,13 +0,0 @@ |
||||
import type { FunctionComponent } from "react"; |
||||
import React from "react"; |
||||
import { Router } from "./Layout"; |
||||
import { BrowserSolidLdoProvider } from "@ldo/solid-react"; |
||||
|
||||
const ProfileApp: FunctionComponent = () => { |
||||
return ( |
||||
<BrowserSolidLdoProvider> |
||||
<Router /> |
||||
</BrowserSolidLdoProvider> |
||||
); |
||||
}; |
||||
export default ProfileApp; |
@ -1,65 +0,0 @@ |
||||
import type { FunctionComponent } from "react"; |
||||
import React, { useCallback } from "react"; |
||||
import { |
||||
BrowserSolidLdoProvider, |
||||
useResource, |
||||
useSolidAuth, |
||||
useSubject, |
||||
} from "@ldo/solid-react"; |
||||
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; |
||||
import { changeData, commitData } from "@ldo/solid"; |
||||
|
||||
// The base component for the app
|
||||
const App: FunctionComponent = () => { |
||||
return ( |
||||
/* The application should be surrounded with the BrowserSolidLdoProvider |
||||
this will set up all the underlying infrastructure for the application */ |
||||
<BrowserSolidLdoProvider> |
||||
<Login /> |
||||
</BrowserSolidLdoProvider> |
||||
); |
||||
}; |
||||
|
||||
// A component that handles login
|
||||
const Login: FunctionComponent = () => { |
||||
// Get login information using the "useSolidAuth" hook
|
||||
const { login, logout, session } = useSolidAuth(); |
||||
|
||||
const onLogin = useCallback(() => { |
||||
const issuer = prompt("What is your Solid IDP?"); |
||||
// Call the "login" function to initiate login
|
||||
if (issuer) login(issuer); |
||||
}, []); |
||||
|
||||
// You can use session.isLoggedIn to check if the user is logged in
|
||||
if (session.isLoggedIn) { |
||||
return ( |
||||
<div> |
||||
{/* Get the user's webId from session.webId */} |
||||
<p>Logged in as {session.webId}</p> |
||||
{/* Use the logout function to log out */} |
||||
<button onClick={logout}>Log Out</button> |
||||
<Profile /> |
||||
</div> |
||||
); |
||||
} |
||||
return <button onClick={onLogin}>Log In</button>; |
||||
}; |
||||
|
||||
const Profile: FunctionComponent = () => { |
||||
const { session } = useSolidAuth(); |
||||
const resource = useResource(session.webId); |
||||
const profile = useSubject(SolidProfileShapeShapeType, session.webId); |
||||
|
||||
const onNameChange = useCallback(async (e) => { |
||||
// Ensure that the
|
||||
if (!profile || !resource) return; |
||||
const cProfile = changeData(profile, resource); |
||||
cProfile.name = e.target.value; |
||||
await commitData(cProfile); |
||||
}, []); |
||||
|
||||
return <input type="text" value={profile?.name} onChange={onNameChange} />; |
||||
}; |
||||
|
||||
export default App; |
@ -1,54 +0,0 @@ |
||||
import { useState } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import React from "react"; |
||||
import { useResource, useSolidAuth, useSubject } from "@ldo/solid-react"; |
||||
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; |
||||
import { Link } from "react-router-dom"; |
||||
|
||||
const DEFAULT_ISSUER = "https://solidweb.me"; |
||||
|
||||
export const LoggedInHeader: FunctionComponent<{ webId: string }> = ({ |
||||
webId, |
||||
}) => { |
||||
const webIdResource = useResource(webId); |
||||
const profile = useSubject(SolidProfileShapeShapeType, webId); |
||||
const { logout } = useSolidAuth(); |
||||
return ( |
||||
<> |
||||
<span> |
||||
Logged in as {webId}. Welcome{" "} |
||||
{webIdResource.isReading() ? "LOADING NAME" : profile.fn} |
||||
</span> |
||||
<button onClick={logout}>Log Out</button> |
||||
</> |
||||
); |
||||
}; |
||||
|
||||
export const Header: FunctionComponent = () => { |
||||
const [issuer, setIssuer] = useState(DEFAULT_ISSUER); |
||||
const { login, signUp, session } = useSolidAuth(); |
||||
return ( |
||||
<header> |
||||
<div style={{ display: "flex" }}> |
||||
{session.isLoggedIn ? ( |
||||
<LoggedInHeader webId={session.webId!} /> |
||||
) : ( |
||||
<> |
||||
<input |
||||
type="text" |
||||
value={issuer} |
||||
onChange={(e) => setIssuer(e.target.value)} |
||||
/> |
||||
<button onClick={() => login(issuer)}>Log In</button> |
||||
<button onClick={() => signUp(issuer)}>Sign Up</button> |
||||
</> |
||||
)} |
||||
</div> |
||||
<p> |
||||
<Link to="/">Blog</Link> |
||||
{" "} |
||||
<Link to="/profile">Profile</Link> |
||||
</p> |
||||
</header> |
||||
); |
||||
}; |
@ -1,50 +0,0 @@ |
||||
import { useSolidAuth } from "@ldo/solid-react"; |
||||
import React, { Fragment } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { createBrowserRouter, Outlet, RouterProvider } from "react-router-dom"; |
||||
import { Blog } from "./blog/Blog"; |
||||
import { PostPage } from "./post/PostPage"; |
||||
import { Header } from "./Header"; |
||||
import { MainContainerProvider } from "./MainContainerProvider"; |
||||
import { Profile } from "./profile/Profile"; |
||||
|
||||
export const Layout: FunctionComponent = () => { |
||||
const { session } = useSolidAuth(); |
||||
return ( |
||||
<div> |
||||
<Header /> |
||||
<hr /> |
||||
<MainContainerProvider> |
||||
{session.isLoggedIn ? <Outlet /> : <Fragment />} |
||||
</MainContainerProvider> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
const router = createBrowserRouter([ |
||||
{ |
||||
element: <Layout />, |
||||
children: [ |
||||
{ |
||||
path: "/", |
||||
element: <Blog />, |
||||
}, |
||||
{ |
||||
path: "/media/:uri", |
||||
element: <PostPage />, |
||||
}, |
||||
{ |
||||
path: "/profile", |
||||
element: <Profile />, |
||||
}, |
||||
], |
||||
}, |
||||
]); |
||||
|
||||
export const Router: FunctionComponent = () => { |
||||
const { ranInitialAuthCheck } = useSolidAuth(); |
||||
if (!ranInitialAuthCheck) { |
||||
return <p>Loading</p>; |
||||
} |
||||
return <RouterProvider router={router} />; |
||||
}; |
@ -1,67 +0,0 @@ |
||||
import React, { useState, useEffect, createContext } from "react"; |
||||
import type { FunctionComponent, PropsWithChildren } from "react"; |
||||
import type { Container, LeafUri } from "@ldo/solid"; |
||||
import { useSolidAuth, useLdo, useResource } from "@ldo/solid-react"; |
||||
|
||||
export const MainContainerContext = createContext<Container | undefined>( |
||||
undefined, |
||||
); |
||||
|
||||
const MainContainerSubProvider: FunctionComponent< |
||||
PropsWithChildren<{ uri?: string }> |
||||
> = ({ uri, children }) => { |
||||
const mainContainer = useResource(uri); |
||||
return ( |
||||
<MainContainerContext.Provider value={mainContainer as Container}> |
||||
{children} |
||||
</MainContainerContext.Provider> |
||||
); |
||||
}; |
||||
|
||||
export const MainContainerProvider: FunctionComponent<PropsWithChildren> = ({ |
||||
children, |
||||
}) => { |
||||
const [mainContainer, setMainContainer] = useState<Container | undefined>(); |
||||
const { session } = useSolidAuth(); |
||||
const { getResource } = useLdo(); |
||||
|
||||
useEffect(() => { |
||||
if (session.webId) { |
||||
const webIdResource = getResource(session.webId as LeafUri); |
||||
webIdResource.getRootContainer().then(async (rootContainer) => { |
||||
if (rootContainer.isError) { |
||||
alert(rootContainer.message); |
||||
return; |
||||
} |
||||
const mainContainer = getResource(`${rootContainer.uri}demo-react/`); |
||||
setMainContainer(mainContainer); |
||||
const createResult = await mainContainer.createIfAbsent(); |
||||
// Only set the access rules if the create was a success.
|
||||
if (createResult.type === "createSuccess") { |
||||
await mainContainer.setAccessRules({ |
||||
public: { |
||||
read: true, |
||||
write: false, |
||||
append: false, |
||||
control: false, |
||||
}, |
||||
agent: { |
||||
[session.webId!]: { |
||||
read: true, |
||||
write: true, |
||||
append: true, |
||||
control: true, |
||||
}, |
||||
}, |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
}, [session.webId]); |
||||
|
||||
return ( |
||||
<MainContainerSubProvider uri={mainContainer?.uri}> |
||||
{children} |
||||
</MainContainerSubProvider> |
||||
); |
||||
}; |
@ -1,30 +0,0 @@ |
||||
import React, { Fragment, useContext } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { MainContainerContext } from "../MainContainerProvider"; |
||||
import { Post } from "../post/Post"; |
||||
import { MakePost } from "./MakePost"; |
||||
|
||||
export const Blog: FunctionComponent = () => { |
||||
const mainContainer = useContext(MainContainerContext); |
||||
if (mainContainer === undefined) { |
||||
return <p>Loading...</p>; |
||||
} |
||||
if (mainContainer.isDoingInitialFetch()) { |
||||
return <p>Loading Blob</p>; |
||||
} |
||||
|
||||
return ( |
||||
<div> |
||||
<div> |
||||
<MakePost mainContainer={mainContainer} /> |
||||
</div> |
||||
<hr /> |
||||
{mainContainer.children().map((child) => ( |
||||
<Fragment key={child.uri}> |
||||
<Post uri={child.uri} /> |
||||
<hr /> |
||||
</Fragment> |
||||
))} |
||||
</div> |
||||
); |
||||
}; |
@ -1,92 +0,0 @@ |
||||
import React, { useCallback, useState, useRef } from "react"; |
||||
import type { FunctionComponent, FormEvent } from "react"; |
||||
import type { Container, Leaf, LeafUri } from "@ldo/solid"; |
||||
import { v4 } from "uuid"; |
||||
import { useLdo, useSolidAuth } from "@ldo/solid-react"; |
||||
import { PostShShapeType } from "../.ldo/post.shapeTypes"; |
||||
|
||||
export const MakePost: FunctionComponent<{ mainContainer: Container }> = ({ |
||||
mainContainer, |
||||
}) => { |
||||
const [message, setMessage] = useState(""); |
||||
const [selectedFile, setSelectedFile] = useState<File | undefined>(); |
||||
const fileInputRef = useRef<HTMLInputElement | null>(null); |
||||
const { createData, commitData } = useLdo(); |
||||
const { session } = useSolidAuth(); |
||||
const onSubmit = useCallback( |
||||
async (e: FormEvent<HTMLFormElement>) => { |
||||
e.preventDefault(); |
||||
|
||||
// Create the container file
|
||||
const mediaContainerResult = await mainContainer.createChildAndOverwrite( |
||||
`${v4()}/`, |
||||
); |
||||
if (mediaContainerResult.isError) { |
||||
alert(mediaContainerResult.message); |
||||
return; |
||||
} |
||||
const mediaContainer = mediaContainerResult.resource; |
||||
|
||||
// Upload Image
|
||||
let uploadedImage: Leaf | undefined; |
||||
if (selectedFile) { |
||||
const result = await mediaContainer.uploadChildAndOverwrite( |
||||
selectedFile.name as LeafUri, |
||||
selectedFile, |
||||
selectedFile.type, |
||||
); |
||||
if (result.isError) { |
||||
alert(result.message); |
||||
await mediaContainer.delete(); |
||||
return; |
||||
} |
||||
uploadedImage = result.resource; |
||||
} |
||||
|
||||
// Create Post
|
||||
const indexResource = mediaContainer.child("index.ttl"); |
||||
const post = createData( |
||||
PostShShapeType, |
||||
indexResource.uri, |
||||
indexResource, |
||||
); |
||||
post.articleBody = message; |
||||
if (uploadedImage) { |
||||
post.image = { "@id": uploadedImage.uri }; |
||||
} |
||||
if (session.webId) { |
||||
post.publisher = { "@id": session.webId }; |
||||
} |
||||
post.type = { "@id": "SocialMediaPosting" }; |
||||
post.uploadDate = new Date().toISOString(); |
||||
const result = await commitData(post); |
||||
if (result.isError) { |
||||
alert(result.message); |
||||
} |
||||
|
||||
// Clear the UI after Upload
|
||||
setMessage(""); |
||||
setSelectedFile(undefined); |
||||
if (fileInputRef.current) fileInputRef.current.value = ""; |
||||
}, |
||||
[message, selectedFile, session.webId], |
||||
); |
||||
|
||||
return ( |
||||
<form onSubmit={onSubmit}> |
||||
<input |
||||
type="text" |
||||
placeholder="Make a Post" |
||||
value={message} |
||||
onChange={(e) => setMessage(e.target.value)} |
||||
/> |
||||
<input |
||||
type="file" |
||||
accept="image/*" |
||||
ref={fileInputRef} |
||||
onChange={(e) => setSelectedFile(e.target.files?.[0])} |
||||
/> |
||||
<input type="submit" value="Post" /> |
||||
</form> |
||||
); |
||||
}; |
@ -1,8 +0,0 @@ |
||||
import React from "react"; |
||||
import ReactDOM from "react-dom/client"; |
||||
import App from "./App"; |
||||
|
||||
const root = ReactDOM.createRoot( |
||||
document.getElementById("root") as HTMLElement, |
||||
); |
||||
root.render(<App />); |
@ -1,42 +0,0 @@ |
||||
import React, { useCallback } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { useLdo, useResource, useSubject } from "@ldo/solid-react"; |
||||
import { PostShShapeType } from "../.ldo/post.shapeTypes"; |
||||
import { useNavigate } from "react-router-dom"; |
||||
import { PostedBy } from "./PostedBy"; |
||||
|
||||
export const Post: FunctionComponent<{ uri: string }> = ({ uri }) => { |
||||
const navigate = useNavigate(); |
||||
const mediaResource = useResource(`${uri}index.ttl`); |
||||
const post = useSubject(PostShShapeType, mediaResource.uri); |
||||
const { getResource } = useLdo(); |
||||
const deletePost = useCallback(async () => { |
||||
const postContainer = getResource(uri); |
||||
const result = await postContainer.delete(); |
||||
if (result.isError) { |
||||
alert(result.message); |
||||
} |
||||
}, [uri]); |
||||
|
||||
if (mediaResource.isReading()) { |
||||
return <p>Loading Post...</p>; |
||||
} else if (mediaResource.status.isError) { |
||||
return <p>Error: {mediaResource.status.message}</p>; |
||||
} else if (mediaResource.isAbsent()) { |
||||
return <p>Post does not exist.</p>; |
||||
} |
||||
|
||||
return ( |
||||
<div> |
||||
{post.publisher?.["@id"] && <PostedBy webId={post.publisher["@id"]} />} |
||||
<div |
||||
onClick={() => navigate(`/media/${encodeURIComponent(uri)}`)} |
||||
style={{ cursor: "pointer" }} |
||||
> |
||||
{post.articleBody && <p>{post.articleBody}</p>} |
||||
{post.image && <img src={post.image["@id"]} style={{ height: 300 }} />} |
||||
</div> |
||||
<button onClick={deletePost}>Delete Post</button> |
||||
</div> |
||||
); |
||||
}; |
@ -1,16 +0,0 @@ |
||||
import React from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { useNavigate, useParams } from "react-router-dom"; |
||||
import { Post } from "./Post"; |
||||
|
||||
export const PostPage: FunctionComponent = () => { |
||||
const navigate = useNavigate(); |
||||
const { uri } = useParams(); |
||||
|
||||
return ( |
||||
<div> |
||||
<button onClick={() => navigate("/")}>Back to Feed</button> |
||||
{uri ? <Post uri={uri} /> : <p>No URI Present</p>} |
||||
</div> |
||||
); |
||||
}; |
@ -1,16 +0,0 @@ |
||||
import type { FunctionComponent } from "react"; |
||||
import React from "react"; |
||||
import { useResource, useSubject } from "@ldo/solid-react"; |
||||
import { SolidProfileShapeShapeType } from "../.ldo/solidProfile.shapeTypes"; |
||||
|
||||
export const PostedBy: FunctionComponent<{ webId: string }> = ({ webId }) => { |
||||
const webIdResource = useResource(webId); |
||||
const profile = useSubject(SolidProfileShapeShapeType, webId); |
||||
|
||||
if (webIdResource.isReading()) { |
||||
return <p>Loading Profile...</p>; |
||||
} else if (webIdResource.status.isError) { |
||||
return <p>Error: {webIdResource.status.message}</p>; |
||||
} |
||||
return <p>Posted By: {profile.fn}</p>; |
||||
}; |
@ -1,34 +0,0 @@ |
||||
import { |
||||
useLdo, |
||||
useResource, |
||||
useSolidAuth, |
||||
useSubject, |
||||
} from "@ldo/solid-react"; |
||||
import type { ChangeEvent } from "react"; |
||||
import React, { useCallback, type FunctionComponent } from "react"; |
||||
import { SolidProfileShapeShapeType } from "../.ldo/solidProfile.shapeTypes"; |
||||
|
||||
export const Profile: FunctionComponent = () => { |
||||
const { session } = useSolidAuth(); |
||||
const profile = useSubject(SolidProfileShapeShapeType, session.webId); |
||||
const webIdResource = useResource(session.webId); |
||||
const { changeData, commitData } = useLdo(); |
||||
|
||||
const onNameChange = useCallback( |
||||
async (e: ChangeEvent<HTMLInputElement>) => { |
||||
if (profile && webIdResource) { |
||||
const cProfile = changeData(profile, webIdResource); |
||||
cProfile.fn = e.target.value; |
||||
await commitData(cProfile); |
||||
} |
||||
}, |
||||
[profile, webIdResource], |
||||
); |
||||
|
||||
return ( |
||||
<> |
||||
<label>Name</label> |
||||
<input type="text" value={profile?.fn || ""} onChange={onNameChange} /> |
||||
</> |
||||
); |
||||
}; |
@ -1,20 +0,0 @@ |
||||
{ |
||||
"extends": "../../tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "./dist", |
||||
"lib": ["dom", "dom.iterable", "esnext"], |
||||
"allowJs": true, |
||||
"skipLibCheck": true, |
||||
"allowSyntheticDefaultImports": true, |
||||
"forceConsistentCasingInFileNames": true, |
||||
"noFallthroughCasesInSwitch": true, |
||||
"moduleResolution": "node", |
||||
"resolveJsonModule": true, |
||||
"isolatedModules": true, |
||||
"noEmit": true, |
||||
"jsx": "react-jsx" |
||||
}, |
||||
"include": [ |
||||
"./src" |
||||
] |
||||
} |
@ -0,0 +1,45 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* wacContext: JSONLD Context for wac |
||||
* ============================================================================= |
||||
*/ |
||||
export const wacContext: ContextDefinition = { |
||||
type: { |
||||
"@id": "@type", |
||||
}, |
||||
Authorization: "http://www.w3.org/ns/auth/acl#Authorization", |
||||
accessTo: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#accessTo", |
||||
"@type": "@id", |
||||
}, |
||||
default: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#default", |
||||
"@type": "@id", |
||||
}, |
||||
agent: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#agent", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
agentGroup: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#agentGroup", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
agentClass: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#agentClass", |
||||
"@container": "@set", |
||||
}, |
||||
AuthenticatedAgent: "http://www.w3.org/ns/auth/acl#AuthenticatedAgent", |
||||
Agent: "http://xmlns.com/foaf/0.1/Agent", |
||||
mode: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#mode", |
||||
"@container": "@set", |
||||
}, |
||||
Read: "http://www.w3.org/ns/auth/acl#Read", |
||||
Write: "http://www.w3.org/ns/auth/acl#Write", |
||||
Append: "http://www.w3.org/ns/auth/acl#Append", |
||||
Control: "http://www.w3.org/ns/auth/acl#Control", |
||||
}; |
@ -0,0 +1,19 @@ |
||||
import { ShapeType } from "@ldo/ldo"; |
||||
import { wacSchema } from "./wac.schema"; |
||||
import { wacContext } from "./wac.context"; |
||||
import { Authorization } from "./wac.typings"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* LDO ShapeTypes wac |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* Authorization ShapeType |
||||
*/ |
||||
export const AuthorizationShapeType: ShapeType<Authorization> = { |
||||
schema: wacSchema, |
||||
shape: "http://www.w3.org/ns/auth/acls#Authorization", |
||||
context: wacContext, |
||||
}; |
@ -0,0 +1,73 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* Typescript Typings for wac |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* Authorization Type |
||||
*/ |
||||
export interface Authorization { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* Denotes this as an acl:Authorization |
||||
*/ |
||||
type: { |
||||
"@id": "Authorization"; |
||||
}; |
||||
/** |
||||
* The subject of this authorization |
||||
*/ |
||||
accessTo?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* The container subject of this authorization |
||||
*/ |
||||
default?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* An agent is a person, social entity or software identified by a URI, e.g., a WebID denotes an agent |
||||
*/ |
||||
agent?: { |
||||
"@id": string; |
||||
}[]; |
||||
/** |
||||
* Denotes a group of agents being given the access permission |
||||
*/ |
||||
agentGroup?: { |
||||
"@id": string; |
||||
}[]; |
||||
/** |
||||
* An agent class is a class of persons or entities identified by a URI. |
||||
*/ |
||||
agentClass?: ( |
||||
| { |
||||
"@id": "AuthenticatedAgent"; |
||||
} |
||||
| { |
||||
"@id": "Agent"; |
||||
} |
||||
)[]; |
||||
/** |
||||
* Denotes a class of operations that the agents can perform on a resource. |
||||
*/ |
||||
mode?: ( |
||||
| { |
||||
"@id": "Read"; |
||||
} |
||||
| { |
||||
"@id": "Write"; |
||||
} |
||||
| { |
||||
"@id": "Append"; |
||||
} |
||||
| { |
||||
"@id": "Control"; |
||||
} |
||||
)[]; |
||||
} |
@ -0,0 +1,23 @@ |
||||
PREFIX acl: <http://www.w3.org/ns/auth/acl#> |
||||
PREFIX acls: <http://www.w3.org/ns/auth/acls#> |
||||
PREFIX foaf: <http://xmlns.com/foaf/0.1/> |
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> |
||||
|
||||
acls:Authorization EXTRA a { |
||||
$acls:AuthorizationShape ( |
||||
a [ acl:Authorization ] |
||||
// rdfs:comment "Denotes this as an acl:Authorization"; |
||||
acl:accessTo IRI? |
||||
// rdfs:comment "The subject of this authorization"; |
||||
acl:default IRI? |
||||
// rdfs:comment "The container subject of this authorization"; |
||||
acl:agent IRI* |
||||
// rdfs:comment "An agent is a person, social entity or software identified by a URI, e.g., a WebID denotes an agent"; |
||||
acl:agentGroup IRI* |
||||
// rdfs:comment "Denotes a group of agents being given the access permission"; |
||||
acl:agentClass [ acl:AuthenticatedAgent foaf:Agent ]* |
||||
// rdfs:comment "An agent class is a class of persons or entities identified by a URI."; |
||||
acl:mode [ acl:Read acl:Write acl:Append acl:Control ]* |
||||
// rdfs:comment "Denotes a class of operations that the agents can perform on a resource."; |
||||
) |
||||
} |
@ -1,13 +0,0 @@ |
||||
/* istanbul ignore file */ |
||||
|
||||
export async function getAccessRules(): Promise<undefined> { |
||||
throw new Error("Not Implemented"); |
||||
// const [publicAccess, agentAccess] = await Promise.all([
|
||||
// universalAccess.getPublicAccess(uri, { fetch }),
|
||||
// universalAccess.getAgentAccessAll(uri, { fetch }),
|
||||
// ]);
|
||||
// if (agentAccess === null || publicAccess === null) {
|
||||
// return new AccessRuleFetchError(uri);
|
||||
// }
|
||||
// return new AccessRuleResult(uri, publicAccess, agentAccess);
|
||||
} |
@ -1,88 +0,0 @@ |
||||
/* istanbul ignore file */ |
||||
|
||||
import type { AclDataset, WithChangeLog } from "@inrupt/solid-client"; |
||||
import { |
||||
getSolidDatasetWithAcl, |
||||
hasResourceAcl, |
||||
hasFallbackAcl, |
||||
hasAccessibleAcl, |
||||
createAclFromFallbackAcl, |
||||
getResourceAcl, |
||||
setAgentResourceAccess, |
||||
saveAclFor, |
||||
setPublicDefaultAccess, |
||||
setPublicResourceAccess, |
||||
setAgentDefaultAccess, |
||||
} from "@inrupt/solid-client"; |
||||
import { guaranteeFetch } from "../../util/guaranteeFetch"; |
||||
import { isContainerUri } from "../../util/uriTypes"; |
||||
import type { AccessRule } from "../results/success/AccessRule"; |
||||
import type { SetAccessRuleSuccess } from "../results/success/AccessRule"; |
||||
import { AccessRuleFetchError } from "../results/error/AccessControlError"; |
||||
import type { BasicRequestOptions } from "./requestOptions"; |
||||
|
||||
export type SetAccessRulesResult = |
||||
| SetAccessRuleSuccess |
||||
| SetAccessRulesResultError; |
||||
export type SetAccessRulesResultError = AccessRuleFetchError; |
||||
|
||||
export async function setAccessRules( |
||||
uri: string, |
||||
newAccessRules: AccessRule, |
||||
options?: BasicRequestOptions, |
||||
): Promise<SetAccessRulesResult> { |
||||
console.warn("Access Control is stil underdeveloped. Use with caution."); |
||||
const fetch = guaranteeFetch(options?.fetch); |
||||
const isContainer = isContainerUri(uri); |
||||
|
||||
// Code Copied from https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/manage-wac/
|
||||
// Fetch the SolidDataset and its associated ACLs, if available:
|
||||
const myDatasetWithAcl = await getSolidDatasetWithAcl(uri, { fetch }); |
||||
|
||||
// Obtain the SolidDataset's own ACL, if available,
|
||||
// or initialise a new one, if possible:
|
||||
let resourceAcl; |
||||
if (!hasResourceAcl(myDatasetWithAcl)) { |
||||
if (!hasAccessibleAcl(myDatasetWithAcl)) { |
||||
return new AccessRuleFetchError( |
||||
uri, |
||||
"The current user does not have permission to change access rights to this Resource.", |
||||
); |
||||
} |
||||
if (!hasFallbackAcl(myDatasetWithAcl)) { |
||||
return new AccessRuleFetchError( |
||||
"The current user does not have permission to see who currently has access to this Resource.", |
||||
); |
||||
} |
||||
resourceAcl = createAclFromFallbackAcl(myDatasetWithAcl); |
||||
} else { |
||||
resourceAcl = getResourceAcl(myDatasetWithAcl); |
||||
} |
||||
|
||||
// Give someone Control access to the given Resource:
|
||||
|
||||
let updatedAcl: AclDataset & WithChangeLog = resourceAcl; |
||||
if (newAccessRules.public) { |
||||
if (isContainer) { |
||||
updatedAcl = setPublicDefaultAccess(updatedAcl, newAccessRules.public); |
||||
} else { |
||||
updatedAcl = setPublicResourceAccess(updatedAcl, newAccessRules.public); |
||||
} |
||||
} |
||||
if (newAccessRules.agent) { |
||||
const setAgentAccess = isContainer |
||||
? setAgentDefaultAccess |
||||
: setAgentResourceAccess; |
||||
Object.entries(newAccessRules.agent).forEach(([webId, rules]) => { |
||||
updatedAcl = setAgentAccess(updatedAcl, webId, rules); |
||||
}); |
||||
} |
||||
|
||||
// Now save the ACL:
|
||||
await saveAclFor(myDatasetWithAcl, updatedAcl, { fetch }); |
||||
return { |
||||
isError: false, |
||||
uri, |
||||
type: "setAccessRuleSuccess", |
||||
}; |
||||
} |
@ -1,11 +0,0 @@ |
||||
import type { Access } from "@inrupt/solid-client"; |
||||
import type { ResourceSuccess } from "./SuccessResult"; |
||||
|
||||
export interface AccessRule { |
||||
public?: Access; |
||||
agent?: Record<string, Access>; |
||||
} |
||||
|
||||
export interface SetAccessRuleSuccess extends ResourceSuccess { |
||||
type: "setAccessRuleSuccess"; |
||||
} |
@ -0,0 +1,18 @@ |
||||
/** |
||||
* A list of modes that a certain agent has access to |
||||
*/ |
||||
export interface AccessModeList { |
||||
read: boolean; |
||||
append: boolean; |
||||
write: boolean; |
||||
control: boolean; |
||||
} |
||||
|
||||
/** |
||||
* A list of modes for each kind of agent |
||||
*/ |
||||
export interface WacRule { |
||||
public: AccessModeList; |
||||
authenticated: AccessModeList; |
||||
agent: Record<string, AccessModeList>; |
||||
} |
@ -0,0 +1,118 @@ |
||||
import type { GetWacRuleSuccess } from "./results/GetWacRuleSuccess"; |
||||
import { guaranteeFetch } from "../../util/guaranteeFetch"; |
||||
import type { BasicRequestOptions } from "../../requester/requests/requestOptions"; |
||||
import type { HttpErrorResultType } from "../../requester/results/error/HttpErrorResult"; |
||||
import { HttpErrorResult } from "../../requester/results/error/HttpErrorResult"; |
||||
import type { NoncompliantPodError } from "../../requester/results/error/NoncompliantPodError"; |
||||
import type { UnexpectedResourceError } from "../../requester/results/error/ErrorResult"; |
||||
import { rawTurtleToDataset } from "../../util/rdfUtils"; |
||||
import { AuthorizationShapeType } from "../../.ldo/wac.shapeTypes"; |
||||
import type { AccessModeList, WacRule } from "./WacRule"; |
||||
import type { Authorization } from "../../.ldo/wac.typings"; |
||||
import type { WacRuleAbsent } from "./results/WacRuleAbsent"; |
||||
|
||||
export type GetWacRuleError = |
||||
| HttpErrorResultType |
||||
| NoncompliantPodError |
||||
| UnexpectedResourceError; |
||||
export type GetWacRuleResult = |
||||
| GetWacRuleSuccess |
||||
| GetWacRuleError |
||||
| WacRuleAbsent; |
||||
|
||||
/** |
||||
* Given the URI of an ACL document, return the Web Access Control (WAC) rules |
||||
* @param aclUri: The URI for the ACL document |
||||
* @param options: Options object to include an authenticated fetch function |
||||
* @returns GetWacRuleResult |
||||
*/ |
||||
export async function getWacRuleWithAclUri( |
||||
aclUri: string, |
||||
options?: BasicRequestOptions, |
||||
): Promise<GetWacRuleResult> { |
||||
const fetch = guaranteeFetch(options?.fetch); |
||||
const response = await fetch(aclUri); |
||||
const errorResult = HttpErrorResult.checkResponse(aclUri, response); |
||||
if (errorResult) return errorResult; |
||||
|
||||
if (response.status === 404) { |
||||
return { |
||||
type: "wacRuleAbsent", |
||||
uri: aclUri, |
||||
isError: false, |
||||
}; |
||||
} |
||||
|
||||
// Parse Turtle
|
||||
const rawTurtle = await response.text(); |
||||
const rawTurtleResult = await rawTurtleToDataset(rawTurtle, aclUri); |
||||
if (rawTurtleResult.isError) return rawTurtleResult; |
||||
const dataset = rawTurtleResult.dataset; |
||||
const authorizations = dataset |
||||
.usingType(AuthorizationShapeType) |
||||
.matchSubject( |
||||
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", |
||||
"http://www.w3.org/ns/auth/acl#Authorization", |
||||
); |
||||
|
||||
const wacRule: WacRule = { |
||||
public: { |
||||
read: false, |
||||
write: false, |
||||
append: false, |
||||
control: false, |
||||
}, |
||||
authenticated: { |
||||
read: false, |
||||
write: false, |
||||
append: false, |
||||
control: false, |
||||
}, |
||||
agent: {}, |
||||
}; |
||||
|
||||
function applyAccessModesToList( |
||||
accessModeList: AccessModeList, |
||||
authorization: Authorization, |
||||
): void { |
||||
authorization.mode?.forEach((mode) => { |
||||
accessModeList[mode["@id"].toLowerCase()] = true; |
||||
}); |
||||
} |
||||
|
||||
authorizations.forEach((authorization) => { |
||||
if ( |
||||
authorization.agentClass?.some( |
||||
(agentClass) => agentClass["@id"] === "Agent", |
||||
) |
||||
) { |
||||
applyAccessModesToList(wacRule.public, authorization); |
||||
applyAccessModesToList(wacRule.authenticated, authorization); |
||||
} |
||||
if ( |
||||
authorization.agentClass?.some( |
||||
(agentClass) => agentClass["@id"] === "AuthenticatedAgent", |
||||
) |
||||
) { |
||||
applyAccessModesToList(wacRule.authenticated, authorization); |
||||
} |
||||
authorization.agent?.forEach((agent) => { |
||||
if (!wacRule.agent[agent["@id"]]) { |
||||
wacRule.agent[agent["@id"]] = { |
||||
read: false, |
||||
write: false, |
||||
append: false, |
||||
control: false, |
||||
}; |
||||
} |
||||
applyAccessModesToList(wacRule.agent[agent["@id"]], authorization); |
||||
}); |
||||
}); |
||||
|
||||
return { |
||||
type: "getWacRuleSuccess", |
||||
uri: aclUri, |
||||
isError: false, |
||||
wacRule, |
||||
}; |
||||
} |
@ -0,0 +1,70 @@ |
||||
import type { GetWacUriSuccess } from "./results/GetWacUriSuccess"; |
||||
import type { HttpErrorResultType } from "../../requester/results/error/HttpErrorResult"; |
||||
import { |
||||
HttpErrorResult, |
||||
NotFoundHttpError, |
||||
} from "../../requester/results/error/HttpErrorResult"; |
||||
import { UnexpectedResourceError } from "../../requester/results/error/ErrorResult"; |
||||
import { guaranteeFetch } from "../../util/guaranteeFetch"; |
||||
import type { BasicRequestOptions } from "../../requester/requests/requestOptions"; |
||||
import { NoncompliantPodError } from "../../requester/results/error/NoncompliantPodError"; |
||||
import { parse as parseLinkHeader } from "http-link-header"; |
||||
import type { LeafUri } from "../../util/uriTypes"; |
||||
|
||||
export type GetWacUriError = |
||||
| HttpErrorResultType |
||||
| NotFoundHttpError |
||||
| NoncompliantPodError |
||||
| UnexpectedResourceError; |
||||
export type GetWacUriResult = GetWacUriSuccess | GetWacUriError; |
||||
|
||||
/** |
||||
* Get the URI for the WAC rules of a specific resource |
||||
* @param resourceUri: the URI of the resource |
||||
* @param options: Options object to include an authenticated fetch function |
||||
* @returns GetWacUriResult |
||||
*/ |
||||
export async function getWacUri( |
||||
resourceUri: string, |
||||
options?: BasicRequestOptions, |
||||
): Promise<GetWacUriResult> { |
||||
try { |
||||
const fetch = guaranteeFetch(options?.fetch); |
||||
const response = await fetch(resourceUri, { |
||||
method: "head", |
||||
}); |
||||
const errorResult = HttpErrorResult.checkResponse(resourceUri, response); |
||||
if (errorResult) return errorResult; |
||||
if (NotFoundHttpError.is(response)) { |
||||
return new NotFoundHttpError( |
||||
resourceUri, |
||||
response, |
||||
"Could not get access control rules because the resource does not exist.", |
||||
); |
||||
} |
||||
// Get the URI from the link header
|
||||
const linkHeader = response.headers.get("link"); |
||||
if (!linkHeader) { |
||||
return new NoncompliantPodError( |
||||
resourceUri, |
||||
"No link header present in request.", |
||||
); |
||||
} |
||||
const parsedLinkHeader = parseLinkHeader(linkHeader); |
||||
const aclUris = parsedLinkHeader.get("rel", "acl"); |
||||
if (aclUris.length !== 1) { |
||||
return new NoncompliantPodError( |
||||
resourceUri, |
||||
`There must be one link with a rel="acl"`, |
||||
); |
||||
} |
||||
return { |
||||
type: "getWacUriSuccess", |
||||
isError: false, |
||||
uri: resourceUri, |
||||
wacUri: aclUris[0].uri as LeafUri, |
||||
}; |
||||
} catch (err: unknown) { |
||||
return UnexpectedResourceError.fromThrown(resourceUri, err); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; |
||||
import type { WacRule } from "../WacRule"; |
||||
|
||||
/** |
||||
* Returned when a WAC rule is successfully retrieved |
||||
*/ |
||||
export interface GetWacRuleSuccess extends ResourceSuccess { |
||||
type: "getWacRuleSuccess"; |
||||
/** |
||||
* The rule that was retrieved |
||||
*/ |
||||
wacRule: WacRule; |
||||
} |
@ -0,0 +1,13 @@ |
||||
import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; |
||||
import type { LeafUri } from "../../../util/uriTypes"; |
||||
|
||||
/** |
||||
* Returned when the URI for a resources ACL document was successfully retried |
||||
*/ |
||||
export interface GetWacUriSuccess extends ResourceSuccess { |
||||
type: "getWacUriSuccess"; |
||||
/** |
||||
* The URI of the ACL document |
||||
*/ |
||||
wacUri: LeafUri; |
||||
} |
@ -0,0 +1,13 @@ |
||||
import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; |
||||
import type { WacRule } from "../WacRule"; |
||||
|
||||
/** |
||||
* Returned when rules were successfully written |
||||
*/ |
||||
export interface SetWacRuleSuccess extends ResourceSuccess { |
||||
type: "setWacRuleSuccess"; |
||||
/** |
||||
* The written rule |
||||
*/ |
||||
wacRule: WacRule; |
||||
} |
@ -0,0 +1,8 @@ |
||||
import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; |
||||
|
||||
/** |
||||
* Returned if no WAC rule was returned from the server |
||||
*/ |
||||
export interface WacRuleAbsent extends ResourceSuccess { |
||||
type: "wacRuleAbsent"; |
||||
} |
@ -0,0 +1,109 @@ |
||||
import { createLdoDataset } from "@ldo/ldo"; |
||||
import type { BasicRequestOptions } from "../../requester/requests/requestOptions"; |
||||
import type { UnexpectedResourceError } from "../../requester/results/error/ErrorResult"; |
||||
import { |
||||
HttpErrorResult, |
||||
type HttpErrorResultType, |
||||
} from "../../requester/results/error/HttpErrorResult"; |
||||
import { isContainerUri, type LeafUri } from "../../util/uriTypes"; |
||||
import type { AccessModeList, WacRule } from "./WacRule"; |
||||
import type { SetWacRuleSuccess } from "./results/SetWacRuleSuccess"; |
||||
import type { Authorization } from "../../.ldo/wac.typings"; |
||||
import { AuthorizationShapeType } from "../../.ldo/wac.shapeTypes"; |
||||
import { v4 } from "uuid"; |
||||
import { guaranteeFetch } from "../../util/guaranteeFetch"; |
||||
|
||||
export type SetWacRuleError = HttpErrorResultType | UnexpectedResourceError; |
||||
export type SetWacRuleResult = SetWacRuleSuccess | SetWacRuleError; |
||||
|
||||
/** |
||||
* Given the URI of an ACL document and some WAC rules, set the WAC rules of |
||||
* that document |
||||
* @param aclUri: The URI for the ACL document |
||||
* @param newRule: A new WAC rule to set. This will overwrite old rules |
||||
* @param accessTo: The document this rule refers to |
||||
* @param options: Options object to include an authenticated fetch function |
||||
* @returns SetWacRuleResult |
||||
*/ |
||||
export async function setWacRuleForAclUri( |
||||
aclUri: LeafUri, |
||||
newRule: WacRule, |
||||
accessTo: string, |
||||
options?: BasicRequestOptions, |
||||
): Promise<SetWacRuleResult> { |
||||
const fetch = guaranteeFetch(options?.fetch); |
||||
// The rule map keeps track of all the rules that are currently being used
|
||||
// so that similar rules can be grouped together
|
||||
const ruleMap: Record<string, Authorization> = {}; |
||||
// The dataset that will eventually be sent to the Pod
|
||||
const dataset = createLdoDataset(); |
||||
|
||||
// Helper function to add rules to the dataset by grouping them in the ruleMap
|
||||
function addRuleToDataset( |
||||
type: "public" | "authenticated" | "agent", |
||||
accessModeList: AccessModeList, |
||||
agentId?: string, |
||||
) { |
||||
const accessModeListHash = hashAccessModeList(accessModeList); |
||||
// No need to add if all access is false
|
||||
if (accessModeListHash === "") return; |
||||
if (!ruleMap[accessModeListHash]) { |
||||
const authorization = dataset |
||||
.usingType(AuthorizationShapeType) |
||||
.fromSubject(`${aclUri}#${v4()}`); |
||||
authorization.type = { "@id": "Authorization" }; |
||||
if (accessModeList.read) authorization.mode?.push({ "@id": "Read" }); |
||||
if (accessModeList.write) authorization.mode?.push({ "@id": "Write" }); |
||||
if (accessModeList.append) authorization.mode?.push({ "@id": "Append" }); |
||||
if (accessModeList.control) |
||||
authorization.mode?.push({ "@id": "Control" }); |
||||
authorization.accessTo = { "@id": accessTo }; |
||||
if (isContainerUri(accessTo)) { |
||||
authorization.default = { "@id": accessTo }; |
||||
} |
||||
ruleMap[accessModeListHash] = authorization; |
||||
} |
||||
const authorization = ruleMap[accessModeListHash]; |
||||
// Add agents to the rule
|
||||
if (type === "public") { |
||||
authorization.agentClass?.push({ "@id": "Agent" }); |
||||
} else if (type === "authenticated") { |
||||
authorization.agentClass?.push({ "@id": "AuthenticatedAgent" }); |
||||
} else if (type === "agent" && agentId) { |
||||
authorization.agent?.push({ "@id": agentId }); |
||||
} |
||||
} |
||||
|
||||
// Add each rule to the dataset
|
||||
addRuleToDataset("public", newRule.public); |
||||
addRuleToDataset("authenticated", newRule.authenticated); |
||||
Object.entries(newRule.agent).forEach(([agentUri, accessModeList]) => { |
||||
addRuleToDataset("agent", accessModeList, agentUri); |
||||
}); |
||||
|
||||
// Save to Pod
|
||||
const response = await fetch(aclUri, { |
||||
method: "PUT", |
||||
headers: { |
||||
"content-type": "text/turtle", |
||||
}, |
||||
body: dataset.toString(), |
||||
}); |
||||
const errorResult = HttpErrorResult.checkResponse(aclUri, response); |
||||
if (errorResult) return errorResult; |
||||
|
||||
return { |
||||
type: "setWacRuleSuccess", |
||||
uri: aclUri, |
||||
isError: false, |
||||
wacRule: newRule, |
||||
}; |
||||
} |
||||
|
||||
// Hashes the access mode list for use in the rule map
|
||||
function hashAccessModeList(list: AccessModeList): string { |
||||
return Object.entries(list).reduce( |
||||
(agg, [key, isPresent]) => (isPresent ? agg + key : agg), |
||||
"", |
||||
); |
||||
} |
Loading…
Reference in new issue