diff --git a/apps/viewer/src/legacy.spec.ts b/apps/viewer/src/legacy.spec.ts index 40679ec5ea286..f4e8827d64fdd 100644 --- a/apps/viewer/src/legacy.spec.ts +++ b/apps/viewer/src/legacy.spec.ts @@ -110,6 +110,27 @@ describe('OCA.Viewer compatibility layer', () => { expect(target.basename).toBe('pineapple.jpg') }) + it('addresses a file with a dav source relative to its dav home', async () => { + await viewer().open({ + fileInfo: { source: 'https://cloud.example/remote.php/dav/files/emma/Photos/2019/x.jpg', filename: '/Photos/2019/x.jpg', mime: 'image/jpeg' }, + }) + + const [, target] = viewerOpen.mock.calls[0] + expect(target.source).toBe('https://cloud.example/remote.php/dav/files/emma/Photos/2019/x.jpg') + expect(target.root).toBe('/files/emma') + expect(target.path).toBe('/Photos/2019/x.jpg') + }) + + it('addresses a file of another dav service relative to its home there', async () => { + await viewer().open({ + fileInfo: { source: 'https://cloud.example/remote.php/dav/photos/emma/albums/Trip/x.jpg', mime: 'image/jpeg' }, + }) + + const [, target] = viewerOpen.mock.calls[0] + expect(target.root).toBe('/photos/emma') + expect(target.basename).toBe('x.jpg') + }) + it('passes the handler on to openWith', async () => { await viewer().openWith('richdocuments', { fileInfo: { fileid: 1, filename: '/a.pdf', mime: 'application/pdf' } }) expect(viewerOpen.mock.calls[0][3]).toBe('richdocuments') diff --git a/apps/viewer/src/legacy.ts b/apps/viewer/src/legacy.ts index 0681dafb69885..e884f45c8cd07 100644 --- a/apps/viewer/src/legacy.ts +++ b/apps/viewer/src/legacy.ts @@ -145,12 +145,33 @@ function directoryOf(source: string): string { } } +/** + * The root a node served from an address is relative to. + * + * An address on dav sits under a home of one of its services, such as + * `/files/emma`, and a node has to be relative to that home. Anything else + * has no home, so the folder the file sits in stands in for it and the node + * still knows its own name. + * + * @param source - the address the file is served from + */ +function rootOf(source: string): string { + const davRemote = getRemoteURL() + '/' + if (source.startsWith(davRemote)) { + const [service, home] = source.slice(davRemote.length).split('/') + if (service && home) { + return `/${service}/${home}` + } + } + return directoryOf(source) +} + /** * Build a node out of what an app handed over. * * Callers filled in what they had, so most of this is defaulting. A file - * with a `source` of its own is served from somewhere that is not dav, and - * keeps it; everything else is addressed under the user's files. + * with a `source` of its own keeps it; everything else is addressed under + * the user's files. * * @param info - the file info an app passed to open */ @@ -169,10 +190,7 @@ function nodeFromFileInfo(info: LegacyFileInfo): IFile { const data: NodeData = { source, - // A file under the user's files is relative to their dav home. One - // served from somewhere else has no home, so the folder it sits in - // stands in for it and the node still knows its own name. - root: info.source === undefined ? getRootPath() : directoryOf(info.source), + root: info.source === undefined ? getRootPath() : rootOf(info.source), displayname: info.basename ?? basenameOf(source), mime: info.mime ?? 'application/octet-stream', owner,