import { FolderData } from "../models/data/folderData" ; import { Folder } from "../models/domain/folder" ; import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey" ; import { TreeNode } from "../models/domain/treeNode" ; import { FolderRequest } from "../models/request/folderRequest" ; import { FolderResponse } from "../models/response/folderResponse" ; import { FolderView } from "../models/view/folderView" ; import { ApiService } from "../abstractions/api.service" ; import { CipherService } from "../abstractions/cipher.service" ; import { CryptoService } from "../abstractions/crypto.service" ; import { FolderService as FolderServiceAbstraction } from "../abstractions/folder.service" ; import { I18nService } from "../abstractions/i18n.service" ; import { StateService } from "../abstractions/state.service" ; import { CipherData } from "../models/data/cipherData" ; import { ServiceUtils } from "../misc/serviceUtils" ; import { Utils } from "../misc/utils" ; const NestingDelimiter = "/" ; export class FolderService implements FolderServiceAbstraction { constructor ( private cryptoService , private apiService , private i18nService , private cipherService , private stateService ) { } async clearCache ( userId ? ) { await this . stateService . setDecryptedFolders ( null , { userId : userId } ) ; } async encrypt ( model , key ? ) { const folder = new Folder ( ) ; folder . id = model . id ; folder . name = await this . cryptoService . encrypt ( model . name , key ) ; return folder ; } async get ( id ) { const folders = await this . stateService . getEncryptedFolders ( ) ; if ( folders == null || ! folders . hasOwnProperty ( id ) ) { return null ; } return new Folder ( folders [ id ] ) ; } async getAll ( ) { const folders = await this . stateService . getEncryptedFolders ( ) ; const response = [ ] ; for ( const id in folders ) { if ( folders . hasOwnProperty ( id ) ) { response . push ( new Folder ( folders [ id ] ) ) ; } } return response ; } async getAllDecrypted ( ) { const decryptedFolders = await this . stateService . getDecryptedFolders ( ) ; if ( decryptedFolders != null ) { return decryptedFolders ; } const hasKey = await this . cryptoService . hasKey ( ) ; if ( ! hasKey ) { throw new Error ( "No key." ) ; } const decFolders = [ ] ; const promises = [ ] ; const folders = await this . getAll ( ) ; folders . forEach ( ( folder ) => { promises . push ( folder . decrypt ( ) . then ( ( f ) => decFolders . push ( f ) ) ) ; } ) ; await Promise . all ( promises ) ; decFolders . sort ( Utils . getSortFunction ( this . i18nService , "name" ) ) ; const noneFolder = new FolderView ( ) ; noneFolder . name = this . i18nService . t ( "noneFolder" ) ; decFolders . push ( noneFolder ) ; await this . stateService . setDecryptedFolders ( decFolders ) ; return decFolders ; } async getAllNested ( ) { const folders = await this . getAllDecrypted ( ) ; const nodes = [ ] ; folders . forEach ( ( f ) => { const folderCopy = new FolderView ( ) ; folderCopy . id = f . id ; folderCopy . revisionDate = f . revisionDate ; const parts = f . name != null ? f . name . replace ( /^\/+|\/+$/g , "" ) . split ( NestingDelimiter ) : [ ] ; ServiceUtils . nestedTraverse ( nodes , 0 , parts , folderCopy , null , NestingDelimiter ) ; } ) ; return nodes ; } async getNested ( id ) { const folders = await this . getAllNested ( ) ; return ServiceUtils . getTreeNodeObject ( folders , id ) as TreeNode < FolderView > ; } async saveWithServer ( folder ) { const request = new FolderRequest ( folder ) ; let response ; if ( folder . id == null ) { response = await this . apiService . postFolder ( request ) ; folder . id = response . id ; } else { response = await this . apiService . putFolder ( folder . id , request ) ; } const userId = await this . stateService . getUserId ( ) ; const data = new FolderData ( response , userId ) ; await this . upsert ( data ) ; } async upsert ( folder ) { let folders = await this . stateService . getEncryptedFolders ( ) ; if ( folders == null ) { folders = { } ; } if ( folder instanceof FolderData ) { const f = folder as FolderData ; folders [ f . id ] = f ; } else { ( folder as FolderData [ ] ) . forEach ( ( f ) => { folders [ f . id ] = f ; } ) ; } await this . stateService . setDecryptedFolders ( null ) ; await this . stateService . setEncryptedFolders ( folders ) ; } async replace ( folders ) { await this . stateService . setDecryptedFolders ( null ) ; await this . stateService . setEncryptedFolders ( folders ) ; } async clear ( userId ? ) { await this . stateService . setDecryptedFolders ( null , { userId : userId } ) ; await this . stateService . setEncryptedFolders ( null , { userId : userId } ) ; } async delete ( id ) { const folders = await this . stateService . getEncryptedFolders ( ) ; if ( folders == null ) { return ; } if ( typeof id === "string" ) { if ( folders [ id ] == null ) { return ; } delete folders [ id ] ; } else { ( id as string [ ] ) . forEach ( ( i ) => { delete folders [ i ] ; } ) ; } await this . stateService . setDecryptedFolders ( null ) ; await this . stateService . setEncryptedFolders ( folders ) ; const ciphers = await this . stateService . getEncryptedCiphers ( ) ; if ( ciphers != null ) { const updates = [ ] ; for ( const cId in ciphers ) { if ( ciphers [ cId ] . folderId === id ) { ciphers [ cId ] . folderId = null ; updates . push ( ciphers [ cId ] ) ; } } if ( updates . length > 0 ) { this . cipherService . upsert ( updates ) ; } } } async deleteWithServer ( id ) { await this . apiService . deleteFolder ( id ) ; await this . delete ( id ) ; } }