diff --git a/db/migrations/0151__add_isCleaned_to_note.sql b/db/migrations/0151__add_isErased_to_note.sql similarity index 100% rename from db/migrations/0151__add_isCleaned_to_note.sql rename to db/migrations/0151__add_isErased_to_note.sql diff --git a/db/migrations/0152__add_contentLength_to_note.sql b/db/migrations/0152__add_contentLength_to_note.sql new file mode 100644 index 000000000..4d4cf0c8c --- /dev/null +++ b/db/migrations/0152__add_contentLength_to_note.sql @@ -0,0 +1,34 @@ +CREATE TABLE IF NOT EXISTS "notes_mig" ( + `noteId` TEXT NOT NULL, + `title` TEXT NOT NULL DEFAULT "note", + `contentLength` INT NOT NULL, + `isProtected` INT NOT NULL DEFAULT 0, + `type` TEXT NOT NULL DEFAULT 'text', + `mime` TEXT NOT NULL DEFAULT 'text/html', + `hash` TEXT DEFAULT "" NOT NULL, + `isDeleted` INT NOT NULL DEFAULT 0, + `isErased` INT NOT NULL DEFAULT 0, + `dateCreated` TEXT NOT NULL, + `dateModified` TEXT NOT NULL, + `utcDateCreated` TEXT NOT NULL, + `utcDateModified` TEXT NOT NULL, + PRIMARY KEY(`noteId`)); + +INSERT INTO notes_mig (noteId, title, contentLength, isProtected, type, mime, hash, isDeleted, isErased, dateCreated, dateModified, utcDateCreated, utcDateModified) +SELECT noteId, title, -1, isProtected, type, mime, hash, isDeleted, isErased, dateCreated, dateModified, utcDateCreated, utcDateModified FROM notes; + +DROP TABLE notes; +ALTER TABLE notes_mig RENAME TO notes; + +UPDATE notes SET contentLength = (SELECT COALESCE(LENGTH(content), 0) FROM note_contents WHERE note_contents.noteId = notes.noteId); + +CREATE INDEX `IDX_notes_isDeleted` ON `notes` (`isDeleted`); +CREATE INDEX `IDX_notes_title` ON `notes` (`title`); +CREATE INDEX `IDX_notes_type` ON `notes` (`type`); +CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`); +CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`); +CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`); +CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`); + +-- should be OK since sync protocol changes so all instances must upgrade +UPDATE attributes SET isDeleted = 1 WHERE name = 'fileSize'; \ No newline at end of file diff --git a/src/entities/api_token.js b/src/entities/api_token.js index ff11f277f..cc643d99c 100644 --- a/src/entities/api_token.js +++ b/src/entities/api_token.js @@ -6,10 +6,10 @@ const dateUtils = require('../services/date_utils'); /** * ApiToken is an entity representing token used to authenticate against Trilium API from client applications. Currently used only by Trilium Sender. * - * @param {string} apiTokenId - primary key - * @param {string} token - * @param {boolean} isDeleted - true if API token is deleted - * @param {string} utcDateCreated + * @property {string} apiTokenId - primary key + * @property {string} token + * @property {boolean} isDeleted - true if API token is deleted + * @property {string} utcDateCreated * * @extends Entity */ diff --git a/src/entities/attribute.js b/src/entities/attribute.js index c31e2ce09..0bc68afa2 100644 --- a/src/entities/attribute.js +++ b/src/entities/attribute.js @@ -8,16 +8,16 @@ const sql = require('../services/sql'); /** * Attribute is key value pair owned by a note. * - * @param {string} attributeId - * @param {string} noteId - * @param {string} type - * @param {string} name - * @param {string} value - * @param {int} position - * @param {boolean} isInheritable - * @param {boolean} isDeleted - * @param {string} utcDateCreated - * @param {string} utcDateModified + * @property {string} attributeId + * @property {string} noteId + * @property {string} type + * @property {string} name + * @property {string} value + * @property {int} position + * @property {boolean} isInheritable + * @property {boolean} isDeleted + * @property {string} utcDateCreated + * @property {string} utcDateModified * * @extends Entity */ diff --git a/src/entities/branch.js b/src/entities/branch.js index 8c1b14d32..4567f0ca1 100644 --- a/src/entities/branch.js +++ b/src/entities/branch.js @@ -9,15 +9,15 @@ const sql = require('../services/sql'); * Branch represents note's placement in the tree - it's essentially pair of noteId and parentNoteId. * Each note can have multiple (at least one) branches, meaning it can be placed into multiple places in the tree. * - * @param {string} branchId - primary key - * @param {string} noteId - * @param {string} parentNoteId - * @param {int} notePosition - * @param {string} prefix - * @param {boolean} isExpanded - * @param {boolean} isDeleted - * @param {string} utcDateModified - * @param {string} utcDateCreated + * @property {string} branchId - primary key + * @property {string} noteId + * @property {string} parentNoteId + * @property {int} notePosition + * @property {string} prefix + * @property {boolean} isExpanded + * @property {boolean} isDeleted + * @property {string} utcDateModified + * @property {string} utcDateCreated * * @extends Entity */ diff --git a/src/entities/note.js b/src/entities/note.js index 641b764f1..60b603cf2 100644 --- a/src/entities/note.js +++ b/src/entities/note.js @@ -21,6 +21,7 @@ const RELATION_DEFINITION = 'relation-definition'; * @property {string} type - one of "text", "code", "file" or "render" * @property {string} mime - MIME type, e.g. "text/html" * @property {string} title - note title + * @property {int} contentLength - length of content * @property {boolean} isProtected - true if note is protected * @property {boolean} isDeleted - true if note is deleted * @property {boolean} isErased - true if note's content is erased after it has been deleted @@ -115,6 +116,7 @@ class Note extends Entity { async setContent(content) { // force updating note itself so that dateModified is represented correctly even for the content this.forcedChange = true; + this.contentLength = content.length; await this.save(); this.content = content; @@ -739,6 +741,10 @@ class Note extends Entity { this.utcDateCreated = dateUtils.utcNowDateTime(); } + if (this.contentLength === undefined) { + this.contentLength = -1; + } + super.beforeSaving(); if (this.isChanged) { diff --git a/src/entities/note_revision.js b/src/entities/note_revision.js index 72263d782..8de57a76b 100644 --- a/src/entities/note_revision.js +++ b/src/entities/note_revision.js @@ -11,17 +11,18 @@ const syncTableService = require('../services/sync_table'); /** * NoteRevision represents snapshot of note's title and content at some point in the past. It's used for seamless note versioning. * - * @param {string} noteRevisionId - * @param {string} noteId - * @param {string} type - * @param {string} mime - * @param {string} title - * @param {string} isProtected - * @param {string} dateLastEdited - * @param {string} dateCreated - * @param {string} utcDateLastEdited - * @param {string} utcDateCreated - * @param {string} utcDateModified + * @property {string} noteRevisionId + * @property {string} noteId + * @property {string} type + * @property {string} mime + * @property {string} title + * @property {int} contentLength - length of content + * @property {string} isProtected + * @property {string} dateLastEdited + * @property {string} dateCreated + * @property {string} utcDateLastEdited + * @property {string} utcDateCreated + * @property {string} utcDateModified * * @extends Entity */ diff --git a/src/entities/option.js b/src/entities/option.js index 25457f241..1b64311d3 100644 --- a/src/entities/option.js +++ b/src/entities/option.js @@ -6,11 +6,11 @@ const dateUtils = require('../services/date_utils'); /** * Option represents name-value pair, either directly configurable by the user or some system property. * - * @param {string} name - * @param {string} value - * @param {boolean} isSynced - * @param {string} utcDateModified - * @param {string} utcDateCreated + * @property {string} name + * @property {string} value + * @property {boolean} isSynced + * @property {string} utcDateModified + * @property {string} utcDateCreated * * @extends Entity */ diff --git a/src/entities/recent_note.js b/src/entities/recent_note.js index eab6cb77a..45012a731 100644 --- a/src/entities/recent_note.js +++ b/src/entities/recent_note.js @@ -6,10 +6,10 @@ const dateUtils = require('../services/date_utils'); /** * RecentNote represents recently visited note. * - * @param {string} noteId - * @param {string} notePath - * @param {boolean} isDeleted - * @param {string} utcDateModified + * @property {string} noteId + * @property {string} notePath + * @property {boolean} isDeleted + * @property {string} utcDateModified * * @extends Entity */ diff --git a/src/public/javascripts/entities/note_short.js b/src/public/javascripts/entities/note_short.js index a29844803..3a5c74337 100644 --- a/src/public/javascripts/entities/note_short.js +++ b/src/public/javascripts/entities/note_short.js @@ -21,6 +21,8 @@ class NoteShort { this.noteId = row.noteId; /** @param {string} */ this.title = row.title; + /** @param {int} */ + this.contentLength = row.contentLength; /** @param {boolean} */ this.isProtected = row.isProtected; /** @param {string} one of 'text', 'code', 'file' or 'render' */ diff --git a/src/public/javascripts/services/note_detail_file.js b/src/public/javascripts/services/note_detail_file.js index 69e8f111f..a13ab13d9 100644 --- a/src/public/javascripts/services/note_detail_file.js +++ b/src/public/javascripts/services/note_detail_file.js @@ -39,7 +39,7 @@ class NoteDetailFile { this.$fileNoteId.text(this.ctx.note.noteId); this.$fileName.text(attributeMap.originalFileName || "?"); - this.$fileSize.text((attributeMap.fileSize || "?") + " bytes"); + this.$fileSize.text(this.ctx.note.contentLength + " bytes"); this.$fileType.text(this.ctx.note.mime); if (this.ctx.note.content) { diff --git a/src/public/javascripts/services/note_detail_image.js b/src/public/javascripts/services/note_detail_image.js index 457e90f5a..ee4cf00eb 100644 --- a/src/public/javascripts/services/note_detail_image.js +++ b/src/public/javascripts/services/note_detail_image.js @@ -81,7 +81,7 @@ class NoteDetailImage { this.$component.show(); this.$fileName.text(attributeMap.originalFileName || "?"); - this.$fileSize.text((attributeMap.fileSize || "?") + " bytes"); + this.$fileSize.text(this.ctx.note.contentLength + " bytes"); this.$fileType.text(this.ctx.note.mime); const imageHash = this.ctx.note.utcDateModified.replace(" ", "_"); diff --git a/src/routes/api/file_upload.js b/src/routes/api/file_upload.js index 8c68232c1..e5a9a6a01 100644 --- a/src/routes/api/file_upload.js +++ b/src/routes/api/file_upload.js @@ -23,10 +23,7 @@ async function uploadFile(req) { isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), type: mime.startsWith("image/") ? 'image' : 'file', mime: file.mimetype, - attributes: [ - { type: "label", name: "originalFileName", value: originalName }, - { type: "label", name: "fileSize", value: size } - ] + attributes: [{ type: "label", name: "originalFileName", value: originalName }] }); return { diff --git a/src/services/app_info.js b/src/services/app_info.js index b1c19ab5d..94be796c4 100644 --- a/src/services/app_info.js +++ b/src/services/app_info.js @@ -4,7 +4,7 @@ const build = require('./build'); const packageJson = require('../../package'); const {TRILIUM_DATA_DIR} = require('./data_dir'); -const APP_DB_VERSION = 151; +const APP_DB_VERSION = 152; const SYNC_VERSION = 11; const CLIPPER_PROTOCOL_VERSION = "1.0"; diff --git a/src/services/image.js b/src/services/image.js index fac5ea1ff..8ac59d79c 100644 --- a/src/services/image.js +++ b/src/services/image.js @@ -60,7 +60,6 @@ async function updateImage(noteId, uploadBuffer, originalName) { await note.setContent(buffer); await note.setLabel('originalFileName', originalName); - await note.setLabel('fileSize', buffer.byteLength); await noteService.protectNoteRevisions(note); } @@ -77,10 +76,7 @@ async function saveImage(parentNoteId, uploadBuffer, originalName, shrinkImageSw type: 'image', isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), mime: 'image/' + imageFormat.ext.toLowerCase(), - attributes: [ - { type: 'label', name: 'originalFileName', value: originalName }, - { type: 'label', name: 'fileSize', value: buffer.byteLength } - ] + attributes: [{ type: 'label', name: 'originalFileName', value: originalName }] }); return { diff --git a/src/services/import/enex.js b/src/services/import/enex.js index 2f4fa7614..c898498d9 100644 --- a/src/services/import/enex.js +++ b/src/services/import/enex.js @@ -139,12 +139,6 @@ async function importEnex(taskContext, file, parentNote) { text = text.replace(/\s/g, ''); resource.content = utils.fromBase64(text); - - resource.attributes.push({ - type: 'label', - name: 'fileSize', - value: resource.content.length - }); } else if (currentTag === 'mime') { resource.mime = text.toLowerCase(); diff --git a/src/services/import/single.js b/src/services/import/single.js index ed98f01ee..18c871fd0 100644 --- a/src/services/import/single.js +++ b/src/services/import/single.js @@ -48,10 +48,7 @@ async function importFile(taskContext, file, parentNote) { isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), type: 'file', mime: mimeService.getMime(originalName) || file.mimetype, - attributes: [ - { type: "label", name: "originalFileName", value: originalName }, - { type: "label", name: "fileSize", value: size } - ] + attributes: [{ type: "label", name: "originalFileName", value: originalName }] }); taskContext.increaseProgressCount(); diff --git a/src/services/import/tar.js b/src/services/import/tar.js index e8118b678..b459d8c17 100644 --- a/src/services/import/tar.js +++ b/src/services/import/tar.js @@ -352,13 +352,6 @@ async function importTar(taskContext, fileBuffer, importRootNote) { name: 'originalFileName', value: path.basename(filePath) }); - - attributes.push({ - noteId, - type: 'label', - name: 'fileSize', - value: content.byteLength - }); } } diff --git a/src/services/notes.js b/src/services/notes.js index 07942e4c1..c36ec1ca9 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -465,9 +465,10 @@ async function eraseDeletedNotes() { // it's better to not use repository for this because it will complain about saving protected notes // out of protected session + // setting contentLength to zero would serve no benefit and it leaves potentially useful trail await sql.executeMany(` UPDATE notes - SET isErased = 1, + SET isErased = 1, utcDateModified = '${utcNowDateTime}', dateModified = '${localNowDateTime}' WHERE noteId IN (???)`, noteIdsToErase);