diff --git a/__tests__/files/file.spec.ts b/__tests__/files/file.spec.ts index 62ae2acd0..a56c09c08 100644 --- a/__tests__/files/file.spec.ts +++ b/__tests__/files/file.spec.ts @@ -7,7 +7,9 @@ describe('File creation', () => { const file = new File({ source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg', mime: 'image/jpeg', - owner: 'emma' + owner: 'emma', + mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)), + crtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)), }) expect(file).toBeInstanceOf(File) @@ -19,6 +21,10 @@ describe('File creation', () => { expect(file.size).toBeUndefined() expect(file.attributes).toStrictEqual({}) + // Times + expect(file.mtime?.toISOString()).toBe('2023-01-01T00:00:00.000Z') + expect(file.crtime?.toISOString()).toBe('1990-01-01T00:00:00.000Z') + // path checks expect(file.basename).toBe('picture.jpg') expect(file.extension).toBe('.jpg') @@ -87,12 +93,14 @@ describe('File data change', () => { const file = new File({ source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg', mime: 'image/jpeg', - owner: 'emma' + owner: 'emma', + mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)), }) expect(file.basename).toBe('picture.jpg') expect(file.dirname).toBe('/') expect(file.root).toBe('/files/emma/Photos') + expect(file.mtime?.toISOString()).toBe('2023-01-01T00:00:00.000Z') file.rename('picture-old.jpg') @@ -100,18 +108,23 @@ describe('File data change', () => { expect(file.dirname).toBe('/') expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture-old.jpg') expect(file.root).toBe('/files/emma/Photos') + + // 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', mime: 'image/jpeg', - owner: 'emma' + owner: 'emma', + mtime: new Date(Date.UTC(2023, 0, 1, 0, 0, 0)), }) expect(file.basename).toBe('picture.jpg') expect(file.dirname).toBe('/') 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') @@ -119,6 +132,9 @@ describe('File data change', () => { expect(file.dirname).toBe('/') expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg') expect(file.root).toBe('/files/emma/Pictures') + + // Check that mtime has been updated + expect(file.mtime?.getDate()).toBe(new Date().getDate()) }) test('Moving a file to a different folder with root', () => { @@ -141,3 +157,57 @@ describe('File data change', () => { expect(file.root).toBe('/files/emma') }) }) + + +describe('Altering attributes updates mtime', () => { + test('mtime is updated on existing attribute', () => { + const file = new File({ + source: 'https://cloud.domain.com/remote.php/dav/files/emma', + mime: 'image/jpeg', + owner: 'emma', + mtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)), + attributes: { + test: true + }, + }) + expect(file.attributes.test).toBe(true) + file.attributes.test = false + + // Check that mtime has been updated + expect(file.mtime?.getDate()).toBe(new Date().getDate()) + expect(file.attributes.test).toBe(false) + }) + + test('mtime is updated on new attribute', () => { + const file = new File({ + source: 'https://cloud.domain.com/remote.php/dav/files/emma', + mime: 'image/jpeg', + owner: 'emma', + mtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)), + }) + expect(file.attributes.test).toBeFalsy() + file.attributes.test = true + + // Check that mtime has been updated + expect(file.mtime?.getDate()).toBe(new Date().getDate()) + expect(file.attributes.test).toBe(true) + }) + + test('mtime is updated on deleted attribute', () => { + const file = new File({ + source: 'https://cloud.domain.com/remote.php/dav/files/emma', + mime: 'image/jpeg', + owner: 'emma', + mtime: new Date(Date.UTC(1990, 0, 1, 0, 0, 0)), + attributes: { + test: true + }, + }) + expect(file.attributes.test).toBe(true) + delete file.attributes.test + + // Check that mtime has been updated + expect(file.mtime?.getDate()).toBe(new Date().getDate()) + expect(file.attributes.test).toBeUndefined() + }) +}) diff --git a/__tests__/files/node.spec.ts b/__tests__/files/node.spec.ts index 391186962..8eabb6935 100644 --- a/__tests__/files/node.spec.ts +++ b/__tests__/files/node.spec.ts @@ -252,4 +252,4 @@ describe('Root and paths detection', () => { }) expect(file1.dirname).toBe('/') }) -}) \ No newline at end of file +}) diff --git a/lib/files/node.ts b/lib/files/node.ts index cb992a236..ef3539235 100644 --- a/lib/files/node.ts +++ b/lib/files/node.ts @@ -24,9 +24,10 @@ import { Permission } from '../permissions' import { FileType } from './fileType' import NodeData, { Attribute, validateData } from './nodeData' + export abstract class Node { private _data: NodeData - private _attributes: Attribute[] + private _attributes: Attribute private _knownDavService = /(remote|public)\.php\/(web)?dav/i constructor(data: NodeData, davService?: RegExp) { @@ -34,7 +35,24 @@ export abstract class Node { validateData(data) this._data = data - this._attributes = data.attributes || {} as any + + const handler = { + set: (target: Attribute, prop: string, value: any): any => { + // Edit modification time + this._data['mtime'] = new Date() + // Apply original changes + return Reflect.set(target, prop, value) + }, + deleteProperty: (target: Attribute, prop: string) => { + // Edit modification time + this._data['mtime'] = new Date() + // Apply original changes + return Reflect.deleteProperty(target, prop) + }, + } as ProxyHandler + + // Proxy the attributes to update the mtime on change + this._attributes = new Proxy(data.attributes || {} as any, handler) delete this._data.attributes if (davService) { @@ -87,6 +105,20 @@ export abstract class Node { return this._data.mime } + /** + * Get the file modification time + */ + get mtime(): Date|undefined { + return this._data.mtime + } + + /** + * Get the file creation time + */ + get crtime(): Date|undefined { + return this._data.crtime + } + /** * Get the file size */ @@ -171,6 +203,7 @@ export abstract class Node { */ move(destination: string) { this._data.source = destination + this._data.mtime = new Date() } /**