From e9e09b82b908690991cd9c60e4baedd8833c83f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 9 Jul 2019 10:55:46 +0200 Subject: Reconnect after session has timed out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Service/ApiService.php | 4 +++- lib/Service/DocumentService.php | 4 ++++ src/EditorFactory.js | 7 +++++-- src/components/EditorWrapper.vue | 21 ++++++++++++++++++--- src/services/PollingBackend.js | 11 +++++++++++ src/services/SyncService.js | 6 +++++- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/lib/Service/ApiService.php b/lib/Service/ApiService.php index 83a7a8124..c6a35c610 100644 --- a/lib/Service/ApiService.php +++ b/lib/Service/ApiService.php @@ -145,7 +145,7 @@ class ApiService { } return new DataResponse($steps); } - return new DataResponse([], 500); + return new DataResponse([], 403); } public function sync($documentId, $sessionId, $sessionToken, $version = 0, $autosaveContent = null, bool $force = false, bool $manualSave = false, $token = null): DataResponse { @@ -176,6 +176,8 @@ class ApiService { } catch (LockedException $e) { // Ignore locked exception since it might happen due to an autosave action happening at the same time } + } catch (NotFoundException $e) { + return new DataResponse([], 404); } catch (Exception $e) { $this->logger->logException($e); return new DataResponse([ diff --git a/lib/Service/DocumentService.php b/lib/Service/DocumentService.php index f2784da5c..31dcb6910 100644 --- a/lib/Service/DocumentService.php +++ b/lib/Service/DocumentService.php @@ -237,6 +237,10 @@ class DocumentService { $file = $this->getFileByShareToken($token, $filePath); } + if ($file === null) { + throw new NotFoundException(); + } + if ($this->isReadOnly($file, $token)) { return $document; } diff --git a/src/EditorFactory.js b/src/EditorFactory.js index e0cbd3206..32fbf12be 100644 --- a/src/EditorFactory.js +++ b/src/EditorFactory.js @@ -101,7 +101,7 @@ const createEditor = ({ content, onUpdate, extensions, enableRichEditing, langua const markdownit = MarkdownIt('commonmark', { html: false, breaks: false }) .enable('strikethrough') -const SerializeException = (message) => { +const SerializeException = function(message) { this.message = message } const createMarkdownSerializer = (_nodes, _marks) => { @@ -135,7 +135,10 @@ const createMarkdownSerializer = (_nodes, _marks) => { const serializePlainText = (tiptap) => { const doc = tiptap.getJSON() - if (doc.content.length !== 1 || doc.content[0].content.length !== 1) { + if (doc.content.length !== 1 || typeof doc.content[0].content === 'undefined' || doc.content[0].content.length !== 1) { + if (doc.content[0].type === 'code_block' && typeof doc.content[0].content === 'undefined') { + return '' + } throw new SerializeException('Failed to serialize document to plain text') } const codeBlock = doc.content[0].content[0] diff --git a/src/components/EditorWrapper.vue b/src/components/EditorWrapper.vue index 0f606378c..50046e6db 100644 --- a/src/components/EditorWrapper.vue +++ b/src/components/EditorWrapper.vue @@ -305,14 +305,24 @@ export default { this.document = document }) .on('error', (error, data) => { + this.tiptap.setOptions({ editable: false }) if (error === ERROR_TYPE.SAVE_COLLISSION && (!this.syncError || this.syncError.type !== ERROR_TYPE.SAVE_COLLISSION)) { this.initialLoading = true this.syncError = { - type: ERROR_TYPE.SAVE_COLLISSION, + type: error, data: data } - this.tiptap.setOptions({ editable: false }) - + } + if (error === ERROR_TYPE.CONNECTION_FAILED) { + this.initialLoading = false + // FIXME: ideally we just try to reconnect in the service, so we don't loose steps + OC.Notification.showTemporary('Connection failed, reconnecting') + this.reconnect() + } + if (error === ERROR_TYPE.SOURCE_NOT_FOUND) { + this.initialLoading = false + OC.Notification.showTemporary('Source not found') + this.$emit('close') } }) .on('stateChange', (state) => { @@ -334,6 +344,11 @@ export default { }, resolveUseServerVersion() { + this.forceRecreate = true + this.reconnect() + }, + + reconnect() { this.forceRecreate = true this.syncService.close() this.syncService = null diff --git a/src/services/PollingBackend.js b/src/services/PollingBackend.js index b650516f0..a41d1353f 100644 --- a/src/services/PollingBackend.js +++ b/src/services/PollingBackend.js @@ -145,6 +145,8 @@ class PollingBackend { this._authority.emit('error', ERROR_TYPE.SAVE_COLLISSION, { outsideChange: e.response.data.outsideChange }) + } else if (e.response.status === 403) { + this._authority.emit('error', ERROR_TYPE.CONNECTION_FAILED, {}) } else { console.error('Failed to fetch steps due to other reason', e) } @@ -179,6 +181,15 @@ class PollingBackend { }).catch((e) => { console.error('failed to apply steps due to collission, retrying') this.lock = false + if (!e.response) { + throw e + } + // Only emit conflict event if we have synced until the latest version + if (e.response.status === 403 && e.response.data.document.currentVersion === this._authority.document.currentVersion) { + this._authority.emit('error', ERROR_TYPE.PUSH_FAILURE, {}) + OC.Notification.showTemporary('Changes could not be sent yet') + } + this.fetchSteps() this.carefulRetry() }) diff --git a/src/services/SyncService.js b/src/services/SyncService.js index 306ffc5f8..2d7a95829 100644 --- a/src/services/SyncService.js +++ b/src/services/SyncService.js @@ -42,7 +42,11 @@ const ERROR_TYPE = { */ PUSH_FAILURE: 1, - LOAD_ERROR: 2 + LOAD_ERROR: 2, + + CONNECTION_FAILED: 3, + + SOURCE_NOT_FOUND: 4 } class SyncService { -- cgit v1.2.3 From 8586ebed1acf5667192ced305c94dec6f021cc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 10 Jul 2019 16:26:18 +0200 Subject: Do not force recreate on reconnection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/components/EditorWrapper.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/EditorWrapper.vue b/src/components/EditorWrapper.vue index 50046e6db..f9edfa48b 100644 --- a/src/components/EditorWrapper.vue +++ b/src/components/EditorWrapper.vue @@ -349,7 +349,6 @@ export default { }, reconnect() { - this.forceRecreate = true this.syncService.close() this.syncService = null this.tiptap.destroy() -- cgit v1.2.3 From 31ad3a0d765e0dbbbe099dc5f683aeea1a25d884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 10 Jul 2019 16:44:12 +0200 Subject: Add proper mimetype for public shares MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/public.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public.js b/src/public.js index aa87dfee8..54a491c3a 100644 --- a/src/public.js +++ b/src/public.js @@ -34,7 +34,7 @@ documentReady(() => { props: { active: true, shareToken: sharingToken, - mimetype: mimetype + mime: mimetype } }) }) -- cgit v1.2.3