Skip to content

Commit e5607c1

Browse files
committed
Updated README
1 parent 1548025 commit e5607c1

7 files changed

Lines changed: 314 additions & 36 deletions

File tree

README.md

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,94 @@ Generic toolkit for server and web applications.
44

55
- [ ]
66

7-
87
## Usage
98

9+
### Model
10+
11+
#### Load
12+
13+
```javascript
14+
const model = new HDSLib.HDSModel('https://model.datasafe.dev/pack.json');
15+
await model.load();
16+
```
17+
18+
#### IdemDef
19+
20+
An `ItemdDef` is an object representation of the items from the data Model
21+
22+
```javascript
23+
// retrieve an itemDef by it's key
24+
const weight = mode.itemDefs.forKey('body-weight');
25+
weight.streamId; // => 'body-weight'
26+
weight.eventTypes; // => 'mass/kg', 'mass/lb']
27+
```
28+
29+
```javascript
30+
// retrieve an itemDef from an event
31+
const anEvent = {
32+
streamIds: ['body-weight', 'dummy'],
33+
type: 'mass/kg'
34+
};
35+
const itemDef = model.itemsDefs.forEvent(fakeEvent);
36+
itemDef.key // => 'body-weight'
37+
```
38+
39+
#### Streams
40+
41+
```javascript
42+
// get the list of streams to be created to store theses items
43+
const itemKeys = [
44+
'profile-name',
45+
'profile-date-of-birth',
46+
'body-vulva-mucus-stretch',
47+
'profile-surname'
48+
];
49+
const streamsToBeCreated = model.streams.getNecessaryListForItemKeys(itemKeys);
50+
```
51+
52+
#### Authorizations
53+
54+
```javascript
55+
// get the authorization needed to manipulate a set of items
56+
const itemKeys = [
57+
'body-vulva-mucus-inspect',
58+
'profile-name',
59+
'profile-date-of-birth',
60+
'body-vulva-mucus-stretch',
61+
'profile-surname'
62+
];
63+
const options = {
64+
preRequest: [ // optional, will be considered in the request
65+
{ streamId: 'profile' },
66+
{ streamId: 'app-test', defaultName: 'App test', level: 'write' }
67+
]
68+
};
69+
const authorizationSet = model.authorizations.forItemKeys(itemKeys, options);
70+
// the following object is the result
71+
const expected = [
72+
{ streamId: 'profile', defaultName: 'Profile', level: 'read' },
73+
{ streamId: 'app-test', defaultName: 'App test', level: 'write' },
74+
{
75+
streamId: 'body-vulva-mucus-inspect',
76+
defaultName: 'Vulva Mucus Inspect',
77+
level: 'read'
78+
},
79+
{
80+
streamId: 'body-vulva-mucus-stretch',
81+
defaultName: 'Vulva Mucus Stretch',
82+
level: 'read'
83+
}
84+
];
85+
```
86+
87+
88+
89+
### AppTemplates
90+
91+
92+
93+
94+
1095
### Browser
1196

1297
```html
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
const pryv = require('../patchedPryv');
2+
3+
/**
4+
* - applications
5+
* - [baseStreamId] "Root" stream from this app
6+
*/
7+
class AppClientAccount {
8+
conection;
9+
baseStreamId;
10+
appName;
11+
#cache;
12+
13+
get streamData () {
14+
return this.#cache.streamData;
15+
}
16+
17+
/**
18+
* Create with an apiEnpoint
19+
* @param {string} apiEndpoint
20+
* @param {string} baseStreamId - application base Strem ID
21+
* @param {string} appName
22+
* @returns {AppClientAccount}
23+
*/
24+
static async newFromApiEndpoint (apiEndpoint, baseStreamId, appName) {
25+
const connection = new pryv.Connection(apiEndpoint);
26+
return await this.newWithConnection(connection, baseStreamId, appName);
27+
}
28+
29+
/**
30+
* Create with an apiEnpoint
31+
* @param {Pryv.connection} connection - must be a connection with personnalToken or masterToken
32+
* @param {string} baseStreamId - application base Strem ID
33+
* @param {string} appName
34+
* @returns {AppClientAccount}
35+
*/
36+
static async newWithConnection (connection, baseStreamId, appName) {
37+
const appClientAccount = new AppClientAccount(connection, baseStreamId, appName);
38+
await appClientAccount.init();
39+
return appClientAccount;
40+
}
41+
42+
/**
43+
* @private
44+
* use one of AppClientAccount.createWith..()
45+
* @param {string} baseStreamId - application base Strem ID
46+
* @param {Pryv.connection} connection - must be a connection with personnalToken or masterToken
47+
*/
48+
constructor (connection, baseStreamId, appName) {
49+
if (!baseStreamId || baseStreamId.length < 2) throw new Error('Missing or too short baseStreamId');
50+
this.connection = connection;
51+
this.baseStreamId = baseStreamId;
52+
this.appName = appName;
53+
this.#cache = {};
54+
}
55+
56+
/**
57+
* - Check connection validity
58+
* - Make sure stream structure exists
59+
*/
60+
async init () {
61+
// check that connection has a master token or is a personnal token
62+
const infos = await this.connection.accessInfo();
63+
if (infos.type !== 'personal') {
64+
if (infos.type !== 'app') throw new Error('AppClientAccount requires a "personal" or "app" type of access');
65+
const masterFound = infos.permissions.find(p => (p.streamId === '*' && p.level === 'manage'));
66+
if (!masterFound) throw new Error('AppClientAccount with "app" type of access requires "master" token (streamId = "*", level = "manage")');
67+
}
68+
// get streamStructure
69+
let found = false;
70+
try {
71+
const streams = await this.connection.apiOne('streams.get', { id: this.baseStreamId }, 'streams');
72+
if (streams[0]) this.#cache.streamData = streams[0];
73+
found = true;
74+
} catch (e) {
75+
if (e.innerObject?.id !== 'unknown-referenced-resource' || e.innerObject?.data?.id !== 'test-app-template-client') {
76+
throw e;
77+
}
78+
}
79+
// not found create streams
80+
if (!found) {
81+
const apiCalls = [
82+
{ method: 'streams.create', params: { id: 'applications', name: 'Applications' } },
83+
{ method: 'streams.create', params: { id: this.baseStreamId, name: this.appName, parentId: 'applications' } }
84+
];
85+
const streamCreateResult = await this.connection.api(apiCalls);
86+
const stream = streamCreateResult[1].stream;
87+
this.#cache.streamData = stream;
88+
}
89+
}
90+
}
91+
92+
module.exports = AppClientAccount;

src/appTemplates/AppManagingAccount.js

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ const Collector = require('./Collector');
1010
* The App can create multiple "collectors e.g. Questionnaries"
1111
*
1212
* Stream structure
13-
* - [baseStreamId] "Root" stream for this app
13+
* - applications
14+
* - [baseStreamId] "Root" stream for this app
1415
* - [baseStreamId]-[collectorsId] Each "questionnary" or "request for a set of data" has it's own stream
1516
* - [baseStreamId]-[collectorsId]-internal Private stuff not to be shared
1617
* - [baseStreamId]-[collectorsId]-public Contains events with the current settings of this app (this stream will be shared in "read" with the request)
@@ -30,6 +31,7 @@ class AppManagingAccount {
3031
#cache;
3132

3233
/**
34+
* @private
3335
* use AppManagingAccount.newFromConnection() to create new AppManagingAccount
3436
* @param {string} appName
3537
* @param {string} baseStreamId
@@ -44,7 +46,7 @@ class AppManagingAccount {
4446

4547
/**
4648
* Return an initialized AppManagingAccount instance
47-
* @param {Pryv.Connection} connection
49+
* @param {Pryv.Connection} connection - should be personalConnection, a connection with "manage" right on `baseStreamId` or "manage" on "*"
4850
* @returns {AppManagingAccount}
4951
*/
5052
static async newFromConnection (connection, baseStreamId) {
@@ -72,7 +74,23 @@ class AppManagingAccount {
7274
return Object.values(this.#cache.collectorsMap);
7375
}
7476

77+
/**
78+
* Create an iniatilized Collector
79+
* @param {string} name
80+
* @returns {Collector}
81+
*/
7582
async createCollector (name) {
83+
const collector = await this.createCollectorUnitialized(name);
84+
await collector.init();
85+
return collector;
86+
}
87+
88+
/**
89+
* Create an unitialized Collector (mostly used by tests)
90+
* @param {string} name
91+
* @returns {Collector}
92+
*/
93+
async createCollectorUnitialized (name) {
7694
const streamId = this.baseStreamId + '-' + collectorIdGenerator.rnd();
7795
const params = {
7896
id: streamId,
@@ -90,15 +108,17 @@ module.exports = AppManagingAccount;
90108

91109
async function newAppManagingAccountFromConnection (connection, baseStreamId) {
92110
const accessInfo = await connection.apiOne('getAccessInfo');
93-
if (!accessInfo.type === 'app') throw new Error('Failed creating new AppManagingAccount, "app" authorization required: ' + JSON.stringify(accessInfo));
94-
// check if baseStreamId is in pemission set
95-
const found = accessInfo.permissions.find(p => (p.streamId === baseStreamId || p.streamId === '*'));
96-
if (found && found.level !== 'manage') { // check if level 'manage'
97-
throw new Error(`Failed creating new AppManagingAccount, Not sufficient permissions on stream: ${baseStreamId}`);
98-
}
99-
if (!found) {
100-
// here we may check if we can create or manage baseStreamId as it might be covered by permissions
101-
throw new Error(`Failed creating new AppManagingAccount, cannot find "${baseStreamId}" in permission list`);
111+
if (!accessInfo.type === 'personal') {
112+
if (!accessInfo.type === 'app') throw new Error('Failed creating new AppManagingAccount, "app" authorization required: ' + JSON.stringify(accessInfo));
113+
// check if baseStreamId is in pemission set
114+
const found = accessInfo.permissions.find(p => (p.streamId === baseStreamId || p.streamId === '*'));
115+
if (found && found.level !== 'manage') { // check if level 'manage'
116+
throw new Error(`Failed creating new AppManagingAccount, Not sufficient permissions on stream: ${baseStreamId}`);
117+
}
118+
if (!found) {
119+
// here we may check if we can create or manage baseStreamId as it might be covered by permissions
120+
throw new Error(`Failed creating new AppManagingAccount, cannot find "${baseStreamId}" in permission list`);
121+
}
102122
}
103123
const appManagingAccount = new AppManagingAccount(accessInfo.name, baseStreamId, connection);
104124
return appManagingAccount;

src/appTemplates/Collector.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,21 @@ class Collector {
107107
* @param {Object} [options]
108108
* @param {Object} [options.customData] any data to be used by the client app
109109
*/
110-
async createInvite (name, options) {
111-
110+
async createInvite (name, options = {}) {
111+
const eventParams = {
112+
type: 'invite/collector-v1',
113+
streamIds: [this.streamIdFor(Collector.STREAMID_SUFFIXES.pending)],
114+
content: {
115+
name,
116+
customData: options.customData || {}
117+
}
118+
};
119+
const newInvite = await this.appManaging.connection.apiOne('events.create', eventParams, 'event');
120+
const result = {
121+
apiEndpoint: await this.sharingApiEndpoint(),
122+
eventId: newInvite.id
123+
};
124+
return result;
112125
}
113126

114127
/**
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Client App in realtion with a AppManagingAccount/Collector
3+
* A "Collector" can be seen as a "Request" and set of "Responses"
4+
*
5+
*/
6+
7+
class CollectorClient {
8+
apiEndpoint;
9+
eventId;
10+
constructor (apiEndpoint, eventId) {
11+
this.apiEndpoint = apiEndpoint;
12+
this.eventId = eventId;
13+
}
14+
}
15+
16+
module.exports = CollectorClient;

0 commit comments

Comments
 (0)