From 4f0425f210e89811a900700247a26178d121aba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6?= Date: Wed, 14 Sep 2022 16:41:54 +0200 Subject: [PATCH] Improve root folder handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ --- lib/components/UploadPicker.cy.ts | 59 +++++++++++++++++++++++++++++ lib/components/UploadPicker.vue | 23 ++++++++++- lib/index.ts | 2 +- lib/uploader.ts | 63 ++++++++++++++++++++++++------- 4 files changed, 131 insertions(+), 16 deletions(-) diff --git a/lib/components/UploadPicker.cy.ts b/lib/components/UploadPicker.cy.ts index b1584924..128916ad 100644 --- a/lib/components/UploadPicker.cy.ts +++ b/lib/components/UploadPicker.cy.ts @@ -232,3 +232,62 @@ describe('Destination management', () => { }) }) }) + +describe('Root management', () => { + const propsData = { + root: null, + destination: '/', + } + + it('Upload then changes the root', () => { + // Mount picker + cy.mount(UploadPicker, { propsData }) + + // Check and init aliases + cy.get('form input[type="file"]').as('input').should('exist') + cy.get('form .upload-picker__progress').as('progress').should('exist') + + // Intercept single upload + cy.intercept('PUT', '/remote.php/dav/files/*/**', { + statusCode: 201, + }).as('upload') + + cy.get('@input').attachFile({ + // Fake file of 5 MB + fileContent: new Blob([new ArrayBuffer(5 * 1024 * 1024)]), + fileName: 'image.jpg', + mimeType: 'image/jpeg', + encoding: 'utf8', + lastModified: new Date().getTime(), + }) + + cy.wait('@upload').then((upload) => { + expect(upload.request.url).to.have.string('/remote.php/dav/files/user/image.jpg') + }) + + cy.get('@component').then(component => { + component.setRoot('dav/photos/admin/albums') + component.setDestination('/2022 Summer Vacations') + // Wait for prop propagation + expect(component.uploadManager.root).to.match(/dav\/photos\/admin\/albums$/i) + }) + + // Intercept single upload + cy.intercept('PUT', '/remote.php/dav/photos/admin/albums/*/*', { + statusCode: 201, + }).as('upload') + + cy.get('@input').attachFile({ + // Fake file of 5 MB + fileContent: new Blob([new ArrayBuffer(5 * 1024 * 1024)]), + fileName: 'image.jpg', + mimeType: 'image/jpeg', + encoding: 'utf8', + lastModified: new Date().getTime(), + }) + + cy.wait('@upload').then((upload) => { + expect(upload.request.url).to.have.string('/remote.php/dav/photos/admin/albums/2022%20Summer%20Vacations/image.jpg') + }) + }) +}) diff --git a/lib/components/UploadPicker.vue b/lib/components/UploadPicker.vue index 27fb7ac3..9137e465 100644 --- a/lib/components/UploadPicker.vue +++ b/lib/components/UploadPicker.vue @@ -122,7 +122,11 @@ export default { }, destination: { type: String, - default: '/', + default: null, + }, + root: { + type: String, + default: null, }, context: { type: Object, @@ -197,6 +201,10 @@ export default { this.setDestination(destination) }, + root(path) { + this.setRoot(path) + }, + queue(queue, oldQueue) { if (queue.length < oldQueue.length) { this.$emit('uploaded', oldQueue.filter(upload => !queue.includes(upload))) @@ -219,7 +227,13 @@ export default { }, beforeMount() { - this.setDestination(this.destination) + if (this.destination) { + this.setDestination(this.destination) + } + if (this.root) { + this.setRoot(this.root) + } + this.setContext(this.context) logger.debug('UploadPicker initialised') }, @@ -284,6 +298,11 @@ export default { this.uploadManager.destination = destination }, + setRoot(path) { + logger.debug(`Root path set to ${path}`) + this.uploadManager.root = path + }, + setContext(context) { logger.debug('Context changed to', context); this.newFileMenuEntries = getNewFileMenuEntries(context) diff --git a/lib/index.ts b/lib/index.ts index 20696438..e6511539 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,7 +1,7 @@ import { Uploader } from './uploader' import UploadPicker from './components/UploadPicker.js' export { Status as UploaderStatus } from './uploader' -export { Status as UploadStatus } from './upload' +export { Upload, Status as UploadStatus } from './upload' declare global { interface Window { diff --git a/lib/uploader.ts b/lib/uploader.ts index 161cf2fd..b23fbd6f 100644 --- a/lib/uploader.ts +++ b/lib/uploader.ts @@ -18,8 +18,9 @@ export enum Status { export class Uploader { - private _userRootFolder: string - private _destinationFolder: string = '/' + // Initialized via setter in the constructor + private rootFolder!: string + private destinationFolder!: string private _isPublic: boolean @@ -34,39 +35,75 @@ export class Uploader { * Initialize uploader * * @param {boolean} isPublic are we in public mode ? + * @param {string} rootFolder the operation root folder + * @param {string} destinationFolder the context folder to operate, relative to the root folder */ - constructor(isPublic: boolean = false) { + constructor( + isPublic: boolean = false, + rootFolder = `dav/files/${getCurrentUser()?.uid}`, + destinationFolder = '/' + ) { this._isPublic = isPublic - this._userRootFolder = generateRemoteUrl(`dav/files/${getCurrentUser()?.uid}`) + this.root = rootFolder + this.destination = destinationFolder logger.debug('Upload workspace initialized', { - destinationFolder: this._destinationFolder, - userRootFolder: this._userRootFolder, + destinationFolder: this.destination, + rootFolder: this.root, isPublic, maxChunksSize: getMaxChunksSize(), }) } /** - * Get the upload destination path relative to the user root folder + * Get the upload destination path relative to the root folder */ get destination() { - return this._destinationFolder + return this.destinationFolder } /** - * Set the upload destination path relative to the user root folder + * Set the upload destination path relative to the root folder */ set destination(path: string) { if (typeof path !== 'string' || path === '') { - this._destinationFolder = '/' + this.destinationFolder = '/' return } if (!path.startsWith('/')) { path = `/${path}` } - this._destinationFolder = path.replace(/\/$/, '') + this.destinationFolder = path.replace(/\/$/, '') + } + + /** + * Get the root folder + */ + get root() { + return this.rootFolder + } + + /** + * Set the root folder + * + * @param {string} path should be the remoteUrl path. + * This method uses the generateRemoteUrl method + */ + set root(path: string) { + if (typeof path !== 'string' || path === '') { + this.rootFolder = generateRemoteUrl(`dav/files/${getCurrentUser()?.uid}`) + return + } + + if (path.startsWith('http')) { + throw new Error('The path should be a remote url string. E.g `dav/files/admin`.') + } + + if (path.startsWith('/')) { + path = path.slice(1) + } + this.rootFolder = generateRemoteUrl(path) } /** @@ -134,8 +171,8 @@ export class Uploader { * Upload a file to the given path */ upload(destinationPath: string, file: File) { - const destinationFolder = this._destinationFolder === '/' ? '' : this._destinationFolder - const destinationFile = `${this._userRootFolder}${destinationFolder}/${destinationPath.replace(/^\//, '')}` + const destinationFolder = this.destinationFolder === '/' ? '' : this.destinationFolder + const destinationFile = `${this.rootFolder}${destinationFolder}/${destinationPath.replace(/^\//, '')}` logger.debug(`Uploading ${file.name} to ${destinationFile}`)