mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	WIP blobs
This commit is contained in:
		| @@ -1,10 +1,8 @@ | |||||||
|  |  | ||||||
| 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 note_contents 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 note_revisions SET title = 'title'; | ||||||
| UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL; |  | ||||||
| UPDATE note_ancillary_contents SET content = 'text' WHERE content IS NOT NULL; |  | ||||||
|  |  | ||||||
| UPDATE attributes SET name = 'name', value = 'value' | UPDATE attributes SET name = 'name', value = 'value' | ||||||
|                   WHERE type = 'label' |                   WHERE type = 'label' | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ CREATE TABLE IF NOT EXISTS "note_ancillaries" | |||||||
|     name         TEXT not null, |     name         TEXT not null, | ||||||
|     mime         TEXT not null, |     mime         TEXT not null, | ||||||
|     isProtected    INT  not null DEFAULT 0, |     isProtected    INT  not null DEFAULT 0, | ||||||
|     contentCheckSum    TEXT not null, |  | ||||||
|     blobId    TEXT not null, |     blobId    TEXT not null, | ||||||
|     utcDateModified TEXT not null, |     utcDateModified TEXT not null, | ||||||
|     isDeleted    INT  not null, |     isDeleted    INT  not null, | ||||||
| @@ -119,13 +119,10 @@ CREATE TABLE IF NOT EXISTS "note_ancillaries" | |||||||
|     name         TEXT not null, |     name         TEXT not null, | ||||||
|     mime         TEXT not null, |     mime         TEXT not null, | ||||||
|     isProtected    INT  not null DEFAULT 0, |     isProtected    INT  not null DEFAULT 0, | ||||||
|     contentCheckSum    TEXT not null, |  | ||||||
|     utcDateModified TEXT not null, |     utcDateModified TEXT not null, | ||||||
|     isDeleted    INT  not null, |     isDeleted    INT  not null, | ||||||
|     `deleteId`    TEXT DEFAULT NULL); |     `deleteId`    TEXT DEFAULT NULL); | ||||||
| CREATE TABLE IF NOT EXISTS "note_ancillary_contents" (`noteAncillaryId`	TEXT NOT NULL PRIMARY KEY, |  | ||||||
|                                                      `content`	TEXT DEFAULT NULL, |  | ||||||
|                                                      `utcDateModified` TEXT NOT NULL); |  | ||||||
| CREATE INDEX IDX_note_ancillaries_name | CREATE INDEX IDX_note_ancillaries_name | ||||||
|     on note_ancillaries (name); |     on note_ancillaries (name); | ||||||
| CREATE UNIQUE INDEX IDX_note_ancillaries_noteId_name | CREATE UNIQUE INDEX IDX_note_ancillaries_noteId_name | ||||||
|   | |||||||
| @@ -74,7 +74,7 @@ function dumpDocument(documentPath, targetPath, options) { | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             let {content} = sql.getRow("SELECT content FROM note_contents WHERE noteId = ?", [noteId]); |             let {content} = sql.getRow("SELECT content FROM blobs WHERE blobId = ?", [note.blobId]); | ||||||
|  |  | ||||||
|             if (content !== null && note.isProtected && dataKey) { |             if (content !== null && note.isProtected && dataKey) { | ||||||
|                 content = decryptService.decrypt(dataKey, content); |                 content = decryptService.decrypt(dataKey, content); | ||||||
|   | |||||||
| @@ -125,7 +125,7 @@ class Becca { | |||||||
|     getNoteAncillary(noteAncillaryId) { |     getNoteAncillary(noteAncillaryId) { | ||||||
|         const row = sql.getRow("SELECT * FROM note_ancillaries WHERE noteAncillaryId = ?", [noteAncillaryId]); |         const row = sql.getRow("SELECT * FROM note_ancillaries WHERE noteAncillaryId = ?", [noteAncillaryId]); | ||||||
|  |  | ||||||
|         const BNoteAncillary = require("./entities/bnote_ancillary"); // avoiding circular dependency problems |         const BNoteAncillary = require("./entities/bnote_attachment.js"); // avoiding circular dependency problems | ||||||
|         return row ? new BNoteAncillary(row) : null; |         return row ? new BNoteAncillary(row) : null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ const dateUtils = require('../../services/date_utils'); | |||||||
| const entityChangesService = require('../../services/entity_changes'); | const entityChangesService = require('../../services/entity_changes'); | ||||||
| const AbstractBeccaEntity = require("./abstract_becca_entity"); | const AbstractBeccaEntity = require("./abstract_becca_entity"); | ||||||
| const BNoteRevision = require("./bnote_revision"); | const BNoteRevision = require("./bnote_revision"); | ||||||
| const BNoteAncillary = require("./bnote_ancillary"); | const BNoteAncillary = require("./bnote_attachment.js"); | ||||||
| const TaskContext = require("../../services/task_context"); | const TaskContext = require("../../services/task_context"); | ||||||
| const dayjs = require("dayjs"); | const dayjs = require("dayjs"); | ||||||
| const utc = require('dayjs/plugin/utc'); | const utc = require('dayjs/plugin/utc'); | ||||||
| @@ -1507,13 +1507,6 @@ class BNote extends AbstractBeccaEntity { | |||||||
|     saveNoteAncillary(name, mime, content) { |     saveNoteAncillary(name, mime, content) { | ||||||
|         let noteAncillary = this.getNoteAncillaryByName(name); |         let noteAncillary = this.getNoteAncillaryByName(name); | ||||||
|  |  | ||||||
|         if (noteAncillary |  | ||||||
|             && noteAncillary.mime === mime |  | ||||||
|             && noteAncillary.contentCheckSum === noteAncillary.calculateCheckSum(content)) { |  | ||||||
|  |  | ||||||
|             return noteAncillary; // no change |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         noteAncillary = new BNoteAncillary({ |         noteAncillary = new BNoteAncillary({ | ||||||
|             noteId: this.noteId, |             noteId: this.noteId, | ||||||
|             name, |             name, | ||||||
|   | |||||||
| @@ -41,8 +41,6 @@ class BNoteAncillary extends AbstractBeccaEntity { | |||||||
|         /** @type {boolean} */ |         /** @type {boolean} */ | ||||||
|         this.isProtected = !!row.isProtected; |         this.isProtected = !!row.isProtected; | ||||||
|         /** @type {string} */ |         /** @type {string} */ | ||||||
|         this.contentCheckSum = row.contentCheckSum; |  | ||||||
|         /** @type {string} */ |  | ||||||
|         this.utcDateModified = row.utcDateModified; |         this.utcDateModified = row.utcDateModified; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -91,7 +89,6 @@ class BNoteAncillary extends AbstractBeccaEntity { | |||||||
| 
 | 
 | ||||||
|     setContent(content) { |     setContent(content) { | ||||||
|         sql.transactional(() => { |         sql.transactional(() => { | ||||||
|             this.contentCheckSum = this.calculateCheckSum(content); |  | ||||||
|             this.save(); // also explicitly save note_ancillary to update contentCheckSum
 |             this.save(); // also explicitly save note_ancillary to update contentCheckSum
 | ||||||
| 
 | 
 | ||||||
|             const pojo = { |             const pojo = { | ||||||
| @@ -113,7 +110,7 @@ class BNoteAncillary extends AbstractBeccaEntity { | |||||||
|             entityChangesService.addEntityChange({ |             entityChangesService.addEntityChange({ | ||||||
|                 entityName: 'note_ancillary_contents', |                 entityName: 'note_ancillary_contents', | ||||||
|                 entityId: this.noteAncillaryId, |                 entityId: this.noteAncillaryId, | ||||||
|                 hash: this.contentCheckSum, |                 hash: this.contentCheckSum, // FIXME
 | ||||||
|                 isErased: false, |                 isErased: false, | ||||||
|                 utcDateChanged: pojo.utcDateModified, |                 utcDateChanged: pojo.utcDateModified, | ||||||
|                 isSynced: true |                 isSynced: true | ||||||
| @@ -144,7 +141,7 @@ class BNoteAncillary extends AbstractBeccaEntity { | |||||||
|             name: this.name, |             name: this.name, | ||||||
|             mime: this.mime, |             mime: this.mime, | ||||||
|             isProtected: !!this.isProtected, |             isProtected: !!this.isProtected, | ||||||
|             contentCheckSum: this.contentCheckSum, |             contentCheckSum: this.contentCheckSum, // FIXME
 | ||||||
|             isDeleted: false, |             isDeleted: false, | ||||||
|             utcDateModified: this.utcDateModified |             utcDateModified: this.utcDateModified | ||||||
|         }; |         }; | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| const BNote = require('./entities/bnote'); | const BNote = require('./entities/bnote'); | ||||||
| const BNoteRevision = require('./entities/bnote_revision'); | const BNoteRevision = require('./entities/bnote_revision'); | ||||||
| const BNoteAncillary = require("./entities/bnote_ancillary"); | const BNoteAncillary = require("./entities/bnote_attachment.js"); | ||||||
| const BBranch = require('./entities/bbranch'); | const BBranch = require('./entities/bbranch'); | ||||||
| const BAttribute = require('./entities/battribute'); | const BAttribute = require('./entities/battribute'); | ||||||
| const BRecentNote = require('./entities/brecent_note'); | const BRecentNote = require('./entities/brecent_note'); | ||||||
| @@ -11,11 +11,8 @@ const ENTITY_NAME_TO_ENTITY = { | |||||||
|     "attributes": BAttribute, |     "attributes": BAttribute, | ||||||
|     "branches": BBranch, |     "branches": BBranch, | ||||||
|     "notes": BNote, |     "notes": BNote, | ||||||
|     "note_contents": BNote, |  | ||||||
|     "note_revisions": BNoteRevision, |     "note_revisions": BNoteRevision, | ||||||
|     "note_revision_contents": BNoteRevision, |  | ||||||
|     "note_ancillaries": BNoteAncillary, |     "note_ancillaries": BNoteAncillary, | ||||||
|     "note_ancillary_contents": BNoteAncillary, |  | ||||||
|     "recent_notes": BRecentNote, |     "recent_notes": BRecentNote, | ||||||
|     "etapi_tokens": BEtapiToken, |     "etapi_tokens": BEtapiToken, | ||||||
|     "options": BOption |     "options": BOption | ||||||
|   | |||||||
| @@ -25,8 +25,6 @@ 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 === 'note_revisions') { | ||||||
|                 loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.componentId); |                 loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.componentId); | ||||||
|             } else if (ec.entityName === 'note_revision_contents') { |  | ||||||
|                 // this should change only when toggling isProtected, ignore |  | ||||||
|             } else if (ec.entityName === 'options') { |             } else if (ec.entityName === 'options') { | ||||||
|                 if (ec.entity.name === 'openTabs') { |                 if (ec.entity.name === 'openTabs') { | ||||||
|                     continue; // only noise |                     continue; // only noise | ||||||
| @@ -36,7 +34,7 @@ async function processEntityChanges(entityChanges) { | |||||||
|  |  | ||||||
|                 loadResults.addOption(ec.entity.name); |                 loadResults.addOption(ec.entity.name); | ||||||
|             } |             } | ||||||
|             else if (['etapi_tokens', 'note_ancillaries', 'note_ancillary_contents'].includes(ec.entityName)) { |             else if (['etapi_tokens', 'note_ancillaries'].includes(ec.entityName)) { | ||||||
|                 // NOOP |                 // NOOP | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ import NoteMapTypeWidget from "./type_widgets/note_map.js"; | |||||||
| import WebViewTypeWidget from "./type_widgets/web_view.js"; | import WebViewTypeWidget from "./type_widgets/web_view.js"; | ||||||
| import DocTypeWidget from "./type_widgets/doc.js"; | import DocTypeWidget from "./type_widgets/doc.js"; | ||||||
| import ContentWidgetTypeWidget from "./type_widgets/content_widget.js"; | import ContentWidgetTypeWidget from "./type_widgets/content_widget.js"; | ||||||
| import AncillariesTypeWidget from "./type_widgets/ancillaries.js"; | import AncillariesTypeWidget from "./type_widgets/attachments.js"; | ||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="note-detail"> | <div class="note-detail"> | ||||||
|   | |||||||
| @@ -12,9 +12,9 @@ const becca = require("../../becca/becca"); | |||||||
| function getNoteRevisions(req) { | function getNoteRevisions(req) { | ||||||
|     return becca.getNoteRevisionsFromQuery(` |     return becca.getNoteRevisionsFromQuery(` | ||||||
|         SELECT note_revisions.*, |         SELECT note_revisions.*, | ||||||
|                LENGTH(note_revision_contents.content) AS contentLength |                LENGTH(blobs.content) AS contentLength | ||||||
|         FROM note_revisions |         FROM note_revisions | ||||||
|         JOIN note_revision_contents ON note_revisions.noteRevisionId = note_revision_contents.noteRevisionId  |         JOIN blobs ON note_revisions.blobId = blobs.blobId  | ||||||
|         WHERE noteId = ? |         WHERE noteId = ? | ||||||
|         ORDER BY utcDateCreated DESC`, [req.params.noteId]); |         ORDER BY utcDateCreated DESC`, [req.params.noteId]); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,18 +4,19 @@ const NotFoundError = require("../../errors/not_found_error"); | |||||||
|  |  | ||||||
| function getNoteSize(req) { | function getNoteSize(req) { | ||||||
|     const {noteId} = req.params; |     const {noteId} = req.params; | ||||||
|  |     const note = becca.getNote(noteId); | ||||||
|  |  | ||||||
|     const noteSize = sql.getValue(` |     const noteSize = sql.getValue(` | ||||||
|         SELECT |         SELECT | ||||||
|             COALESCE((SELECT LENGTH(content) FROM note_contents WHERE noteId = ?), 0) |             COALESCE((SELECT LENGTH(content) FROM blobs WHERE blobId = ?), 0) | ||||||
|             + |             + | ||||||
|             COALESCE( |             COALESCE( | ||||||
|                     (SELECT SUM(LENGTH(content)) |                     (SELECT SUM(LENGTH(content)) | ||||||
|                      FROM note_revisions |                      FROM note_revisions | ||||||
|                               JOIN note_revision_contents USING (noteRevisionId) |                               JOIN blobs USING (blobId) | ||||||
|                      WHERE note_revisions.noteId = ?), |                      WHERE note_revisions.noteId = ?), | ||||||
|                     0 |                     0 | ||||||
|             )`, [noteId, noteId]); |             )`, [note.blobId, noteId]); | ||||||
|  |  | ||||||
|     return { |     return { | ||||||
|         noteSize |         noteSize | ||||||
| @@ -38,14 +39,15 @@ function getSubtreeSize(req) { | |||||||
|         SELECT |         SELECT | ||||||
|             COALESCE(( |             COALESCE(( | ||||||
|                 SELECT SUM(LENGTH(content))  |                 SELECT SUM(LENGTH(content))  | ||||||
|                 FROM note_contents  |                 FROM notes | ||||||
|                 JOIN param_list ON param_list.paramId = note_contents.noteId |                 JOIN blobs USING (blobId)     | ||||||
|  |                 JOIN param_list ON param_list.paramId = notes.noteId | ||||||
|             ), 0) |             ), 0) | ||||||
|             + |             + | ||||||
|             COALESCE( |             COALESCE( | ||||||
|                     (SELECT SUM(LENGTH(content)) |                     (SELECT SUM(LENGTH(content)) | ||||||
|                      FROM note_revisions |                      FROM note_revisions | ||||||
|                      JOIN note_revision_contents USING (noteRevisionId) |                      JOIN blobs USING (blobId) | ||||||
|                      JOIN param_list ON param_list.paramId = note_revisions.noteId), |                      JOIN param_list ON param_list.paramId = note_revisions.noteId), | ||||||
|                     0 |                     0 | ||||||
|             )`); |             )`); | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ const syncOptions = require('../../services/sync_options'); | |||||||
| const dateUtils = require('../../services/date_utils'); | const dateUtils = require('../../services/date_utils'); | ||||||
| const utils = require('../../services/utils'); | const utils = require('../../services/utils'); | ||||||
| const ws = require('../../services/ws'); | const ws = require('../../services/ws'); | ||||||
|  | const becca = require("../../becca/becca.js"); | ||||||
|  |  | ||||||
| async function testSync() { | async function testSync() { | ||||||
|     try { |     try { | ||||||
| @@ -85,14 +86,15 @@ function forceFullSync() { | |||||||
|  |  | ||||||
| function forceNoteSync(req) { | function forceNoteSync(req) { | ||||||
|     const noteId = req.params.noteId; |     const noteId = req.params.noteId; | ||||||
|  |     const note = becca.getNote(noteId); | ||||||
|  |  | ||||||
|     const now = dateUtils.utcNowDateTime(); |     const now = dateUtils.utcNowDateTime(); | ||||||
|  |  | ||||||
|     sql.execute(`UPDATE notes SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]); |     sql.execute(`UPDATE notes SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]); | ||||||
|     entityChangesService.moveEntityChangeToTop('notes', noteId); |     entityChangesService.moveEntityChangeToTop('notes', noteId); | ||||||
|  |  | ||||||
|     sql.execute(`UPDATE note_contents SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]); |     sql.execute(`UPDATE blobs SET utcDateModified = ? WHERE blobId = ?`, [now, note.blobId]); | ||||||
|     entityChangesService.moveEntityChangeToTop('note_contents', noteId); |     entityChangesService.moveEntityChangeToTop('blobs', note.blobId); | ||||||
|  |  | ||||||
|     for (const branchId of sql.getColumn("SELECT branchId FROM branches WHERE noteId = ?", [noteId])) { |     for (const branchId of sql.getColumn("SELECT branchId FROM branches WHERE noteId = ?", [noteId])) { | ||||||
|         sql.execute(`UPDATE branches SET utcDateModified = ? WHERE branchId = ?`, [now, branchId]); |         sql.execute(`UPDATE branches SET utcDateModified = ? WHERE branchId = ?`, [now, branchId]); | ||||||
| @@ -109,17 +111,11 @@ function forceNoteSync(req) { | |||||||
|     for (const noteRevisionId of sql.getColumn("SELECT noteRevisionId FROM note_revisions WHERE noteId = ?", [noteId])) { |     for (const noteRevisionId of sql.getColumn("SELECT noteRevisionId FROM note_revisions WHERE noteId = ?", [noteId])) { | ||||||
|         sql.execute(`UPDATE note_revisions SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]); |         sql.execute(`UPDATE note_revisions SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]); | ||||||
|         entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId); |         entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId); | ||||||
|  |  | ||||||
|         sql.execute(`UPDATE note_revision_contents SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]); |  | ||||||
|         entityChangesService.moveEntityChangeToTop('note_revision_contents', noteRevisionId); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (const noteAncillaryId of sql.getColumn("SELECT noteAncillaryId FROM note_ancillaries WHERE noteId = ?", [noteId])) { |     for (const noteAncillaryId of sql.getColumn("SELECT noteAncillaryId FROM note_ancillaries WHERE noteId = ?", [noteId])) { | ||||||
|         sql.execute(`UPDATE note_ancillaries SET utcDateModified = ? WHERE noteAncillaryId = ?`, [now, noteAncillaryId]); |         sql.execute(`UPDATE note_ancillaries SET utcDateModified = ? WHERE noteAncillaryId = ?`, [now, noteAncillaryId]); | ||||||
|         entityChangesService.moveEntityChangeToTop('note_ancillaries', noteAncillaryId); |         entityChangesService.moveEntityChangeToTop('note_ancillaries', noteAncillaryId); | ||||||
|  |  | ||||||
|         sql.execute(`UPDATE note_ancillary_contents SET utcDateModified = ? WHERE noteAncillaryId = ?`, [now, noteAncillaryId]); |  | ||||||
|         entityChangesService.moveEntityChangeToTop('note_ancillary_contents', noteAncillaryId); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     log.info(`Forcing note sync for ${noteId}`); |     log.info(`Forcing note sync for ${noteId}`); | ||||||
|   | |||||||
| @@ -14,9 +14,8 @@ function getFullAnonymizationScript() { | |||||||
|     const anonymizeScript = ` |     const anonymizeScript = ` | ||||||
| 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 note_contents 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 note_revisions SET title = 'title'; | ||||||
| UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL; |  | ||||||
|  |  | ||||||
| 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}); | ||||||
| @@ -34,14 +33,11 @@ VACUUM; | |||||||
| } | } | ||||||
|  |  | ||||||
| function getLightAnonymizationScript() { | function getLightAnonymizationScript() { | ||||||
|     return ` |     return `UPDATE blobs SET content = 'text' WHERE content IS NOT NULL AND blobId NOT IN ( | ||||||
|          UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL AND noteId NOT IN ( |                 SELECT blobId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') | ||||||
|                 SELECT noteId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') |               UNION ALL | ||||||
|          ); |                 SELECT blobId FROM note_revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') | ||||||
|          UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL AND noteRevisionId NOT IN ( |             );`; | ||||||
|                 SELECT noteRevisionId FROM note_revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') |  | ||||||
|          ); |  | ||||||
|      `; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| async function createAnonymizedCopy(type) { | async function createAnonymizedCopy(type) { | ||||||
|   | |||||||
| @@ -656,11 +656,9 @@ class ConsistencyChecks { | |||||||
|  |  | ||||||
|     findEntityChangeIssues() { |     findEntityChangeIssues() { | ||||||
|         this.runEntityChangeChecks("notes", "noteId"); |         this.runEntityChangeChecks("notes", "noteId"); | ||||||
|         //this.runEntityChangeChecks("note_contents", "noteId"); |  | ||||||
|         this.runEntityChangeChecks("note_revisions", "noteRevisionId"); |         this.runEntityChangeChecks("note_revisions", "noteRevisionId"); | ||||||
|         //this.runEntityChangeChecks("note_revision_contents", "noteRevisionId"); |  | ||||||
|         this.runEntityChangeChecks("note_ancillaries", "noteAncillaryId"); |         this.runEntityChangeChecks("note_ancillaries", "noteAncillaryId"); | ||||||
|         //this.runEntityChangeChecks("note_ancillary_contents", "noteAncillaryId"); |         this.runEntityChangeChecks("blobs", "blobId"); | ||||||
|         this.runEntityChangeChecks("branches", "branchId"); |         this.runEntityChangeChecks("branches", "branchId"); | ||||||
|         this.runEntityChangeChecks("attributes", "attributeId"); |         this.runEntityChangeChecks("attributes", "attributeId"); | ||||||
|         this.runEntityChangeChecks("etapi_tokens", "etapiTokenId"); |         this.runEntityChangeChecks("etapi_tokens", "etapiTokenId"); | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ function fillEntityChanges(entityName, entityPrimaryKey, condition = '') { | |||||||
|                 let utcDateChanged; |                 let utcDateChanged; | ||||||
|                 let isSynced; |                 let isSynced; | ||||||
|  |  | ||||||
|                 if (entityName.endsWith("_contents")) { |                 if (entityName === 'blobs') { | ||||||
|                     // FIXME: hacky, not sure if it might cause some problems |                     // FIXME: hacky, not sure if it might cause some problems | ||||||
|                     hash = "fake value"; |                     hash = "fake value"; | ||||||
|                     utcDateChanged = dateUtils.utcNowDateTime(); |                     utcDateChanged = dateUtils.utcNowDateTime(); | ||||||
| @@ -147,12 +147,10 @@ function fillAllEntityChanges() { | |||||||
|         sql.execute("DELETE FROM entity_changes WHERE isErased = 0"); |         sql.execute("DELETE FROM entity_changes WHERE isErased = 0"); | ||||||
|  |  | ||||||
|         fillEntityChanges("notes", "noteId"); |         fillEntityChanges("notes", "noteId"); | ||||||
|         fillEntityChanges("note_contents", "noteId"); |  | ||||||
|         fillEntityChanges("branches", "branchId"); |         fillEntityChanges("branches", "branchId"); | ||||||
|         fillEntityChanges("note_revisions", "noteRevisionId"); |         fillEntityChanges("note_revisions", "noteRevisionId"); | ||||||
|         fillEntityChanges("note_revision_contents", "noteRevisionId"); |  | ||||||
|         fillEntityChanges("note_ancillaries", "noteAncillaryId"); |         fillEntityChanges("note_ancillaries", "noteAncillaryId"); | ||||||
|         fillEntityChanges("note_ancillary_contents", "noteAncillaryId"); |         fillEntityChanges("blobs", "blobId"); | ||||||
|         fillEntityChanges("attributes", "attributeId"); |         fillEntityChanges("attributes", "attributeId"); | ||||||
|         fillEntityChanges("etapi_tokens", "etapiTokenId"); |         fillEntityChanges("etapi_tokens", "etapiTokenId"); | ||||||
|         fillEntityChanges("options", "name", 'isSynced = 1'); |         fillEntityChanges("options", "name", 'isSynced = 1'); | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ eventService.subscribe([ eventService.ENTITY_CHANGED, eventService.ENTITY_DELETE | |||||||
| }); | }); | ||||||
|  |  | ||||||
| eventService.subscribe(eventService.ENTITY_CHANGED, ({entityName, entity}) => { | eventService.subscribe(eventService.ENTITY_CHANGED, ({entityName, entity}) => { | ||||||
|     if (entityName === 'note_contents') { |     if (entityName === 'note_contents') { // FIXME | ||||||
|         runAttachedRelations(entity, 'runOnNoteContentChange', entity); |         runAttachedRelations(entity, 'runOnNoteContentChange', entity); | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -206,7 +206,7 @@ function importEnex(taskContext, file, parentNote) { | |||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     function updateDates(noteId, utcDateCreated, utcDateModified) { |     function updateDates(note, utcDateCreated, utcDateModified) { | ||||||
|         // it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL |         // it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL | ||||||
|         sql.execute(` |         sql.execute(` | ||||||
|                 UPDATE notes  |                 UPDATE notes  | ||||||
| @@ -215,13 +215,13 @@ function importEnex(taskContext, file, parentNote) { | |||||||
|                     dateModified = ?, |                     dateModified = ?, | ||||||
|                     utcDateModified = ? |                     utcDateModified = ? | ||||||
|                 WHERE noteId = ?`, |                 WHERE noteId = ?`, | ||||||
|             [utcDateCreated, utcDateCreated, utcDateModified, utcDateModified, noteId]); |             [utcDateCreated, utcDateCreated, utcDateModified, utcDateModified, note.noteId]); | ||||||
|  |  | ||||||
|         sql.execute(` |         sql.execute(` | ||||||
|                 UPDATE note_contents |                 UPDATE blobs | ||||||
|                 SET utcDateModified = ? |                 SET utcDateModified = ? | ||||||
|                 WHERE noteId = ?`, |                 WHERE blobId = ?`, | ||||||
|             [utcDateModified, noteId]); |             [utcDateModified, note.blobId]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function saveNote() { |     function saveNote() { | ||||||
| @@ -287,7 +287,7 @@ function importEnex(taskContext, file, parentNote) { | |||||||
|                     resourceNote.addAttribute(attr.type, attr.name, attr.value); |                     resourceNote.addAttribute(attr.type, attr.name, attr.value); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 updateDates(resourceNote.noteId, utcDateCreated, utcDateModified); |                 updateDates(resourceNote, utcDateCreated, utcDateModified); | ||||||
|  |  | ||||||
|                 taskContext.increaseProgressCount(); |                 taskContext.increaseProgressCount(); | ||||||
|  |  | ||||||
| @@ -310,7 +310,7 @@ function importEnex(taskContext, file, parentNote) { | |||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     updateDates(imageNote.noteId, utcDateCreated, utcDateModified); |                     updateDates(imageNote, utcDateCreated, utcDateModified); | ||||||
|  |  | ||||||
|                     const imageLink = `<img src="${url}">`; |                     const imageLink = `<img src="${url}">`; | ||||||
|  |  | ||||||
| @@ -337,7 +337,7 @@ function importEnex(taskContext, file, parentNote) { | |||||||
|  |  | ||||||
|         noteService.asyncPostProcessContent(noteEntity, content); |         noteService.asyncPostProcessContent(noteEntity, content); | ||||||
|  |  | ||||||
|         updateDates(noteEntity.noteId, utcDateCreated, utcDateModified); |         updateDates(noteEntity, utcDateCreated, utcDateModified); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     saxStream.on("closetag", tag => { |     saxStream.on("closetag", tag => { | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ const treeService = require("../tree"); | |||||||
| const yauzl = require("yauzl"); | const yauzl = require("yauzl"); | ||||||
| const htmlSanitizer = require('../html_sanitizer'); | const htmlSanitizer = require('../html_sanitizer'); | ||||||
| const becca = require("../../becca/becca"); | const becca = require("../../becca/becca"); | ||||||
| const BNoteAncillary = require("../../becca/entities/bnote_ancillary"); | const BNoteAncillary = require("../../becca/entities/bnote_attachment.js"); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @param {TaskContext} taskContext |  * @param {TaskContext} taskContext | ||||||
|   | |||||||
| @@ -44,9 +44,6 @@ function eraseNoteRevisions(noteRevisionIdsToErase) { | |||||||
|  |  | ||||||
|     sql.executeMany(`DELETE FROM note_revisions WHERE noteRevisionId IN (???)`, noteRevisionIdsToErase); |     sql.executeMany(`DELETE FROM note_revisions WHERE noteRevisionId IN (???)`, noteRevisionIdsToErase); | ||||||
|     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 = 'note_revisions' AND entityId IN (???)`, noteRevisionIdsToErase); | ||||||
|  |  | ||||||
|     sql.executeMany(`DELETE FROM note_revision_contents WHERE noteRevisionId IN (???)`, noteRevisionIdsToErase); |  | ||||||
|     sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_revision_contents' AND entityId IN (???)`, noteRevisionIdsToErase); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   | |||||||
| @@ -220,7 +220,7 @@ function createNewNote(params) { | |||||||
|             entity: note |             entity: note | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         eventService.emit(eventService.ENTITY_CREATED, { |         eventService.emit(eventService.ENTITY_CREATED, { // FIXME | ||||||
|             entityName: 'note_contents', |             entityName: 'note_contents', | ||||||
|             entity: note |             entity: note | ||||||
|         }); |         }); | ||||||
| @@ -499,7 +499,7 @@ function downloadImages(noteId, content) { | |||||||
|                     asyncPostProcessContent(origNote, updatedContent); |                     asyncPostProcessContent(origNote, updatedContent); | ||||||
|  |  | ||||||
|                     eventService.emit(eventService.ENTITY_CHANGED, { |                     eventService.emit(eventService.ENTITY_CHANGED, { | ||||||
|                         entityName: 'note_contents', |                         entityName: 'note_contents', // FIXME | ||||||
|                         entity: origNote |                         entity: origNote | ||||||
|                     }); |                     }); | ||||||
|  |  | ||||||
| @@ -733,9 +733,6 @@ function eraseNotes(noteIdsToErase) { | |||||||
|     sql.executeMany(`DELETE FROM notes WHERE noteId IN (???)`, noteIdsToErase); |     sql.executeMany(`DELETE FROM notes WHERE noteId IN (???)`, noteIdsToErase); | ||||||
|     setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'notes' AND entityId IN (???)`, noteIdsToErase)); |     setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'notes' AND entityId IN (???)`, noteIdsToErase)); | ||||||
|  |  | ||||||
|     sql.executeMany(`DELETE FROM note_contents WHERE noteId IN (???)`, noteIdsToErase); |  | ||||||
|     setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'note_contents' AND entityId IN (???)`, noteIdsToErase)); |  | ||||||
|  |  | ||||||
|     // we also need to erase all "dependent" entities of the erased notes |     // we also need to erase all "dependent" entities of the erased notes | ||||||
|     const branchIdsToErase = sql.getManyRows(`SELECT branchId FROM branches WHERE noteId IN (???)`, noteIdsToErase) |     const branchIdsToErase = sql.getManyRows(`SELECT branchId FROM branches WHERE noteId IN (???)`, noteIdsToErase) | ||||||
|         .map(row => row.branchId); |         .map(row => row.branchId); | ||||||
|   | |||||||
| @@ -42,7 +42,7 @@ class NoteContentFulltextExp extends Expression { | |||||||
|  |  | ||||||
|         for (const row of sql.iterateRows(` |         for (const row of sql.iterateRows(` | ||||||
|                 SELECT noteId, type, mime, content, isProtected |                 SELECT noteId, type, mime, content, isProtected | ||||||
|                 FROM notes JOIN note_contents USING (noteId)  |                 FROM notes JOIN blobs USING (blobId)  | ||||||
|                 WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0`)) { |                 WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0`)) { | ||||||
|  |  | ||||||
|             this.findInText(row, inputNoteSet, resultNoteSet); |             this.findInText(row, inputNoteSet, resultNoteSet); | ||||||
|   | |||||||
| @@ -103,7 +103,7 @@ function loadNeededInfoFromDatabase() { | |||||||
|             noteId,  |             noteId,  | ||||||
|             LENGTH(content) AS length  |             LENGTH(content) AS length  | ||||||
|         FROM notes |         FROM notes | ||||||
|              JOIN note_contents USING(noteId)  |              JOIN blobs USING(blobId)  | ||||||
|         WHERE notes.isDeleted = 0`); |         WHERE notes.isDeleted = 0`); | ||||||
|  |  | ||||||
|     for (const {noteId, length} of noteContentLengths) { |     for (const {noteId, length} of noteContentLengths) { | ||||||
| @@ -122,7 +122,7 @@ function loadNeededInfoFromDatabase() { | |||||||
|             LENGTH(content) AS length  |             LENGTH(content) AS length  | ||||||
|         FROM notes |         FROM notes | ||||||
|              JOIN note_revisions USING(noteId)  |              JOIN note_revisions USING(noteId)  | ||||||
|              JOIN note_revision_contents USING(noteRevisionId)  |              JOIN blobs USING(blobId)  | ||||||
|         WHERE notes.isDeleted = 0`); |         WHERE notes.isDeleted = 0`); | ||||||
|  |  | ||||||
|     for (const {noteId, length} of noteRevisionContentLengths) { |     for (const {noteId, length} of noteRevisionContentLengths) { | ||||||
|   | |||||||
| @@ -321,7 +321,7 @@ function getEntityChangeRow(entityName, entityId) { | |||||||
|             throw new Error(`Entity ${entityName} ${entityId} not found.`); |             throw new Error(`Entity ${entityName} ${entityId} not found.`); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (['note_contents', 'note_revision_contents', 'note_ancillary_contents'].includes(entityName) && entity.content !== null) { |         if (entityName === 'blobs' && entity.content !== null) { | ||||||
|             if (typeof entity.content === 'string') { |             if (typeof entity.content === 'string') { | ||||||
|                 entity.content = Buffer.from(entity.content, 'UTF-8'); |                 entity.content = Buffer.from(entity.content, 'UTF-8'); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -64,7 +64,7 @@ function updateNormalEntity(remoteEntityChange, remoteEntityRow, instanceId) { | |||||||
|         || localEntityChange.utcDateChanged < remoteEntityChange.utcDateChanged |         || localEntityChange.utcDateChanged < remoteEntityChange.utcDateChanged | ||||||
|         || localEntityChange.hash !== remoteEntityChange.hash // sync error, we should still update |         || localEntityChange.hash !== remoteEntityChange.hash // sync error, we should still update | ||||||
|     ) { |     ) { | ||||||
|         if (['note_contents', 'note_revision_contents', 'note_ancillary_contents'].includes(remoteEntityChange.entityName)) { |         if (remoteEntityChange.entityName === 'blobs') { | ||||||
|             remoteEntityRow.content = handleContent(remoteEntityRow.content); |             remoteEntityRow.content = handleContent(remoteEntityRow.content); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -94,7 +94,7 @@ function updateNoteReordering(entityChange, entity, instanceId) { | |||||||
|  |  | ||||||
| function handleContent(content) { | function handleContent(content) { | ||||||
|     // we always use Buffer object which is different from normal saving - there we use simple string type for |     // we always use Buffer object which is different from normal saving - there we use simple string type for | ||||||
|     // "string notes". The problem is that in general it's not possible to detect whether a note_content |     // "string notes". The problem is that in general it's not possible to detect whether a blob content | ||||||
|     // is string note or note (syncs can arrive out of order) |     // is string note or note (syncs can arrive out of order) | ||||||
|     content = content === null ? null : Buffer.from(content, 'base64'); |     content = content === null ? null : Buffer.from(content, 'base64'); | ||||||
|  |  | ||||||
| @@ -111,13 +111,11 @@ function eraseEntity(entityChange, instanceId) { | |||||||
|  |  | ||||||
|     const entityNames = [ |     const entityNames = [ | ||||||
|         "notes", |         "notes", | ||||||
|         "note_contents", |  | ||||||
|         "branches", |         "branches", | ||||||
|         "attributes", |         "attributes", | ||||||
|         "note_revisions", |         "note_revisions", | ||||||
|         "note_revision_contents", |  | ||||||
|         "note_ancillaries", |         "note_ancillaries", | ||||||
|         "note_ancillary_contents" |         "blobs", | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     if (!entityNames.includes(entityName)) { |     if (!entityNames.includes(entityName)) { | ||||||
|   | |||||||
| @@ -147,13 +147,13 @@ function fillInAdditionalProperties(entityChange) { | |||||||
| // entities with higher number can reference the entities with lower number | // entities with higher number can reference the entities with lower number | ||||||
| const ORDERING = { | const ORDERING = { | ||||||
|     "etapi_tokens": 0, |     "etapi_tokens": 0, | ||||||
|     "attributes": 1, |     "attributes": 2, | ||||||
|     "branches": 1, |     "branches": 2, | ||||||
|     "note_contents": 1, |     "blobs": 0, | ||||||
|     "note_reordering": 1, |     "note_reordering": 2, | ||||||
|     "note_revision_contents": 2, |     "note_revisions": 2, | ||||||
|     "note_revisions": 1, |     "note_attachments": 3, | ||||||
|     "notes": 0, |     "notes": 1, | ||||||
|     "options": 0 |     "options": 0 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ const CREDENTIALS = 'shareCredentials'; | |||||||
| const isCredentials = attr => attr.type === 'label' && attr.name === CREDENTIALS; | const isCredentials = attr => attr.type === 'label' && attr.name === CREDENTIALS; | ||||||
|  |  | ||||||
| class SNote extends AbstractShacaEntity { | class SNote extends AbstractShacaEntity { | ||||||
|     constructor([noteId, title, type, mime, utcDateModified, isProtected]) { |     constructor([noteId, title, type, mime, blobId, utcDateModified, isProtected]) { | ||||||
|         super(); |         super(); | ||||||
|  |  | ||||||
|         /** @param {string} */ |         /** @param {string} */ | ||||||
| @@ -24,6 +24,8 @@ class SNote extends AbstractShacaEntity { | |||||||
|         /** @param {string} */ |         /** @param {string} */ | ||||||
|         this.mime = mime; |         this.mime = mime; | ||||||
|         /** @param {string} */ |         /** @param {string} */ | ||||||
|  |         this.blobId = blobId; | ||||||
|  |         /** @param {string} */ | ||||||
|         this.utcDateModified = utcDateModified; // used for caching of images |         this.utcDateModified = utcDateModified; // used for caching of images | ||||||
|         /** @param {boolean} */ |         /** @param {boolean} */ | ||||||
|         this.isProtected = isProtected; |         this.isProtected = isProtected; | ||||||
| @@ -92,14 +94,14 @@ class SNote extends AbstractShacaEntity { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     getContent(silentNotFoundError = false) { |     getContent(silentNotFoundError = false) { | ||||||
|         const row = sql.getRow(`SELECT content FROM note_contents WHERE noteId = ?`, [this.noteId]); |         const row = sql.getRow(`SELECT content FROM blobs WHERE blobId = ?`, [this.blobId]); | ||||||
|  |  | ||||||
|         if (!row) { |         if (!row) { | ||||||
|             if (silentNotFoundError) { |             if (silentNotFoundError) { | ||||||
|                 return undefined; |                 return undefined; | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|                 throw new Error(`Cannot find note content for noteId=${this.noteId}`); |                 throw new Error(`Cannot find note content for noteId '${this.noteId}', blobId '${this.blobId}'`); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ function load() { | |||||||
|     const noteIdStr = noteIds.map(noteId => `'${noteId}'`).join(","); |     const noteIdStr = noteIds.map(noteId => `'${noteId}'`).join(","); | ||||||
|  |  | ||||||
|     const rawNoteRows = sql.getRawRows(` |     const rawNoteRows = sql.getRawRows(` | ||||||
|         SELECT noteId, title, type, mime, utcDateModified, isProtected |         SELECT noteId, title, type, mime, blobId, utcDateModified, isProtected | ||||||
|         FROM notes  |         FROM notes  | ||||||
|         WHERE isDeleted = 0  |         WHERE isDeleted = 0  | ||||||
|           AND noteId IN (${noteIdStr})`); |           AND noteId IN (${noteIdStr})`); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user