diff --git a/src/mixins/AttachmentMixin.js b/src/mixins/AttachmentMixin.js index f214b4ef4b..5ecd559c66 100644 --- a/src/mixins/AttachmentMixin.js +++ b/src/mixins/AttachmentMixin.js @@ -3,6 +3,20 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +const PDF_MIME = 'application/pdf' +const PDF_HANDLER_ID = 'pdf' + +/** + * Mail attachments have no Nextcloud file id, so office handlers that hijack + * application/pdf (Nextcloud Office, ONLYOFFICE) cannot open them and bail out + * with an empty WOPI config. Only files_pdfviewer works off a plain URL. + * + * @return {boolean} whether files_pdfviewer is registered in the viewer + */ +function hasPdfViewer() { + return (OCA?.Viewer?.availableHandlers ?? []).some((handler) => handler.id === PDF_HANDLER_ID) +} + export default { computed: { fileInfos() { @@ -24,7 +38,7 @@ export default { return this.fileInfos.filter((fileInfo) => (fileInfo.mime.startsWith('image/') || fileInfo.mime.startsWith('video/') || fileInfo.mime.startsWith('audio/') - || fileInfo.mime === 'application/pdf') + || (fileInfo.mime === PDF_MIME && hasPdfViewer())) && OCA.Viewer.mimetypes.includes(fileInfo.mime)) }, }, @@ -37,10 +51,17 @@ export default { return } - OCA.Viewer.open({ + const options = { fileInfo, list: this.previewableFileInfos, - }) + } + + if (fileInfo.mime === PDF_MIME && OCA.Viewer.openWith) { + OCA.Viewer.openWith(PDF_HANDLER_ID, options) + return + } + + OCA.Viewer.open(options) }, }, diff --git a/src/tests/unit/mixins/AttachmentMixin.spec.js b/src/tests/unit/mixins/AttachmentMixin.spec.js index 45a71607e4..eb701428b7 100644 --- a/src/tests/unit/mixins/AttachmentMixin.spec.js +++ b/src/tests/unit/mixins/AttachmentMixin.spec.js @@ -9,6 +9,7 @@ import AttachmentMixin from '../../../mixins/AttachmentMixin.js' const attachments = [ { downloadUrl: '/cat.png', fileName: 'cat.png', mime: 'image/png' }, { downloadUrl: '/notes.txt', fileName: 'notes.txt', mime: 'text/plain' }, + { downloadUrl: '/invoice.pdf', fileName: 'invoice.pdf', mime: 'application/pdf' }, ] function mountMixin() { @@ -25,7 +26,7 @@ describe('AttachmentMixin', () => { }) it('previews attachments supported by the viewer', () => { - global.OCA = { Viewer: { mimetypes: ['image/png'] } } + global.OCA = { Viewer: { mimetypes: ['image/png'], availableHandlers: [] } } const view = mountMixin() @@ -42,4 +43,44 @@ describe('AttachmentMixin', () => { expect(view.vm.previewableFileInfos).toEqual([]) expect(view.vm.canPreview(view.vm.fileInfos[0])).toBe(false) }) + + it('does not preview pdf attachments without files_pdfviewer', () => { + global.OCA = { + Viewer: { + mimetypes: ['application/pdf'], + availableHandlers: [{ id: 'onlyoffice', mimes: ['application/pdf'] }], + }, + } + + const view = mountMixin() + + expect(view.vm.previewableFileInfos).toEqual([]) + expect(view.vm.canPreview(view.vm.fileInfos[2])).toBe(false) + }) + + it('opens pdf attachments with files_pdfviewer', () => { + const openWith = vi.fn() + const open = vi.fn() + global.OCA = { + Viewer: { + mimetypes: ['application/pdf', 'image/png'], + availableHandlers: [{ id: 'onlyoffice' }, { id: 'pdf' }], + openWith, + open, + }, + } + + const view = mountMixin() + view.vm.showViewer(view.vm.fileInfos[2]) + + expect(openWith).toHaveBeenCalledWith('pdf', { + fileInfo: view.vm.fileInfos[2], + list: view.vm.previewableFileInfos, + }) + expect(open).not.toHaveBeenCalled() + + view.vm.showViewer(view.vm.fileInfos[0]) + + expect(open).toHaveBeenCalledTimes(1) + }) })