Skip to content

Commit

Permalink
feat(node): allow and recommend to provide a specific root
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Feb 3, 2023
1 parent e953b2a commit 364866c
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 15 deletions.
60 changes: 54 additions & 6 deletions __tests__/files/file.spec.ts
Expand Up @@ -22,8 +22,36 @@ describe('File creation', () => {
// path checks
expect(file.basename).toBe('picture.jpg')
expect(file.extension).toBe('.jpg')
expect(file.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Photos')
expect(file.dirname).toBe('/')
expect(file.root).toBe('/files/emma/Photos')
expect(file.path).toBe('/picture.jpg')
expect(file.isDavRessource).toBe(true)
expect(file.permissions).toBe(Permission.READ)
})

test('Valid dav file with root', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma',
root: '/files/emma'
})

expect(file).toBeInstanceOf(File)
expect(file.type).toBe(FileType.File)

// various data
expect(file.mime).toBe('image/jpeg')
expect(file.owner).toBe('emma')
expect(file.size).toBeUndefined()
expect(file.attributes).toStrictEqual({})

// path checks
expect(file.basename).toBe('picture.jpg')
expect(file.extension).toBe('.jpg')
expect(file.dirname).toBe('/Photos')
expect(file.root).toBe('/files/emma')
expect(file.path).toBe('/Photos/picture.jpg')
expect(file.isDavRessource).toBe(true)
expect(file.permissions).toBe(Permission.READ)
})
Expand Down Expand Up @@ -63,33 +91,53 @@ describe('File data change', () => {
})

expect(file.basename).toBe('picture.jpg')
expect(file.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Photos')
expect(file.dirname).toBe('/')
expect(file.root).toBe('/files/emma/Photos')

file.rename('picture-old.jpg')

expect(file.basename).toBe('picture-old.jpg')
expect(file.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Photos')
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')
})

test('Changing source', () => {
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'
})

expect(file.basename).toBe('picture.jpg')
expect(file.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Photos')
expect(file.dirname).toBe('/')
expect(file.root).toBe('/files/emma/Photos')

file.move('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/picture-old.jpg')

expect(file.basename).toBe('picture-old.jpg')
expect(file.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures')
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')
})

test('Moving a file to a different folder with root', () => {
const file = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma',
root: '/files/emma'
})

expect(file.basename).toBe('picture.jpg')
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')

expect(file.basename).toBe('picture-old.jpg')
expect(file.dirname).toBe('/Pictures/Old')
expect(file.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/Old/picture-old.jpg')
expect(file.root).toBe('/files/emma')
})
})
56 changes: 50 additions & 6 deletions __tests__/files/folder.spec.ts
Expand Up @@ -21,7 +21,32 @@ describe('File creation', () => {
// path checks
expect(folder.basename).toBe('Photos')
expect(folder.extension).toBeNull()
expect(folder.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma')
expect(folder.dirname).toBe('/')
expect(folder.root).toBe('/files/emma')
expect(folder.isDavRessource).toBe(true)
expect(folder.permissions).toBe(Permission.READ)
})

test('Valid dav folder with root', () => {
const folder = new Folder({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/Berlin',
owner: 'emma',
root: '/files/emma'
})

expect(folder).toBeInstanceOf(Folder)
expect(folder.type).toBe(FileType.Folder)

// various data
expect(folder.mime).toBe('httpd/unix-directory')
expect(folder.owner).toBe('emma')
expect(folder.size).toBeUndefined()
expect(folder.attributes).toStrictEqual({})

// path checks
expect(folder.basename).toBe('Berlin')
expect(folder.extension).toBeNull()
expect(folder.dirname).toBe('/Photos')
expect(folder.root).toBe('/files/emma')
expect(folder.isDavRessource).toBe(true)
expect(folder.permissions).toBe(Permission.READ)
Expand Down Expand Up @@ -60,32 +85,51 @@ describe('Folder data change', () => {
})

expect(folder.basename).toBe('Photos')
expect(folder.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma')
expect(folder.dirname).toBe('/')
expect(folder.root).toBe('/files/emma')

folder.rename('Pictures')

expect(folder.basename).toBe('Pictures')
expect(folder.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma')
expect(folder.dirname).toBe('/')
expect(folder.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures')
expect(folder.root).toBe('/files/emma')
})

test('Changing source', () => {
test('Moving a folder', () => {
const folder = new Folder({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/',
owner: 'emma'
})

expect(folder.basename).toBe('Photos')
expect(folder.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma')
expect(folder.dirname).toBe('/')
expect(folder.root).toBe('/files/emma')

folder.move('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/')

expect(folder.basename).toBe('Pictures')
expect(folder.dirname).toBe('https://cloud.domain.com/remote.php/dav/files/emma')
expect(folder.dirname).toBe('/')
expect(folder.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures')
expect(folder.root).toBe('/files/emma')
})

test('Moving a folder to a different location with root', () => {
const folder = new Folder({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/',
owner: 'emma',
root: '/files/emma'
})

expect(folder.basename).toBe('Photos')
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')

expect(folder.basename).toBe('3')
expect(folder.dirname).toBe('/Pictures/1/2')
expect(folder.source).toBe('https://cloud.domain.com/remote.php/dav/files/emma/Pictures/1/2/3')
expect(folder.root).toBe('/files/emma')
})
})
59 changes: 59 additions & 0 deletions __tests__/files/node.spec.ts
Expand Up @@ -122,6 +122,21 @@ describe('Sanity checks', () => {
owner: true as unknown as string,
})).toThrowError('Invalid owner')
})

test('Invalid root', () => {
expect(() => new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma',
root: true as unknown as string,
})).toThrowError('Invalid root format')
expect(() => new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma',
root: 'https://cloud.domain.com/remote.php/dav/',
})).toThrowError('Root must start with a leading slash')
})
})

describe('Dav service detection', () => {
Expand Down Expand Up @@ -171,3 +186,47 @@ describe('Dav service detection', () => {
expect(file2.isDavRessource).toBe(false)
})
})


describe('Root and paths detection', () => {
test('Unknown root', () => {
const file1 = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma',
})
expect(file1.root).toBe('/files/emma/Photos')
expect(file1.dirname).toBe('/')
})

test('Provided root dav service', () => {
const file1 = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma',
root: '/files/emma',
})
expect(file1.root).toBe('/files/emma')
expect(file1.dirname).toBe('/Photos')
})

test('Root with ending slash is removed', () => {
const file1 = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg',
mime: 'image/jpeg',
owner: 'emma',
root: '/files/emma/',
})
expect(file1.root).toBe('/files/emma')
})

test('Root and source are the same', () => {
const file1 = new File({
source: 'https://cloud.domain.com/remote.php/dav/files/emma',
mime: 'image/jpeg',
owner: 'emma',
root: '/files/emma',
})
expect(file1.dirname).toBe('/')
})
})
23 changes: 21 additions & 2 deletions lib/files/node.ts
Expand Up @@ -66,8 +66,12 @@ export abstract class Node {

/**
* Get the directory path leading to this object
* Will use the relative path to root if available
*/
get dirname(): string {
if (this.root) {
return dirname(this.source.split(this.root).pop() || '/')
}
return dirname(this.source)
}

Expand Down Expand Up @@ -131,12 +135,27 @@ export abstract class Node {
* Get the dav root of this object
*/
get root(): string|null {
// If provided (recommended), use the root and strip away the ending slash
if (this._data.root) {
return this._data.root.replace(/^(.+)\/$/, '$1')
}

// Use the source to get the root from the dav service
if (this.isDavRessource) {
return this.dirname.split(this._knownDavService).pop() || null
const root = dirname(this.source)
return root.split(this._knownDavService).pop() || null
}

return null
}

/**
* Get the absolute path of this object relative to the root
*/
get path(): string|null {
return (this.dirname + '/' + this.basename).replace(/\/\//g, '/')
}

/**
* Move the node to a new destination
*
Expand All @@ -155,6 +174,6 @@ export abstract class Node {
if (basename.includes('/')) {
throw new Error('Invalid basename')
}
this.move(this.dirname + '/' + basename)
this.move(dirname(this.source) + '/' + basename)
}
}
18 changes: 17 additions & 1 deletion lib/files/nodeData.ts
Expand Up @@ -28,7 +28,8 @@ export default interface NodeData {
/** Unique ID */
id?: number

/** URL to the ressource
/**
* URL to the ressource.
* e.g. https://cloud.domain.com/remote.php/dav/files/emma/Photos/picture.jpg
* or https://domain.com/Photos/picture.jpg
*/
Expand All @@ -53,6 +54,13 @@ export default interface NodeData {
owner: string|null

attributes?: Attribute

/**
* The absolute root of the home relative to the service.
* It is highly recommended to provide that information.
* e.g. /files/emma
*/
root?: string
}

/**
Expand Down Expand Up @@ -105,4 +113,12 @@ export const validateData = (data: NodeData) => {
if ('attributes' in data && typeof data.attributes !== 'object') {
throw new Error('Invalid attributes format')
}

if ('root' in data && typeof data.root !== 'string') {
throw new Error('Invalid root format')
}

if (data.root && !data.root.startsWith('/')) {
throw new Error('Root must start with a leading slash')
}
}

0 comments on commit 364866c

Please sign in to comment.