From d83005fe4d8a84e39e394d74ec5321ab21e10ad3 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 16 Mar 2023 16:37:31 +0100 Subject: [PATCH] improved saving attachment --- src/becca/entities/abstract_becca_entity.js | 7 ++-- src/becca/entities/battachment.js | 16 ++++----- src/becca/entities/bnote.js | 39 ++++++++++++++------- src/becca/entities/bnote_revision.js | 11 +++--- src/routes/api/notes.js | 6 ++-- src/routes/routes.js | 2 +- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/becca/entities/abstract_becca_entity.js b/src/becca/entities/abstract_becca_entity.js index 918e31d74..ee2064515 100644 --- a/src/becca/entities/abstract_becca_entity.js +++ b/src/becca/entities/abstract_becca_entity.js @@ -125,7 +125,10 @@ class AbstractBeccaEntity { } /** @protected */ - _setContent(content) { + _setContent(content, opts = {}) { + // client code asks to save entity even if blobId didn't change (something else was changed) + opts.forceSave = !!opts.forceSave; + if (content === null || content === undefined) { throw new Error(`Cannot set null content to ${this.constructor.primaryKeyName} '${this[this.constructor.primaryKeyName]}'`); } @@ -149,7 +152,7 @@ class AbstractBeccaEntity { sql.transactional(() => { let newBlobId = this._saveBlob(content); - if (newBlobId !== this.blobId) { + if (newBlobId !== this.blobId || opts.forceSave) { this.blobId = newBlobId; this.save(); } diff --git a/src/becca/entities/battachment.js b/src/becca/entities/battachment.js index 92f190c55..5f48761f9 100644 --- a/src/becca/entities/battachment.js +++ b/src/becca/entities/battachment.js @@ -1,11 +1,8 @@ "use strict"; -const protectedSessionService = require('../../services/protected_session'); const utils = require('../../services/utils'); -const sql = require('../../services/sql'); const dateUtils = require('../../services/date_utils'); const becca = require('../becca'); -const entityChangesService = require('../../services/entity_changes'); const AbstractBeccaEntity = require("./abstract_becca_entity"); /** @@ -34,7 +31,7 @@ class BAttachment extends AbstractBeccaEntity { } /** @type {string} */ - this.attachmentId = row.attachmentId || `${this.noteId}_${this.name}`; // FIXME + this.attachmentId = row.attachmentId; /** @type {string} either noteId or noteRevisionId to which this attachment belongs */ this.parentId = row.parentId; /** @type {string} */ @@ -65,8 +62,13 @@ class BAttachment extends AbstractBeccaEntity { return this._getContent(); } - setContent(content) { - this._setContent(content); + /** + * @param content + * @param {object} [opts] + * @param {object} [opts.forceSave=false] - will also save this BAttachment entity + */ + setContent(content, opts) { + this._setContent(content, opts); } calculateCheckSum(content) { @@ -78,8 +80,6 @@ class BAttachment extends AbstractBeccaEntity { throw new Error(`Name must be alphanumerical, "${this.name}" given.`); } - this.attachmentId = `${this.noteId}_${this.name}`; // FIXME - super.beforeSaving(); this.utcDateModified = dateUtils.utcNowDateTime(); diff --git a/src/becca/entities/bnote.js b/src/becca/entities/bnote.js index 2b310b5a8..47ec91148 100644 --- a/src/becca/entities/bnote.js +++ b/src/becca/entities/bnote.js @@ -5,14 +5,13 @@ const log = require('../../services/log'); const sql = require('../../services/sql'); const utils = require('../../services/utils'); const dateUtils = require('../../services/date_utils'); -const entityChangesService = require('../../services/entity_changes'); const AbstractBeccaEntity = require("./abstract_becca_entity"); const BNoteRevision = require("./bnote_revision"); const BAttachment = require("./battachment"); const TaskContext = require("../../services/task_context"); const dayjs = require("dayjs"); const utc = require('dayjs/plugin/utc'); -const eventService = require("../../services/events"); +const NotFoundError = require("../../errors/not_found_error.js"); dayjs.extend(utc); const LABEL = 'label'; @@ -238,8 +237,13 @@ class BNote extends AbstractBeccaEntity { return ['text', 'code', 'relationMap', 'canvas', 'mermaid'].includes(this.type); } - setContent(content) { - this._setContent(content) + /** + * @param content + * @param {object} [opts] + * @param {object} [opts.forceSave=false] - will also save this BNote entity + */ + setContent(content, opts) { + this._setContent(content, opts); } setJsonContent(content) { @@ -1414,17 +1418,26 @@ class BNote extends AbstractBeccaEntity { /** * @returns {BAttachment} */ - saveAttachment(name, mime, content) { - let attachment = this.getAttachmentByName(name); + saveAttachment({attachmentId, role, mime, title, content}) { + let attachment; - attachment = new BAttachment({ - noteId: this.noteId, - name, - mime, - isProtected: this.isProtected - }); + if (attachmentId) { + attachment = this.becca.getAttachment(attachmentId); - attachment.setContent(content); + if (!attachment) { + throw new NotFoundError(`Attachment '${attachmentId}' has not been found.`); + } + } else { + attachment = new BAttachment({ + noteId: this.noteId, + title, + role, + mime, + isProtected: this.isProtected + }); + } + + attachment.setContent(content, { forceSave: true }); return attachment; } diff --git a/src/becca/entities/bnote_revision.js b/src/becca/entities/bnote_revision.js index 6e8fedfc4..6457a37da 100644 --- a/src/becca/entities/bnote_revision.js +++ b/src/becca/entities/bnote_revision.js @@ -2,10 +2,8 @@ const protectedSessionService = require('../../services/protected_session'); const utils = require('../../services/utils'); -const sql = require('../../services/sql'); const dateUtils = require('../../services/date_utils'); const becca = require('../becca'); -const entityChangesService = require('../../services/entity_changes'); const AbstractBeccaEntity = require("./abstract_becca_entity"); /** @@ -79,8 +77,13 @@ class BNoteRevision extends AbstractBeccaEntity { return this._getContent(); } - setContent(content) { - this._setContent(content); + /** + * @param content + * @param {object} [opts] + * @param {object} [opts.forceSave=false] - will also save this BNoteRevision entity + */ + setContent(content, opts) { + this._setContent(content, opts); } beforeSaving() { diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js index 2e9bb12c7..d52897950 100644 --- a/src/routes/api/notes.js +++ b/src/routes/api/notes.js @@ -158,8 +158,8 @@ function getAttachments(req) { } function saveAttachment(req) { - const {noteId, name} = req.params; - const {mime, content} = req.body; + const {noteId} = req.params; + const {attachmentId, role, mime, title, content} = req.body; const note = becca.getNote(noteId); @@ -167,7 +167,7 @@ function saveAttachment(req) { throw new NotFoundError(`Note '${noteId}' doesn't exist.`); } - note.saveAttachment(name, mime, content); + note.saveAttachment({attachmentId, role, mime, title, content}); } function getRelationMap(req) { diff --git a/src/routes/routes.js b/src/routes/routes.js index 979916551..8a91952ab 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -127,7 +127,7 @@ function register(app) { apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote); apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime); apiRoute(GET, '/api/notes/:noteId/attachments', notesApiRoute.getAttachments); - apiRoute(PUT, '/api/notes/:noteId/attachments/:name', notesApiRoute.saveAttachment); + apiRoute(POST, '/api/notes/:noteId/attachments', notesApiRoute.saveAttachment); apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions); apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions); apiRoute(GET, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision);