diff --git a/spec/search/parser.spec.js b/spec/search/parser.spec.js index 6eadd2ec1..1d1e49d24 100644 --- a/spec/search/parser.spec.js +++ b/spec/search/parser.spec.js @@ -31,7 +31,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: tokens(["hello", "hi"]), expressionTokens: [], - searchContext: new SearchContext({includeNoteContent: false, excludeArchived: true}) + searchContext: new SearchContext({excludeArchived: true}) }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -45,7 +45,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: tokens(["hello", "hi"]), expressionTokens: [], - searchContext: new SearchContext({includeNoteContent: true}) + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("AndExp"); diff --git a/src/becca/becca.js b/src/becca/becca.js index ee22d03b5..c40a08c37 100644 --- a/src/becca/becca.js +++ b/src/becca/becca.js @@ -153,16 +153,25 @@ class Becca { } /** @returns {BAttachment|null} */ - getAttachment(attachmentId) { - const row = sql.getRow("SELECT * FROM attachments WHERE attachmentId = ? AND isDeleted = 0", [attachmentId]); + getAttachment(attachmentId, opts = {}) { + opts.includeContentLength = !!opts.includeContentLength; + + const query = opts.includeContentLength + ? `SELECT attachments.*, LENGTH(blobs.content) AS contentLength + FROM attachments + JOIN blobs USING (blobId) + WHERE attachmentId = ? AND isDeleted = 0` + : `SELECT * FROM attachments WHERE attachmentId = ? AND isDeleted = 0`; const BAttachment = require("./entities/battachment"); // avoiding circular dependency problems - return row ? new BAttachment(row) : null; + + return sql.getRows(query, [attachmentId]) + .map(row => new BAttachment(row))[0]; } /** @returns {BAttachment} */ - getAttachmentOrThrow(attachmentId) { - const attachment = this.getAttachment(attachmentId); + getAttachmentOrThrow(attachmentId, opts = {}) { + const attachment = this.getAttachment(attachmentId, opts); if (!attachment) { throw new NotFoundError(`Attachment '${attachmentId}' has not been found.`); } diff --git a/src/becca/entities/battachment.js b/src/becca/entities/battachment.js index cc2e30011..cc2eadf00 100644 --- a/src/becca/entities/battachment.js +++ b/src/becca/entities/battachment.js @@ -59,6 +59,9 @@ class BAttachment extends AbstractBeccaEntity { /** @type {string} */ this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; + /** @type {integer} optionally added to the entity */ + this.contentLength = row.contentLength; + this.decrypt(); } @@ -206,12 +209,14 @@ class BAttachment extends AbstractBeccaEntity { isDeleted: false, dateModified: this.dateModified, utcDateModified: this.utcDateModified, - utcDateScheduledForErasureSince: this.utcDateScheduledForErasureSince + utcDateScheduledForErasureSince: this.utcDateScheduledForErasureSince, + contentLength: this.contentLength }; } getPojoToSave() { const pojo = this.getPojo(); + delete pojo.contentLength; if (pojo.isProtected) { if (this.isDecrypted) { diff --git a/src/becca/entities/bnote.js b/src/becca/entities/bnote.js index 40bdbf308..bd22acb4e 100644 --- a/src/becca/entities/bnote.js +++ b/src/becca/entities/bnote.js @@ -1114,24 +1114,33 @@ class BNote extends AbstractBeccaEntity { } /** @returns {BAttachment[]} */ - getAttachments() { - return sql.getRows(` - SELECT attachments.* - FROM attachments - WHERE parentId = ? - AND isDeleted = 0 - ORDER BY position`, [this.noteId]) + getAttachments(opts = {}) { + opts.includeContentLength = !!opts.includeContentLength; + + const query = opts.includeContentLength + ? `SELECT attachments.*, LENGTH(blobs.content) AS contentLength + FROM attachments + JOIN blobs USING (blobId) + WHERE parentId = ? AND isDeleted = 0 + ORDER BY position` + : `SELECT * FROM attachments WHERE parentId = ? AND isDeleted = 0 ORDER BY position`; + + return sql.getRows(query, [this.noteId]) .map(row => new BAttachment(row)); } /** @returns {BAttachment|null} */ - getAttachmentById(attachmentId) { - return sql.getRows(` - SELECT attachments.* - FROM attachments - WHERE parentId = ? - AND attachmentId = ? - AND isDeleted = 0`, [this.noteId, attachmentId]) + getAttachmentById(attachmentId, opts = {}) { + opts.includeContentLength = !!opts.includeContentLength; + + const query = opts.includeContentLength + ? `SELECT attachments.*, LENGTH(blobs.content) AS contentLength + FROM attachments + JOIN blobs USING (blobId) + WHERE parentId = ? AND attachmentId = ? AND isDeleted = 0` + : `SELECT * FROM attachments WHERE parentId = ? AND attachmentId = ? AND isDeleted = 0`; + + return sql.getRows(query, [this.noteId, attachmentId]) .map(row => new BAttachment(row))[0]; } diff --git a/src/public/app/entities/fattachment.js b/src/public/app/entities/fattachment.js index becd6a24f..e565efcb3 100644 --- a/src/public/app/entities/fattachment.js +++ b/src/public/app/entities/fattachment.js @@ -23,6 +23,9 @@ class FAttachment { /** @type {string} */ this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; + /** @type {integer} optionally added to the entity */ + this.contentLength = row.contentLength; + this.froca.attachments[this.attachmentId] = this; } diff --git a/src/public/app/services/content_renderer.js b/src/public/app/services/content_renderer.js index 97496431c..3d1523dcd 100644 --- a/src/public/app/services/content_renderer.js +++ b/src/public/app/services/content_renderer.js @@ -26,7 +26,7 @@ async function getRenderedContent(entity, options = {}) { const type = getRenderingType(entity); // attachment supports only image and file/pdf/audio/video - const $renderedContent = $('