Skip to content

Commit

Permalink
feat: create pod when no storage found (#550)
Browse files Browse the repository at this point in the history
* feat: add create pod option when signing in with new webid WIP

* test: update tests

* fix: only display setup page when waiting for user input

* test: coverage

* chore: update copy

* fix: add username as name when creating webid doc

* fix: show alerts in authenticate page

* test: update tests

* fix: logout without refresh

* Merge branch 'develop' of github.com:netwerk-digitaal-erfgoed/solid-crs into feat/create-pod-when-not-found

* chore: update dockerfile
  • Loading branch information
lem-onade authored Jan 10, 2022
1 parent affcaec commit 31990d5
Show file tree
Hide file tree
Showing 20 changed files with 1,029 additions and 189 deletions.
6 changes: 5 additions & 1 deletion packages/solid-crs-id-proxy/config/local-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,11 @@
"pathToJwks": {
"@id": "urn:dgt-id-proxy:variables:jwksFilePath"
},
"webIdPattern": "http://localhost:3007/:customclaim"
"webIdPattern": "http://localhost:3007/:customclaim",
"predicates": [
[ "http://schema.org/name", [ "https://netwerkdigitaalerfgoed.nl/username" ] ],
[ "http://xmlns.com/foaf/0.1/name", [ "https://netwerkdigitaalerfgoed.nl/username" ] ]
]
},
{
"@id": "urn:dgt-id-proxy:default:JwtEncodeResponseHandler"
Expand Down
6 changes: 5 additions & 1 deletion packages/solid-crs-id-proxy/config/proxy-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,11 @@
"pathToJwks": {
"@id": "urn:dgt-id-proxy:variables:jwksFilePath"
},
"webIdPattern": "https://webid.netwerkdigitaalerfgoed.nl/:customclaim"
"webIdPattern": "https://webid.netwerkdigitaalerfgoed.nl/:customclaim",
"predicates": [
[ "http://schema.org/name", [ "https://netwerkdigitaalerfgoed.nl/username" ] ],
[ "http://xmlns.com/foaf/0.1/name", [ "https://netwerkdigitaalerfgoed.nl/username" ] ]
]
},
{
"@id": "urn:dgt-id-proxy:default:JwtEncodeResponseHandler"
Expand Down
1 change: 1 addition & 0 deletions packages/solid-crs-manage/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ VITE_TERM_ENDPOINT=https://termennetwerk-api.netwerkdigitaalerfgoed.nl/graphql
VITE_ID_PROXY_URI=http://localhost:3006/
VITE_WEBID_URI=http://localhost:3007/
VITE_PRESENTATION_URI=http://localhost:3005/
VITE_PODS_URI=http://localhost:3000/
1 change: 1 addition & 0 deletions packages/solid-crs-manage/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ VITE_TERM_ENDPOINT=https://termennetwerk-api.netwerkdigitaalerfgoed.nl/graphql
VITE_ID_PROXY_URI=https://auth.netwerkdigitaalerfgoed.nl/
VITE_WEBID_URI=https://webid.netwerkdigitaalerfgoed.nl/
VITE_PRESENTATION_URI=https://solid-crs-presentatie.netwerkdigitaalerfgoed.nl/
VITE_PODS_URI=https://pods.netwerkdigitaalerfgoed.nl/
18 changes: 9 additions & 9 deletions packages/solid-crs-manage/lib/app-root.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { RxLitElement } from 'rx-lit';
import { Theme, Logout, Plus, Cross, Search } from '@netwerk-digitaal-erfgoed/solid-crs-theme';
import { unsafeSVG } from 'lit-html/directives/unsafe-svg';
import { define, hydrate } from '@digita-ai/dgt-components';
import { Client, Session, SolidSDKService } from '@digita-ai/inrupt-solid-service';
import { AppActors, AppAuthenticateStates, AppContext, AppDataStates, AppFeatureStates, appMachine, AppRootStates } from './app.machine';
import { Session, SolidSDKService } from '@digita-ai/inrupt-solid-service';
import { AppActors, AppAuthenticateStates, AppContext, AppFeatureStates, appMachine, AppRootStates } from './app.machine';
import { AppEvents, ClickedCreateCollectionEvent, DismissAlertEvent, LoggedInEvent } from './app.events';
import { CollectionEvents } from './features/collection/collection.events';
import { SearchEvent, SearchUpdatedEvent } from './features/search/search.events';
Expand Down Expand Up @@ -175,7 +175,8 @@ export class AppRootComponent extends RxLitElement {
)).withContext({
alerts: [],
}), { devTools: process.env.MODE === 'DEV' },
);
// eslint-disable-next-line no-console
).onTransition((state) => { if (process.env.MODE === 'DEV') console.log(state.value); });

this.subscribe('state', from(this.actor));

Expand Down Expand Up @@ -260,11 +261,9 @@ export class AppRootComponent extends RxLitElement {
*/
render(): TemplateResult {

const showLoading = this.state?.matches({ [AppRootStates.DATA]: AppDataStates.CREATING })
|| this.state?.matches({ [AppRootStates.DATA]: AppDataStates.REFRESHING });
const showLoading = this.state?.hasTag('loading');

const hideSidebar = this.state?.matches({ [AppRootStates.DATA]: AppDataStates.DETERMINING_POD_TYPE })
|| this.state?.matches({ [AppRootStates.DATA]: AppDataStates.CHECKING_TYPE_REGISTRATIONS })
const hideSidebar = this.state?.hasTag('setup')
|| !this.state?.matches({ [AppRootStates.AUTHENTICATE]: AppAuthenticateStates.AUTHENTICATED });

return html`
Expand Down Expand Up @@ -307,13 +306,14 @@ export class AppRootComponent extends RxLitElement {
</nde-sidebar-item>
</nde-sidebar>
` : '' }
${ !this.state?.matches({ [AppRootStates.AUTHENTICATE]: AppAuthenticateStates.AUTHENTICATED })
${ this.state?.matches({ [AppRootStates.AUTHENTICATE]: AppAuthenticateStates.UNAUTHENTICATED })
? html`<nde-authenticate-root
@authenticated="${(event: CustomEvent<Session>) => this.actor.send(new LoggedInEvent(event.detail))}"
.solidService="${this.solidService}"
.translator="${this.translator}"
.appActor="${this.actor}"
></nde-authenticate-root>`: ''}
${ this.state?.matches({ [AppRootStates.DATA]: AppDataStates.DETERMINING_POD_TYPE }) ? html`<nde-authenticate-setup .actor='${this.actor}' .logger='${this.logger}' .translator='${this.translator}'></nde-authenticate-setup>` : html`
${ this.state?.hasTag('setup') ? html`<nde-authenticate-setup .actor='${this.actor}' .logger='${this.logger}' .translator='${this.translator}'></nde-authenticate-setup>` : html`
${ this.state?.matches({ [AppRootStates.AUTHENTICATE]: AppAuthenticateStates.AUTHENTICATED, [AppRootStates.FEATURE]: AppFeatureStates.COLLECTION }) ? html`<nde-collection-root .actor='${this.actor.children.get(AppActors.COLLECTION_MACHINE)}' .showDelete='${this.collections?.length > 1}' .logger='${this.logger}' .translator='${this.translator}'></nde-collection-root>` : '' }
${ this.state?.matches({ [AppRootStates.AUTHENTICATE]: AppAuthenticateStates.AUTHENTICATED, [AppRootStates.FEATURE]: AppFeatureStates.SEARCH }) ? html`<nde-search-root .actor='${this.actor.children.get(AppActors.SEARCH_MACHINE)}' .logger='${this.logger}' .translator='${this.translator}'></nde-search-root>` : '' }
${ this.state?.matches({ [AppRootStates.AUTHENTICATE]: AppAuthenticateStates.AUTHENTICATED, [AppRootStates.FEATURE]: AppFeatureStates.OBJECT }) ? html`<nde-object-root .actor='${this.actor.children.get(AppActors.OBJECT_MACHINE)}' .logger='${this.logger}' .translator='${this.translator}'></nde-object-root>` : '' }
Expand Down
17 changes: 14 additions & 3 deletions packages/solid-crs-manage/lib/app.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export enum AppEvents {
CLICKED_ADMINISTRATOR_TYPE = '[AppEvent: Clicked Admin Pod Type]',
CLICKED_INSTITUTION_TYPE = '[AppEvent: Clicked Institution Pod Type]',
SET_PROFILE = '[AppEvent: Set Profile]',
CLICKED_CREATE_POD = '[AppEvent: Clicked Create Pod]',
}

/**
Expand Down Expand Up @@ -70,7 +71,7 @@ export class LoggedOutEvent implements EventObject {
/**
* An event which is dispatched when an error occurs.
*/
export class LoggingOutEvent implements EventObject {
export class ClickedLogoutEvent implements EventObject {

public type: AppEvents.CLICKED_LOGOUT = AppEvents.CLICKED_LOGOUT;

Expand Down Expand Up @@ -122,13 +123,22 @@ export class SetProfileEvent implements EventObject {

}

/**
* An event which is dispatched when an error occurs.
*/
export class ClickedCreatePodEvent implements EventObject {

public type: AppEvents.CLICKED_CREATE_POD = AppEvents.CLICKED_CREATE_POD;

}

/**
* Union type of app events.
*/
export type AppEvent =
| RouterEvent
| LoggedInEvent
| LoggingOutEvent
| ClickedLogoutEvent
| LoggedOutEvent
| ErrorEvent
| DismissAlertEvent
Expand All @@ -142,7 +152,8 @@ export type AppEvent =
| ClickedDeleteObjectEvent
| ClickedInstitutionTypeEvent
| ClickedAdministratorTypeEvent
| SetProfileEvent;
| SetProfileEvent
| ClickedCreatePodEvent;

/**
* Actions for the alerts component.
Expand Down
1 change: 1 addition & 0 deletions packages/solid-crs-manage/lib/app.machine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const solidService = {
uri: 'https://example.com/profile',
})),
logout: jest.fn(async() => undefined),
getStorages: jest.fn(async () => [ 'https://storage.uri/' ]),
} as any;

describe('AppMachine', () => {
Expand Down
79 changes: 70 additions & 9 deletions packages/solid-crs-manage/lib/app.machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import { Alert, FormActors, formMachine, FormValidatorResult, State } from '@net
import { Collection, CollectionObjectStore, CollectionObject, CollectionStore, SolidProfile, SolidSession, Route, routerStateConfig, NavigatedEvent, RouterStates, createRoute, activeRoute, routerEventsConfig, RouterEvents, updateHistory } from '@netwerk-digitaal-erfgoed/solid-crs-core';
import { createMachine } from 'xstate';
import { assign, forwardTo, log, send } from 'xstate/lib/actions';
import { SolidService } from '@digita-ai/inrupt-solid-service';
import { addAlert, AddAlertEvent, addCollection, AppEvent, AppEvents, dismissAlert, LoggedOutEvent, LoggingOutEvent, removeSession, setCollections, setProfile, SetProfileEvent, setSession } from './app.events';
import { SolidSDKService } from '@digita-ai/inrupt-solid-service';
import { addAlert, AddAlertEvent, addCollection, AppEvent, AppEvents, dismissAlert, LoggedOutEvent, ClickedLogoutEvent, removeSession, setCollections, setProfile, SetProfileEvent, setSession } from './app.events';
import { collectionMachine } from './features/collection/collection.machine';
import { CollectionEvents, SelectedCollectionEvent } from './features/collection/collection.events';
import { searchMachine } from './features/search/search.machine';
import { SearchEvents, SearchUpdatedEvent } from './features/search/search.events';
import { objectMachine } from './features/object/object.machine';
import { ObjectEvents } from './features/object/object.events';
import { createPod } from './app.services';

/**
* The root context of the application.
Expand Down Expand Up @@ -92,6 +93,9 @@ export enum AppDataStates {
CREATING = '[AppDataStates: Creating]',
CHECKING_TYPE_REGISTRATIONS = '[AppDataStates: Checking Type Registrations]',
DETERMINING_POD_TYPE = '[AppDataStates: Determining Pod Type]',
CHECKING_STORAGE= '[AppDataStates: Checking Storage]',
AWAITING_POD_CREATION= '[AppDataStates: Awaiting Pod Creation]',
CREATING_POD= '[AppDataStates: Creating Pod]',
}

/**
Expand Down Expand Up @@ -122,7 +126,7 @@ export const routes: Route[] = [
* The application root machine and its configuration.
*/
export const appMachine = (
solid: SolidService,
solid: SolidSDKService,
collectionStore: CollectionStore,
objectStore: CollectionObjectStore,
collectionTemplate: Collection,
Expand Down Expand Up @@ -363,13 +367,16 @@ export const appMachine = (
*/
src: () => solid.logout(),
onDone: {
actions: send(new LoggedOutEvent()),
actions: [
send(new LoggedOutEvent()),
() => window.localStorage.removeItem('solidClientAuthn:currentSession'),
],
},
},
on: {
[AppEvents.LOGGED_OUT]: {
target: AppAuthenticateStates.UNAUTHENTICATED,
actions: () => location.reload(),
// actions: () => location.reload(),
},
},
},
Expand All @@ -388,7 +395,7 @@ export const appMachine = (
},
},
/**
* Determines if the current user is creating a collection.
* Handles pod config and collection creation.
*/
[AppRootStates.DATA]: {
initial: AppDataStates.IDLE,
Expand All @@ -399,17 +406,68 @@ export const appMachine = (
[AppDataStates.IDLE]: {
on: {
[AppEvents.CLICKED_CREATE_COLLECTION]: AppDataStates.CREATING,
[AppEvents.SET_PROFILE]: AppDataStates.CHECKING_TYPE_REGISTRATIONS,
[AppEvents.SET_PROFILE]: AppDataStates.CHECKING_STORAGE,
[CollectionEvents.CLICKED_DELETE]: AppDataStates.REFRESHING,
[ObjectEvents.CLICKED_DELETE]: AppDataStates.REFRESHING,
[CollectionEvents.SAVED_COLLECTION]: AppDataStates.REFRESHING,
},
},
/**
* Check whether a storage triple is present in the WebID.
*/
[AppDataStates.CHECKING_STORAGE]: {
tags: [ 'setup', 'loading' ],
invoke: {
src: (context) => solid.getStorages(context.session.webId),
onDone: [
{
target: AppDataStates.AWAITING_POD_CREATION,
cond: (c: AppContext, event) => event?.data && event.data.length === 0,
},
{
target: AppDataStates.CHECKING_TYPE_REGISTRATIONS,
},
],
onError: send((c, event) => event),
},

},
/**
* No storage triple present in the WebID, waiting for user input
*/
[AppDataStates.AWAITING_POD_CREATION]: {
tags: [ 'setup' ],
on: {
[AppEvents.CLICKED_LOGOUT]: {
target: AppDataStates.IDLE,
actions: send((c, event) => event),
},
[AppEvents.CLICKED_CREATE_POD]: {
target: AppDataStates.CREATING_POD,
},
},
},
/**
* Creates a Solid pod at pods.netwerkdigitaalerfgoed.nl.
*/
[AppDataStates.CREATING_POD]: {
tags: [ 'setup', 'loading' ],
invoke: {
src: () => createPod(solid),
onDone: {
target: AppDataStates.CHECKING_TYPE_REGISTRATIONS,
},
onError: {
actions: send((c, event) => event),
},
},
},
/**
* Checks existance of DataCatalog type registration
* When none was found, further set-up is needed (DETERMINING_POD_TYPE)
*/
[AppDataStates.CHECKING_TYPE_REGISTRATIONS]: {
tags: [ 'setup', 'loading' ],
invoke: {
src: (context) => collectionStore.getInstanceForClass(context.profile.uri, 'http://schema.org/DataCatalog'),
onDone: [
Expand All @@ -424,7 +482,7 @@ export const appMachine = (
onError: {
actions: [
send(new AddAlertEvent({ message: 'authenticate.error.no-valid-type-registration', type: 'warning' })),
send(new LoggingOutEvent()),
send(new ClickedLogoutEvent()),
],
},
},
Expand All @@ -435,14 +493,15 @@ export const appMachine = (
* or that it is an administrator's pod, accessing an institution's pod (pod type: administrator)
*/
[AppDataStates.DETERMINING_POD_TYPE]: {
tags: [ 'setup' ],
on: {
[AppEvents.CLICKED_ADMINISTRATOR_TYPE]: [
{
// The user is an admin, but no (valid) type registration was found
target: AppDataStates.IDLE,
actions: [
send(new AddAlertEvent({ message: 'authenticate.error.no-valid-type-registration', type: 'warning' })),
send(new LoggingOutEvent()),
send(new ClickedLogoutEvent()),
],
},
],
Expand All @@ -461,6 +520,7 @@ export const appMachine = (
*/
[AppDataStates.REFRESHING]: {
id: AppDataStates.REFRESHING,
tags: [ 'loading' ],
invoke: {
/**
* Get all collections from store.
Expand Down Expand Up @@ -488,6 +548,7 @@ export const appMachine = (
* Creating a new collection.
*/
[AppDataStates.CREATING]: {
tags: [ 'loading' ],
invoke: {
/**
* Save collection to the store.
Expand Down
Loading

0 comments on commit 31990d5

Please sign in to comment.