diff --git a/__tests__/files/file.spec.ts b/__tests__/files/file.spec.ts index fc8e39f1a..379e845c7 100644 --- a/__tests__/files/file.spec.ts +++ b/__tests__/files/file.spec.ts @@ -122,6 +122,33 @@ describe('File data change', () => { expect(file.mtime?.getDate()).toBe(new Date().getDate()) }) + test('Rename a file with special characters', () => { + const file = new File({ + source: 'https://cloud.domain.com/remote.php/dav/files/emma/~⛰️ shot of a $[big} mountain/realy #1\'s.jpeg', + encodedSource: 'https://cloud.domain.com/remote.php/dav/files/emma/~%E2%9B%B0%EF%B8%8F%20shot%20of%20a%20%24%5Bbig%7D%20mountain/realy%20%231\'s.jpeg', + mime: 'image/jpeg', + owner: 'emma', + mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)), + root: '/files/emma', + }) + + expect(file.basename).toBe('realy #1\'s.jpeg') + expect(file.dirname).toBe('/~⛰️ shot of a $[big} mountain') + expect(file.root).toBe('/files/emma') + expect(file.mtime?.toISOString()).toBe('2023-01-01T00:00:00.000Z') + + file.rename('picture with #!&$"§.jpg') + + expect(file.basename).toBe('picture with #!&$"§.jpg') + expect(file.dirname).toBe('/~⛰️ shot of a $[big} mountain') + expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/~⛰️ shot of a $[big} mountain/picture with #!&$"§.jpg') + expect(file.root).toBe('/files/emma') + expect(file.encodedSource).toBe('https://cloud.domain.com/remote.php/dav/files/emma/~%E2%9B%B0%EF%B8%8F%20shot%20of%20a%20%24%5Bbig%7D%20mountain/picture%20with%20%23!%26%24%22%C2%A7.jpg') + + // Check that mtime has been updated + expect(file.mtime?.getDate()).toBe(new Date().getDate()) + }) + test('Moving a file', () => { const file = new File({ source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg', @@ -136,11 +163,15 @@ describe('File data change', () => { expect(file.root).toBe('/files/emma/Photos') expect(file.mtime?.toISOString()).toBe('2023-01-01T00:00:00.000Z') - file.move('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg') + file.move( + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old#.jpg', + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old%23.jpg', + ) - expect(file.basename).toBe('picture-old.jpg') + expect(file.basename).toBe('picture-old#.jpg') expect(file.dirname).toBe('/') - expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg') + expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old#.jpg') + expect(file.encodedSource).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old%23.jpg') expect(file.root).toBe('/files/emma/Pictures') // Check that mtime has been updated @@ -156,7 +187,10 @@ describe('File data change', () => { mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)), }) expect(() => { - file.move('ftp://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg') + file.move( + 'ftp://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg', + 'ftp://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg', + ) }).toThrowError('Invalid source format, only http(s) is supported') }) @@ -173,7 +207,10 @@ describe('File data change', () => { expect(file.dirname).toBe('/Photos') expect(file.root).toBe('/files/emma') - file.move('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/Old/picture-old.jpg') + file.move( + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/Old/picture-old.jpg', + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/Old/picture-old.jpg', + ) expect(file.basename).toBe('picture-old.jpg') expect(file.dirname).toBe('/Pictures/Old') diff --git a/__tests__/files/folder.spec.ts b/__tests__/files/folder.spec.ts index 3e0834e4f..975e2be63 100644 --- a/__tests__/files/folder.spec.ts +++ b/__tests__/files/folder.spec.ts @@ -102,6 +102,26 @@ describe('Folder data change', () => { expect(folder.root).toBe('/files/emma') }) + test('Rename a folder with special characters', () => { + const file = new Folder({ + source: 'https://cloud.domain.com/remote.php/dav/files/emma/~⛰️ shot of a $[big} mountain', + encodedSource: 'https://cloud.domain.com/remote.php/dav/files/emma/~%E2%9B%B0%EF%B8%8F%20shot%20of%20a%20%24%5Bbig%7D%20mountain', + owner: 'emma', + }) + + expect(file.basename).toBe('~⛰️ shot of a $[big} mountain') + expect(file.dirname).toBe('/') + expect(file.root).toBe('/files/emma') + + file.rename('folder with #!&$"§') + + expect(file.basename).toBe('folder with #!&$"§') + expect(file.dirname).toBe('/') + expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/folder with #!&$"§') + expect(file.root).toBe('/files/emma') + expect(file.encodedSource).toBe('https://cloud.domain.com/remote.php/dav/files/emma/folder%20with%20%23!%26%24%22%C2%A7') + }) + test('Moving a folder', () => { const folder = new Folder({ source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/', @@ -113,7 +133,10 @@ describe('Folder data change', () => { expect(folder.dirname).toBe('/') expect(folder.root).toBe('/files/emma') - folder.move('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/') + folder.move( + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/', + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/', + ) expect(folder.basename).toBe('Pictures') expect(folder.dirname).toBe('/') @@ -133,7 +156,10 @@ describe('Folder data change', () => { expect(folder.dirname).toBe('/') expect(folder.root).toBe('/files/emma') - folder.move('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/1/2/3') + folder.move( + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/1/2/3', + 'https://cloud.domain.com/remote.php/dav/files/emma/Pictures/1/2/3', + ) expect(folder.basename).toBe('3') expect(folder.dirname).toBe('/Pictures/1/2') diff --git a/lib/files/node.ts b/lib/files/node.ts index c59b4eef5..bd9aaeefb 100644 --- a/lib/files/node.ts +++ b/lib/files/node.ts @@ -23,6 +23,7 @@ import { basename, extname, dirname } from 'path' import { Permission } from '../permissions' import { FileType } from './fileType' import { Attribute, NodeData, isDavRessource, validateData } from './nodeData' +import { encodePath } from 'webdav/dist/node/tools/path.js' export enum NodeStatus { /** This is a new node and it doesn't exists on the filesystem yet */ @@ -250,11 +251,13 @@ export abstract class Node { * Move the node to a new destination * * @param {string} destination the new source. + * @param {string} encodedDestination the new encoded source. * e.g. https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg */ - move(destination: string) { - validateData({ ...this._data, source: destination }, this._knownDavService) + move(destination: string, encodedDestination: string) { + validateData({ ...this._data, source: destination, encodedSource: encodedDestination }, this._knownDavService) this._data.source = destination + this._data.encodedSource = encodedDestination this.updateMtime() } @@ -268,7 +271,10 @@ export abstract class Node { if (basename.includes('/')) { throw new Error('Invalid basename') } - this.move(dirname(this.source) + '/' + basename) + this.move( + dirname(this.source) + '/' + basename, + dirname(this.encodedSource) + '/' + encodePath(basename), + ) } /**