From 3cfca27b5423b1e6001221e7128d0033aebc83fd Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 2 Jun 2022 17:25:58 +0200 Subject: [PATCH] expose ability to create note revisions in backend API #2890 --- docs/backend_api/BackendScriptApi.html | 72 ++ docs/backend_api/Note.html | 267 +++++-- docs/backend_api/becca_entities_note.js.html | 37 + .../services_backend_script_api.js.html | 9 + docs/frontend_api/FrontendScriptApi.html | 755 ++++++++++++++---- .../services_frontend_script_api.js.html | 6 +- src/becca/entities/note.js | 37 + src/routes/api/notes.js | 2 +- src/services/note_revisions.js | 41 - src/services/notes.js | 8 +- 10 files changed, 949 insertions(+), 285 deletions(-) diff --git a/docs/backend_api/BackendScriptApi.html b/docs/backend_api/BackendScriptApi.html index d99d0c219..8e1204851 100644 --- a/docs/backend_api/BackendScriptApi.html +++ b/docs/backend_api/BackendScriptApi.html @@ -131,6 +131,78 @@ +

__private :Object

+ + + + +
+ This object contains "at your risk" and "no BC guarantees" objects for advanced use cases. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + +

axios

diff --git a/docs/backend_api/Note.html b/docs/backend_api/Note.html index c5eea4f2f..2afe54588 100644 --- a/docs/backend_api/Note.html +++ b/docs/backend_api/Note.html @@ -93,7 +93,7 @@
Source:
@@ -204,7 +204,7 @@
Source:
@@ -279,7 +279,7 @@
Source:
@@ -347,7 +347,7 @@
Source:
@@ -415,7 +415,7 @@
Source:
@@ -486,7 +486,7 @@
Source:
@@ -554,7 +554,7 @@
Source:
@@ -622,7 +622,7 @@
Source:
@@ -690,7 +690,7 @@
Source:
@@ -758,7 +758,7 @@
Source:
@@ -833,7 +833,7 @@
Source:
@@ -901,7 +901,7 @@
Source:
@@ -969,7 +969,7 @@
Source:
@@ -1037,7 +1037,7 @@
Source:
@@ -1112,7 +1112,7 @@
Source:
@@ -1180,7 +1180,7 @@
Source:
@@ -1248,7 +1248,7 @@
Source:
@@ -1316,7 +1316,7 @@
Source:
@@ -1384,7 +1384,7 @@
Source:
@@ -1452,7 +1452,7 @@
Source:
@@ -1528,7 +1528,7 @@
Source:
@@ -1630,7 +1630,7 @@
Source:
@@ -1830,7 +1830,7 @@
Source:
@@ -1914,7 +1914,7 @@
Source:
@@ -2020,7 +2020,7 @@
Source:
@@ -2194,7 +2194,7 @@
Source:
@@ -2394,7 +2394,7 @@
Source:
@@ -2572,7 +2572,7 @@
Source:
@@ -2683,7 +2683,7 @@
Source:
@@ -2785,7 +2785,7 @@
Source:
@@ -2887,7 +2887,7 @@
Source:
@@ -2989,7 +2989,7 @@
Source:
@@ -3091,7 +3091,7 @@
Source:
@@ -3199,7 +3199,7 @@
Source:
@@ -3305,7 +3305,7 @@
Source:
@@ -3456,7 +3456,7 @@
Source:
@@ -3626,7 +3626,7 @@
Source:
@@ -3781,7 +3781,7 @@
Source:
@@ -3951,7 +3951,7 @@
Source:
@@ -4057,7 +4057,7 @@
Source:
@@ -4259,7 +4259,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4437,7 +4437,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4595,7 +4595,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4765,7 +4765,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4920,7 +4920,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5090,7 +5090,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5245,7 +5245,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5415,7 +5415,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5570,7 +5570,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5679,7 +5679,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5781,7 +5781,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5932,7 +5932,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6102,7 +6102,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6257,7 +6257,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6366,7 +6366,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6475,7 +6475,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6577,7 +6577,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6679,7 +6679,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6781,7 +6781,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6888,7 +6888,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6990,7 +6990,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7141,7 +7141,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7319,7 +7319,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7474,7 +7474,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7629,7 +7629,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7784,7 +7784,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7934,7 +7934,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8040,7 +8040,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8146,7 +8146,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8252,7 +8252,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8358,7 +8358,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8464,7 +8464,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8856,7 +8856,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -9036,7 +9036,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -9216,7 +9216,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -9363,6 +9363,111 @@ This is a low level method, for notes and branches use `note.deleteNote()` and ' +

saveNoteRevision() → {NoteRevision|null}

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +NoteRevision +| + +null + + +
+
+ + + + + + + + + + + + +

setAttribute(type, name, valueopt)

@@ -9538,7 +9643,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -9718,7 +9823,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -9878,7 +9983,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -10120,7 +10225,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -10331,7 +10436,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
@@ -10542,7 +10647,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
Source:
diff --git a/docs/backend_api/becca_entities_note.js.html b/docs/backend_api/becca_entities_note.js.html index 3af1da710..57d0527e7 100644 --- a/docs/backend_api/becca_entities_note.js.html +++ b/docs/backend_api/becca_entities_note.js.html @@ -37,6 +37,8 @@ const entityChangesService = require('../../services/entity_changes'); const AbstractEntity = require("./abstract_entity"); const NoteRevision = require("./note_revision"); const TaskContext = require("../../services/task_context.js"); +const optionService = require("../../services/options.js"); +const noteRevisionService = require("../../services/note_revisions.js"); const LABEL = 'label'; const RELATION = 'relation'; @@ -1192,6 +1194,41 @@ class Note extends AbstractEntity { return !(this.noteId in this.becca.notes); } + /** + * @return {NoteRevision|null} + */ + saveNoteRevision() { + const content = this.getContent(); + + if (!content || (Buffer.isBuffer(content) && content.byteLength === 0)) { + return null; + } + + const contentMetadata = this.getContentMetadata(); + + const noteRevision = new NoteRevision({ + noteId: this.noteId, + // title and text should be decrypted now + title: this.title, + type: this.type, + mime: this.mime, + isProtected: false, // will be fixed in the protectNoteRevisions() call + utcDateLastEdited: this.utcDateModified > contentMetadata.utcDateModified + ? this.utcDateModified + : contentMetadata.utcDateModified, + utcDateCreated: dateUtils.utcNowDateTime(), + utcDateModified: dateUtils.utcNowDateTime(), + dateLastEdited: this.dateModified > contentMetadata.dateModified + ? this.dateModified + : contentMetadata.dateModified, + dateCreated: dateUtils.localNowDateTime() + }).save(); + + noteRevision.setContent(content); + + return noteRevision; + } + beforeSaving() { super.beforeSaving(); diff --git a/docs/backend_api/services_backend_script_api.js.html b/docs/backend_api/services_backend_script_api.js.html index 3c73eee9f..23c98b39e 100644 --- a/docs/backend_api/services_backend_script_api.js.html +++ b/docs/backend_api/services_backend_script_api.js.html @@ -454,6 +454,15 @@ function BackendScriptApi(currentNote, apiParams) { * @return {{syncVersion, appVersion, buildRevision, dbVersion, dataDirectory, buildDate}|*} - object representing basic info about running Trilium version */ this.getAppInfo = () => appInfo + + /** + * This object contains "at your risk" and "no BC guarantees" objects for advanced use cases. + * + * @type {{becca: Becca}} + */ + this.__private = { + becca + } } module.exports = BackendScriptApi; diff --git a/docs/frontend_api/FrontendScriptApi.html b/docs/frontend_api/FrontendScriptApi.html index 9ac977093..f464ae182 100644 --- a/docs/frontend_api/FrontendScriptApi.html +++ b/docs/frontend_api/FrontendScriptApi.html @@ -1671,7 +1671,7 @@ -

addTextToActiveTabEditor(text)

+

addTextToActiveContextEditor(text)

@@ -1772,7 +1772,146 @@
Source:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

addTextToActiveTabEditor(text)

+ + + + + + +
+ Adds given text to the editor cursor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +string + + + + this must be clear text, HTML is not supported.
+ + + + + + +
+ + + + + + + + + + + + + + + + +
Deprecated:
  • use addTextToActiveContextEditor() instead
+ + + + + + + + + + + +
Source:
+
@@ -1928,7 +2067,7 @@
Source:
@@ -2479,114 +2618,7 @@ -

getActiveNoteDetailWidget() → {Promise.<NoteDetailWidget>}

- - - - - - -
- Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the -implementation of actual widget type. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -Promise.<NoteDetailWidget> - - -
-
- - - - - - - - - - - - - -

getActiveTabCodeEditor() → {Promise.<CodeMirror>}

+

getActiveContextCodeEditor() → {Promise.<CodeMirror>}

@@ -2638,7 +2670,7 @@ implementation of actual widget type.
Source:
@@ -2696,7 +2728,7 @@ implementation of actual widget type. -

getActiveTabNote() → {NoteShort}

+

getActiveContextNote() → {NoteShort}

@@ -2744,7 +2776,438 @@ implementation of actual widget type.
Source:
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ active note (loaded into right pane) +
+ + + +
+
+ Type +
+
+ +NoteShort + + +
+
+ + + + + + + + + + + + + +

getActiveContextNotePath() → {Promise.<(string|null)>}

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns note path of active note or null if there isn't active note +
+ + + +
+
+ Type +
+
+ +Promise.<(string|null)> + + +
+
+ + + + + + + + + + + + + +

getActiveContextTextEditor() → {Promise.<CKEditor>}

+ + + + + + +
+ See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ instance of CKEditor +
+ + + +
+
+ Type +
+
+ +Promise.<CKEditor> + + +
+
+ + + + + + + + + + + + + +

getActiveNoteDetailWidget() → {Promise.<NoteDetailWidget>}

+ + + + + + +
+ Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the +implementation of actual widget type. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<NoteDetailWidget> + + +
+
+ + + + + + + + + + + + + +

getActiveTabNote() → {NoteShort}

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
Deprecated:
  • use getActiveContextNote() instead
+ + + + + + + + + + + +
Source:
+
@@ -2838,6 +3301,8 @@ implementation of actual widget type. +
Deprecated:
  • use getActiveContextNotePath() instead
+ @@ -2850,7 +3315,7 @@ implementation of actual widget type.
Source:
@@ -2908,7 +3373,7 @@ implementation of actual widget type. -

getActiveTabTextEditor(callbackopt) → {Promise.<CKEditor>}

+

getActiveTabTextEditor(callbackopt)

@@ -2975,7 +3440,7 @@ implementation of actual widget type. - deprecated (use returned promise): callback receiving "textEditor" instance + callback receiving "textEditor" instance @@ -3004,6 +3469,8 @@ implementation of actual widget type. +
Deprecated:
  • use getActiveContextTextEditor()
+ @@ -3016,7 +3483,7 @@ implementation of actual widget type.
Source:
@@ -3041,28 +3508,6 @@ implementation of actual widget type. -
Returns:
- - -
- instance of CKEditor -
- - - -
-
- Type -
-
- -Promise.<CKEditor> - - -
-
- - @@ -3175,7 +3620,7 @@ implementation of actual widget type.
Source:
@@ -3332,7 +3777,7 @@ implementation of actual widget type.
Source:
@@ -3487,7 +3932,7 @@ implementation of actual widget type.
Source:
@@ -3749,7 +4194,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -4212,7 +4657,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4367,7 +4812,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4522,7 +4967,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4959,7 +5404,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5115,7 +5560,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5271,7 +5716,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5408,7 +5853,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5562,7 +6007,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -6503,7 +6948,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -6654,7 +7099,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -7340,7 +7785,7 @@ Typical use case is when new note has been created, we should wait until it is s
Source:
diff --git a/docs/frontend_api/services_frontend_script_api.js.html b/docs/frontend_api/services_frontend_script_api.js.html index fe896a184..0bb38dc24 100644 --- a/docs/frontend_api/services_frontend_script_api.js.html +++ b/docs/frontend_api/services_frontend_script_api.js.html @@ -412,7 +412,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain this.getActiveTabTextEditor = callback => { console.warn("api.getActiveTabTextEditor() is deprecated, use getActiveContextTextEditor() instead."); - return appContext.tabManager.getActiveContextTextEditor(callback); + return appContext.tabManager.getActiveContext()?.getTextEditor(callback); }; /** @@ -421,7 +421,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain * @method * @returns {Promise<CKEditor>} instance of CKEditor */ - this.getActiveContextTextEditor = () => appContext.tabManager.getActiveContextTextEditor(); + this.getActiveContextTextEditor = () => appContext.tabManager.getActiveContext()?.getTextEditor(); /** * See https://codemirror.net/doc/manual.html#api @@ -429,7 +429,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain * @method * @returns {Promise<CodeMirror>} instance of CodeMirror */ - this.getActiveContextCodeEditor = () => appContext.tabManager.getActiveContextCodeEditor(); + this.getActiveContextCodeEditor = () => appContext.tabManager.getActiveContext()?.getCodeEditor(); /** * Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the diff --git a/src/becca/entities/note.js b/src/becca/entities/note.js index 595e41052..a815df1c3 100644 --- a/src/becca/entities/note.js +++ b/src/becca/entities/note.js @@ -9,6 +9,8 @@ const entityChangesService = require('../../services/entity_changes'); const AbstractEntity = require("./abstract_entity"); const NoteRevision = require("./note_revision"); const TaskContext = require("../../services/task_context.js"); +const optionService = require("../../services/options.js"); +const noteRevisionService = require("../../services/note_revisions.js"); const LABEL = 'label'; const RELATION = 'relation'; @@ -1164,6 +1166,41 @@ class Note extends AbstractEntity { return !(this.noteId in this.becca.notes); } + /** + * @return {NoteRevision|null} + */ + saveNoteRevision() { + const content = this.getContent(); + + if (!content || (Buffer.isBuffer(content) && content.byteLength === 0)) { + return null; + } + + const contentMetadata = this.getContentMetadata(); + + const noteRevision = new NoteRevision({ + noteId: this.noteId, + // title and text should be decrypted now + title: this.title, + type: this.type, + mime: this.mime, + isProtected: false, // will be fixed in the protectNoteRevisions() call + utcDateLastEdited: this.utcDateModified > contentMetadata.utcDateModified + ? this.utcDateModified + : contentMetadata.utcDateModified, + utcDateCreated: dateUtils.utcNowDateTime(), + utcDateModified: dateUtils.utcNowDateTime(), + dateLastEdited: this.dateModified > contentMetadata.dateModified + ? this.dateModified + : contentMetadata.dateModified, + dateCreated: dateUtils.localNowDateTime() + }).save(); + + noteRevision.setContent(content); + + return noteRevision; + } + beforeSaving() { super.beforeSaving(); diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js index 5f334edc8..272cc88e0 100644 --- a/src/routes/api/notes.js +++ b/src/routes/api/notes.js @@ -206,7 +206,7 @@ function changeTitle(req) { const noteTitleChanged = note.title !== title; if (noteTitleChanged) { - noteService.saveNoteRevision(note); + noteService.saveNoteRevisionIfNeeded(note); } note.title = title; diff --git a/src/services/note_revisions.js b/src/services/note_revisions.js index 3ff9b692a..3759d2d2e 100644 --- a/src/services/note_revisions.js +++ b/src/services/note_revisions.js @@ -30,46 +30,6 @@ function protectNoteRevisions(note) { } } -/** - * @param {Note} note - * @return {NoteRevision|null} - */ -function createNoteRevision(note) { - if (note.hasLabel("disableVersioning")) { - return null; - } - - const content = note.getContent(); - - if (!content || (Buffer.isBuffer(content) && content.byteLength === 0)) { - return null; - } - - const contentMetadata = note.getContentMetadata(); - - const noteRevision = new NoteRevision({ - noteId: note.noteId, - // title and text should be decrypted now - title: note.title, - type: note.type, - mime: note.mime, - isProtected: false, // will be fixed in the protectNoteRevisions() call - utcDateLastEdited: note.utcDateModified > contentMetadata.utcDateModified - ? note.utcDateModified - : contentMetadata.utcDateModified, - utcDateCreated: dateUtils.utcNowDateTime(), - utcDateModified: dateUtils.utcNowDateTime(), - dateLastEdited: note.dateModified > contentMetadata.dateModified - ? note.dateModified - : contentMetadata.dateModified, - dateCreated: dateUtils.localNowDateTime() - }).save(); - - noteRevision.setContent(content); - - return noteRevision; -} - function eraseNoteRevisions(noteRevisionIdsToErase) { if (noteRevisionIdsToErase.length === 0) { return; @@ -86,6 +46,5 @@ function eraseNoteRevisions(noteRevisionIdsToErase) { module.exports = { protectNoteRevisions, - createNoteRevision, eraseNoteRevisions }; diff --git a/src/services/notes.js b/src/services/notes.js index 5e3670727..15526e9b6 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -491,7 +491,7 @@ function saveLinks(note, content) { return content; } -function saveNoteRevision(note) { +function saveNoteRevisionIfNeeded(note) { // files and images are versioned separately if (note.type === 'file' || note.type === 'image' || note.hasLabel('disableVersioning')) { return; @@ -508,7 +508,7 @@ function saveNoteRevision(note) { const msSinceDateCreated = now.getTime() - dateUtils.parseDateTime(note.utcDateCreated).getTime(); if (!existingNoteRevisionId && msSinceDateCreated >= noteRevisionSnapshotTimeInterval * 1000) { - noteRevisionService.createNoteRevision(note); + note.saveNoteRevision(); } } @@ -519,7 +519,7 @@ function updateNote(noteId, noteUpdates) { throw new Error(`Note '${noteId}' is not available for change!`); } - saveNoteRevision(note); + saveNoteRevisionIfNeeded(note); // if protected status changed, then we need to encrypt/decrypt the content anyway if (['file', 'image'].includes(note.type) && note.isProtected !== noteUpdates.isProtected) { @@ -910,6 +910,6 @@ module.exports = { triggerNoteTitleChanged, eraseDeletedNotesNow, eraseNotesWithDeleteId, - saveNoteRevision, + saveNoteRevisionIfNeeded, downloadImages };