Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(node): allow and recommend to provide a specific root #574

Merged
merged 1 commit into from Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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')
}
}