Skip to content

Commit 1548025

Browse files
committed
Implemented apiOne() when possible - Created a single file for Collector
1 parent 69ea53c commit 1548025

4 files changed

Lines changed: 226 additions & 237 deletions

File tree

src/appTemplates/AppManagingAccount.js

Lines changed: 12 additions & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
const { HDSLibError } = require('../errors');
21
const ShortUniqueId = require('short-unique-id');
32
const collectorIdGenerator = new ShortUniqueId({ dictionary: 'alphanum_lower', length: 7 });
3+
const Collector = require('./Collector');
44

55
/**
66
* App which manages Collectors
7-
* A "Collector" can be see as a "Request" and set of "Responses"
7+
* A "Collector" can be seen as a "Request" and set of "Responses"
88
* - Responses are authorization tokens from individuals
99
*
1010
* The App can create multiple "collectors e.g. Questionnaries"
@@ -62,17 +62,9 @@ class AppManagingAccount {
6262
async getCollectors (forceRefresh) {
6363
if (!forceRefresh && this.#cache.collectorsMap) return Object.values(this.#cache.collectorsMap);
6464
// Collectors are materialized by streams
65-
const apiCalls = [{
66-
method: 'streams.get',
67-
params: {
68-
parentId: this.baseStreamId
69-
}
70-
}];
71-
const result = (await this.connection.api(apiCalls))[0];
72-
if (result.error) throw new HDSLibError('Failed getting collectors', result.error);
73-
if (!result.streams || !Array.isArray(result.streams)) throw new HDSLibError('Failed getting collectors, invalid result', result);
65+
const streams = await this.connection.apiOne('streams.get', { parentId: this.baseStreamId }, 'streams');
7466
const collectorsMap = {};
75-
for (const stream of result.streams) {
67+
for (const stream of streams) {
7668
const collector = new Collector(this, stream);
7769
collectorsMap[collector.streamId] = collector;
7870
}
@@ -82,237 +74,22 @@ class AppManagingAccount {
8274

8375
async createCollector (name) {
8476
const streamId = this.baseStreamId + '-' + collectorIdGenerator.rnd();
85-
const apiCalls = [{
86-
method: 'streams.create',
87-
params: {
88-
id: streamId,
89-
name,
90-
parentId: this.baseStreamId
91-
}
92-
}];
93-
const result = (await this.connection.api(apiCalls))[0];
94-
if (result.error) throw new HDSLibError('Failed creating collector', result.error);
95-
if (!result.stream?.name) throw new HDSLibError('Failed creating collector, invalid result', result);
96-
const collector = new Collector(this, result.stream);
77+
const params = {
78+
id: streamId,
79+
name,
80+
parentId: this.baseStreamId
81+
};
82+
const stream = await this.connection.apiOne('streams.create', params, 'stream');
83+
const collector = new Collector(this, stream);
9784
this.#cache.collectorsMap[collector.streamId] = collector;
9885
return collector;
9986
}
10087
}
10188

102-
const COLLECTOR_STREAMID_SUFFIXES = {
103-
internal: 'internal',
104-
public: 'public',
105-
pending: 'pending',
106-
inbox: 'inbox',
107-
active: 'active',
108-
error: 'error'
109-
};
110-
Object.freeze(COLLECTOR_STREAMID_SUFFIXES);
111-
class Collector {
112-
static STREAMID_SUFFIXES = COLLECTOR_STREAMID_SUFFIXES;
113-
static STATUSES = Object.freeze({
114-
draft: 'draft',
115-
active: 'active',
116-
deactivated: 'deactivated'
117-
});
118-
119-
appManaging;
120-
streamId;
121-
name;
122-
#streamData;
123-
#cache;
124-
125-
/**
126-
* @param {AppManagingAccount} appManaging
127-
* @param {Pryv.Stream} streamData
128-
*/
129-
constructor (appManaging, streamData) {
130-
this.streamId = streamData.id;
131-
this.name = streamData.name;
132-
this.appManaging = appManaging;
133-
this.#streamData = streamData;
134-
this.#cache = {};
135-
}
136-
137-
/**
138-
* @property {string} one of 'draft', 'active', 'deactivated'
139-
*/
140-
get statusCode () {
141-
if (this.#cache.status == null) throw new Error('Init Collector first');
142-
return this.#cache.status.content.status;
143-
}
144-
145-
/**
146-
* Fetch online data
147-
*/
148-
async init () {
149-
await this.checkStreamStructure();
150-
await this.getStatus();
151-
}
152-
153-
/**
154-
* @type {StatusEvent} - extends PryvEvent with a specific content
155-
* @property {Object} content - content
156-
* @property {String} content.status - one of 'draft', 'active', 'deactivated'
157-
* @property {Data} content.data - app specific data
158-
*/
159-
160-
/**
161-
* Get Collector status,
162-
* @param {boolean} forceRefresh - if true, forces fetching the status from the server
163-
* @returns {StatusEvent}
164-
*/
165-
async getStatus (forceRefresh = false) {
166-
if (!forceRefresh && this.#cache.status) return this.#cache.status;
167-
const params = { types: ['status/collector-v1'], limit: 1, streams: [this.streamIdFor(Collector.STREAMID_SUFFIXES.internal)] };
168-
const statusEvents = await this.appManaging.connection.apiOne('events.get', params, 'events');
169-
if (statusEvents.length === 0) { // non exsitent set "draft" status
170-
return this.setStatus(Collector.STATUSES.draft, {});
171-
}
172-
this.#cache.status = statusEvents[0];
173-
return this.#cache.status;
174-
}
175-
176-
/**
177-
* Change the status
178-
* @param {string} status one of of 'draft', 'active', 'deactivated'
179-
* @param {object} data - custom data
180-
* @returns {StatusEvent}
181-
*/
182-
async setStatus (status, data) {
183-
if (!Collector.STATUSES[status]) throw new HDSLibError('Unkown status key', { status, data });
184-
const event = {
185-
type: 'status/collector-v1',
186-
streamIds: [this.streamIdFor(Collector.STREAMID_SUFFIXES.internal)],
187-
content: {
188-
status,
189-
data
190-
}
191-
};
192-
const statusEvent = await this.appManaging.connection.apiOne('events.create', event, 'event');
193-
this.#cache.status = statusEvent;
194-
return this.#cache.status;
195-
}
196-
197-
/**
198-
* Create a "pending" invite to be sent to an app usin AppSharingAccount
199-
* @param {string} name a default display name for this request
200-
* @param {Object} [options]
201-
* @param {Object} [options.customData] any data to be used by the client app
202-
*/
203-
async createInvite (name, options) {
204-
205-
}
206-
207-
/**
208-
* Get sharing api endpoint
209-
*/
210-
async sharingApiEndpoint () {
211-
if (this.#cache.sharingApiEndpoint) return this.#cache.sharingApiEndpoint;
212-
// check if sharing present
213-
const sharedAccessId = 'a-' + this.streamId;
214-
const accessesCheckRes = (await this.appManaging.connection.api([
215-
{ method: 'accesses.get', params: {} }
216-
]))[0];
217-
if (accessesCheckRes?.error) throw new HDSLibError('Failed getting list of accesses', accessesCheckRes.error);
218-
if (!accessesCheckRes?.accesses) throw new HDSLibError('Failed getting list of accesses', accessesCheckRes);
219-
const sharedAccess = accessesCheckRes.accesses.find(
220-
(access) => access.name === sharedAccessId
221-
);
222-
// found return it
223-
if (sharedAccess) {
224-
this.#cache.sharingApiEndpoint = sharedAccess.apiEndpoint;
225-
return sharedAccess.apiEndpoint;
226-
}
227-
228-
// not found create it
229-
const permissions = [
230-
{ streamId: this.streamIdFor(Collector.STREAMID_SUFFIXES.inbox), level: 'create-only' },
231-
{ streamId: this.streamIdFor(Collector.STREAMID_SUFFIXES.public), level: 'read' },
232-
// for "publicly shared access" always forbid the selfRevoke feature
233-
{ feature: 'selfRevoke', setting: 'forbidden' },
234-
// for "publicly shared access" always forbid the selfAudit feature
235-
{ feature: 'selfAudit', setting: 'forbidden' }
236-
];
237-
const clientData = {
238-
hdsCollector: {
239-
public: {
240-
streamId: this.streamIdFor(Collector.public)
241-
},
242-
inbox: {
243-
streamId: this.streamIdFor(Collector.inbox)
244-
}
245-
}
246-
};
247-
const accessesCreate = await this.appManaging.connection.api([{
248-
method: 'accesses.create',
249-
params: {
250-
name: sharedAccessId,
251-
type: 'shared',
252-
permissions,
253-
clientData
254-
}
255-
}]);
256-
if (accessesCreate?.[0]?.error) throw new HDSLibError('Failed creating shared token', accessesCreate?.[0]?.error);
257-
const newSharingApiEndpoint = accessesCreate?.[0]?.access?.apiEndpoint;
258-
if (!newSharingApiEndpoint) throw new HDSLibError('Cannot find apiEndpoint in sharing creation request', accessesCreate);
259-
this.#cache.sharingApiEndpoint = newSharingApiEndpoint;
260-
return newSharingApiEndpoint;
261-
}
262-
263-
/**
264-
* check if required streams are present, if not create them
265-
*/
266-
async checkStreamStructure () {
267-
// if streamData has correct children structure we assume all is OK
268-
const childrenData = this.#streamData.children;
269-
const toCreate = Object.values(Collector.STREAMID_SUFFIXES)
270-
.filter((suffix) => {
271-
if (!childrenData) return true;
272-
if (childrenData.find(child => child.id === this.streamIdFor(suffix))) return false;
273-
return true;
274-
});
275-
276-
if (toCreate.length === 0) return { created: [] };
277-
// create required streams
278-
const apiCalls = toCreate.map(suffix => ({
279-
method: 'streams.create',
280-
params: {
281-
id: this.streamIdFor(suffix),
282-
parentId: this.streamId,
283-
name: this.name + ' ' + suffix
284-
}
285-
}));
286-
const result = { created: [], errors: [] };
287-
const resultsApi = await this.appManaging.connection.api(apiCalls);
288-
for (const resultCreate of resultsApi) {
289-
if (resultCreate.error) {
290-
result.errors.push(resultCreate.error);
291-
continue;
292-
}
293-
if (resultCreate.stream) {
294-
result.created.push(resultCreate.stream);
295-
if (!this.#streamData.children) this.#streamData.children = [];
296-
this.#streamData.children.push(resultCreate.stream);
297-
continue;
298-
}
299-
result.errors.push({ id: 'unkown-error', message: 'Cannot find stream in result', data: resultCreate });
300-
}
301-
return result;
302-
}
303-
304-
/**
305-
* @param {string} suffix
306-
*/
307-
streamIdFor (suffix) {
308-
return this.streamId + '-' + suffix;
309-
}
310-
}
311-
31289
module.exports = AppManagingAccount;
31390

31491
async function newAppManagingAccountFromConnection (connection, baseStreamId) {
315-
const accessInfo = (await connection.api([{ method: 'getAccessInfo', params: {} }]))[0];
92+
const accessInfo = await connection.apiOne('getAccessInfo');
31693
if (!accessInfo.type === 'app') throw new Error('Failed creating new AppManagingAccount, "app" authorization required: ' + JSON.stringify(accessInfo));
31794
// check if baseStreamId is in pemission set
31895
const found = accessInfo.permissions.find(p => (p.streamId === baseStreamId || p.streamId === '*'));

0 commit comments

Comments
 (0)