import { Injectable } from "@angular/core" ; import { AppConfig } from "../app-config/app-config" ; import { DomSanitizer , SafeUrl } from "@angular/platform-browser" ; import { SessionService } from "../session/session-service/session.service" ; import { WebdavWrapperService } from "./webdav-wrapper.service" ; import { WebDAVClient } from "webdav" ; import { EntityMapperService } from "../entity/entity-mapper.service" ; import { User } from "../user/user" ; /**
 * Connect and access a remote cloud file system like Nextcloud
 * to upload and download files.
 *
 * Connection requires setup of the server in the AppConfig
 * as well as valid user credentials for that server in the currently logged in user entity.
 */ @ Injectable ( ) export class CloudFileService { private client : WebDAVClient ; private basePath : string ; private fileList : string ; private currentlyGettingList : Promise < boolean > ; static get WEBDAV_ENABLED ( ) : boolean { return ! ! AppConfig . settings ?. webdav ?. remote_url ; } /**
     * Construct the service and immediately attempt to connect to the server with the current user.
     */ constructor ( private domSanitizer , private sessionService , private webdav , private entityMapper ) { this . connect ( ) ; } param username param password public async connect ( username = null , password = null ) { const currentUser = this . sessionService . getCurrentUser ( ) ; if ( ! CloudFileService . WEBDAV_ENABLED || ! this . sessionService . getCurrentUser ( ) ) { return ; } this . reset ( ) ; const userEntity = await this . entityMapper . load ( User , currentUser . name ) ; this . basePath = userEntity . cloudBaseFolder ; if ( username === null && password == null ) { username = userEntity . cloudUserName ; password = userEntity . cloudPasswordDec ; } if ( ! username || ! password ) { this . client = null ; return ; } this . client = await this . webdav . createClient ( AppConfig . settings . webdav . remote_url , { username : username , password : password , } ) ; } /**
     * Reset the current state and requests.
     * e.g. clear promise that retrieves the root dir
     */ private reset ( ) { this . currentlyGettingList = null ; this . fileList = null ; } /**
     * checkConnection
     *
     * tries to upload and redownload a file.
     */ public async checkConnection ( ) { const fileName = this . basePath + "/test.txt" ; if ( await this . doesFileExist ( fileName ) ) { await this . client . deleteFile ( fileName ) ; } await this . client . putFileContents ( fileName , "TestString" ) ; const buffer = < ArrayBuffer > await this . client . getFileContents ( fileName ) ; const tmpContent = String . fromCharCode . apply ( null , new Uint8Array ( buffer ) ) ; await this . client . deleteFile ( fileName ) ; return tmpContent === "TestString" ; } param path public async getDir ( path ) { const contents = await this . client . getDirectoryContents ( this . basePath + path ) ; return JSON . stringify ( contents , undefined , 4 ) ; } param name public async doesFileExist ( name ) { if ( ! this . fileList && ! this . currentlyGettingList ) { this . currentlyGettingList = new Promise ( ( resolve ) => { this . getDir ( "" ) . then ( ( list ) => { this . fileList = list ; resolve ( true ) ; } ) ; } ) ; } if ( ! this . fileList ) { await this . currentlyGettingList ; } return this . fileList . includes ( '"basename": "' + name . split ( "/" ) . pop ( ) + '"' ) ; } param path public createDir ( path ) { return this . client . createDirectory ( this . basePath + path ) ; } param file param filePath public uploadFile ( file , filePath ) { return this . client . putFileContents ( this . basePath + filePath , file ) ; } param filePath public async getFile ( filePath ) { let file ; try { file = await this . client . getFileContents ( this . basePath + filePath ) ; return this . bufferArrayToBase64 ( file ) ; } catch ( err ) { return Promise . reject ( "Could not load file." ) ; } } param arrayBuffer private bufferArrayToBase64 ( arrayBuffer ) { const base64String = btoa ( new Uint8Array ( arrayBuffer ) . reduce ( ( data , byte ) => { return data + String . fromCharCode ( byte ) ; } , "" ) ) ; return this . domSanitizer . bypassSecurityTrustUrl ( "data:image/jpg;base64," + base64String ) ; } /**
     * Check whether the client is connected and therefore this service is able to execute its remote actions.
     */ public isConnected ( ) { return ! ! this . client ; } }