1- const { HDSLibError } = require ( '../errors' ) ;
21const ShortUniqueId = require ( 'short-unique-id' ) ;
32const 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-
31289module . exports = AppManagingAccount ;
31390
31491async 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