mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	rename "note revision" to just "revision"
This commit is contained in:
		| @@ -2,7 +2,7 @@ | |||||||
| UPDATE etapi_tokens SET tokenHash = 'API token hash value'; | UPDATE etapi_tokens SET tokenHash = 'API token hash value'; | ||||||
| UPDATE notes SET title = 'title' WHERE noteId != 'root' AND noteId NOT LIKE '\_%' ESCAPE '\'; | UPDATE notes SET title = 'title' WHERE noteId != 'root' AND noteId NOT LIKE '\_%' ESCAPE '\'; | ||||||
| UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; | UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; | ||||||
| UPDATE note_revisions SET title = 'title'; | UPDATE revisions SET title = 'title'; | ||||||
|  |  | ||||||
| UPDATE attributes SET name = 'name', value = 'value' | UPDATE attributes SET name = 'name', value = 'value' | ||||||
|                   WHERE type = 'label' |                   WHERE type = 'label' | ||||||
| @@ -28,7 +28,7 @@ UPDATE attributes SET name = 'name', value = 'value' | |||||||
|                                      'widget', |                                      'widget', | ||||||
|                                      'noteInfoWidgetDisabled', |                                      'noteInfoWidgetDisabled', | ||||||
|                                      'linkMapWidgetDisabled', |                                      'linkMapWidgetDisabled', | ||||||
|                                      'noteRevisionsWidgetDisabled', |                                      'revisionsWidgetDisabled', | ||||||
|                                      'whatLinksHereWidgetDisabled', |                                      'whatLinksHereWidgetDisabled', | ||||||
|                                      'similarNotesWidgetDisabled', |                                      'similarNotesWidgetDisabled', | ||||||
|                                      'workspace', |                                      'workspace', | ||||||
| @@ -103,7 +103,7 @@ UPDATE attributes SET name = 'name' | |||||||
|                                      'widget', |                                      'widget', | ||||||
|                                      'noteInfoWidgetDisabled', |                                      'noteInfoWidgetDisabled', | ||||||
|                                      'linkMapWidgetDisabled', |                                      'linkMapWidgetDisabled', | ||||||
|                                      'noteRevisionsWidgetDisabled', |                                      'revisionsWidgetDisabled', | ||||||
|                                      'whatLinksHereWidgetDisabled', |                                      'whatLinksHereWidgetDisabled', | ||||||
|                                      'similarNotesWidgetDisabled', |                                      'similarNotesWidgetDisabled', | ||||||
|                                      'workspace', |                                      'workspace', | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								db/migrations/0221__rename_note_revision_to_revision.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								db/migrations/0221__rename_note_revision_to_revision.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | CREATE TABLE IF NOT EXISTS "revisions" (`revisionId`	TEXT NOT NULL PRIMARY KEY, | ||||||
|  |                                         `noteId`	TEXT NOT NULL, | ||||||
|  |                                         type TEXT DEFAULT '' NOT NULL, | ||||||
|  |                                         mime TEXT DEFAULT '' NOT NULL, | ||||||
|  |                                         `title`	TEXT NOT NULL, | ||||||
|  |                                         `isProtected`	INT NOT NULL DEFAULT 0, | ||||||
|  |                                         blobId TEXT DEFAULT NULL, | ||||||
|  |                                         `utcDateLastEdited` TEXT NOT NULL, | ||||||
|  |                                         `utcDateCreated` TEXT NOT NULL, | ||||||
|  |                                         `utcDateModified` TEXT NOT NULL, | ||||||
|  |                                         `dateLastEdited` TEXT NOT NULL, | ||||||
|  |                                         `dateCreated` TEXT NOT NULL); | ||||||
|  |  | ||||||
|  | INSERT INTO revisions (revisionId, noteId, type, mime, title, isProtected, utcDateLastEdited, utcDateCreated, utcDateModified, dateLastEdited, dateCreated, blobId) | ||||||
|  | SELECT noteRevisionId, noteId, type, mime, title, isProtected, utcDateLastEdited, utcDateCreated, utcDateModified, dateLastEdited, dateCreated, blobId FROM note_revisions; | ||||||
|  |  | ||||||
|  | DROP TABLE note_revisions; | ||||||
|  |  | ||||||
|  | CREATE INDEX `IDX_revisions_noteId` ON `revisions` (`noteId`); | ||||||
|  | CREATE INDEX `IDX_revisions_utcDateCreated` ON `revisions` (`utcDateCreated`); | ||||||
|  | CREATE INDEX `IDX_revisions_utcDateLastEdited` ON `revisions` (`utcDateLastEdited`); | ||||||
|  | CREATE INDEX `IDX_revisions_dateCreated` ON `revisions` (`dateCreated`); | ||||||
|  | CREATE INDEX `IDX_revisions_dateLastEdited` ON `revisions` (`dateLastEdited`); | ||||||
|  |  | ||||||
|  | UPDATE entity_changes SET entity_name = 'revisions' WHERE entity_name = 'note_revisions'; | ||||||
| @@ -35,24 +35,26 @@ CREATE TABLE IF NOT EXISTS "notes" ( | |||||||
|                                        `isProtected`	INT NOT NULL DEFAULT 0, |                                        `isProtected`	INT NOT NULL DEFAULT 0, | ||||||
|                                        `type` TEXT NOT NULL DEFAULT 'text', |                                        `type` TEXT NOT NULL DEFAULT 'text', | ||||||
|                                        `mime` TEXT NOT NULL DEFAULT 'text/html', |                                        `mime` TEXT NOT NULL DEFAULT 'text/html', | ||||||
|  |                                        blobId TEXT DEFAULT NULL, | ||||||
|                                        `isDeleted`	INT NOT NULL DEFAULT 0, |                                        `isDeleted`	INT NOT NULL DEFAULT 0, | ||||||
|                                        `deleteId`   TEXT DEFAULT NULL, |                                        `deleteId`   TEXT DEFAULT NULL, | ||||||
|                                        `dateCreated`	TEXT NOT NULL, |                                        `dateCreated`	TEXT NOT NULL, | ||||||
|                                        `dateModified`	TEXT NOT NULL, |                                        `dateModified`	TEXT NOT NULL, | ||||||
|                                        `utcDateCreated`	TEXT NOT NULL, |                                        `utcDateCreated`	TEXT NOT NULL, | ||||||
|                                        `utcDateModified`	TEXT NOT NULL, blobId TEXT DEFAULT NULL, |                                        `utcDateModified`	TEXT NOT NULL, | ||||||
|                                        PRIMARY KEY(`noteId`)); |                                        PRIMARY KEY(`noteId`)); | ||||||
| CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId`	TEXT NOT NULL PRIMARY KEY, | CREATE TABLE IF NOT EXISTS "revisions" (`revisionId`	TEXT NOT NULL PRIMARY KEY, | ||||||
|                                              `noteId`	TEXT NOT NULL, |                                              `noteId`	TEXT NOT NULL, | ||||||
|                                              type TEXT DEFAULT '' NOT NULL, |                                              type TEXT DEFAULT '' NOT NULL, | ||||||
|                                              mime TEXT DEFAULT '' NOT NULL, |                                              mime TEXT DEFAULT '' NOT NULL, | ||||||
|                                              `title`	TEXT NOT NULL, |                                              `title`	TEXT NOT NULL, | ||||||
|                                              `isProtected`	INT NOT NULL DEFAULT 0, |                                              `isProtected`	INT NOT NULL DEFAULT 0, | ||||||
|  |                                             blobId TEXT DEFAULT NULL, | ||||||
|                                              `utcDateLastEdited` TEXT NOT NULL, |                                              `utcDateLastEdited` TEXT NOT NULL, | ||||||
|                                              `utcDateCreated` TEXT NOT NULL, |                                              `utcDateCreated` TEXT NOT NULL, | ||||||
|                                              `utcDateModified` TEXT NOT NULL, |                                              `utcDateModified` TEXT NOT NULL, | ||||||
|                                              `dateLastEdited` TEXT NOT NULL, |                                              `dateLastEdited` TEXT NOT NULL, | ||||||
|                                              `dateCreated` TEXT NOT NULL, blobId TEXT DEFAULT NULL); |                                              `dateCreated` TEXT NOT NULL); | ||||||
| CREATE TABLE IF NOT EXISTS "options" | CREATE TABLE IF NOT EXISTS "options" | ||||||
| ( | ( | ||||||
|     name TEXT not null PRIMARY KEY, |     name TEXT not null PRIMARY KEY, | ||||||
| @@ -84,11 +86,11 @@ CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`); | |||||||
| CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`); | CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`); | ||||||
| CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`); | CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`); | ||||||
| CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`); | CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`); | ||||||
| CREATE INDEX `IDX_note_revisions_noteId` ON `note_revisions` (`noteId`); | CREATE INDEX `IDX_revisions_noteId` ON `revisions` (`noteId`); | ||||||
| CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCreated`); | CREATE INDEX `IDX_revisions_utcDateCreated` ON `revisions` (`utcDateCreated`); | ||||||
| CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`); | CREATE INDEX `IDX_revisions_utcDateLastEdited` ON `revisions` (`utcDateLastEdited`); | ||||||
| CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`); | CREATE INDEX `IDX_revisions_dateCreated` ON `revisions` (`dateCreated`); | ||||||
| CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`); | CREATE INDEX `IDX_revisions_dateLastEdited` ON `revisions` (`dateLastEdited`); | ||||||
| CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`); | CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`); | ||||||
| CREATE INDEX IDX_attributes_name_value | CREATE INDEX IDX_attributes_name_value | ||||||
|     on attributes (name, value); |     on attributes (name, value); | ||||||
|   | |||||||
| @@ -144,12 +144,12 @@ class Becca { | |||||||
|         return this.childParentToBranch[`${childNoteId}-${parentNoteId}`]; |         return this.childParentToBranch[`${childNoteId}-${parentNoteId}`]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {BNoteRevision|null} */ |     /** @returns {BRevision|null} */ | ||||||
|     getNoteRevision(noteRevisionId) { |     getRevision(revisionId) { | ||||||
|         const row = sql.getRow("SELECT * FROM note_revisions WHERE noteRevisionId = ?", [noteRevisionId]); |         const row = sql.getRow("SELECT * FROM revisions WHERE revisionId = ?", [revisionId]); | ||||||
|  |  | ||||||
|         const BNoteRevision = require("./entities/bnote_revision"); // avoiding circular dependency problems |         const BRevision = require("./entities/brevision.js"); // avoiding circular dependency problems | ||||||
|         return row ? new BNoteRevision(row) : null; |         return row ? new BRevision(row) : null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {BAttachment|null} */ |     /** @returns {BAttachment|null} */ | ||||||
| @@ -213,8 +213,8 @@ class Becca { | |||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (entityName === 'note_revisions') { |         if (entityName === 'revisions') { | ||||||
|             return this.getNoteRevision(entityId); |             return this.getRevision(entityId); | ||||||
|         } else if (entityName === 'attachments') { |         } else if (entityName === 'attachments') { | ||||||
|             return this.getAttachment(entityId); |             return this.getAttachment(entityId); | ||||||
|         } else if (entityName === 'blobs') { |         } else if (entityName === 'blobs') { | ||||||
| @@ -243,12 +243,12 @@ class Becca { | |||||||
|         return rows.map(row => new BRecentNote(row)); |         return rows.map(row => new BRecentNote(row)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {BNoteRevision[]} */ |     /** @returns {BRevision[]} */ | ||||||
|     getNoteRevisionsFromQuery(query, params = []) { |     getRevisionsFromQuery(query, params = []) { | ||||||
|         const rows = sql.getRows(query, params); |         const rows = sql.getRows(query, params); | ||||||
|  |  | ||||||
|         const BNoteRevision = require("./entities/bnote_revision"); // avoiding circular dependency problems |         const BRevision = require("./entities/brevision.js"); // avoiding circular dependency problems | ||||||
|         return rows.map(row => new BNoteRevision(row)); |         return rows.map(row => new BRevision(row)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** Should be called when the set of all non-skeleton notes changes (added/removed) */ |     /** Should be called when the set of all non-skeleton notes changes (added/removed) */ | ||||||
|   | |||||||
| @@ -170,7 +170,7 @@ class AbstractBeccaEntity { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (sql.getValue("SELECT 1 FROM note_revisions WHERE blobId = ? LIMIT 1", [blobId])) { |         if (sql.getValue("SELECT 1 FROM revisions WHERE blobId = ? LIMIT 1", [blobId])) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ class BAttachment extends AbstractBeccaEntity { | |||||||
|  |  | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.attachmentId = row.attachmentId; |         this.attachmentId = row.attachmentId; | ||||||
|         /** @type {string} either noteId or noteRevisionId to which this attachment belongs */ |         /** @type {string} either noteId or revisionId to which this attachment belongs */ | ||||||
|         this.parentId = row.parentId; |         this.parentId = row.parentId; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.role = row.role; |         this.role = row.role; | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ const sql = require('../../services/sql'); | |||||||
| const utils = require('../../services/utils'); | const utils = require('../../services/utils'); | ||||||
| const dateUtils = require('../../services/date_utils'); | const dateUtils = require('../../services/date_utils'); | ||||||
| const AbstractBeccaEntity = require("./abstract_becca_entity"); | const AbstractBeccaEntity = require("./abstract_becca_entity"); | ||||||
| const BNoteRevision = require("./bnote_revision"); | const BRevision = require("./brevision.js"); | ||||||
| const BAttachment = require("./battachment"); | const BAttachment = require("./battachment"); | ||||||
| const TaskContext = require("../../services/task_context"); | const TaskContext = require("../../services/task_context"); | ||||||
| const dayjs = require("dayjs"); | const dayjs = require("dayjs"); | ||||||
| @@ -1102,10 +1102,10 @@ class BNote extends AbstractBeccaEntity { | |||||||
|         return minDistance; |         return minDistance; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {BNoteRevision[]} */ |     /** @returns {BRevision[]} */ | ||||||
|     getNoteRevisions() { |     getRevisions() { | ||||||
|         return sql.getRows("SELECT * FROM note_revisions WHERE noteId = ?", [this.noteId]) |         return sql.getRows("SELECT * FROM revisions WHERE noteId = ?", [this.noteId]) | ||||||
|             .map(row => new BNoteRevision(row)); |             .map(row => new BRevision(row)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {BAttachment[]} */ |     /** @returns {BAttachment[]} */ | ||||||
| @@ -1571,14 +1571,14 @@ class BNote extends AbstractBeccaEntity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @returns {BNoteRevision|null} |      * @returns {BRevision|null} | ||||||
|      */ |      */ | ||||||
|     saveNoteRevision() { |     saveRevision() { | ||||||
|         return sql.transactional(() => { |         return sql.transactional(() => { | ||||||
|             let noteContent = this.getContent(); |             let noteContent = this.getContent(); | ||||||
|             const contentMetadata = this.getContentMetadata(); |             const contentMetadata = this.getContentMetadata(); | ||||||
|  |  | ||||||
|             const noteRevision = new BNoteRevision({ |             const revision = new BRevision({ | ||||||
|                 noteId: this.noteId, |                 noteId: this.noteId, | ||||||
|                 // title and text should be decrypted now |                 // title and text should be decrypted now | ||||||
|                 title: this.title, |                 title: this.title, | ||||||
| @@ -1596,7 +1596,7 @@ class BNote extends AbstractBeccaEntity { | |||||||
|                 dateCreated: dateUtils.localNowDateTime() |                 dateCreated: dateUtils.localNowDateTime() | ||||||
|             }, true); |             }, true); | ||||||
|  |  | ||||||
|             noteRevision.save(); // to generate noteRevisionId which is then used to save attachments |             revision.save(); // to generate revisionId which is then used to save attachments | ||||||
|  |  | ||||||
|             for (const noteAttachment of this.getAttachments()) { |             for (const noteAttachment of this.getAttachments()) { | ||||||
|                 if (noteAttachment.utcDateScheduledForErasureSince) { |                 if (noteAttachment.utcDateScheduledForErasureSince) { | ||||||
| @@ -1604,16 +1604,16 @@ class BNote extends AbstractBeccaEntity { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 const revisionAttachment = noteAttachment.copy(); |                 const revisionAttachment = noteAttachment.copy(); | ||||||
|                 revisionAttachment.parentId = noteRevision.noteRevisionId; |                 revisionAttachment.parentId = revision.revisionId; | ||||||
|                 revisionAttachment.setContent(noteAttachment.getContent(), { forceSave: true }); |                 revisionAttachment.setContent(noteAttachment.getContent(), { forceSave: true }); | ||||||
|  |  | ||||||
|                 // content is rewritten to point to the revision attachments |                 // content is rewritten to point to the revision attachments | ||||||
|                 noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`, `attachments/${revisionAttachment.attachmentId}`); |                 noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`, `attachments/${revisionAttachment.attachmentId}`); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             noteRevision.setContent(noteContent, { forceSave: true }); |             revision.setContent(noteContent, { forceSave: true }); | ||||||
|  |  | ||||||
|             return noteRevision; |             return revision; | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,21 +9,21 @@ const sql = require("../../services/sql"); | |||||||
| const BAttachment = require("./battachment"); | const BAttachment = require("./battachment"); | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * NoteRevision represents a snapshot of note's title and content at some point in the past. |  * Revision represents a snapshot of note's title and content at some point in the past. | ||||||
|  * It's used for seamless note versioning. |  * It's used for seamless note versioning. | ||||||
|  * |  * | ||||||
|  * @extends AbstractBeccaEntity |  * @extends AbstractBeccaEntity | ||||||
|  */ |  */ | ||||||
| class BNoteRevision extends AbstractBeccaEntity { | class BRevision extends AbstractBeccaEntity { | ||||||
|     static get entityName() { return "note_revisions"; } |     static get entityName() { return "revisions"; } | ||||||
|     static get primaryKeyName() { return "noteRevisionId"; } |     static get primaryKeyName() { return "revisionId"; } | ||||||
|     static get hashedProperties() { return ["noteRevisionId", "noteId", "title", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; } |     static get hashedProperties() { return ["revisionId", "noteId", "title", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; } | ||||||
| 
 | 
 | ||||||
|     constructor(row, titleDecrypted = false) { |     constructor(row, titleDecrypted = false) { | ||||||
|         super(); |         super(); | ||||||
| 
 | 
 | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.noteRevisionId = row.noteRevisionId; |         this.revisionId = row.revisionId; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.noteId = row.noteId; |         this.noteId = row.noteId; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
| @@ -66,14 +66,14 @@ class BNoteRevision extends AbstractBeccaEntity { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     isContentAvailable() { |     isContentAvailable() { | ||||||
|         return !this.noteRevisionId // new note which was not encrypted yet
 |         return !this.revisionId // new note which was not encrypted yet
 | ||||||
|             || !this.isProtected |             || !this.isProtected | ||||||
|             || protectedSessionService.isProtectedSessionAvailable() |             || protectedSessionService.isProtectedSessionAvailable() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* |     /* | ||||||
|      * Note revision content has quite special handling - it's not a separate entity, but a lazily loaded |      * Note revision content has quite special handling - it's not a separate entity, but a lazily loaded | ||||||
|      * part of NoteRevision entity with its own sync. The reason behind this hybrid design is that |      * part of Revision entity with its own sync. The reason behind this hybrid design is that | ||||||
|      * content can be quite large, and it's not necessary to load it / fill memory for any note access even |      * content can be quite large, and it's not necessary to load it / fill memory for any note access even | ||||||
|      * if we don't need a content, especially for bulk operations like search. |      * if we don't need a content, especially for bulk operations like search. | ||||||
|      * |      * | ||||||
| @@ -88,7 +88,7 @@ class BNoteRevision extends AbstractBeccaEntity { | |||||||
|     /** |     /** | ||||||
|      * @param content |      * @param content | ||||||
|      * @param {object} [opts] |      * @param {object} [opts] | ||||||
|      * @param {object} [opts.forceSave=false] - will also save this BNoteRevision entity |      * @param {object} [opts.forceSave=false] - will also save this BRevision entity | ||||||
|      */ |      */ | ||||||
|     setContent(content, opts) { |     setContent(content, opts) { | ||||||
|         this._setContent(content, opts); |         this._setContent(content, opts); | ||||||
| @@ -100,7 +100,7 @@ class BNoteRevision extends AbstractBeccaEntity { | |||||||
|                 SELECT attachments.* |                 SELECT attachments.* | ||||||
|                 FROM attachments  |                 FROM attachments  | ||||||
|                 WHERE parentId = ?  |                 WHERE parentId = ?  | ||||||
|                   AND isDeleted = 0`, [this.noteRevisionId])
 |                   AND isDeleted = 0`, [this.revisionId])
 | ||||||
|             .map(row => new BAttachment(row)); |             .map(row => new BAttachment(row)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -112,7 +112,7 @@ class BNoteRevision extends AbstractBeccaEntity { | |||||||
| 
 | 
 | ||||||
|     getPojo() { |     getPojo() { | ||||||
|         return { |         return { | ||||||
|             noteRevisionId: this.noteRevisionId, |             revisionId: this.revisionId, | ||||||
|             noteId: this.noteId, |             noteId: this.noteId, | ||||||
|             type: this.type, |             type: this.type, | ||||||
|             mime: this.mime, |             mime: this.mime, | ||||||
| @@ -148,4 +148,4 @@ class BNoteRevision extends AbstractBeccaEntity { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = BNoteRevision; | module.exports = BRevision; | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| const BNote = require('./entities/bnote'); | const BNote = require('./entities/bnote'); | ||||||
| const BNoteRevision = require('./entities/bnote_revision'); | const BRevision = require('./entities/brevision.js'); | ||||||
| const BAttachment = require("./entities/battachment"); | const BAttachment = require("./entities/battachment"); | ||||||
| const BBranch = require('./entities/bbranch'); | const BBranch = require('./entities/bbranch'); | ||||||
| const BAttribute = require('./entities/battribute'); | const BAttribute = require('./entities/battribute'); | ||||||
| @@ -11,7 +11,7 @@ const ENTITY_NAME_TO_ENTITY = { | |||||||
|     "attributes": BAttribute, |     "attributes": BAttribute, | ||||||
|     "branches": BBranch, |     "branches": BBranch, | ||||||
|     "notes": BNote, |     "notes": BNote, | ||||||
|     "note_revisions": BNoteRevision, |     "revisions": BRevision, | ||||||
|     "attachments": BAttachment, |     "attachments": BAttachment, | ||||||
|     "recent_notes": BRecentNote, |     "recent_notes": BRecentNote, | ||||||
|     "etapi_tokens": BEtapiToken, |     "etapi_tokens": BEtapiToken, | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ const IGNORED_ATTR_NAMES = [ | |||||||
|     "keyboardshortcut", |     "keyboardshortcut", | ||||||
|     "noteinfowidgetdisabled", |     "noteinfowidgetdisabled", | ||||||
|     "linkmapwidgetdisabled", |     "linkmapwidgetdisabled", | ||||||
|     "noterevisionswidgetdisabled", |     "revisionswidgetdisabled", | ||||||
|     "whatlinksherewidgetdisabled", |     "whatlinksherewidgetdisabled", | ||||||
|     "similarnoteswidgetdisabled", |     "similarnoteswidgetdisabled", | ||||||
|     "disableinclusion", |     "disableinclusion", | ||||||
|   | |||||||
| @@ -308,7 +308,7 @@ paths: | |||||||
|           default: html |           default: html | ||||||
|     post: |     post: | ||||||
|       description: Create a note revision for the given note |       description: Create a note revision for the given note | ||||||
|       operationId: createNoteRevision |       operationId: createRevision | ||||||
|       responses: |       responses: | ||||||
|         '204': |         '204': | ||||||
|           description: revision has been created |           description: revision has been created | ||||||
|   | |||||||
| @@ -149,7 +149,7 @@ function register(router) { | |||||||
|     eu.route(router, 'post' ,'/etapi/notes/:noteId/note-revision', (req, res, next) => { |     eu.route(router, 'post' ,'/etapi/notes/:noteId/note-revision', (req, res, next) => { | ||||||
|         const note = eu.getAndCheckNote(req.params.noteId); |         const note = eu.getAndCheckNote(req.params.noteId); | ||||||
|  |  | ||||||
|         note.saveNoteRevision(); |         note.saveRevision(); | ||||||
|  |  | ||||||
|         return res.sendStatus(204); |         return res.sendStatus(204); | ||||||
|     }); |     }); | ||||||
|   | |||||||
| @@ -197,7 +197,7 @@ export default class Entrypoints extends Component { | |||||||
|         this.hideAllPopups(); |         this.hideAllPopups(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async forceSaveNoteRevisionCommand() { |     async forceSaveRevisionCommand() { | ||||||
|         const noteId = appContext.tabManager.getActiveContextNoteId(); |         const noteId = appContext.tabManager.getActiveContextNoteId(); | ||||||
|  |  | ||||||
|         await server.post(`notes/${noteId}/revision`); |         await server.post(`notes/${noteId}/revision`); | ||||||
|   | |||||||
| @@ -61,7 +61,7 @@ import ImportDialog from "../widgets/dialogs/import.js"; | |||||||
| import ExportDialog from "../widgets/dialogs/export.js"; | import ExportDialog from "../widgets/dialogs/export.js"; | ||||||
| import MarkdownImportDialog from "../widgets/dialogs/markdown_import.js"; | import MarkdownImportDialog from "../widgets/dialogs/markdown_import.js"; | ||||||
| import ProtectedSessionPasswordDialog from "../widgets/dialogs/protected_session_password.js"; | import ProtectedSessionPasswordDialog from "../widgets/dialogs/protected_session_password.js"; | ||||||
| import NoteRevisionsDialog from "../widgets/dialogs/note_revisions.js"; | import RevisionsDialog from "../widgets/dialogs/revisions.js"; | ||||||
| import DeleteNotesDialog from "../widgets/dialogs/delete_notes.js"; | import DeleteNotesDialog from "../widgets/dialogs/delete_notes.js"; | ||||||
| import InfoDialog from "../widgets/dialogs/info.js"; | import InfoDialog from "../widgets/dialogs/info.js"; | ||||||
| import ConfirmDialog from "../widgets/dialogs/confirm.js"; | import ConfirmDialog from "../widgets/dialogs/confirm.js"; | ||||||
| @@ -70,7 +70,7 @@ import FloatingButtons from "../widgets/floating_buttons/floating_buttons.js"; | |||||||
| import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons.js"; | import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons.js"; | ||||||
| import MermaidExportButton from "../widgets/floating_buttons/mermaid_export_button.js"; | import MermaidExportButton from "../widgets/floating_buttons/mermaid_export_button.js"; | ||||||
| import LauncherContainer from "../widgets/containers/launcher_container.js"; | import LauncherContainer from "../widgets/containers/launcher_container.js"; | ||||||
| import NoteRevisionsButton from "../widgets/buttons/note_revisions_button.js"; | import RevisionsButton from "../widgets/buttons/revisions_button.js"; | ||||||
| import CodeButtonsWidget from "../widgets/floating_buttons/code_buttons.js"; | import CodeButtonsWidget from "../widgets/floating_buttons/code_buttons.js"; | ||||||
| import ApiLogWidget from "../widgets/api_log.js"; | import ApiLogWidget from "../widgets/api_log.js"; | ||||||
| import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js"; | import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js"; | ||||||
| @@ -147,7 +147,7 @@ export default class DesktopLayout { | |||||||
|                                             .ribbon(new NoteMapRibbonWidget()) |                                             .ribbon(new NoteMapRibbonWidget()) | ||||||
|                                             .ribbon(new SimilarNotesWidget()) |                                             .ribbon(new SimilarNotesWidget()) | ||||||
|                                             .ribbon(new NoteInfoWidget()) |                                             .ribbon(new NoteInfoWidget()) | ||||||
|                                             .button(new NoteRevisionsButton()) |                                             .button(new RevisionsButton()) | ||||||
|                                             .button(new NoteActionsWidget()) |                                             .button(new NoteActionsWidget()) | ||||||
|                                     ) |                                     ) | ||||||
|                                     .child(new SharedInfoWidget()) |                                     .child(new SharedInfoWidget()) | ||||||
| @@ -204,7 +204,7 @@ export default class DesktopLayout { | |||||||
|             .child(new UploadAttachmentsDialog()) |             .child(new UploadAttachmentsDialog()) | ||||||
|             .child(new MarkdownImportDialog()) |             .child(new MarkdownImportDialog()) | ||||||
|             .child(new ProtectedSessionPasswordDialog()) |             .child(new ProtectedSessionPasswordDialog()) | ||||||
|             .child(new NoteRevisionsDialog()) |             .child(new RevisionsDialog()) | ||||||
|             .child(new DeleteNotesDialog()) |             .child(new DeleteNotesDialog()) | ||||||
|             .child(new InfoDialog()) |             .child(new InfoDialog()) | ||||||
|             .child(new ConfirmDialog()) |             .child(new ConfirmDialog()) | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ import server from "./server.js"; | |||||||
| import ws from "./ws.js"; | import ws from "./ws.js"; | ||||||
| import MoveNoteBulkAction from "../widgets/bulk_actions/note/move_note.js"; | import MoveNoteBulkAction from "../widgets/bulk_actions/note/move_note.js"; | ||||||
| import DeleteNoteBulkAction from "../widgets/bulk_actions/note/delete_note.js"; | import DeleteNoteBulkAction from "../widgets/bulk_actions/note/delete_note.js"; | ||||||
| import DeleteNoteRevisionsBulkAction from "../widgets/bulk_actions/note/delete_note_revisions.js"; | import DeleteRevisionsBulkAction from "../widgets/bulk_actions/note/delete_revisions.js"; | ||||||
| import DeleteLabelBulkAction from "../widgets/bulk_actions/label/delete_label.js"; | import DeleteLabelBulkAction from "../widgets/bulk_actions/label/delete_label.js"; | ||||||
| import DeleteRelationBulkAction from "../widgets/bulk_actions/relation/delete_relation.js"; | import DeleteRelationBulkAction from "../widgets/bulk_actions/relation/delete_relation.js"; | ||||||
| import RenameLabelBulkAction from "../widgets/bulk_actions/label/rename_label.js"; | import RenameLabelBulkAction from "../widgets/bulk_actions/label/rename_label.js"; | ||||||
| @@ -25,7 +25,7 @@ const ACTION_GROUPS = [ | |||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         title: 'Notes', |         title: 'Notes', | ||||||
|         actions: [RenameNoteBulkAction, MoveNoteBulkAction, DeleteNoteBulkAction, DeleteNoteRevisionsBulkAction], |         actions: [RenameNoteBulkAction, MoveNoteBulkAction, DeleteNoteBulkAction, DeleteRevisionsBulkAction], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         title: 'Other', |         title: 'Other', | ||||||
| @@ -37,7 +37,7 @@ const ACTION_CLASSES = [ | |||||||
|     RenameNoteBulkAction, |     RenameNoteBulkAction, | ||||||
|     MoveNoteBulkAction, |     MoveNoteBulkAction, | ||||||
|     DeleteNoteBulkAction, |     DeleteNoteBulkAction, | ||||||
|     DeleteNoteRevisionsBulkAction, |     DeleteRevisionsBulkAction, | ||||||
|     DeleteLabelBulkAction, |     DeleteLabelBulkAction, | ||||||
|     DeleteRelationBulkAction, |     DeleteRelationBulkAction, | ||||||
|     RenameLabelBulkAction, |     RenameLabelBulkAction, | ||||||
|   | |||||||
| @@ -30,8 +30,8 @@ async function processEntityChanges(entityChanges) { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 loadResults.addNoteContent(ec.noteIds, ec.componentId); |                 loadResults.addNoteContent(ec.noteIds, ec.componentId); | ||||||
|             } else if (ec.entityName === 'note_revisions') { |             } else if (ec.entityName === 'revisions') { | ||||||
|                 loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.componentId); |                 loadResults.addRevision(ec.entityId, ec.noteId, ec.componentId); | ||||||
|             } else if (ec.entityName === 'options') { |             } else if (ec.entityName === 'options') { | ||||||
|                 if (ec.entity.name === 'openNoteContexts') { |                 if (ec.entity.name === 'openNoteContexts') { | ||||||
|                     continue; // only noise |                     continue; // only noise | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ export default class LoadResults { | |||||||
|  |  | ||||||
|         this.noteReorderings = []; |         this.noteReorderings = []; | ||||||
|  |  | ||||||
|         this.noteRevisions = []; |         this.revisions = []; | ||||||
|  |  | ||||||
|         this.contentNoteIdToComponentId = []; |         this.contentNoteIdToComponentId = []; | ||||||
|  |  | ||||||
| @@ -75,12 +75,12 @@ export default class LoadResults { | |||||||
|             .filter(attr => !!attr); |             .filter(attr => !!attr); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     addNoteRevision(noteRevisionId, noteId, componentId) { |     addRevision(revisionId, noteId, componentId) { | ||||||
|         this.noteRevisions.push({noteRevisionId, noteId, componentId}); |         this.revisions.push({revisionId, noteId, componentId}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     hasNoteRevisionForNote(noteId) { |     hasRevisionForNote(noteId) { | ||||||
|         return !!this.noteRevisions.find(nr => nr.noteId === noteId); |         return !!this.revisions.find(nr => nr.noteId === noteId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     getNoteIds() { |     getNoteIds() { | ||||||
| @@ -140,7 +140,7 @@ export default class LoadResults { | |||||||
|             && this.branches.length === 0 |             && this.branches.length === 0 | ||||||
|             && this.attributes.length === 0 |             && this.attributes.length === 0 | ||||||
|             && this.noteReorderings.length === 0 |             && this.noteReorderings.length === 0 | ||||||
|             && this.noteRevisions.length === 0 |             && this.revisions.length === 0 | ||||||
|             && this.contentNoteIdToComponentId.length === 0 |             && this.contentNoteIdToComponentId.length === 0 | ||||||
|             && this.options.length === 0 |             && this.options.length === 0 | ||||||
|             && this.attachments.length === 0; |             && this.attachments.length === 0; | ||||||
|   | |||||||
| @@ -102,8 +102,8 @@ async function openNoteCustom(noteId) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| function downloadNoteRevision(noteId, noteRevisionId) { | function downloadRevision(noteId, revisionId) { | ||||||
|     const url = getUrlForDownload(`api/revisions/${noteRevisionId}/download`); |     const url = getUrlForDownload(`api/revisions/${revisionId}/download`); | ||||||
|  |  | ||||||
|     download(url); |     download(url); | ||||||
| } | } | ||||||
| @@ -164,7 +164,7 @@ function getHost() { | |||||||
| export default { | export default { | ||||||
|     download, |     download, | ||||||
|     downloadFileNote, |     downloadFileNote, | ||||||
|     downloadNoteRevision, |     downloadRevision, | ||||||
|     downloadAttachment, |     downloadAttachment, | ||||||
|     getUrlForDownload, |     getUrlForDownload, | ||||||
|     openNoteExternally, |     openNoteExternally, | ||||||
|   | |||||||
| @@ -19,8 +19,8 @@ const TPL = ` | |||||||
|     </td> |     </td> | ||||||
| </tr>`; | </tr>`; | ||||||
| 
 | 
 | ||||||
| export default class DeleteNoteRevisionsBulkAction extends AbstractBulkAction { | export default class DeleteRevisionsBulkAction extends AbstractBulkAction { | ||||||
|     static get actionName() { return "deleteNoteRevisions"; } |     static get actionName() { return "deleteRevisions"; } | ||||||
|     static get actionTitle() { return "Delete note revisions"; } |     static get actionTitle() { return "Delete note revisions"; } | ||||||
| 
 | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
| @@ -1,12 +1,12 @@ | |||||||
| import CommandButtonWidget from "./command_button.js"; | import CommandButtonWidget from "./command_button.js"; | ||||||
| 
 | 
 | ||||||
| export default class NoteRevisionsButton extends CommandButtonWidget { | export default class RevisionsButton extends CommandButtonWidget { | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
| 
 | 
 | ||||||
|         this.icon('bx-history') |         this.icon('bx-history') | ||||||
|             .title("Note Revisions") |             .title("Note Revisions") | ||||||
|             .command("showNoteRevisions") |             .command("showRevisions") | ||||||
|             .titlePlacement("bottom") |             .titlePlacement("bottom") | ||||||
|             .class("icon-action"); |             .class("icon-action"); | ||||||
|     } |     } | ||||||
| @@ -72,13 +72,13 @@ const TPL = ` | |||||||
|     </div> |     </div> | ||||||
| </div>`; | </div>`; | ||||||
| 
 | 
 | ||||||
| export default class NoteRevisionsDialog extends BasicWidget { | export default class RevisionsDialog extends BasicWidget { | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
| 
 | 
 | ||||||
|         this.revisionItems = []; |         this.revisionItems = []; | ||||||
|         this.note = null; |         this.note = null; | ||||||
|         this.noteRevisionId = null; |         this.revisionId = null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
| @@ -100,7 +100,7 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         this.$widget.on('shown.bs.modal', () => { |         this.$widget.on('shown.bs.modal', () => { | ||||||
|             this.$list.find(`[data-note-revision-id="${this.noteRevisionId}"]`) |             this.$list.find(`[data-note-revision-id="${this.revisionId}"]`) | ||||||
|                 .trigger('focus'); |                 .trigger('focus'); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @@ -130,13 +130,13 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async showNoteRevisionsEvent({noteId = appContext.tabManager.getActiveContextNoteId()}) { |     async showRevisionsEvent({noteId = appContext.tabManager.getActiveContextNoteId()}) { | ||||||
|         utils.openDialog(this.$widget); |         utils.openDialog(this.$widget); | ||||||
| 
 | 
 | ||||||
|         await this.loadNoteRevisions(noteId); |         await this.loadRevisions(noteId); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async loadNoteRevisions(noteId) { |     async loadRevisions(noteId) { | ||||||
|         this.$list.empty(); |         this.$list.empty(); | ||||||
|         this.$content.empty(); |         this.$content.empty(); | ||||||
|         this.$titleButtons.empty(); |         this.$titleButtons.empty(); | ||||||
| @@ -148,7 +148,7 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|             this.$list.append( |             this.$list.append( | ||||||
|                 $('<a class="dropdown-item" tabindex="0">') |                 $('<a class="dropdown-item" tabindex="0">') | ||||||
|                     .text(`${item.dateLastEdited.substr(0, 16)} (${item.contentLength} bytes)`) |                     .text(`${item.dateLastEdited.substr(0, 16)} (${item.contentLength} bytes)`) | ||||||
|                     .attr('data-note-revision-id', item.noteRevisionId) |                     .attr('data-note-revision-id', item.revisionId) | ||||||
|                     .attr('title', `This revision was last edited on ${item.dateLastEdited}`) |                     .attr('title', `This revision was last edited on ${item.dateLastEdited}`) | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
| @@ -156,21 +156,21 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|         this.$listDropdown.dropdown('show'); |         this.$listDropdown.dropdown('show'); | ||||||
| 
 | 
 | ||||||
|         if (this.revisionItems.length > 0) { |         if (this.revisionItems.length > 0) { | ||||||
|             if (!this.noteRevisionId) { |             if (!this.revisionId) { | ||||||
|                 this.noteRevisionId = this.revisionItems[0].noteRevisionId; |                 this.revisionId = this.revisionItems[0].revisionId; | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             this.$title.text("No revisions for this note yet..."); |             this.$title.text("No revisions for this note yet..."); | ||||||
|             this.noteRevisionId = null; |             this.revisionId = null; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.$eraseAllRevisionsButton.toggle(this.revisionItems.length > 0); |         this.$eraseAllRevisionsButton.toggle(this.revisionItems.length > 0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async setContentPane() { |     async setContentPane() { | ||||||
|         const noteRevisionId = this.$list.find(".active").attr('data-note-revision-id'); |         const revisionId = this.$list.find(".active").attr('data-note-revision-id'); | ||||||
| 
 | 
 | ||||||
|         const revisionItem = this.revisionItems.find(r => r.noteRevisionId === noteRevisionId); |         const revisionItem = this.revisionItems.find(r => r.revisionId === revisionId); | ||||||
| 
 | 
 | ||||||
|         this.$title.html(revisionItem.title); |         this.$title.html(revisionItem.title); | ||||||
| 
 | 
 | ||||||
| @@ -188,7 +188,7 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|             const text = 'Do you want to restore this revision? This will overwrite current title/content of the note with this revision.'; |             const text = 'Do you want to restore this revision? This will overwrite current title/content of the note with this revision.'; | ||||||
| 
 | 
 | ||||||
|             if (await dialogService.confirm(text)) { |             if (await dialogService.confirm(text)) { | ||||||
|                 await server.post(`revisions/${revisionItem.noteRevisionId}/restore`); |                 await server.post(`revisions/${revisionItem.revisionId}/restore`); | ||||||
| 
 | 
 | ||||||
|                 this.$widget.modal('hide'); |                 this.$widget.modal('hide'); | ||||||
| 
 | 
 | ||||||
| @@ -202,9 +202,9 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|             const text = 'Do you want to delete this revision? This action will delete revision title and content, but still preserve revision metadata.'; |             const text = 'Do you want to delete this revision? This action will delete revision title and content, but still preserve revision metadata.'; | ||||||
| 
 | 
 | ||||||
|             if (await dialogService.confirm(text)) { |             if (await dialogService.confirm(text)) { | ||||||
|                 await server.remove(`revisions/${revisionItem.noteRevisionId}`); |                 await server.remove(`revisions/${revisionItem.revisionId}`); | ||||||
| 
 | 
 | ||||||
|                 this.loadNoteRevisions(revisionItem.noteId); |                 this.loadRevisions(revisionItem.noteId); | ||||||
| 
 | 
 | ||||||
|                 toastService.showMessage('Note revision has been deleted.'); |                 toastService.showMessage('Note revision has been deleted.'); | ||||||
|             } |             } | ||||||
| @@ -222,7 +222,7 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
| 
 | 
 | ||||||
|         const $downloadButton = $('<button class="btn btn-sm btn-primary" type="button">Download</button>'); |         const $downloadButton = $('<button class="btn btn-sm btn-primary" type="button">Download</button>'); | ||||||
| 
 | 
 | ||||||
|         $downloadButton.on('click', () => openService.downloadNoteRevision(revisionItem.noteId, revisionItem.noteRevisionId)); |         $downloadButton.on('click', () => openService.downloadRevision(revisionItem.noteId, revisionItem.revisionId)); | ||||||
| 
 | 
 | ||||||
|         if (!revisionItem.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) { |         if (!revisionItem.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) { | ||||||
|             this.$titleButtons.append($downloadButton); |             this.$titleButtons.append($downloadButton); | ||||||
| @@ -232,10 +232,10 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|     async renderContent(revisionItem) { |     async renderContent(revisionItem) { | ||||||
|         this.$content.empty(); |         this.$content.empty(); | ||||||
| 
 | 
 | ||||||
|         const fullNoteRevision = await server.get(`revisions/${revisionItem.noteRevisionId}`); |         const fullRevision = await server.get(`revisions/${revisionItem.revisionId}`); | ||||||
| 
 | 
 | ||||||
|         if (revisionItem.type === 'text') { |         if (revisionItem.type === 'text') { | ||||||
|             this.$content.html(fullNoteRevision.content); |             this.$content.html(fullRevision.content); | ||||||
| 
 | 
 | ||||||
|             if (this.$content.find('span.math-tex').length > 0) { |             if (this.$content.find('span.math-tex').length > 0) { | ||||||
|                 await libraryLoader.requireLibrary(libraryLoader.KATEX); |                 await libraryLoader.requireLibrary(libraryLoader.KATEX); | ||||||
| @@ -243,12 +243,12 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|                 renderMathInElement(this.$content[0], {trust: true}); |                 renderMathInElement(this.$content[0], {trust: true}); | ||||||
|             } |             } | ||||||
|         } else if (revisionItem.type === 'code' || revisionItem.type === 'mermaid') { |         } else if (revisionItem.type === 'code' || revisionItem.type === 'mermaid') { | ||||||
|             this.$content.html($("<pre>").text(fullNoteRevision.content)); |             this.$content.html($("<pre>").text(fullRevision.content)); | ||||||
|         } else if (revisionItem.type === 'image') { |         } else if (revisionItem.type === 'image') { | ||||||
|             this.$content.html($("<img>") |             this.$content.html($("<img>") | ||||||
|                 // reason why we put this inline as base64 is that we do not want to let user copy this
 |                 // reason why we put this inline as base64 is that we do not want to let user copy this
 | ||||||
|                 // as a URL to be used in a note. Instead, if they copy and paste it into a note, it will be an uploaded as a new note
 |                 // as a URL to be used in a note. Instead, if they copy and paste it into a note, it will be an uploaded as a new note
 | ||||||
|                 .attr("src", `data:${fullNoteRevision.mime};base64,${fullNoteRevision.content}`) |                 .attr("src", `data:${fullRevision.mime};base64,${fullRevision.content}`) | ||||||
|                 .css("max-width", "100%") |                 .css("max-width", "100%") | ||||||
|                 .css("max-height", "100%")); |                 .css("max-height", "100%")); | ||||||
|         } else if (revisionItem.type === 'file') { |         } else if (revisionItem.type === 'file') { | ||||||
| @@ -262,12 +262,12 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|                     $("<td>").text(`${revisionItem.contentLength} bytes`) |                     $("<td>").text(`${revisionItem.contentLength} bytes`) | ||||||
|                 )); |                 )); | ||||||
| 
 | 
 | ||||||
|             if (fullNoteRevision.content) { |             if (fullRevision.content) { | ||||||
|                 $table.append($("<tr>").append( |                 $table.append($("<tr>").append( | ||||||
|                     $('<td colspan="2">').append( |                     $('<td colspan="2">').append( | ||||||
|                         $('<div style="font-weight: bold;">').text("Preview:"), |                         $('<div style="font-weight: bold;">').text("Preview:"), | ||||||
|                         $('<pre class="file-preview-content"></pre>') |                         $('<pre class="file-preview-content"></pre>') | ||||||
|                             .text(fullNoteRevision.content) |                             .text(fullRevision.content) | ||||||
|                     ) |                     ) | ||||||
|                 )); |                 )); | ||||||
|             } |             } | ||||||
| @@ -278,7 +278,7 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|              * FIXME: We load a font called Virgil.wof2, which originates from excalidraw.com |              * FIXME: We load a font called Virgil.wof2, which originates from excalidraw.com | ||||||
|              *        REMOVE external dependency!!!! This is defined in the svg in defs.style |              *        REMOVE external dependency!!!! This is defined in the svg in defs.style | ||||||
|              */ |              */ | ||||||
|             const content = fullNoteRevision.content; |             const content = fullRevision.content; | ||||||
| 
 | 
 | ||||||
|             try { |             try { | ||||||
|                 const data = JSON.parse(content) |                 const data = JSON.parse(content) | ||||||
| @@ -291,7 +291,7 @@ export default class NoteRevisionsDialog extends BasicWidget { | |||||||
|                 const $svgHtml = $(svg).css({maxWidth: "100%", height: "auto"}); |                 const $svgHtml = $(svg).css({maxWidth: "100%", height: "auto"}); | ||||||
|                 this.$content.html($('<div>').append($svgHtml)); |                 this.$content.html($('<div>').append($svgHtml)); | ||||||
|             } catch (err) { |             } catch (err) { | ||||||
|                 console.error("error parsing fullNoteRevision.content as JSON", fullNoteRevision.content, err); |                 console.error("error parsing fullRevision.content as JSON", fullRevision.content, err); | ||||||
|                 this.$content.html($("<div>").text("Error parsing content. Please check console.error() for more details.")); |                 this.$content.html($("<div>").text("Error parsing content. Please check console.error() for more details.")); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
| @@ -21,7 +21,7 @@ import SyncOptions from "./options/sync.js"; | |||||||
| import SearchEngineOptions from "./options/other/search_engine.js"; | import SearchEngineOptions from "./options/other/search_engine.js"; | ||||||
| import TrayOptions from "./options/other/tray.js"; | import TrayOptions from "./options/other/tray.js"; | ||||||
| import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js"; | import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js"; | ||||||
| import NoteRevisionsSnapshotIntervalOptions from "./options/other/note_revisions_snapshot_interval.js"; | import RevisionsSnapshotIntervalOptions from "./options/other/revisions_snapshot_interval.js"; | ||||||
| import NetworkConnectionsOptions from "./options/other/network_connections.js"; | import NetworkConnectionsOptions from "./options/other/network_connections.js"; | ||||||
| import AdvancedSyncOptions from "./options/advanced/sync.js"; | import AdvancedSyncOptions from "./options/advanced/sync.js"; | ||||||
| import DatabaseIntegrityCheckOptions from "./options/advanced/database_integrity_check.js"; | import DatabaseIntegrityCheckOptions from "./options/advanced/database_integrity_check.js"; | ||||||
| @@ -81,7 +81,7 @@ const CONTENT_WIDGETS = { | |||||||
|         TrayOptions, |         TrayOptions, | ||||||
|         NoteErasureTimeoutOptions, |         NoteErasureTimeoutOptions, | ||||||
|         AttachmentErasureTimeoutOptions, |         AttachmentErasureTimeoutOptions, | ||||||
|         NoteRevisionsSnapshotIntervalOptions, |         RevisionsSnapshotIntervalOptions, | ||||||
|         NetworkConnectionsOptions |         NetworkConnectionsOptions | ||||||
|     ], |     ], | ||||||
|     _optionsAdvanced: [ |     _optionsAdvanced: [ | ||||||
|   | |||||||
| @@ -12,15 +12,15 @@ const TPL = ` | |||||||
|     </div> |     </div> | ||||||
| </div>`; | </div>`; | ||||||
| 
 | 
 | ||||||
| export default class NoteRevisionsSnapshotIntervalOptions extends OptionsWidget { | export default class RevisionsSnapshotIntervalOptions extends OptionsWidget { | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.$noteRevisionsTimeInterval = this.$widget.find(".note-revision-snapshot-time-interval-in-seconds"); |         this.$revisionsTimeInterval = this.$widget.find(".note-revision-snapshot-time-interval-in-seconds"); | ||||||
|         this.$noteRevisionsTimeInterval.on('change', () => |         this.$revisionsTimeInterval.on('change', () => | ||||||
|             this.updateOption('noteRevisionSnapshotTimeInterval', this.$noteRevisionsTimeInterval.val())); |             this.updateOption('revisionSnapshotTimeInterval', this.$revisionsTimeInterval.val())); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async optionsLoaded(options) { |     async optionsLoaded(options) { | ||||||
|         this.$noteRevisionsTimeInterval.val(options.noteRevisionSnapshotTimeInterval); |         this.$revisionsTimeInterval.val(options.revisionSnapshotTimeInterval); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -16,7 +16,7 @@ function updateFile(req) { | |||||||
|     const note = becca.getNoteOrThrow(req.params.noteId); |     const note = becca.getNoteOrThrow(req.params.noteId); | ||||||
|  |  | ||||||
|     const file = req.file; |     const file = req.file; | ||||||
|     note.saveNoteRevision(); |     note.saveRevision(); | ||||||
|  |  | ||||||
|     note.mime = file.mimetype.toLowerCase(); |     note.mime = file.mimetype.toLowerCase(); | ||||||
|     note.save(); |     note.save(); | ||||||
| @@ -35,7 +35,7 @@ function updateFile(req) { | |||||||
| function updateAttachment(req) { | function updateAttachment(req) { | ||||||
|     const attachment = becca.getAttachmentOrThrow(req.params.attachmentId); |     const attachment = becca.getAttachmentOrThrow(req.params.attachmentId); | ||||||
|     const file = req.file; |     const file = req.file; | ||||||
|     attachment.getNote().saveNoteRevision(); |     attachment.getNote().saveRevision(); | ||||||
|  |  | ||||||
|     attachment.mime = file.mimetype.toLowerCase(); |     attachment.mime = file.mimetype.toLowerCase(); | ||||||
|     attachment.setContent(file.buffer, {forceSave: true}); |     attachment.setContent(file.buffer, {forceSave: true}); | ||||||
| @@ -186,7 +186,7 @@ function uploadModifiedFileToNote(req) { | |||||||
|  |  | ||||||
|     log.info(`Updating note '${noteId}' with content from '${filePath}'`); |     log.info(`Updating note '${noteId}' with content from '${filePath}'`); | ||||||
|  |  | ||||||
|     note.saveNoteRevision(); |     note.saveRevision(); | ||||||
|  |  | ||||||
|     const fileContent = fs.readFileSync(filePath); |     const fileContent = fs.readFileSync(filePath); | ||||||
|  |  | ||||||
| @@ -205,7 +205,7 @@ function uploadModifiedFileToAttachment(req) { | |||||||
|  |  | ||||||
|     log.info(`Updating attachment '${attachmentId}' with content from '${filePath}'`); |     log.info(`Updating attachment '${attachmentId}' with content from '${filePath}'`); | ||||||
|  |  | ||||||
|     attachment.getNote().saveNoteRevision(); |     attachment.getNote().saveRevision(); | ||||||
|  |  | ||||||
|     const fileContent = fs.readFileSync(filePath); |     const fileContent = fs.readFileSync(filePath); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -131,7 +131,7 @@ function changeTitle(req) { | |||||||
|     const noteTitleChanged = note.title !== title; |     const noteTitleChanged = note.title !== title; | ||||||
|  |  | ||||||
|     if (noteTitleChanged) { |     if (noteTitleChanged) { | ||||||
|         noteService.saveNoteRevisionIfNeeded(note); |         noteService.saveRevisionIfNeeded(note); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     note.title = title; |     note.title = title; | ||||||
| @@ -216,7 +216,7 @@ function getDeleteNotesPreview(req) { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| function forceSaveNoteRevision(req) { | function forceSaveRevision(req) { | ||||||
|     const {noteId} = req.params; |     const {noteId} = req.params; | ||||||
|     const note = becca.getNoteOrThrow(noteId); |     const note = becca.getNoteOrThrow(noteId); | ||||||
|  |  | ||||||
| @@ -224,7 +224,7 @@ function forceSaveNoteRevision(req) { | |||||||
|         throw new ValidationError(`Note revision of a protected note cannot be created outside of a protected session.`); |         throw new ValidationError(`Note revision of a protected note cannot be created outside of a protected session.`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     note.saveNoteRevision(); |     note.saveRevision(); | ||||||
| } | } | ||||||
|  |  | ||||||
| function convertNoteToAttachment(req) { | function convertNoteToAttachment(req) { | ||||||
| @@ -252,6 +252,6 @@ module.exports = { | |||||||
|     eraseDeletedNotesNow, |     eraseDeletedNotesNow, | ||||||
|     eraseUnusedAttachmentsNow, |     eraseUnusedAttachmentsNow, | ||||||
|     getDeleteNotesPreview, |     getDeleteNotesPreview, | ||||||
|     forceSaveNoteRevision, |     forceSaveRevision, | ||||||
|     convertNoteToAttachment |     convertNoteToAttachment | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ const ValidationError = require("../../errors/validation_error"); | |||||||
| const ALLOWED_OPTIONS = new Set([ | const ALLOWED_OPTIONS = new Set([ | ||||||
|     'eraseEntitiesAfterTimeInSeconds', |     'eraseEntitiesAfterTimeInSeconds', | ||||||
|     'protectedSessionTimeout', |     'protectedSessionTimeout', | ||||||
|     'noteRevisionSnapshotTimeInterval', |     'revisionSnapshotTimeInterval', | ||||||
|     'zoomFactor', |     'zoomFactor', | ||||||
|     'theme', |     'theme', | ||||||
|     'syncServerHost', |     'syncServerHost', | ||||||
| @@ -28,7 +28,7 @@ const ALLOWED_OPTIONS = new Set([ | |||||||
|     'noteInfoWidget', |     'noteInfoWidget', | ||||||
|     'attributesWidget', |     'attributesWidget', | ||||||
|     'linkMapWidget', |     'linkMapWidget', | ||||||
|     'noteRevisionsWidget', |     'revisionsWidget', | ||||||
|     'whatLinksHereWidget', |     'whatLinksHereWidget', | ||||||
|     'similarNotesWidget', |     'similarNotesWidget', | ||||||
|     'editedNotesWidget', |     'editedNotesWidget', | ||||||
|   | |||||||
| @@ -10,25 +10,25 @@ function getRecentChanges(req) { | |||||||
|  |  | ||||||
|     let recentChanges = []; |     let recentChanges = []; | ||||||
|  |  | ||||||
|     const noteRevisionRows = sql.getRows(` |     const revisionRows = sql.getRows(` | ||||||
|         SELECT  |         SELECT  | ||||||
|             notes.noteId, |             notes.noteId, | ||||||
|             notes.isDeleted AS current_isDeleted, |             notes.isDeleted AS current_isDeleted, | ||||||
|             notes.deleteId AS current_deleteId, |             notes.deleteId AS current_deleteId, | ||||||
|             notes.title AS current_title, |             notes.title AS current_title, | ||||||
|             notes.isProtected AS current_isProtected, |             notes.isProtected AS current_isProtected, | ||||||
|             note_revisions.title, |             revisions.title, | ||||||
|             note_revisions.utcDateCreated AS utcDate, |             revisions.utcDateCreated AS utcDate, | ||||||
|             note_revisions.dateCreated AS date |             revisions.dateCreated AS date | ||||||
|         FROM  |         FROM  | ||||||
|             note_revisions |             revisions | ||||||
|             JOIN notes USING(noteId)`); |             JOIN notes USING(noteId)`); | ||||||
|  |  | ||||||
|     for (const noteRevisionRow of noteRevisionRows) { |     for (const revisionRow of revisionRows) { | ||||||
|         const note = becca.getNote(noteRevisionRow.noteId); |         const note = becca.getNote(revisionRow.noteId); | ||||||
|  |  | ||||||
|         if (note?.hasAncestor(ancestorNoteId)) { |         if (note?.hasAncestor(ancestorNoteId)) { | ||||||
|             recentChanges.push(noteRevisionRow); |             recentChanges.push(revisionRow); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| const beccaService = require('../../becca/becca_service'); | const beccaService = require('../../becca/becca_service'); | ||||||
| const noteRevisionService = require('../../services/note_revisions'); | const revisionService = require('../../services/revisions.js'); | ||||||
| const utils = require('../../services/utils'); | const utils = require('../../services/utils'); | ||||||
| const sql = require('../../services/sql'); | const sql = require('../../services/sql'); | ||||||
| const cls = require('../../services/cls'); | const cls = require('../../services/cls'); | ||||||
| @@ -9,50 +9,50 @@ const path = require('path'); | |||||||
| const becca = require("../../becca/becca"); | const becca = require("../../becca/becca"); | ||||||
| const blobService = require("../../services/blob.js"); | const blobService = require("../../services/blob.js"); | ||||||
| 
 | 
 | ||||||
| function getNoteRevisionBlob(req) { | function getRevisionBlob(req) { | ||||||
|     const preview = req.query.preview === 'true'; |     const preview = req.query.preview === 'true'; | ||||||
| 
 | 
 | ||||||
|     return blobService.getBlobPojo('note_revisions', req.params.noteRevisionId, { preview }); |     return blobService.getBlobPojo('revisions', req.params.revisionId, { preview }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getNoteRevisions(req) { | function getRevisions(req) { | ||||||
|     return becca.getNoteRevisionsFromQuery(` |     return becca.getRevisionsFromQuery(` | ||||||
|         SELECT note_revisions.*, |         SELECT revisions.*, | ||||||
|                LENGTH(blobs.content) AS contentLength |                LENGTH(blobs.content) AS contentLength | ||||||
|         FROM note_revisions |         FROM revisions | ||||||
|         JOIN blobs ON note_revisions.blobId = blobs.blobId  |         JOIN blobs ON revisions.blobId = blobs.blobId  | ||||||
|         WHERE noteId = ? |         WHERE noteId = ? | ||||||
|         ORDER BY utcDateCreated DESC`, [req.params.noteId]);
 |         ORDER BY utcDateCreated DESC`, [req.params.noteId]);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getNoteRevision(req) { | function getRevision(req) { | ||||||
|     const noteRevision = becca.getNoteRevision(req.params.noteRevisionId); |     const revision = becca.getRevision(req.params.revisionId); | ||||||
| 
 | 
 | ||||||
|     if (noteRevision.type === 'file') { |     if (revision.type === 'file') { | ||||||
|         if (noteRevision.hasStringContent()) { |         if (revision.hasStringContent()) { | ||||||
|             noteRevision.content = noteRevision.getContent().substr(0, 10000); |             revision.content = revision.getContent().substr(0, 10000); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         noteRevision.content = noteRevision.getContent(); |         revision.content = revision.getContent(); | ||||||
| 
 | 
 | ||||||
|         if (noteRevision.content && noteRevision.type === 'image') { |         if (revision.content && revision.type === 'image') { | ||||||
|             noteRevision.content = noteRevision.content.toString('base64'); |             revision.content = revision.content.toString('base64'); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return noteRevision; |     return revision; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @param {BNoteRevision} noteRevision |  * @param {BRevision} revision | ||||||
|  * @returns {string} |  * @returns {string} | ||||||
|  */ |  */ | ||||||
| function getRevisionFilename(noteRevision) { | function getRevisionFilename(revision) { | ||||||
|     let filename = utils.formatDownloadTitle(noteRevision.title, noteRevision.type, noteRevision.mime); |     let filename = utils.formatDownloadTitle(revision.title, revision.type, revision.mime); | ||||||
| 
 | 
 | ||||||
|     const extension = path.extname(filename); |     const extension = path.extname(filename); | ||||||
|     const date = noteRevision.dateCreated |     const date = revision.dateCreated | ||||||
|         .substr(0, 19) |         .substr(0, 19) | ||||||
|         .replace(' ', '_') |         .replace(' ', '_') | ||||||
|         .replace(/[^0-9_]/g, ''); |         .replace(/[^0-9_]/g, ''); | ||||||
| @@ -67,50 +67,50 @@ function getRevisionFilename(noteRevision) { | |||||||
|     return filename; |     return filename; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function downloadNoteRevision(req, res) { | function downloadRevision(req, res) { | ||||||
|     const noteRevision = becca.getNoteRevision(req.params.noteRevisionId); |     const revision = becca.getRevision(req.params.revisionId); | ||||||
| 
 | 
 | ||||||
|     if (!noteRevision.isContentAvailable()) { |     if (!revision.isContentAvailable()) { | ||||||
|         return res.setHeader("Content-Type", "text/plain") |         return res.setHeader("Content-Type", "text/plain") | ||||||
|             .status(401) |             .status(401) | ||||||
|             .send("Protected session not available"); |             .send("Protected session not available"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const filename = getRevisionFilename(noteRevision); |     const filename = getRevisionFilename(revision); | ||||||
| 
 | 
 | ||||||
|     res.setHeader('Content-Disposition', utils.getContentDisposition(filename)); |     res.setHeader('Content-Disposition', utils.getContentDisposition(filename)); | ||||||
|     res.setHeader('Content-Type', noteRevision.mime); |     res.setHeader('Content-Type', revision.mime); | ||||||
| 
 | 
 | ||||||
|     res.send(noteRevision.getContent()); |     res.send(revision.getContent()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function eraseAllNoteRevisions(req) { | function eraseAllRevisions(req) { | ||||||
|     const noteRevisionIdsToErase = sql.getColumn('SELECT noteRevisionId FROM note_revisions WHERE noteId = ?', |     const revisionIdsToErase = sql.getColumn('SELECT revisionId FROM revisions WHERE noteId = ?', | ||||||
|         [req.params.noteId]); |         [req.params.noteId]); | ||||||
| 
 | 
 | ||||||
|     noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase); |     revisionService.eraseRevisions(revisionIdsToErase); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function eraseNoteRevision(req) { | function eraseRevision(req) { | ||||||
|     noteRevisionService.eraseNoteRevisions([req.params.noteRevisionId]); |     revisionService.eraseRevisions([req.params.revisionId]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function restoreNoteRevision(req) { | function restoreRevision(req) { | ||||||
|     const noteRevision = becca.getNoteRevision(req.params.noteRevisionId); |     const revision = becca.getRevision(req.params.revisionId); | ||||||
| 
 | 
 | ||||||
|     if (noteRevision) { |     if (revision) { | ||||||
|         const note = noteRevision.getNote(); |         const note = revision.getNote(); | ||||||
| 
 | 
 | ||||||
|         sql.transactional(() => { |         sql.transactional(() => { | ||||||
|             note.saveNoteRevision(); |             note.saveRevision(); | ||||||
| 
 | 
 | ||||||
|             for (const oldNoteAttachment of note.getAttachments()) { |             for (const oldNoteAttachment of note.getAttachments()) { | ||||||
|                 oldNoteAttachment.markAsDeleted(); |                 oldNoteAttachment.markAsDeleted(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             let revisionContent = noteRevision.getContent(); |             let revisionContent = revision.getContent(); | ||||||
| 
 | 
 | ||||||
|             for (const revisionAttachment of noteRevision.getAttachments()) { |             for (const revisionAttachment of revision.getAttachments()) { | ||||||
|                 const noteAttachment = revisionAttachment.copy(); |                 const noteAttachment = revisionAttachment.copy(); | ||||||
|                 noteAttachment.parentId = note.noteId; |                 noteAttachment.parentId = note.noteId; | ||||||
|                 noteAttachment.setContent(revisionAttachment.getContent(), { forceSave: true }); |                 noteAttachment.setContent(revisionAttachment.getContent(), { forceSave: true }); | ||||||
| @@ -119,7 +119,7 @@ function restoreNoteRevision(req) { | |||||||
|                 revisionContent = revisionContent.replaceAll(`attachments/${revisionAttachment.attachmentId}`, `attachments/${noteAttachment.attachmentId}`); |                 revisionContent = revisionContent.replaceAll(`attachments/${revisionAttachment.attachmentId}`, `attachments/${noteAttachment.attachmentId}`); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             note.title = noteRevision.title; |             note.title = revision.title; | ||||||
|             note.setContent(revisionContent, { forceSave: true }); |             note.setContent(revisionContent, { forceSave: true }); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| @@ -134,8 +134,8 @@ function getEditedNotesOnDate(req) { | |||||||
|                 WHERE notes.dateCreated LIKE :date |                 WHERE notes.dateCreated LIKE :date | ||||||
|                    OR notes.dateModified LIKE :date |                    OR notes.dateModified LIKE :date | ||||||
|             UNION ALL |             UNION ALL | ||||||
|                 SELECT noteId FROM note_revisions |                 SELECT noteId FROM revisions | ||||||
|                 WHERE note_revisions.dateLastEdited LIKE :date |                 WHERE revisions.dateLastEdited LIKE :date | ||||||
|         ) |         ) | ||||||
|         ORDER BY isDeleted |         ORDER BY isDeleted | ||||||
|         LIMIT 50`, {date: `${req.params.date}%`});
 |         LIMIT 50`, {date: `${req.params.date}%`});
 | ||||||
| @@ -186,12 +186,12 @@ function getNotePathData(note) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|     getNoteRevisionBlob, |     getRevisionBlob, | ||||||
|     getNoteRevisions, |     getRevisions, | ||||||
|     getNoteRevision, |     getRevision, | ||||||
|     downloadNoteRevision, |     downloadRevision, | ||||||
|     getEditedNotesOnDate, |     getEditedNotesOnDate, | ||||||
|     eraseAllNoteRevisions, |     eraseAllRevisions, | ||||||
|     eraseNoteRevision, |     eraseRevision, | ||||||
|     restoreNoteRevision |     restoreRevision | ||||||
| }; | }; | ||||||
| @@ -9,10 +9,10 @@ function getNoteSize(req) { | |||||||
|         FROM blobs |         FROM blobs | ||||||
|         LEFT JOIN notes ON notes.blobId = blobs.blobId AND notes.noteId = ? AND notes.isDeleted = 0 |         LEFT JOIN notes ON notes.blobId = blobs.blobId AND notes.noteId = ? AND notes.isDeleted = 0 | ||||||
|         LEFT JOIN attachments ON attachments.blobId = blobs.blobId AND attachments.parentId = ? AND attachments.isDeleted = 0 |         LEFT JOIN attachments ON attachments.blobId = blobs.blobId AND attachments.parentId = ? AND attachments.isDeleted = 0 | ||||||
|         LEFT JOIN note_revisions ON note_revisions.blobId = blobs.blobId AND note_revisions.noteId = ? |         LEFT JOIN revisions ON revisions.blobId = blobs.blobId AND revisions.noteId = ? | ||||||
|         WHERE notes.noteId IS NOT NULL  |         WHERE notes.noteId IS NOT NULL  | ||||||
|            OR attachments.attachmentId IS NOT NULL |            OR attachments.attachmentId IS NOT NULL | ||||||
|            OR note_revisions.noteRevisionId IS NOT NULL`, [noteId, noteId, noteId]); |            OR revisions.revisionId IS NOT NULL`, [noteId, noteId, noteId]); | ||||||
|  |  | ||||||
|     const noteSize = Object.values(blobSizes).reduce((acc, blobSize) => acc + blobSize, 0); |     const noteSize = Object.values(blobSizes).reduce((acc, blobSize) => acc + blobSize, 0); | ||||||
|  |  | ||||||
| @@ -33,8 +33,8 @@ function getSubtreeSize(req) { | |||||||
|         FROM param_list |         FROM param_list | ||||||
|         JOIN notes ON notes.noteId = param_list.paramId AND notes.isDeleted = 0 |         JOIN notes ON notes.noteId = param_list.paramId AND notes.isDeleted = 0 | ||||||
|         LEFT JOIN attachments ON attachments.parentId = param_list.paramId AND attachments.isDeleted = 0 |         LEFT JOIN attachments ON attachments.parentId = param_list.paramId AND attachments.isDeleted = 0 | ||||||
|         LEFT JOIN note_revisions ON note_revisions.noteId = param_list.paramId |         LEFT JOIN revisions ON revisions.noteId = param_list.paramId | ||||||
|         JOIN blobs ON blobs.blobId = notes.blobId OR blobs.blobId = attachments.blobId OR blobs.blobId = note_revisions.blobId`); |         JOIN blobs ON blobs.blobId = notes.blobId OR blobs.blobId = attachments.blobId OR blobs.blobId = revisions.blobId`); | ||||||
|  |  | ||||||
|     const subTreeSize = Object.values(blobSizes).reduce((acc, blobSize) => acc + blobSize, 0); |     const subTreeSize = Object.values(blobSizes).reduce((acc, blobSize) => acc + blobSize, 0); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -108,9 +108,9 @@ function forceNoteSync(req) { | |||||||
|         entityChangesService.moveEntityChangeToTop('attributes', attributeId); |         entityChangesService.moveEntityChangeToTop('attributes', attributeId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (const noteRevisionId of sql.getColumn("SELECT noteRevisionId FROM note_revisions WHERE noteId = ?", [noteId])) { |     for (const revisionId of sql.getColumn("SELECT revisionId FROM revisions WHERE noteId = ?", [noteId])) { | ||||||
|         sql.execute(`UPDATE note_revisions SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]); |         sql.execute(`UPDATE revisions SET utcDateModified = ? WHERE revisionId = ?`, [now, revisionId]); | ||||||
|         entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId); |         entityChangesService.moveEntityChangeToTop('revisions', revisionId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (const attachmentId of sql.getColumn("SELECT attachmentId FROM attachments WHERE noteId = ?", [noteId])) { |     for (const attachmentId of sql.getColumn("SELECT attachmentId FROM attachments WHERE noteId = ?", [noteId])) { | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ const branchesApiRoute = require('./api/branches'); | |||||||
| const attachmentsApiRoute = require('./api/attachments'); | const attachmentsApiRoute = require('./api/attachments'); | ||||||
| const autocompleteApiRoute = require('./api/autocomplete'); | const autocompleteApiRoute = require('./api/autocomplete'); | ||||||
| const cloningApiRoute = require('./api/cloning'); | const cloningApiRoute = require('./api/cloning'); | ||||||
| const noteRevisionsApiRoute = require('./api/note_revisions'); | const revisionsApiRoute = require('./api/revisions.js'); | ||||||
| const recentChangesApiRoute = require('./api/recent_changes'); | const recentChangesApiRoute = require('./api/recent_changes'); | ||||||
| const optionsApiRoute = require('./api/options'); | const optionsApiRoute = require('./api/options'); | ||||||
| const passwordApiRoute = require('./api/password'); | const passwordApiRoute = require('./api/password'); | ||||||
| @@ -117,7 +117,7 @@ function register(app) { | |||||||
|     apiRoute(PUT, '/api/notes/:noteId/data', notesApiRoute.updateNoteData); |     apiRoute(PUT, '/api/notes/:noteId/data', notesApiRoute.updateNoteData); | ||||||
|     apiRoute(DEL, '/api/notes/:noteId', notesApiRoute.deleteNote); |     apiRoute(DEL, '/api/notes/:noteId', notesApiRoute.deleteNote); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote); |     apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote); | ||||||
|     apiRoute(PST, '/api/notes/:noteId/revision', notesApiRoute.forceSaveNoteRevision); |     apiRoute(PST, '/api/notes/:noteId/revision', notesApiRoute.forceSaveRevision); | ||||||
|     apiRoute(PST, '/api/notes/:parentNoteId/children', notesApiRoute.createNote); |     apiRoute(PST, '/api/notes/:parentNoteId/children', notesApiRoute.createNote); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes); |     apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote); |     apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote); | ||||||
| @@ -171,13 +171,13 @@ function register(app) { | |||||||
|     route(PUT, '/api/attachments/:attachmentId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], |     route(PUT, '/api/attachments/:attachmentId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], | ||||||
|         filesRoute.updateAttachment, apiResultHandler); |         filesRoute.updateAttachment, apiResultHandler); | ||||||
|  |  | ||||||
|     apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions); |     apiRoute(GET, '/api/notes/:noteId/revisions', revisionsApiRoute.getRevisions); | ||||||
|     apiRoute(DEL, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions); |     apiRoute(DEL, '/api/notes/:noteId/revisions', revisionsApiRoute.eraseAllRevisions); | ||||||
|     apiRoute(GET, '/api/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision); |     apiRoute(GET, '/api/revisions/:revisionId', revisionsApiRoute.getRevision); | ||||||
|     apiRoute(GET, '/api/revisions/:noteRevisionId/blob', noteRevisionsApiRoute.getNoteRevisionBlob); |     apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob); | ||||||
|     apiRoute(DEL, '/api/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision); |     apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision); | ||||||
|     apiRoute(PST, '/api/revisions/:noteRevisionId/restore', noteRevisionsApiRoute.restoreNoteRevision); |     apiRoute(PST, '/api/revisions/:revisionId/restore', revisionsApiRoute.restoreRevision); | ||||||
|     route(GET, '/api/revisions/:noteRevisionId/download', [auth.checkApiAuthOrElectron], noteRevisionsApiRoute.downloadNoteRevision); |     route(GET, '/api/revisions/:revisionId/download', [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision); | ||||||
|  |  | ||||||
|  |  | ||||||
|     route(GET, '/api/branches/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch); |     route(GET, '/api/branches/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch); | ||||||
| @@ -321,7 +321,7 @@ function register(app) { | |||||||
|     route(GET, '/api/fonts', [auth.checkApiAuthOrElectron], fontsRoute.getFontCss); |     route(GET, '/api/fonts', [auth.checkApiAuthOrElectron], fontsRoute.getFontCss); | ||||||
|     apiRoute(GET, '/api/other/icon-usage', otherRoute.getIconUsage); |     apiRoute(GET, '/api/other/icon-usage', otherRoute.getIconUsage); | ||||||
|     apiRoute(GET, '/api/recent-changes/:ancestorNoteId', recentChangesApiRoute.getRecentChanges); |     apiRoute(GET, '/api/recent-changes/:ancestorNoteId', recentChangesApiRoute.getRecentChanges); | ||||||
|     apiRoute(GET, '/api/edited-notes/:date', noteRevisionsApiRoute.getEditedNotesOnDate); |     apiRoute(GET, '/api/edited-notes/:date', revisionsApiRoute.getEditedNotesOnDate); | ||||||
|  |  | ||||||
|     apiRoute(PST, '/api/note-map/:noteId/tree', noteMapRoute.getTreeMap); |     apiRoute(PST, '/api/note-map/:noteId/tree', noteMapRoute.getTreeMap); | ||||||
|     apiRoute(PST, '/api/note-map/:noteId/link', noteMapRoute.getLinkMap); |     apiRoute(PST, '/api/note-map/:noteId/link', noteMapRoute.getLinkMap); | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ function getFullAnonymizationScript() { | |||||||
| UPDATE etapi_tokens SET tokenHash = 'API token hash value'; | UPDATE etapi_tokens SET tokenHash = 'API token hash value'; | ||||||
| UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share'); | UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share'); | ||||||
| UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; | UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; | ||||||
| UPDATE note_revisions SET title = 'title'; | UPDATE revisions SET title = 'title'; | ||||||
|  |  | ||||||
| UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN(${builtinAttrNames}); | UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN(${builtinAttrNames}); | ||||||
| UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN (${builtinAttrNames}); | UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN (${builtinAttrNames}); | ||||||
| @@ -36,7 +36,7 @@ function getLightAnonymizationScript() { | |||||||
|     return `UPDATE blobs SET content = 'text' WHERE content IS NOT NULL AND blobId NOT IN ( |     return `UPDATE blobs SET content = 'text' WHERE content IS NOT NULL AND blobId NOT IN ( | ||||||
|                 SELECT blobId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') |                 SELECT blobId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') | ||||||
|               UNION ALL |               UNION ALL | ||||||
|                 SELECT blobId FROM note_revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') |                 SELECT blobId FROM revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') | ||||||
|             );`; |             );`; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ const build = require('./build'); | |||||||
| const packageJson = require('../../package'); | const packageJson = require('../../package'); | ||||||
| const {TRILIUM_DATA_DIR} = require('./data_dir'); | const {TRILIUM_DATA_DIR} = require('./data_dir'); | ||||||
|  |  | ||||||
| const APP_DB_VERSION = 220; | const APP_DB_VERSION = 221; | ||||||
| const SYNC_VERSION = 30; | const SYNC_VERSION = 30; | ||||||
| const CLIPPER_PROTOCOL_VERSION = "1.0"; | const CLIPPER_PROTOCOL_VERSION = "1.0"; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ module.exports = [ | |||||||
|     { type: 'label', name: 'widget', isDangerous: true }, |     { type: 'label', name: 'widget', isDangerous: true }, | ||||||
|     { type: 'label', name: 'noteInfoWidgetDisabled' }, |     { type: 'label', name: 'noteInfoWidgetDisabled' }, | ||||||
|     { type: 'label', name: 'linkMapWidgetDisabled' }, |     { type: 'label', name: 'linkMapWidgetDisabled' }, | ||||||
|     { type: 'label', name: 'noteRevisionsWidgetDisabled' }, |     { type: 'label', name: 'revisionsWidgetDisabled' }, | ||||||
|     { type: 'label', name: 'whatLinksHereWidgetDisabled' }, |     { type: 'label', name: 'whatLinksHereWidgetDisabled' }, | ||||||
|     { type: 'label', name: 'similarNotesWidgetDisabled' }, |     { type: 'label', name: 'similarNotesWidgetDisabled' }, | ||||||
|     { type: 'label', name: 'workspace' }, |     { type: 'label', name: 'workspace' }, | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| const log = require("./log"); | const log = require("./log"); | ||||||
| const noteRevisionService = require("./note_revisions"); | const revisionService = require("./revisions.js"); | ||||||
| const becca = require("../becca/becca"); | const becca = require("../becca/becca"); | ||||||
| const cloningService = require("./cloning"); | const cloningService = require("./cloning"); | ||||||
| const branchService = require("./branches"); | const branchService = require("./branches"); | ||||||
| @@ -17,8 +17,8 @@ const ACTION_HANDLERS = { | |||||||
|  |  | ||||||
|         note.deleteNote(deleteId); |         note.deleteNote(deleteId); | ||||||
|     }, |     }, | ||||||
|     deleteNoteRevisions: (action, note) => { |     deleteRevisions: (action, note) => { | ||||||
|         noteRevisionService.eraseNoteRevisions(note.getNoteRevisions().map(rev => rev.noteRevisionId)); |         revisionService.eraseRevisions(note.getRevisions().map(rev => rev.revisionId)); | ||||||
|     }, |     }, | ||||||
|     deleteLabel: (action, note) => { |     deleteLabel: (action, note) => { | ||||||
|         for (const label of note.getOwnedLabels(action.labelName)) { |         for (const label of note.getOwnedLabels(action.labelName)) { | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ const cls = require('./cls'); | |||||||
| const entityChangesService = require('./entity_changes'); | const entityChangesService = require('./entity_changes'); | ||||||
| const optionsService = require('./options'); | const optionsService = require('./options'); | ||||||
| const BBranch = require('../becca/entities/bbranch'); | const BBranch = require('../becca/entities/bbranch'); | ||||||
| const noteRevisionService = require('./note_revisions'); | const revisionService = require('./revisions.js'); | ||||||
| const becca = require("../becca/becca"); | const becca = require("../becca/becca"); | ||||||
| const utils = require("../services/utils"); | const utils = require("../services/utils"); | ||||||
| const {sanitizeAttributeName} = require("./sanitize_attribute_name"); | const {sanitizeAttributeName} = require("./sanitize_attribute_name"); | ||||||
| @@ -221,7 +221,7 @@ class ConsistencyChecks { | |||||||
|                     WHERE attachments.parentId NOT IN ( |                     WHERE attachments.parentId NOT IN ( | ||||||
|                             SELECT noteId FROM notes |                             SELECT noteId FROM notes | ||||||
|                             UNION ALL |                             UNION ALL | ||||||
|                             SELECT noteRevisionId FROM note_revisions |                             SELECT revisionId FROM revisions | ||||||
|                         ) |                         ) | ||||||
|                       AND attachments.isDeleted = 0`, |                       AND attachments.isDeleted = 0`, | ||||||
|             ({attachmentId, parentId}) => { |             ({attachmentId, parentId}) => { | ||||||
| @@ -461,19 +461,19 @@ class ConsistencyChecks { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.findAndFixIssues(` |         this.findAndFixIssues(` | ||||||
|                     SELECT note_revisions.noteRevisionId |                     SELECT revisions.revisionId | ||||||
|                     FROM note_revisions |                     FROM revisions | ||||||
|                       LEFT JOIN blobs USING (blobId) |                       LEFT JOIN blobs USING (blobId) | ||||||
|                     WHERE blobs.blobId IS NULL`, |                     WHERE blobs.blobId IS NULL`, | ||||||
|             ({noteRevisionId}) => { |             ({revisionId}) => { | ||||||
|                 if (this.autoFix) { |                 if (this.autoFix) { | ||||||
|                     noteRevisionService.eraseNoteRevisions([noteRevisionId]); |                     revisionService.eraseRevisions([revisionId]); | ||||||
|  |  | ||||||
|                     this.reloadNeeded = true; |                     this.reloadNeeded = true; | ||||||
|  |  | ||||||
|                     logFix(`Note revision content '${noteRevisionId}' was set to erased since its content did not exist.`); |                     logFix(`Note revision content '${revisionId}' was set to erased since its content did not exist.`); | ||||||
|                 } else { |                 } else { | ||||||
|                     logError(`Note revision content '${noteRevisionId}' does not exist`); |                     logError(`Note revision content '${revisionId}' does not exist`); | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
| @@ -669,7 +669,7 @@ class ConsistencyChecks { | |||||||
|  |  | ||||||
|     findEntityChangeIssues() { |     findEntityChangeIssues() { | ||||||
|         this.runEntityChangeChecks("notes", "noteId"); |         this.runEntityChangeChecks("notes", "noteId"); | ||||||
|         this.runEntityChangeChecks("note_revisions", "noteRevisionId"); |         this.runEntityChangeChecks("revisions", "revisionId"); | ||||||
|         this.runEntityChangeChecks("attachments", "attachmentId"); |         this.runEntityChangeChecks("attachments", "attachmentId"); | ||||||
|         this.runEntityChangeChecks("blobs", "blobId"); |         this.runEntityChangeChecks("blobs", "blobId"); | ||||||
|         this.runEntityChangeChecks("branches", "branchId"); |         this.runEntityChangeChecks("branches", "branchId"); | ||||||
| @@ -767,7 +767,7 @@ class ConsistencyChecks { | |||||||
|             return `${tableName}: ${count}`; |             return `${tableName}: ${count}`; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const tables = [ "notes", "note_revisions", "attachments", "branches", "attributes", "etapi_tokens" ]; |         const tables = [ "notes", "revisions", "attachments", "branches", "attributes", "etapi_tokens" ]; | ||||||
|  |  | ||||||
|         log.info(`Table counts: ${tables.map(tableName => getTableRowCount(tableName)).join(", ")}`); |         log.info(`Table counts: ${tables.map(tableName => getTableRowCount(tableName)).join(", ")}`); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -148,7 +148,7 @@ function fillAllEntityChanges() { | |||||||
|  |  | ||||||
|         fillEntityChanges("notes", "noteId"); |         fillEntityChanges("notes", "noteId"); | ||||||
|         fillEntityChanges("branches", "branchId"); |         fillEntityChanges("branches", "branchId"); | ||||||
|         fillEntityChanges("note_revisions", "noteRevisionId"); |         fillEntityChanges("revisions", "revisionId"); | ||||||
|         fillEntityChanges("attachments", "attachmentId"); |         fillEntityChanges("attachments", "attachmentId"); | ||||||
|         fillEntityChanges("blobs", "blobId"); |         fillEntityChanges("blobs", "blobId"); | ||||||
|         fillEntityChanges("attributes", "attributeId"); |         fillEntityChanges("attributes", "attributeId"); | ||||||
|   | |||||||
| @@ -70,7 +70,7 @@ function updateImage(noteId, uploadBuffer, originalName) { | |||||||
|  |  | ||||||
|     const note = becca.getNote(noteId); |     const note = becca.getNote(noteId); | ||||||
|  |  | ||||||
|     note.saveNoteRevision(); |     note.saveRevision(); | ||||||
|  |  | ||||||
|     note.setLabel('originalFileName', originalName); |     note.setLabel('originalFileName', originalName); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -249,7 +249,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [ | |||||||
|         scope: "window" |         scope: "window" | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         actionName: "showNoteRevisions", |         actionName: "showRevisions", | ||||||
|         defaultShortcuts: [], |         defaultShortcuts: [], | ||||||
|         description: "Shows Note Revisions dialog", |         description: "Shows Note Revisions dialog", | ||||||
|         scope: "window" |         scope: "window" | ||||||
| @@ -502,7 +502,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [ | |||||||
|         scope: "text-detail" |         scope: "text-detail" | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         actionName: "forceSaveNoteRevision", |         actionName: "forceSaveRevision", | ||||||
|         defaultShortcuts: [], |         defaultShortcuts: [], | ||||||
|         description: "Force creating / saving new note revision of the active note", |         description: "Force creating / saving new note revision of the active note", | ||||||
|         scope: "window" |         scope: "window" | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ const cls = require('../services/cls'); | |||||||
| const protectedSessionService = require('../services/protected_session'); | const protectedSessionService = require('../services/protected_session'); | ||||||
| const log = require('../services/log'); | const log = require('../services/log'); | ||||||
| const utils = require('../services/utils'); | const utils = require('../services/utils'); | ||||||
| const noteRevisionService = require('../services/note_revisions'); | const revisionService = require('./revisions.js'); | ||||||
| const request = require('./request'); | const request = require('./request'); | ||||||
| const path = require('path'); | const path = require('path'); | ||||||
| const url = require('url'); | const url = require('url'); | ||||||
| @@ -315,7 +315,7 @@ function protectNote(note, protect) { | |||||||
|             note.setContent(content, { forceSave: true }); |             note.setContent(content, { forceSave: true }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         noteRevisionService.protectNoteRevisions(note); |         revisionService.protectRevisions(note); | ||||||
|  |  | ||||||
|         for (const attachment of note.getAttachments()) { |         for (const attachment of note.getAttachments()) { | ||||||
|             if (protect !== attachment.isProtected) { |             if (protect !== attachment.isProtected) { | ||||||
| @@ -666,24 +666,24 @@ function saveLinks(note, content) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /** @param {BNote} note */ | /** @param {BNote} note */ | ||||||
| function saveNoteRevisionIfNeeded(note) { | function saveRevisionIfNeeded(note) { | ||||||
|     // files and images are versioned separately |     // files and images are versioned separately | ||||||
|     if (note.type === 'file' || note.type === 'image' || note.hasLabel('disableVersioning')) { |     if (note.type === 'file' || note.type === 'image' || note.hasLabel('disableVersioning')) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     const noteRevisionSnapshotTimeInterval = parseInt(optionService.getOption('noteRevisionSnapshotTimeInterval')); |     const revisionSnapshotTimeInterval = parseInt(optionService.getOption('revisionSnapshotTimeInterval')); | ||||||
|  |  | ||||||
|     const revisionCutoff = dateUtils.utcDateTimeStr(new Date(now.getTime() - noteRevisionSnapshotTimeInterval * 1000)); |     const revisionCutoff = dateUtils.utcDateTimeStr(new Date(now.getTime() - revisionSnapshotTimeInterval * 1000)); | ||||||
|  |  | ||||||
|     const existingNoteRevisionId = sql.getValue( |     const existingRevisionId = sql.getValue( | ||||||
|         "SELECT noteRevisionId FROM note_revisions WHERE noteId = ? AND utcDateCreated >= ?", [note.noteId, revisionCutoff]); |         "SELECT revisionId FROM revisions WHERE noteId = ? AND utcDateCreated >= ?", [note.noteId, revisionCutoff]); | ||||||
|  |  | ||||||
|     const msSinceDateCreated = now.getTime() - dateUtils.parseDateTime(note.utcDateCreated).getTime(); |     const msSinceDateCreated = now.getTime() - dateUtils.parseDateTime(note.utcDateCreated).getTime(); | ||||||
|  |  | ||||||
|     if (!existingNoteRevisionId && msSinceDateCreated >= noteRevisionSnapshotTimeInterval * 1000) { |     if (!existingRevisionId && msSinceDateCreated >= revisionSnapshotTimeInterval * 1000) { | ||||||
|         note.saveNoteRevision(); |         note.saveRevision(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -694,7 +694,7 @@ function updateNoteData(noteId, content) { | |||||||
|         throw new Error(`Note '${noteId}' is not available for change!`); |         throw new Error(`Note '${noteId}' is not available for change!`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     saveNoteRevisionIfNeeded(note); |     saveRevisionIfNeeded(note); | ||||||
|  |  | ||||||
|     const { forceFrontendReload, content: newContent } = saveLinks(note, content); |     const { forceFrontendReload, content: newContent } = saveLinks(note, content); | ||||||
|  |  | ||||||
| @@ -839,10 +839,10 @@ function eraseNotes(noteIdsToErase) { | |||||||
|  |  | ||||||
|     eraseAttributes(attributeIdsToErase); |     eraseAttributes(attributeIdsToErase); | ||||||
|  |  | ||||||
|     const noteRevisionIdsToErase = sql.getManyRows(`SELECT noteRevisionId FROM note_revisions WHERE noteId IN (???)`, noteIdsToErase) |     const revisionIdsToErase = sql.getManyRows(`SELECT revisionId FROM revisions WHERE noteId IN (???)`, noteIdsToErase) | ||||||
|         .map(row => row.noteRevisionId); |         .map(row => row.revisionId); | ||||||
|  |  | ||||||
|     noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase); |     revisionService.eraseRevisions(revisionIdsToErase); | ||||||
|  |  | ||||||
|     log.info(`Erased notes: ${JSON.stringify(noteIdsToErase)}`); |     log.info(`Erased notes: ${JSON.stringify(noteIdsToErase)}`); | ||||||
| } | } | ||||||
| @@ -899,10 +899,10 @@ function eraseUnusedBlobs() { | |||||||
|         FROM blobs |         FROM blobs | ||||||
|         LEFT JOIN notes ON notes.blobId = blobs.blobId |         LEFT JOIN notes ON notes.blobId = blobs.blobId | ||||||
|         LEFT JOIN attachments ON attachments.blobId = blobs.blobId |         LEFT JOIN attachments ON attachments.blobId = blobs.blobId | ||||||
|         LEFT JOIN note_revisions ON note_revisions.blobId = blobs.blobId |         LEFT JOIN revisions ON revisions.blobId = blobs.blobId | ||||||
|         WHERE notes.noteId IS NULL  |         WHERE notes.noteId IS NULL  | ||||||
|           AND attachments.attachmentId IS NULL |           AND attachments.attachmentId IS NULL | ||||||
|           AND note_revisions.noteRevisionId IS NULL`); |           AND revisions.revisionId IS NULL`); | ||||||
|  |  | ||||||
|     if (unusedBlobIds.length === 0) { |     if (unusedBlobIds.length === 0) { | ||||||
|         return; |         return; | ||||||
| @@ -1136,7 +1136,7 @@ module.exports = { | |||||||
|     eraseDeletedNotesNow, |     eraseDeletedNotesNow, | ||||||
|     eraseUnusedAttachmentsNow, |     eraseUnusedAttachmentsNow, | ||||||
|     eraseNotesWithDeleteId, |     eraseNotesWithDeleteId, | ||||||
|     saveNoteRevisionIfNeeded, |     saveRevisionIfNeeded, | ||||||
|     downloadImages, |     downloadImages, | ||||||
|     asyncPostProcessContent |     asyncPostProcessContent | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ function initNotSyncedOptions(initialized, opts = {}) { | |||||||
| } | } | ||||||
|  |  | ||||||
| const defaultOptions = [ | const defaultOptions = [ | ||||||
|     { name: 'noteRevisionSnapshotTimeInterval', value: '600', isSynced: true }, |     { name: 'revisionSnapshotTimeInterval', value: '600', isSynced: true }, | ||||||
|     { name: 'protectedSessionTimeout', value: '600', isSynced: true }, |     { name: 'protectedSessionTimeout', value: '600', isSynced: true }, | ||||||
|     { name: 'zoomFactor', value: process.platform === "win32" ? '0.9' : '1.0', isSynced: false }, |     { name: 'zoomFactor', value: process.platform === "win32" ? '0.9' : '1.0', isSynced: false }, | ||||||
|     { name: 'overrideThemeFonts', value: 'false', isSynced: false }, |     { name: 'overrideThemeFonts', value: 'false', isSynced: false }, | ||||||
|   | |||||||
| @@ -7,12 +7,12 @@ const protectedSessionService = require("./protected_session"); | |||||||
| /** | /** | ||||||
|  * @param {BNote} note |  * @param {BNote} note | ||||||
|  */ |  */ | ||||||
| function protectNoteRevisions(note) { | function protectRevisions(note) { | ||||||
|     if (!protectedSessionService.isProtectedSessionAvailable()) { |     if (!protectedSessionService.isProtectedSessionAvailable()) { | ||||||
|         throw new Error(`Cannot (un)protect revisions of note '${note.noteId}' without active protected session`); |         throw new Error(`Cannot (un)protect revisions of note '${note.noteId}' without active protected session`); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (const revision of note.getNoteRevisions()) { |     for (const revision of note.getRevisions()) { | ||||||
|         if (note.isProtected === revision.isProtected) { |         if (note.isProtected === revision.isProtected) { | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
| @@ -25,25 +25,25 @@ function protectNoteRevisions(note) { | |||||||
|             // this will force de/encryption
 |             // this will force de/encryption
 | ||||||
|             revision.setContent(content, {forceSave: true}); |             revision.setContent(content, {forceSave: true}); | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             log.error(`Could not un/protect note revision '${revision.noteRevisionId}'`); |             log.error(`Could not un/protect note revision '${revision.revisionId}'`); | ||||||
| 
 | 
 | ||||||
|             throw e; |             throw e; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function eraseNoteRevisions(noteRevisionIdsToErase) { | function eraseRevisions(revisionIdsToErase) { | ||||||
|     if (noteRevisionIdsToErase.length === 0) { |     if (revisionIdsToErase.length === 0) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     log.info(`Removing note revisions: ${JSON.stringify(noteRevisionIdsToErase)}`); |     log.info(`Removing note revisions: ${JSON.stringify(revisionIdsToErase)}`); | ||||||
| 
 | 
 | ||||||
|     sql.executeMany(`DELETE FROM note_revisions WHERE noteRevisionId IN (???)`, noteRevisionIdsToErase); |     sql.executeMany(`DELETE FROM revisions WHERE revisionId IN (???)`, revisionIdsToErase); | ||||||
|     sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_revisions' AND entityId IN (???)`, noteRevisionIdsToErase); |     sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'revisions' AND entityId IN (???)`, revisionIdsToErase); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|     protectNoteRevisions, |     protectRevisions, | ||||||
|     eraseNoteRevisions |     eraseRevisions | ||||||
| }; | }; | ||||||
| @@ -116,16 +116,16 @@ function loadNeededInfoFromDatabase() { | |||||||
|         becca.notes[noteId].noteSize = length; |         becca.notes[noteId].noteSize = length; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const noteRevisionContentLengths = sql.getRows(` |     const revisionContentLengths = sql.getRows(` | ||||||
|         SELECT  |         SELECT  | ||||||
|             noteId,  |             noteId,  | ||||||
|             LENGTH(content) AS length  |             LENGTH(content) AS length  | ||||||
|         FROM notes |         FROM notes | ||||||
|              JOIN note_revisions USING(noteId)  |              JOIN revisions USING(noteId)  | ||||||
|              JOIN blobs USING(blobId)  |              JOIN blobs USING(blobId)  | ||||||
|         WHERE notes.isDeleted = 0`); |         WHERE notes.isDeleted = 0`); | ||||||
|  |  | ||||||
|     for (const {noteId, length} of noteRevisionContentLengths) { |     for (const {noteId, length} of revisionContentLengths) { | ||||||
|         if (!(noteId in becca.notes)) { |         if (!(noteId in becca.notes)) { | ||||||
|             log.error(`Note ${noteId} not found in becca.`); |             log.error(`Note ${noteId} not found in becca.`); | ||||||
|             continue; |             continue; | ||||||
|   | |||||||
| @@ -113,7 +113,7 @@ function eraseEntity(entityChange, instanceId) { | |||||||
|         "notes", |         "notes", | ||||||
|         "branches", |         "branches", | ||||||
|         "attributes", |         "attributes", | ||||||
|         "note_revisions", |         "revisions", | ||||||
|         "attachments", |         "attachments", | ||||||
|         "blobs", |         "blobs", | ||||||
|     ]; |     ]; | ||||||
|   | |||||||
| @@ -127,10 +127,10 @@ function fillInAdditionalProperties(entityChange) { | |||||||
|                 entityChange.entity.title = protectedSessionService.decryptString(entityChange.entity.title); |                 entityChange.entity.title = protectedSessionService.decryptString(entityChange.entity.title); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } else if (entityChange.entityName === 'note_revisions') { |     } else if (entityChange.entityName === 'revisions') { | ||||||
|         entityChange.noteId = sql.getValue(`SELECT noteId |         entityChange.noteId = sql.getValue(`SELECT noteId | ||||||
|                                           FROM note_revisions |                                           FROM revisions | ||||||
|                                           WHERE noteRevisionId = ?`, [entityChange.entityId]); |                                           WHERE revisionId = ?`, [entityChange.entityId]); | ||||||
|     } else if (entityChange.entityName === 'note_reordering') { |     } else if (entityChange.entityName === 'note_reordering') { | ||||||
|         entityChange.positions = {}; |         entityChange.positions = {}; | ||||||
|  |  | ||||||
| @@ -165,7 +165,7 @@ const ORDERING = { | |||||||
|     "branches": 2, |     "branches": 2, | ||||||
|     "blobs": 0, |     "blobs": 0, | ||||||
|     "note_reordering": 2, |     "note_reordering": 2, | ||||||
|     "note_revisions": 2, |     "revisions": 2, | ||||||
|     "attachments": 3, |     "attachments": 3, | ||||||
|     "notes": 1, |     "notes": 1, | ||||||
|     "options": 0 |     "options": 0 | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ async function start() { | |||||||
|             isInheritable: Math.random() > 0.1 // 10% are inheritable |             isInheritable: Math.random() > 0.1 // 10% are inheritable | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         note.saveNoteRevision(); |         note.saveRevision(); | ||||||
|  |  | ||||||
|         notes.push(note.noteId); |         notes.push(note.noteId); | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user