import { CollectionData } from "../models/data/collectionData" ; import { Collection } from "../models/domain/collection" ; import { TreeNode } from "../models/domain/treeNode" ; import { CollectionView } from "../models/view/collectionView" ; import { CollectionService as CollectionServiceAbstraction } from "../abstractions/collection.service" ; import { CryptoService } from "../abstractions/crypto.service" ; import { I18nService } from "../abstractions/i18n.service" ; import { StateService } from "../abstractions/state.service" ; import { ServiceUtils } from "../misc/serviceUtils" ; import { Utils } from "../misc/utils" ; const NestingDelimiter = "/" ; export class CollectionService implements CollectionServiceAbstraction { constructor ( private cryptoService , private i18nService , private stateService ) { } async clearCache ( userId ? ) { await this . stateService . setDecryptedCollections ( null , { userId : userId } ) ; } async encrypt ( model ) { if ( model . organizationId == null ) { throw new Error ( "Collection has no organization id." ) ; } const key = await this . cryptoService . getOrgKey ( model . organizationId ) ; if ( key == null ) { throw new Error ( "No key for this collection's organization." ) ; } const collection = new Collection ( ) ; collection . id = model . id ; collection . organizationId = model . organizationId ; collection . readOnly = model . readOnly ; collection . name = await this . cryptoService . encrypt ( model . name , key ) ; return collection ; } async decryptMany ( collections ) { if ( collections == null ) { return [ ] ; } const decCollections = [ ] ; const promises = [ ] ; collections . forEach ( ( collection ) => { promises . push ( collection . decrypt ( ) . then ( ( c ) => decCollections . push ( c ) ) ) ; } ) ; await Promise . all ( promises ) ; return decCollections . sort ( Utils . getSortFunction ( this . i18nService , "name" ) ) ; } async get ( id ) { const collections = await this . stateService . getEncryptedCollections ( ) ; if ( collections == null || ! collections . hasOwnProperty ( id ) ) { return null ; } return new Collection ( collections [ id ] ) ; } async getAll ( ) { const collections = await this . stateService . getEncryptedCollections ( ) ; const response = [ ] ; for ( const id in collections ) { if ( collections . hasOwnProperty ( id ) ) { response . push ( new Collection ( collections [ id ] ) ) ; } } return response ; } async getAllDecrypted ( ) { let decryptedCollections = await this . stateService . getDecryptedCollections ( ) ; if ( decryptedCollections != null ) { return decryptedCollections ; } const hasKey = await this . cryptoService . hasKey ( ) ; if ( ! hasKey ) { throw new Error ( "No key." ) ; } const collections = await this . getAll ( ) ; decryptedCollections = await this . decryptMany ( collections ) ; await this . stateService . setDecryptedCollections ( decryptedCollections ) ; return decryptedCollections ; } async getAllNested ( collections = null ) { if ( collections == null ) { collections = await this . getAllDecrypted ( ) ; } const nodes = [ ] ; collections . forEach ( ( c ) => { const collectionCopy = new CollectionView ( ) ; collectionCopy . id = c . id ; collectionCopy . organizationId = c . organizationId ; const parts = c . name != null ? c . name . replace ( /^\/+|\/+$/g , "" ) . split ( NestingDelimiter ) : [ ] ; ServiceUtils . nestedTraverse ( nodes , 0 , parts , collectionCopy , null , NestingDelimiter ) ; } ) ; return nodes ; } async getNested ( id ) { const collections = await this . getAllNested ( ) ; return ServiceUtils . getTreeNodeObject ( collections , id ) as TreeNode < CollectionView > ; } async upsert ( collection ) { let collections = await this . stateService . getEncryptedCollections ( ) ; if ( collections == null ) { collections = { } ; } if ( collection instanceof CollectionData ) { const c = collection as CollectionData ; collections [ c . id ] = c ; } else { ( collection as CollectionData [ ] ) . forEach ( ( c ) => { collections [ c . id ] = c ; } ) ; } await this . replace ( collections ) ; } async replace ( collections ) { await this . clearCache ( ) ; await this . stateService . setEncryptedCollections ( collections ) ; } async clear ( userId ? ) { await this . clearCache ( userId ) ; await this . stateService . setEncryptedCollections ( null , { userId : userId } ) ; } async delete ( id ) { const collections = await this . stateService . getEncryptedCollections ( ) ; if ( collections == null ) { return ; } if ( typeof id === "string" ) { delete collections [ id ] ; } else { ( id as string [ ] ) . forEach ( ( i ) => { delete collections [ i ] ; } ) ; } await this . replace ( collections ) ; } }