@fleetbase/solid-engine 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/ACL_SOLUTION.md +72 -0
  2. package/CSS_SCOPE_ISSUE.md +140 -0
  3. package/HOTFIX_SYNTAX_ERROR.md +100 -0
  4. package/LICENSE.md +651 -21
  5. package/MANUAL_ACL_SETUP.md +135 -0
  6. package/README.md +74 -27
  7. package/REFACTORING_SUMMARY.md +330 -0
  8. package/VERIFICATION_CHECKLIST.md +82 -0
  9. package/addon/components/modals/create-solid-folder.hbs +29 -0
  10. package/addon/components/modals/import-solid-resources.hbs +85 -0
  11. package/addon/controllers/data/content.js +17 -0
  12. package/addon/controllers/data/index.js +219 -0
  13. package/addon/controllers/home.js +84 -0
  14. package/addon/engine.js +1 -24
  15. package/addon/extension.js +26 -0
  16. package/addon/routes/data/content.js +11 -0
  17. package/addon/routes/data/index.js +17 -0
  18. package/addon/routes.js +2 -7
  19. package/addon/styles/solid-engine.css +1 -2
  20. package/addon/templates/account.hbs +3 -3
  21. package/addon/templates/application.hbs +2 -12
  22. package/addon/templates/data/content.hbs +48 -0
  23. package/addon/templates/{pods/explorer.hbs → data/index.hbs} +6 -5
  24. package/addon/templates/home.hbs +168 -10
  25. package/app/components/modals/{backup-pod.js → create-solid-folder.js} +1 -1
  26. package/app/components/modals/{resync-pod.js → import-solid-resources.js} +1 -1
  27. package/app/components/modals/{create-pod.js → setup-css-credentials.js} +1 -1
  28. package/composer.json +5 -11
  29. package/extension.json +2 -2
  30. package/index.js +0 -11
  31. package/package.json +9 -9
  32. package/server/migrations/2024_12_21_add_css_credentials_to_solid_identities_table.php +32 -0
  33. package/server/src/Client/OpenIDConnectClient.php +686 -15
  34. package/server/src/Client/SolidClient.php +104 -8
  35. package/server/src/Http/Controllers/DataController.php +261 -0
  36. package/server/src/Http/Controllers/OIDCController.php +42 -8
  37. package/server/src/Http/Controllers/SolidController.php +179 -85
  38. package/server/src/Models/SolidIdentity.php +13 -3
  39. package/server/src/Services/AclService.php +146 -0
  40. package/server/src/Services/PodService.php +863 -0
  41. package/server/src/Services/ResourceSyncService.php +336 -0
  42. package/server/src/Services/VehicleSyncService.php +289 -0
  43. package/server/src/Support/Utils.php +10 -0
  44. package/server/src/routes.php +25 -1
  45. package/addon/components/modals/backup-pod.hbs +0 -3
  46. package/addon/components/modals/create-pod.hbs +0 -5
  47. package/addon/components/modals/resync-pod.hbs +0 -3
  48. package/addon/controllers/pods/explorer/content.js +0 -12
  49. package/addon/controllers/pods/explorer.js +0 -149
  50. package/addon/controllers/pods/index/pod.js +0 -12
  51. package/addon/controllers/pods/index.js +0 -137
  52. package/addon/routes/pods/explorer/content.js +0 -10
  53. package/addon/routes/pods/explorer.js +0 -44
  54. package/addon/routes/pods/index/pod.js +0 -3
  55. package/addon/routes/pods/index.js +0 -21
  56. package/addon/templates/pods/explorer/content.hbs +0 -19
  57. package/addon/templates/pods/index/pod.hbs +0 -11
  58. package/addon/templates/pods/index.hbs +0 -19
  59. package/server/src/LegacyClient/Identity/IdentityProvider.php +0 -174
  60. package/server/src/LegacyClient/Identity/Profile.php +0 -18
  61. package/server/src/LegacyClient/OIDCClient.php +0 -350
  62. package/server/src/LegacyClient/Profile/WebID.php +0 -26
  63. package/server/src/LegacyClient/SolidClient.php +0 -271
@@ -1,3 +0,0 @@
1
- <Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
2
- <div class="modal-body-container"></div>
3
- </Modal::Default>
@@ -1,12 +0,0 @@
1
- import Controller from '@ember/controller';
2
- import { action } from '@ember/object';
3
-
4
- export default class PodsExplorerContentController extends Controller {
5
- @action setOverlayContext(overlayContextApi) {
6
- this.overlayContextApi = overlayContextApi;
7
- }
8
-
9
- @action onPressClose() {
10
- window.history.back();
11
- }
12
- }
@@ -1,149 +0,0 @@
1
- import Controller from '@ember/controller';
2
- import { action } from '@ember/object';
3
- import { inject as service } from '@ember/service';
4
- import { tracked } from '@glimmer/tracking';
5
- import { task, timeout } from 'ember-concurrency';
6
-
7
- export default class PodsExplorerController extends Controller {
8
- @service hostRouter;
9
- @service fetch;
10
- @service notifications;
11
- @service explorerState;
12
- @service modalsManager;
13
- @service crud;
14
- @tracked cursor = '';
15
- @tracked pod = '';
16
- @tracked query = '';
17
- queryParams = ['cursor', 'pod', 'query'];
18
- columns = [
19
- {
20
- label: 'Name',
21
- valuePath: 'name',
22
- width: '75%',
23
- cellComponent: 'table/cell/pod-content-name',
24
- onClick: this.viewContents,
25
- },
26
- {
27
- label: 'Type',
28
- valuePath: 'type',
29
- cellClassNames: 'capitalize',
30
- width: '5%',
31
- },
32
- {
33
- label: 'Size',
34
- valuePath: 'size',
35
- width: '5%',
36
- },
37
- {
38
- label: 'Created At',
39
- valuePath: 'created_at',
40
- width: '15%',
41
- },
42
- {
43
- label: '',
44
- cellComponent: 'table/cell/pod-content-actions',
45
- ddButtonText: false,
46
- ddButtonIcon: 'ellipsis-h',
47
- ddButtonIconPrefix: 'fas',
48
- ddMenuLabel: 'Actions',
49
- cellClassNames: 'overflow-visible',
50
- wrapperClass: 'flex items-center justify-end mx-2',
51
- width: '10%',
52
- actions: (content) => {
53
- return [
54
- {
55
- label: content.type === 'folder' ? 'Browse Folder' : 'View Contents',
56
- fn: this.viewContents,
57
- },
58
- {
59
- separator: true,
60
- },
61
- {
62
- label: 'Delete',
63
- fn: this.deleteSomething,
64
- },
65
- ];
66
- },
67
- sortable: false,
68
- filterable: false,
69
- resizable: false,
70
- searchable: false,
71
- },
72
- ];
73
-
74
- @action reload() {
75
- this.hostRouter.refresh();
76
- }
77
-
78
- @action back() {
79
- if (typeof this.cursor === 'string' && this.cursor.length && this.cursor !== this.model.id) {
80
- const current = this.reverseCursor();
81
- return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', current, { queryParams: { cursor: this.cursor, pod: this.pod } });
82
- }
83
-
84
- this.hostRouter.transitionTo('console.solid-protocol.pods.index');
85
- }
86
-
87
- @action viewContents(content) {
88
- if (content.type === 'folder') {
89
- return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', content, { queryParams: { cursor: this.trackCursor(content), pod: this.pod } });
90
- }
91
-
92
- if (content.type === 'file') {
93
- return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer.content', content);
94
- }
95
-
96
- return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', this.pod, { queryParams: { cursor: this.trackCursor(content), pod: this.pod } });
97
- }
98
-
99
- @action deleteSomething() {
100
- this.modalsManager.confirm({
101
- title: 'Are you sure you want to delete this content?',
102
- body: 'Deleting this Content will remove this content from this pod. This is irreversible!',
103
- acceptButtonText: 'Delete Forever',
104
- confirm: () => {},
105
- });
106
- }
107
-
108
- @action deleteSelected() {
109
- const selected = this.table.selectedRows;
110
-
111
- this.crud.bulkDelete(selected, {
112
- modelNamePath: 'name',
113
- acceptButtonText: 'Delete All',
114
- onSuccess: () => {
115
- return this.hostRouter.refresh();
116
- },
117
- });
118
- }
119
-
120
- trackCursor(content) {
121
- if (typeof this.cursor === 'string' && this.cursor.includes(content.id)) {
122
- const segments = this.cursor.split(':');
123
- const currentIndex = segments.findIndex((segment) => segment === content.id);
124
-
125
- if (currentIndex > -1) {
126
- const retainedSegments = segments.slice(0, currentIndex + 1);
127
- this.cursor = retainedSegments.join(':');
128
- return this.cursor;
129
- }
130
- }
131
-
132
- this.cursor = this.cursor ? `${this.cursor}:${content.id}` : content.id;
133
- return this.cursor;
134
- }
135
-
136
- reverseCursor() {
137
- const segments = this.cursor.split(':');
138
- segments.pop();
139
- const current = segments[segments.length - 1];
140
- this.cursor = segments.join(':');
141
- return current;
142
- }
143
-
144
- @task({ restartable: true }) *search(event) {
145
- yield timeout(300);
146
- const query = typeof event.target.value === 'string' ? event.target.value : '';
147
- this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', this.model.id, { queryParams: { cursor: this.cursor, query } });
148
- }
149
- }
@@ -1,12 +0,0 @@
1
- import Controller from '@ember/controller';
2
- import { action } from '@ember/object';
3
-
4
- export default class PodsIndexPodController extends Controller {
5
- @action setOverlayContext(overlayContextApi) {
6
- this.overlayContextApi = overlayContextApi;
7
- }
8
-
9
- @action onPressClose() {
10
- window.history.back();
11
- }
12
- }
@@ -1,137 +0,0 @@
1
- import Controller from '@ember/controller';
2
- import { action } from '@ember/object';
3
- import { inject as service } from '@ember/service';
4
- import { tracked } from '@glimmer/tracking';
5
- import { task, timeout } from 'ember-concurrency';
6
-
7
- export default class PodsIndexController extends Controller {
8
- @service hostRouter;
9
- @service notifications;
10
- @service filters;
11
- @service modalsManager;
12
- @service crud;
13
- @tracked query = '';
14
-
15
- columns = [
16
- {
17
- label: 'Pod',
18
- valuePath: 'name',
19
- width: '80%',
20
- cellComponent: 'table/cell/anchor',
21
- onClick: this.explorePod,
22
- },
23
- {
24
- label: 'Size',
25
- valuePath: 'size',
26
- width: '5%',
27
- },
28
- {
29
- label: 'Created At',
30
- valuePath: 'created_at',
31
- width: '15%',
32
- },
33
- {
34
- label: '',
35
- cellComponent: 'table/cell/dropdown',
36
- ddButtonText: false,
37
- ddButtonIcon: 'ellipsis-h',
38
- ddButtonIconPrefix: 'fas',
39
- ddMenuLabel: 'Pod Actions',
40
- cellClassNames: 'overflow-visible',
41
- wrapperClass: 'flex items-center justify-end mx-2',
42
- width: '10%',
43
- actions: [
44
- {
45
- label: 'Browse',
46
- fn: this.openPod,
47
- },
48
- {
49
- label: 'Backup',
50
- fn: this.backupPod,
51
- },
52
- {
53
- label: 'Re-sync',
54
- fn: this.resyncPod,
55
- },
56
- {
57
- separator: true,
58
- },
59
- {
60
- label: 'Delete',
61
- fn: this.deletePod,
62
- },
63
- ],
64
- sortable: false,
65
- filterable: false,
66
- resizable: false,
67
- searchable: false,
68
- },
69
- ];
70
-
71
- @action reload() {
72
- this.hostRouter.refresh();
73
- }
74
-
75
- @action openPod(pod) {
76
- this.hostRouter.transitionTo('console.solid-protocol.pods.index.pod', pod);
77
- }
78
-
79
- @action explorePod(pod) {
80
- this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', pod, { queryParams: { cursor: pod.id, pod: pod.id } });
81
- }
82
-
83
- @action createPod() {
84
- this.modalsManager.show('modals/create-pod', {
85
- title: 'Create a new Pod',
86
- acceptButtonText: 'Create Pod',
87
- pod: {
88
- name: null,
89
- },
90
- confirm: () => {},
91
- });
92
- }
93
-
94
- @action backupPod() {
95
- this.modalsManager.confirm({
96
- title: 'Are you sure you want to create a backup?',
97
- body: 'Running a backup will create a duplicate Pod with the same contents.',
98
- acceptButtonText: 'Start Backup',
99
- confirm: () => {},
100
- });
101
- }
102
-
103
- @action resyncPod() {
104
- this.modalsManager.confirm({
105
- title: 'Are you sure you want to re-sync?',
106
- body: 'Running a re-sync will update all data from Fleetbase to this pod, overwriting the current contents with the latest.',
107
- acceptButtonText: 'Start Sync',
108
- confirm: () => {},
109
- });
110
- }
111
-
112
- @action deletePod() {
113
- this.modalsManager.confirm({
114
- title: 'Are you sure you want to delete this Pod?',
115
- body: "Deleting this Pod will destroy this pod and all it's contents. This is irreversible!",
116
- acceptButtonText: 'Delete Forever',
117
- confirm: () => {},
118
- });
119
- }
120
-
121
- @action deleteSelectedPods() {
122
- const selected = this.table.selectedRows;
123
-
124
- this.crud.bulkDelete(selected, {
125
- modelNamePath: 'name',
126
- acceptButtonText: 'Delete All',
127
- onSuccess: () => {
128
- return this.hostRouter.refresh();
129
- },
130
- });
131
- }
132
-
133
- @task({ restartable: true }) *search(event) {
134
- yield timeout(300);
135
- this.query = typeof event.target.value === 'string' ? event.target.value : '';
136
- }
137
- }
@@ -1,10 +0,0 @@
1
- import Route from '@ember/routing/route';
2
- import { inject as service } from '@ember/service';
3
-
4
- export default class PodsExplorerContentRoute extends Route {
5
- @service fetch;
6
-
7
- model({ slug }) {
8
- return this.fetch.get('pods', { slug }, { namespace: 'solid/int/v1' });
9
- }
10
- }
@@ -1,44 +0,0 @@
1
- import Route from '@ember/routing/route';
2
- import { inject as service } from '@ember/service';
3
- import { action } from '@ember/object';
4
-
5
- export default class PodsExplorerRoute extends Route {
6
- @service fetch;
7
- @service explorerState;
8
-
9
- queryParmas = {
10
- query: {
11
- refreshModel: true,
12
- },
13
- pod: {
14
- refreshModel: false,
15
- },
16
- cursor: {
17
- refreshModel: false,
18
- },
19
- };
20
-
21
- @action willTransition(transition) {
22
- const pod = transition.to.queryParams.pod;
23
- const cursor = transition.to.queryParams.cursor;
24
- if (pod && cursor) {
25
- this.explorerState.trackWithCursor(pod, cursor);
26
- }
27
- }
28
-
29
- beforeModel(transition) {
30
- const pod = transition.to.queryParams.pod;
31
- const cursor = transition.to.queryParams.cursor;
32
- if (pod && cursor) {
33
- this.explorerState.trackWithCursor(pod, cursor);
34
- }
35
- }
36
-
37
- model({ id, query }) {
38
- return this.fetch.get('pods', { id, query }, { namespace: 'solid/int/v1' });
39
- }
40
-
41
- afterModel(model, transition) {
42
- this.explorerState.track(transition.to.queryParams.pod, model);
43
- }
44
- }
@@ -1,3 +0,0 @@
1
- import Route from '@ember/routing/route';
2
-
3
- export default class PodsIndexPodRoute extends Route {}
@@ -1,21 +0,0 @@
1
- import Route from '@ember/routing/route';
2
- import { inject as service } from '@ember/service';
3
-
4
- export default class PodsIndexRoute extends Route {
5
- @service fetch;
6
- @service appCache;
7
-
8
- queryParams = {
9
- query: {
10
- refreshModel: true,
11
- },
12
- };
13
-
14
- model(params) {
15
- return this.fetch.get('pods', params, { namespace: 'solid/int/v1' });
16
- }
17
-
18
- afterModel(model) {
19
- this.appCache.set('solid:pods', model);
20
- }
21
- }
@@ -1,19 +0,0 @@
1
- <Overlay @isOpen={{true}} @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="600px" @isResizable={{true}}>
2
- <Overlay::Header @title={{@model.name}} @hideStatusDot={{true}} @titleWrapperClass="leading-5">
3
- <div class="flex flex-1 justify-end">
4
- <Button @type="default" @icon="times" @helpText={{t "common.close"}} @onClick={{this.onPressClose}} />
5
- </div>
6
- </Overlay::Header>
7
-
8
- <Overlay::Body>
9
- <div class="p-4 space-y-2">
10
- <div>ID: {{@model.id}}</div>
11
- <div>Name: {{@model.name}}</div>
12
- <div>Size: {{@model.size}}</div>
13
- <div class="mt-2 rounded-md border border-gray-700 p-3 bg-gray-800">
14
- <div class="font-semibold">Contents:</div>
15
- <div></div>
16
- </div>
17
- </div>
18
- </Overlay::Body>
19
- </Overlay>
@@ -1,11 +0,0 @@
1
- <Overlay @isOpen={{true}} @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="600px" @isResizable={{true}}>
2
- <Overlay::Header @title="Pod" @hideStatusDot={{true}} @titleWrapperClass="leading-5">
3
- <div class="flex flex-1 justify-end">
4
- <Button @type="default" @icon="times" @helpText={{t "common.close"}} @onClick={{this.onPressClose}} />
5
- </div>
6
- </Overlay::Header>
7
-
8
- <Overlay::Body class="without-padding">
9
-
10
- </Overlay::Body>
11
- </Overlay>
@@ -1,19 +0,0 @@
1
- <Layout::Section::Header @title="Pods" @searchPlaceholder="Search Pods by Keyword" @searchQuery={{this.query}} @onSearch={{perform this.search}}>
2
- <Button @icon="refresh" @onClick={{this.reload}} @helpText="Refresh" class="mr-2" />
3
- {{#if (safe-has this.table "selectedRows")}}
4
- <DropdownButton @icon="layer-group" @text="Bulk Action" @type="magic" @size="sm" @buttonWrapperClass="mr-2" @contentClass="dropdown-menu" as |dd|>
5
- <div class="next-dd-menu mt-2 mx-0">
6
- <div class="px-1">
7
- <a href="#" class="text-red-500 next-dd-item" {{on "click" (dropdown-fn dd this.deleteSelectedPods)}}>
8
- Delete Selected Pods
9
- </a>
10
- </div>
11
- </div>
12
- </DropdownButton>
13
- {{/if}}
14
- <Button @icon="plus" @iconPrefix="fas" @type="primary" @text="Create new Pod" class="mr-2" @onClick={{this.createPod}} />
15
- </Layout::Section::Header>
16
- <Layout::Section::Body>
17
- <Table @rows={{@model}} @columns={{this.columns}} @selectable={{true}} @canSelectAll={{true}} @onSetup={{fn (mut this.table)}} @tfootVerticalOffset="53" @tfootVerticalOffsetElements=".next-view-section-subheader" />
18
- </Layout::Section::Body>
19
- {{outlet}}
@@ -1,174 +0,0 @@
1
- <?php
2
-
3
- namespace Fleetbase\Solid\LegacyClient\Identity;
4
-
5
- use EasyRdf\Graph;
6
- use Fleetbase\Solid\Client\OIDCClient;
7
- use Fleetbase\Solid\Client\SolidClient;
8
- use Fleetbase\Support\Utils;
9
- use Jumbojett\OpenIDConnectClientException;
10
-
11
- class IdentityProvider
12
- {
13
- /**
14
- * The Solid client instance.
15
- */
16
- private SolidClient $solidClient;
17
-
18
- /**
19
- * The OIDC client instance for handling OpenID Connect authentication.
20
- */
21
- private OIDCClient $oidcClient;
22
-
23
- /**
24
- * Default MIME type for RDF data.
25
- */
26
- private const DEFAULT_MIME_TYPE = 'text/turtle';
27
-
28
- /**
29
- * RDF type for LDP Basic Containers.
30
- */
31
- private const LDP_BASIC_CONTAINER = 'http://www.w3.org/ns/ldp#BasicContainer';
32
-
33
- /**
34
- * RDF type for LDP Resources.
35
- */
36
- private const LDP_RESOURCE = 'http://www.w3.org/ns/ldp#Resource';
37
-
38
- /**
39
- * RDF property for OIDC issuer.
40
- */
41
- private const OIDC_ISSUER = 'http://www.w3.org/ns/solid/terms#oidcIssuer';
42
-
43
- /**
44
- * Constructs a new IdentityProvider instance.
45
- *
46
- * @param SolidClient $solidClient the Solid client instance
47
- */
48
- public function __construct(SolidClient $solidClient)
49
- {
50
- $this->solidClient = $solidClient;
51
- $this->oidcClient = OIDCClient::create($solidClient);
52
- }
53
-
54
- /**
55
- * Gets the OIDC client instance.
56
- *
57
- * @return OIDCClient the OIDC client instance
58
- */
59
- public function getOidcClient(): OIDCClient
60
- {
61
- if (!$this->oidcClient) {
62
- return OIDCClient::create($this->solidClient);
63
- }
64
-
65
- return $this->oidcClient;
66
- }
67
-
68
- /**
69
- * Magic method to delegate method calls to either IdentityProvider or OIDCClient.
70
- *
71
- * @param string $name the name of the method being called
72
- * @param array $arguments the arguments passed to the method
73
- *
74
- * @return mixed the result of the method call
75
- */
76
- public function __call(string $name, $arguments)
77
- {
78
- if (method_exists($this, $name)) {
79
- return $this->{$name}(...$arguments);
80
- }
81
-
82
- if (method_exists($this->oidcClient, $name)) {
83
- return $this->oidcClient->{$name}(...$arguments);
84
- }
85
-
86
- throw new \BadMethodCallException("Method {$name} does not exist.");
87
- }
88
-
89
- public function registerClient(array $options = []): self
90
- {
91
- // Get registration options
92
- $clientName = data_get($options, 'clientName', $this->oidcClient::CLIENT_NAME);
93
- $requestParams = data_get($options, 'requestParams', []);
94
- $requestOptions = data_get($options, 'requestOptions', []);
95
- $redirectUri = data_get($options, 'redirectUri');
96
- if (!$redirectUri) {
97
- $requestCode = data_get($options, 'requestCode');
98
- $redirectUri = Utils::apiUrl('solid/int/v1/oidc/complete-registration' . $requestCode ? '/' . $requestCode : '', [], 8000);
99
- }
100
- $withResponse = data_get($options, 'withResponse');
101
-
102
- // Get OIDC Config and Registration URL
103
- $oidcConfig = $this->solidClient->getOpenIdConfiguration();
104
- $registrationUrl = data_get($oidcConfig, 'registration_endpoint');
105
-
106
- // Request registration for Client which should handle authentication
107
- $response = $this->solidClient->post($registrationUrl, ['client_name' => $clientName, 'redirect_uris' => [$redirectUri], ...$requestParams], ['withoutAuth' => true, ...$requestOptions]);
108
- if ($response->successful()) {
109
- $clientCredentials = $response->json();
110
- $this->setClientCredentials($clientName, $clientCredentials);
111
- if (is_callable($withResponse)) {
112
- $withResponse($clientCredentials);
113
- }
114
- } else {
115
- throw new OpenIDConnectClientException('Error registering: Please contact the OpenID Connect provider and obtain a Client ID and Secret directly from them');
116
- }
117
-
118
- return $this;
119
- }
120
-
121
- public function getClient(array $options = [])
122
- {
123
- $clientName = data_get($options, 'clientName', $this->oidcClient::CLIENT_NAME);
124
- $restoredClient = $this->restoreClientCredentials($clientName);
125
- if ($restoredClient === null) {
126
- return $this->registerClient($options);
127
- }
128
-
129
- return $restoredClient;
130
- }
131
-
132
- /**
133
- * Retrieves the WebID profile of a user as an RDF graph.
134
- *
135
- * @param string $webId the WebID of the user
136
- * @param array $options additional options for the request
137
- *
138
- * @return Graph the user's WebID profile as an RDF graph
139
- */
140
- public function getWebIdProfile(string $webId, array $options = []): Graph
141
- {
142
- $response = $this->solidClient->get($webId, $options);
143
- $format = $response->header('Content-Type');
144
-
145
- if ($format) {
146
- // strip parameters (such as charset) if any
147
- $format = explode(';', $format, 2)[0];
148
- }
149
-
150
- return new Graph($webId, $response->getContent(), $format);
151
- }
152
-
153
- /**
154
- * Retrieves the OIDC issuer URL from a WebID profile.
155
- *
156
- * @param string $webId the WebID of the user
157
- * @param array $options additional options for the request
158
- *
159
- * @return string the OIDC issuer URL
160
- *
161
- * @throws \Exception if the OIDC issuer cannot be found
162
- */
163
- public function getOidcIssuer(string $webId, array $options = []): string
164
- {
165
- $graph = $this->getWebIdProfile($webId, $options);
166
- $issuer = $graph->get($webId, sprintf('<%s>', self::OIDC_ISSUER))->getUri();
167
-
168
- if (!\is_string($issuer)) {
169
- throw new \Exception('Unable to find the OIDC issuer associated with this WebID', 1);
170
- }
171
-
172
- return $issuer;
173
- }
174
- }
@@ -1,18 +0,0 @@
1
- <?php
2
-
3
- namespace Fleetbase\Solid\LegacyClient\Identity;
4
-
5
- use EasyRdf\Graph;
6
-
7
- class Profile
8
- {
9
- private Graph $graph;
10
- public string $webId;
11
- public string $name;
12
- public string $email;
13
-
14
- public function __construct(Graph $graph)
15
- {
16
- $this->graph = $graph;
17
- }
18
- }