From 33e67124cee0b596e4cc7d143558985ca4492782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 15 Apr 2024 20:41:20 +0200 Subject: [PATCH] fix: Use Close_Session post message to properly end the Collabora editing before opening locally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- cypress/e2e/integration.spec.js | 16 +++++++++---- lib/Controller/WopiController.php | 1 + src/mixins/openLocal.js | 39 +++++++++++++++---------------- src/view/Office.vue | 20 ++++++++++++---- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/cypress/e2e/integration.spec.js b/cypress/e2e/integration.spec.js index bd437eba89..fd4067ffcb 100644 --- a/cypress/e2e/integration.spec.js +++ b/cypress/e2e/integration.spec.js @@ -110,11 +110,19 @@ describe('Nextcloud integration', function() { cy.get('.oc-dialog .oc-dialog-title') .should('contain', 'Open file locally ') - cy.on('url:changed', (newUrl) => { - expect(newUrl).to.contain('nc://') - }) + cy.intercept({ + method: 'POST', + url: '**/openlocaleditor', + }).as('getLocalToken') + cy.window() + .then((window) => { + cy.stub(window, 'open').as('open') + }) cy.get('.oc-dialog button.primary').click() - + cy.wait('@getLocalToken').its('response.statusCode').should('equal', 200) + cy.get('@open').should('have.been.calledOnce') + const nextcloudHost = new URL(Cypress.config('baseUrl')).host + cy.get('@open').its('firstCall.args.0').should('contain', 'nc://open/' + randUser.userId + '@' + nextcloudHost + '/document.odt') }) it('Insert image', function() { diff --git a/lib/Controller/WopiController.php b/lib/Controller/WopiController.php index a2d3d01cfb..7b4542e120 100644 --- a/lib/Controller/WopiController.php +++ b/lib/Controller/WopiController.php @@ -224,6 +224,7 @@ public function checkFileInfo($fileId, $access_token) { 'EnableInsertRemoteImage' => !$isPublic, 'EnableShare' => $file->isShareable() && !$isVersion && !$isPublic, 'HideUserList' => '', + 'EnableOwnerTermination' => $wopi->getCanwrite() && !$isPublic, 'DisablePrint' => $wopi->getHideDownload(), 'DisableExport' => $wopi->getHideDownload(), 'DisableCopy' => $wopi->getHideDownload(), diff --git a/src/mixins/openLocal.js b/src/mixins/openLocal.js index 7e6bab5130..b87ebda9b8 100644 --- a/src/mixins/openLocal.js +++ b/src/mixins/openLocal.js @@ -1,5 +1,5 @@ /* - * @copyright Copyright (c) 2023 Julius Härtl +* @copyright Copyright (c) 2023 Julius Härtl * * @author Julius Härtl * @@ -36,20 +36,6 @@ export default { startOpenLocalProcess() { this.showOpenLocalConfirmation() }, - async unlockAndOpenLocally() { - if (this.openingLocally) { - let shouldContinue = true - try { - await this.unlockFile() - } catch (e) { - shouldContinue = e.response.status === 400 - } - - if (shouldContinue) { - this.openLocally() - } - } - }, showOpenLocalConfirmation() { window.OC.dialogs.confirmDestructive( @@ -66,8 +52,20 @@ export default { return } this.openingLocally = true - this.sendPostMessage('Get_Views') - }) + this.postMessage.registerPostMessageHandler(this.handleCloseSession) + this.sendPostMessage('Action_Save', { + DontTerminateEdit: false, + DontSaveIfUnmodified: false, + Notify: false, + }) + this.sendPostMessage('Close_Session') + }, + ) + }, + + handleCloseSession() { + this.postMessage.unregisterPostMessageHandler(this.handleCloseSession) + this.openLocally() }, showOpenLocalFinished() { @@ -91,8 +89,9 @@ export default { return } this.openingLocally = true - this.sendPostMessage('Get_Views') - }) + this.openLocally() + }, + ) }, unlockFile() { @@ -114,7 +113,7 @@ export default { this.showOpenLocalFinished(url, window.top) this.close() - window.location.href = url + window.open(url, '_self') }) } }, diff --git a/src/view/Office.vue b/src/view/Office.vue index 19e381fc50..eaa2d70ab3 100644 --- a/src/view/Office.vue +++ b/src/view/Office.vue @@ -91,6 +91,7 @@ import { NcButton, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue' import AlertOctagonOutline from 'vue-material-design-icons/AlertOctagonOutline.vue' import { loadState } from '@nextcloud/initial-state' +import { showInfo } from '@nextcloud/dialogs' import ZoteroHint from '../components/Modal/ZoteroHint.vue' import { basename, dirname } from 'path' @@ -173,7 +174,6 @@ export default { error: null, errorType: null, loadingMsg: null, - views: [], showLinkPicker: false, showZotero: false, @@ -368,10 +368,8 @@ export default { case 'UI_Close': this.close() break - case 'Get_Views_Resp': - case 'Views_List': - this.views = args - this.unlockAndOpenLocally() + case 'Session_Closed': + this.handleSessionClosed(args) break case 'UI_SaveAs': this.saveAs(args.format) @@ -443,6 +441,18 @@ export default { } }, + handleSessionClosed({ Reason }) { + if (Reason !== 'OwnerTermination') { + return + } + if (this.openingLocally) { + return + } + + showInfo(t('richdocuments', 'The collaborative editing was terminated by another user')) + this.close() + }, + }, }