From bb0c847cfb79b5a4e010df6a97b8222ccffd2a1b 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 | 28 ++++++++++++++++++---------- lib/Controller/WopiController.php | 1 + src/mixins/openLocal.js | 31 ++++++++++++++----------------- src/view/Office.vue | 20 +++++++++++++++----- 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/cypress/e2e/integration.spec.js b/cypress/e2e/integration.spec.js index 699206c37e..7401c94e26 100644 --- a/cypress/e2e/integration.spec.js +++ b/cypress/e2e/integration.spec.js @@ -101,20 +101,28 @@ describe('Nextcloud integration', function() { cy.openFile('document.rtf') }) - it.skip('Open locally', function() { + it('Open locally', function() { cy.get('@loleafletframe').within(() => { cy.get('#Open_Local_Editor').click() }) - cy.get('.oc-dialog').should('be.visible') - cy.get('.oc-dialog .oc-dialog-title') - .should('contain', 'Open file locally ') - - cy.on('url:changed', (newUrl) => { - expect(newUrl).to.contain('nc://') - }) - cy.get('.oc-dialog button.primary').click() - + cy.get('.confirmation-dialog').should('be.visible') + cy.get('.confirmation-dialog h1') + .should('contain', 'Open file locally') + + cy.intercept({ + method: 'POST', + url: '**/openlocaleditor', + }).as('getLocalToken') + cy.window() + .then((window) => { + cy.stub(window, 'open').as('open') + }) + cy.get('.confirmation-dialog button:contains("Open locally")').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 298f1a3849..22303106e8 100644 --- a/lib/Controller/WopiController.php +++ b/lib/Controller/WopiController.php @@ -176,6 +176,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 fb6d50211c..87c1670cc2 100644 --- a/src/mixins/openLocal.js +++ b/src/mixins/openLocal.js @@ -37,20 +37,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() { spawnDialog( @@ -66,11 +52,22 @@ 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() { const fileName = this.filename spawnDialog( @@ -87,7 +84,7 @@ export default { return } this.openingLocally = true - this.sendPostMessage('Get_Views') + this.openLocally() }, ) }, @@ -111,7 +108,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 882ea0e4cb..94dad8ad76 100644 --- a/src/view/Office.vue +++ b/src/view/Office.vue @@ -93,6 +93,7 @@ import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js' import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' 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' @@ -175,7 +176,6 @@ export default { error: null, errorType: null, loadingMsg: null, - views: [], showLinkPicker: false, showZotero: false, @@ -371,10 +371,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) @@ -446,6 +444,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() + }, + }, }