Skip to content

Commit b9cbd9a

Browse files
committed
Adding permission buiilding to request
1 parent 07e5ecb commit b9cbd9a

8 files changed

Lines changed: 426 additions & 174 deletions

File tree

docs/hds-lib.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/hds-lib.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/tests-browser.js

Lines changed: 165 additions & 86 deletions
Large diffs are not rendered by default.

docs/tests-browser.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/appTemplates/CollectorRequest.ts

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { localizableText, localizableTextLanguages } from '../../types/loca
55

66

77
declare type PermissionItem = {streamId: string, defaultName: string, level: string};
8+
declare type PermissionItemLight = {streamId: string, defaultName?: string, level?: string};
89

910
const CURRENT_VERSION = 1;
1011

@@ -25,6 +26,7 @@ export class CollectorRequest {
2526
#consent: localizableText;
2627
#requester: {name: string};
2728
#app: {id: string, url: string | null, data: any};
29+
#permissionsExtra: Array<PermissionItemLight>;
2830
#permissions: Array<PermissionItem>;
2931
#sections: Array<CollectorRequestSection>;
3032

@@ -34,6 +36,7 @@ export class CollectorRequest {
3436
this.#requester = { name: null };
3537
this.#app = { id: null, url: null, data: {} };
3638
this.#permissions = [];
39+
this.#permissionsExtra = [];
3740
this.#sections = [];
3841
this.setContent(content);
3942
}
@@ -47,8 +50,6 @@ export class CollectorRequest {
4750
this.setContent(inviteEvent.content);
4851
}
4952

50-
51-
5253
/**
5354
* Loadfrom status event from Collector
5455
* used by Collector only
@@ -106,22 +107,33 @@ export class CollectorRequest {
106107

107108
// -- sections
108109
if (futureContent.sections != null) {
110+
this.#sections = []; // reset sections
109111
for (const sectionData of futureContent.sections) {
110-
const section = new CollectorRequestSection(sectionData.key, sectionData.type);
112+
const section = this.createSection(sectionData.key, sectionData.type);
111113
section.setName(sectionData.name);
112114
section.addItemKeys(sectionData.itemKeys);
113-
this.#sections.push(section);
114115
}
116+
delete futureContent.sections;
115117
}
116118

117119
// -- permissions
118120
if (futureContent.permissions) {
119121
this.#permissions = []; // reset permissions
120122
futureContent.permissions.forEach((p: PermissionItem)=> {
121-
this.addPermissions(p.streamId, p.defaultName, p.level);
123+
this.addPermission(p.streamId, p.defaultName, p.level);
122124
});
123125
delete futureContent.permissions;
124126
}
127+
128+
// -- permissionsExtra
129+
if (futureContent.permissionsExtra) {
130+
this.#permissionsExtra = []; // reset permissions Extra
131+
futureContent.permissionsExtra.forEach((p: PermissionItem)=> {
132+
this.addPermissionExtra(p);
133+
});
134+
delete futureContent.permissionsExtra;
135+
}
136+
125137
this.#extraContent = futureContent;
126138
}
127139

@@ -152,6 +164,7 @@ export class CollectorRequest {
152164
get appCustomData() { return this.#app.data; }
153165

154166
get permissions() { return this.#permissions; }
167+
get permissionsExtra() { return this.#permissionsExtra; }
155168

156169
// --- section --- //
157170

@@ -162,20 +175,67 @@ export class CollectorRequest {
162175
get sectionsData () {
163176
const result = [];
164177
for (const section of this.#sections) {
165-
result.push(section.getData());
178+
const data = section.getData();
179+
result.push(data);
166180
}
167181
return result;
168182
}
169183

184+
createSection (key: string, type: RequestSectionType) {
185+
if (this.getSectionByKey(key) != null) throw new HDSLibError(`Section with key: ${key} already exists`)
186+
const section = new CollectorRequestSection(key, type);
187+
this.#sections.push(section);
188+
return section;
189+
}
190+
170191
getSectionByKey (key: string) {
171192
return this.#sections.find((s) => (s.key === key));
172193
}
173194

174195
// ---------- permissions ---------- //
175-
addPermissions (streamId: string, defaultName: string, level: string) {
196+
addPermissions (permissions: Array<{streamId: string, defaultName: string, level: string}>) {
197+
for (const permission of permissions) {
198+
this.addPermission(permission.streamId, permission.defaultName, permission.level);
199+
}
200+
}
201+
202+
addPermission (streamId: string, defaultName: string, level: string) {
176203
this.#permissions.push({streamId, defaultName, level});
177204
}
178205

206+
/**
207+
* Add a static permission, not linked to itemKeys for other usages
208+
* @param permission
209+
*/
210+
addPermissionExtra (permission: PermissionItemLight) {
211+
// todo standard checks
212+
this.#permissionsExtra.push(permission);
213+
}
214+
215+
/**
216+
* Reset permissions
217+
*/
218+
resetPermissions() {
219+
this.#permissions.splice(0, this.#permissions.length);
220+
}
221+
222+
/**
223+
* Rebuild permissions based on sections itemKeys and staticPermissions
224+
*/
225+
buildPermissions () {
226+
// 1- get all items form the questionnary sections
227+
const itemKeys = [];
228+
for (const section of this.sections) {
229+
itemKeys.push(...section.itemKeys);
230+
}
231+
// 2 - get the permissions with eventual preRequest
232+
const preRequest = this.permissionsExtra || [];
233+
const permissions = getModel().authorizations.forItemKeys(itemKeys, { preRequest });
234+
// 3 - if no error araised - reset permissions
235+
this.resetPermissions();
236+
this.addPermissions(permissions);
237+
}
238+
179239
// ---------- sections ------------- //
180240

181241
/**
@@ -190,6 +250,7 @@ export class CollectorRequest {
190250
requester: {
191251
name: this.requesterName
192252
},
253+
permissionsExtra: this.permissionsExtra,
193254
permissions: this.permissions,
194255
app: {
195256
id: this.appId,

tests/apptemplates.test.js

Lines changed: 2 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/* eslint-env mocha */
22
const { assert } = require('./test-utils/deps-node');
3-
const { createUserAndPermissions, pryv, createUser, createUserPermissions } = require('./test-utils/pryvService');
3+
const { pryv, createUserPermissions } = require('./test-utils/pryvService');
44
const AppManagingAccount = require('../src/appTemplates/AppManagingAccount');
55
const AppClientAccount = require('../src/appTemplates/AppClientAccount');
66
const Collector = require('../src/appTemplates/Collector');
77
const CollectorClient = require('../src/appTemplates/CollectorClient');
88
const { HDSLibError } = require('../src/errors');
99
const { initHDSModel } = require('../src/index.js');
10+
const { helperNewAppAndUsers, helperNewInvite, helperNewAppManaging } = require('./test-utils/helpersAppTemplate.js');
1011

1112
describe('[APTX] appTemplates', function () {
1213
this.timeout(10000);
@@ -512,80 +513,3 @@ describe('[APTX] appTemplates', function () {
512513
});
513514
});
514515
});
515-
516-
/**
517-
* function helperNewAppManaging
518-
*/
519-
async function helperNewAppManaging (baseStreamIdManager, appName, managingUser = null) {
520-
// -- managing
521-
const initialStreams = [{ id: 'applications', name: 'Applications' }, { id: baseStreamIdManager, name: appName, parentId: 'applications' }];
522-
const permissionsManager = [{ streamId: baseStreamIdManager, level: 'manage' }];
523-
if (!managingUser) {
524-
managingUser = await createUserAndPermissions(null, permissionsManager, initialStreams, appName);
525-
} else {
526-
// replace managing user with new permissions set
527-
managingUser = await createUserPermissions(managingUser, permissionsManager, initialStreams, appName);
528-
}
529-
const connection = new pryv.Connection(managingUser.appApiEndpoint);
530-
const appManaging = await AppManagingAccount.newFromConnection(baseStreamIdManager, connection);
531-
return { managingUser, appManaging };
532-
}
533-
534-
/**
535-
* helper to generate a new managing user and new client user
536-
*/
537-
async function helperNewAppClient (baseStreamIdClient, appClientName) {
538-
// -- receiving user
539-
const clientUser = await createUser();
540-
const permissionsClient = [{ streamId: '*', level: 'manage' }];
541-
const clientUserResultPermissions = await createUserPermissions(clientUser, permissionsClient, [], appClientName);
542-
const appClient = await AppClientAccount.newFromApiEndpoint(baseStreamIdClient, clientUserResultPermissions.appApiEndpoint, appClientName);
543-
return { clientUser, clientUserResultPermissions, appClient };
544-
}
545-
546-
/**
547-
* helper to generate a new managing user and new client user
548-
*/
549-
async function helperNewAppAndUsers (baseStreamIdManager, appName, baseStreamIdClient, appClientName) {
550-
const res = {};
551-
const resManager = await helperNewAppManaging(baseStreamIdManager, appName);
552-
const resClient = await helperNewAppClient(baseStreamIdClient, appClientName);
553-
Object.assign(res, resManager);
554-
Object.assign(res, resClient);
555-
return res;
556-
}
557-
558-
/**
559-
* heper to generate a new collector and invite for this managing application
560-
* @param {AppManagingAccount} appManaging
561-
* @returns {Object}
562-
*/
563-
async function helperNewInvite (appManaging, appClient, code) {
564-
code = code || Math.floor(Math.random() * 1000);
565-
const collector = await appManaging.createCollector('Invite test ' + code);
566-
567-
// set request content
568-
const requestContent = {
569-
version: 0,
570-
requester: { name: 'Test requester name' },
571-
title: { en: 'Title of the request' },
572-
description: { en: 'Short Description' },
573-
consent: { en: 'This is a consent message' },
574-
permissions: [{ streamId: 'profile-name', defaultName: 'Name', level: 'read' }],
575-
app: { id: 'test-app', url: 'https://xxx.yyy', data: { } }
576-
};
577-
collector.request.setContent(requestContent);
578-
579-
await collector.save();
580-
await collector.publish();
581-
// create invite
582-
const options = { customData: { hello: 'bob' } };
583-
const invite = await collector.createInvite('Invite One', options);
584-
const inviteSharingData = await invite.getSharingData();
585-
assert.equal(inviteSharingData.apiEndpoint, await collector.sharingApiEndpoint());
586-
587-
// Invitee receives the invite
588-
const collectorClient = await appClient.handleIncomingRequest(inviteSharingData.apiEndpoint, inviteSharingData.eventId);
589-
590-
return { collector, invite, collectorClient, inviteSharingData };
591-
}

tests/apptemplatesRequest.test.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* eslint-env mocha */
2+
3+
const { initHDSModel } = require('../src');
4+
const { helperNewAppManaging } = require('./test-utils/helpersAppTemplate');
5+
const { assert } = require('./test-utils/deps-node');
6+
7+
describe('[APRX] appTemplates Requests', function () {
8+
before(async () => {
9+
await initHDSModel();
10+
});
11+
it('[APRC] Compute a simple request', async () => {
12+
const baseStreamId = 'aprc';
13+
const { appManaging } = await helperNewAppManaging(baseStreamId, 'test-APRC');
14+
const newCollector = await appManaging.createCollector('Invite test APCV');
15+
16+
const request = newCollector.request;
17+
request.appId = 'dr-form';
18+
request.appUrl = 'https://xxx.yyy';
19+
request.title = { en: 'My title' };
20+
request.requesterName = 'Username APRC';
21+
request.description = { en: 'Short Description' };
22+
request.consent = { en: 'Short Consent' };
23+
request.addPermissionExtra({ streamId: 'profile' });
24+
request.addPermissionExtra({ streamId: 'fertility' });
25+
26+
const sectionA = request.createSection('profile', 'permanent');
27+
sectionA.setNameLocal('en', 'A');
28+
sectionA.addItemKeys([
29+
'profile-name',
30+
'profile-surname',
31+
'profile-sex',
32+
'family-children-count',
33+
'fertility-miscarriages-count'
34+
]);
35+
36+
const sectionB = request.createSection('history', 'recurring');
37+
sectionB.setNameLocal('en', 'B');
38+
sectionB.addItemKeys([
39+
'fertility-ttc-tta',
40+
'body-weight'
41+
]);
42+
// build permissions needed
43+
request.buildPermissions();
44+
const requestContent = request.content;
45+
assert.ok(requestContent.id.startsWith(baseStreamId), 'id should start with the basetreamid of the manager');
46+
47+
const expectedContent = {
48+
version: 1,
49+
title: { en: 'My title' },
50+
consent: { en: 'Short Consent' },
51+
description: { en: 'Short Description' },
52+
requester: { name: 'Username APRC' },
53+
permissionsExtra: [
54+
{ streamId: 'profile', defaultName: 'Profile', level: 'read' },
55+
{
56+
streamId: 'fertility',
57+
defaultName: 'Fertility',
58+
level: 'read'
59+
}
60+
],
61+
permissions: [
62+
{ streamId: 'profile', defaultName: 'Profile', level: 'read' },
63+
{ streamId: 'fertility', defaultName: 'Fertility', level: 'read' },
64+
{
65+
streamId: 'family-children',
66+
defaultName: 'Children',
67+
level: 'read'
68+
},
69+
{
70+
streamId: 'body-weight',
71+
defaultName: 'Body Weight',
72+
level: 'read'
73+
}
74+
],
75+
app: { id: 'dr-form', url: 'https://xxx.yyy', data: {} },
76+
sections: [
77+
{
78+
key: 'profile',
79+
type: 'permanent',
80+
name: { en: 'A' },
81+
itemKeys: [
82+
'profile-name',
83+
'profile-surname',
84+
'profile-sex',
85+
'family-children-count',
86+
'fertility-miscarriages-count'
87+
]
88+
},
89+
{
90+
key: 'history',
91+
type: 'recurring',
92+
name: { en: 'B' },
93+
itemKeys: ['fertility-ttc-tta', 'body-weight']
94+
}
95+
],
96+
id: requestContent.id
97+
};
98+
assert.deepEqual(requestContent, expectedContent);
99+
});
100+
});

0 commit comments

Comments
 (0)