ancillary => attachment

This commit is contained in:
zadam 2023-03-16 11:03:28 +01:00
parent e16bedfab4
commit dc97400dbf
20 changed files with 161 additions and 161 deletions

View File

@ -1,6 +1,6 @@
CREATE TABLE IF NOT EXISTS "note_ancillaries" CREATE TABLE IF NOT EXISTS "note_attachments"
( (
noteAncillaryId TEXT not null primary key, noteAttachmentId TEXT not null primary key,
noteId TEXT not null, noteId TEXT not null,
name TEXT not null, name TEXT not null,
mime TEXT not null, mime TEXT not null,
@ -10,7 +10,7 @@ CREATE TABLE IF NOT EXISTS "note_ancillaries"
isDeleted INT not null, isDeleted INT not null,
`deleteId` TEXT DEFAULT NULL); `deleteId` TEXT DEFAULT NULL);
CREATE INDEX IDX_note_ancillaries_name CREATE INDEX IDX_note_attachments_name
on note_ancillaries (name); on note_attachments (name);
CREATE UNIQUE INDEX IDX_note_ancillaries_noteId_name CREATE UNIQUE INDEX IDX_note_attachments_noteId_name
on note_ancillaries (noteId, name); on note_attachments (noteId, name);

View File

@ -112,9 +112,9 @@ CREATE TABLE IF NOT EXISTS "recent_notes"
notePath TEXT not null, notePath TEXT not null,
utcDateCreated TEXT not null utcDateCreated TEXT not null
); );
CREATE TABLE IF NOT EXISTS "note_ancillaries" CREATE TABLE IF NOT EXISTS "note_attachments"
( (
noteAncillaryId TEXT not null primary key, noteAttachmentId TEXT not null primary key,
noteId TEXT not null, noteId TEXT not null,
name TEXT not null, name TEXT not null,
mime TEXT not null, mime TEXT not null,
@ -123,7 +123,7 @@ CREATE TABLE IF NOT EXISTS "note_ancillaries"
isDeleted INT not null, isDeleted INT not null,
`deleteId` TEXT DEFAULT NULL); `deleteId` TEXT DEFAULT NULL);
CREATE INDEX IDX_note_ancillaries_name CREATE INDEX IDX_note_attachments_name
on note_ancillaries (name); on note_attachments (name);
CREATE UNIQUE INDEX IDX_note_ancillaries_noteId_name CREATE UNIQUE INDEX IDX_note_attachments_noteId_name
on note_ancillaries (noteId, name); on note_attachments (noteId, name);

View File

@ -121,12 +121,12 @@ class Becca {
return row ? new BNoteRevision(row) : null; return row ? new BNoteRevision(row) : null;
} }
/** @returns {BNoteAncillary|null} */ /** @returns {BNoteAttachment|null} */
getNoteAncillary(noteAncillaryId) { getNoteAttachment(noteAttachmentId) {
const row = sql.getRow("SELECT * FROM note_ancillaries WHERE noteAncillaryId = ?", [noteAncillaryId]); const row = sql.getRow("SELECT * FROM note_attachments WHERE noteAttachmentId = ?", [noteAttachmentId]);
const BNoteAncillary = require("./entities/bnote_attachment.js"); // avoiding circular dependency problems const BNoteAttachment = require("./entities/bnote_attachment.js"); // avoiding circular dependency problems
return row ? new BNoteAncillary(row) : null; return row ? new BNoteAttachment(row) : null;
} }
/** @returns {BOption|null} */ /** @returns {BOption|null} */
@ -151,8 +151,8 @@ class Becca {
if (entityName === 'note_revisions') { if (entityName === 'note_revisions') {
return this.getNoteRevision(entityId); return this.getNoteRevision(entityId);
} else if (entityName === 'note_ancillaries') { } else if (entityName === 'note_attachments') {
return this.getNoteAncillary(entityId); return this.getNoteAttachment(entityId);
} }
const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g, const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g,

View File

@ -198,8 +198,8 @@ class BBranch extends AbstractBeccaEntity {
relation.markAsDeleted(deleteId); relation.markAsDeleted(deleteId);
} }
for (const noteAncillary of note.getNoteAncillaries()) { for (const noteAttachment of note.getNoteAttachments()) {
noteAncillary.markAsDeleted(deleteId); noteAttachment.markAsDeleted(deleteId);
} }
note.markAsDeleted(deleteId); note.markAsDeleted(deleteId);

View File

@ -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_attachment.js"); const BNoteAttachment = 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');
@ -1161,16 +1161,16 @@ class BNote extends AbstractBeccaEntity {
.map(row => new BNoteRevision(row)); .map(row => new BNoteRevision(row));
} }
/** @returns {BNoteAncillary[]} */ /** @returns {BNoteAttachment[]} */
getNoteAncillaries() { getNoteAttachments() {
return sql.getRows("SELECT * FROM note_ancillaries WHERE noteId = ? AND isDeleted = 0", [this.noteId]) return sql.getRows("SELECT * FROM note_attachments WHERE noteId = ? AND isDeleted = 0", [this.noteId])
.map(row => new BNoteAncillary(row)); .map(row => new BNoteAttachment(row));
} }
/** @returns {BNoteAncillary|undefined} */ /** @returns {BNoteAttachment|undefined} */
getNoteAncillaryByName(name) { getNoteAttachmentByName(name) {
return sql.getRows("SELECT * FROM note_ancillaries WHERE noteId = ? AND name = ? AND isDeleted = 0", [this.noteId, name]) return sql.getRows("SELECT * FROM note_attachments WHERE noteId = ? AND name = ? AND isDeleted = 0", [this.noteId, name])
.map(row => new BNoteAncillary(row)) .map(row => new BNoteAttachment(row))
[0]; [0];
} }
@ -1502,21 +1502,21 @@ class BNote extends AbstractBeccaEntity {
} }
/** /**
* @returns {BNoteAncillary} * @returns {BNoteAttachment}
*/ */
saveNoteAncillary(name, mime, content) { saveNoteAttachment(name, mime, content) {
let noteAncillary = this.getNoteAncillaryByName(name); let noteAttachment = this.getNoteAttachmentByName(name);
noteAncillary = new BNoteAncillary({ noteAttachment = new BNoteAttachment({
noteId: this.noteId, noteId: this.noteId,
name, name,
mime, mime,
isProtected: this.isProtected isProtected: this.isProtected
}); });
noteAncillary.setContent(content); noteAttachment.setContent(content);
return noteAncillary; return noteAttachment;
} }
beforeSaving() { beforeSaving() {

View File

@ -9,29 +9,29 @@ const entityChangesService = require('../../services/entity_changes');
const AbstractBeccaEntity = require("./abstract_becca_entity"); const AbstractBeccaEntity = require("./abstract_becca_entity");
/** /**
* NoteAncillary represent data related/attached to the note. Conceptually similar to attributes, but intended for * NoteAttachment represent data related/attached to the note. Conceptually similar to attributes, but intended for
* larger amounts of data and generally not accessible to the user. * larger amounts of data and generally not accessible to the user.
* *
* @extends AbstractBeccaEntity * @extends AbstractBeccaEntity
*/ */
class BNoteAncillary extends AbstractBeccaEntity { class BNoteAttachment extends AbstractBeccaEntity {
static get entityName() { return "note_ancillaries"; } static get entityName() { return "note_attachments"; }
static get primaryKeyName() { return "noteAncillaryId"; } static get primaryKeyName() { return "noteAttachmentId"; }
static get hashedProperties() { return ["noteAncillaryId", "noteId", "name", "content", "utcDateModified"]; } static get hashedProperties() { return ["noteAttachmentId", "noteId", "name", "content", "utcDateModified"]; }
constructor(row) { constructor(row) {
super(); super();
if (!row.noteId) { if (!row.noteId) {
throw new Error("'noteId' must be given to initialize a NoteAncillary entity"); throw new Error("'noteId' must be given to initialize a NoteAttachment entity");
} }
if (!row.name) { if (!row.name) {
throw new Error("'name' must be given to initialize a NoteAncillary entity"); throw new Error("'name' must be given to initialize a NoteAttachment entity");
} }
/** @type {string} needs to be set at the initialization time since it's used in the .setContent() */ /** @type {string} needs to be set at the initialization time since it's used in the .setContent() */
this.noteAncillaryId = row.noteAncillaryId || `${this.noteId}_${this.name}`; this.noteAttachmentId = row.noteAttachmentId || `${this.noteId}_${this.name}`;
/** @type {string} */ /** @type {string} */
this.noteId = row.noteId; this.noteId = row.noteId;
/** @type {string} */ /** @type {string} */
@ -55,14 +55,14 @@ class BNoteAncillary extends AbstractBeccaEntity {
/** @returns {*} */ /** @returns {*} */
getContent(silentNotFoundError = false) { getContent(silentNotFoundError = false) {
const res = sql.getRow(`SELECT content FROM note_ancillary_contents WHERE noteAncillaryId = ?`, [this.noteAncillaryId]); const res = sql.getRow(`SELECT content FROM note_attachment_contents WHERE noteAttachmentId = ?`, [this.noteAttachmentId]);
if (!res) { if (!res) {
if (silentNotFoundError) { if (silentNotFoundError) {
return undefined; return undefined;
} }
else { else {
throw new Error(`Cannot find note ancillary content for noteAncillaryId=${this.noteAncillaryId}`); throw new Error(`Cannot find note attachment content for noteAttachmentId=${this.noteAttachmentId}`);
} }
} }
@ -89,10 +89,10 @@ class BNoteAncillary extends AbstractBeccaEntity {
setContent(content) { setContent(content) {
sql.transactional(() => { sql.transactional(() => {
this.save(); // also explicitly save note_ancillary to update contentCheckSum this.save(); // also explicitly save note_attachment to update contentCheckSum
const pojo = { const pojo = {
noteAncillaryId: this.noteAncillaryId, noteAttachmentId: this.noteAttachmentId,
content: content, content: content,
utcDateModified: dateUtils.utcNowDateTime() utcDateModified: dateUtils.utcNowDateTime()
}; };
@ -101,15 +101,15 @@ class BNoteAncillary extends AbstractBeccaEntity {
if (protectedSessionService.isProtectedSessionAvailable()) { if (protectedSessionService.isProtectedSessionAvailable()) {
pojo.content = protectedSessionService.encrypt(pojo.content); pojo.content = protectedSessionService.encrypt(pojo.content);
} else { } else {
throw new Error(`Cannot update content of noteAncillaryId=${this.noteAncillaryId} since we're out of protected session.`); throw new Error(`Cannot update content of noteAttachmentId=${this.noteAttachmentId} since we're out of protected session.`);
} }
} }
sql.upsert("note_ancillary_contents", "noteAncillaryId", pojo); sql.upsert("note_attachment_contents", "noteAttachmentId", pojo);
entityChangesService.addEntityChange({ entityChangesService.addEntityChange({
entityName: 'note_ancillary_contents', entityName: 'note_attachment_contents',
entityId: this.noteAncillaryId, entityId: this.noteAttachmentId,
hash: this.contentCheckSum, // FIXME hash: this.contentCheckSum, // FIXME
isErased: false, isErased: false,
utcDateChanged: pojo.utcDateModified, utcDateChanged: pojo.utcDateModified,
@ -119,7 +119,7 @@ class BNoteAncillary extends AbstractBeccaEntity {
} }
calculateCheckSum(content) { calculateCheckSum(content) {
return utils.hash(`${this.noteAncillaryId}|${content.toString()}`); return utils.hash(`${this.noteAttachmentId}|${content.toString()}`);
} }
beforeSaving() { beforeSaving() {
@ -127,7 +127,7 @@ class BNoteAncillary extends AbstractBeccaEntity {
throw new Error(`Name must be alphanumerical, "${this.name}" given.`); throw new Error(`Name must be alphanumerical, "${this.name}" given.`);
} }
this.noteAncillaryId = `${this.noteId}_${this.name}`; this.noteAttachmentId = `${this.noteId}_${this.name}`;
super.beforeSaving(); super.beforeSaving();
@ -136,7 +136,7 @@ class BNoteAncillary extends AbstractBeccaEntity {
getPojo() { getPojo() {
return { return {
noteAncillaryId: this.noteAncillaryId, noteAttachmentId: this.noteAttachmentId,
noteId: this.noteId, noteId: this.noteId,
name: this.name, name: this.name,
mime: this.mime, mime: this.mime,
@ -155,4 +155,4 @@ class BNoteAncillary extends AbstractBeccaEntity {
} }
} }
module.exports = BNoteAncillary; module.exports = BNoteAttachment;

View File

@ -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_attachment.js"); const BNoteAttachment = 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');
@ -12,7 +12,7 @@ const ENTITY_NAME_TO_ENTITY = {
"branches": BBranch, "branches": BBranch,
"notes": BNote, "notes": BNote,
"note_revisions": BNoteRevision, "note_revisions": BNoteRevision,
"note_ancillaries": BNoteAncillary, "note_attachments": BNoteAttachment,
"recent_notes": BRecentNote, "recent_notes": BRecentNote,
"etapi_tokens": BEtapiToken, "etapi_tokens": BEtapiToken,
"options": BOption "options": BOption

View File

@ -34,7 +34,7 @@ async function processEntityChanges(entityChanges) {
loadResults.addOption(ec.entity.name); loadResults.addOption(ec.entity.name);
} }
else if (['etapi_tokens', 'note_ancillaries'].includes(ec.entityName)) { else if (['etapi_tokens', 'note_attachments'].includes(ec.entityName)) {
// NOOP // NOOP
} }
else { else {

View File

@ -28,7 +28,7 @@ const TPL = `
<a data-trigger-command="renderActiveNote" class="dropdown-item render-note-button"><kbd data-command="renderActiveNote"></kbd> Re-render note</a> <a data-trigger-command="renderActiveNote" class="dropdown-item render-note-button"><kbd data-command="renderActiveNote"></kbd> Re-render note</a>
<a data-trigger-command="findInText" class="dropdown-item find-in-text-button">Search in note <kbd data-command="findInText"></a> <a data-trigger-command="findInText" class="dropdown-item find-in-text-button">Search in note <kbd data-command="findInText"></a>
<a data-trigger-command="showNoteSource" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a> <a data-trigger-command="showNoteSource" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a>
<a data-trigger-command="showNoteAncillaries" class="dropdown-item"><kbd data-command="showNoteAncillaries"></kbd> Note ancillaries</a> <a data-trigger-command="showNoteAttachments" class="dropdown-item"><kbd data-command="showNoteAttachments"></kbd> Note attachments</a>
<a data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button"><kbd data-command="openNoteExternally"></kbd> Open note externally</a> <a data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button"><kbd data-command="openNoteExternally"></kbd> Open note externally</a>
<a class="dropdown-item import-files-button">Import files</a> <a class="dropdown-item import-files-button">Import files</a>
<a class="dropdown-item export-note-button">Export note</a> <a class="dropdown-item export-note-button">Export note</a>

View File

@ -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/attachments.js"; import AttachmentsTypeWidget from "./type_widgets/attachments.js";
const TPL = ` const TPL = `
<div class="note-detail"> <div class="note-detail">
@ -63,7 +63,7 @@ const typeWidgetClasses = {
'webView': WebViewTypeWidget, 'webView': WebViewTypeWidget,
'doc': DocTypeWidget, 'doc': DocTypeWidget,
'contentWidget': ContentWidgetTypeWidget, 'contentWidget': ContentWidgetTypeWidget,
'ancillaries': AncillariesTypeWidget 'attachments': AttachmentsTypeWidget
}; };
export default class NoteDetailWidget extends NoteContextAwareWidget { export default class NoteDetailWidget extends NoteContextAwareWidget {
@ -191,8 +191,8 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
if (type === 'text' && this.noteContext.viewScope.viewMode === 'source') { if (type === 'text' && this.noteContext.viewScope.viewMode === 'source') {
type = 'readOnlyCode'; type = 'readOnlyCode';
} else if (this.noteContext.viewScope.viewMode === 'ancillaries') { } else if (this.noteContext.viewScope.viewMode === 'attachments') {
type = 'ancillaries'; type = 'attachments';
} else if (type === 'text' && await this.noteContext.isReadOnly()) { } else if (type === 'text' && await this.noteContext.isReadOnly()) {
type = 'readOnlyText'; type = 'readOnlyText';
} else if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) { } else if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) {

View File

@ -2,13 +2,13 @@ import TypeWidget from "./type_widget.js";
import server from "../../services/server.js"; import server from "../../services/server.js";
const TPL = ` const TPL = `
<div class="note-ancillaries note-detail-printable"> <div class="note-attachments note-detail-printable">
<style> <style>
.note-ancillaries { .note-attachments {
padding: 15px; padding: 15px;
} }
.ancillary-content { .attachment-content {
max-height: 400px; max-height: 400px;
background: var(--accented-background-color); background: var(--accented-background-color);
padding: 10px; padding: 10px;
@ -16,26 +16,26 @@ const TPL = `
margin-bottom: 10px; margin-bottom: 10px;
} }
.ancillary-details th { .attachment-details th {
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
} }
</style> </style>
<div class="alert alert-info" style="margin: 10px 0 10px 0; padding: 20px;"> <div class="alert alert-info" style="margin: 10px 0 10px 0; padding: 20px;">
Note ancillaries are pieces of data attached to a given note, providing ancillary support. Note attachments are pieces of data attached to a given note, providing attachment support.
This view is useful for diagnostics. This view is useful for diagnostics.
</div> </div>
<div class="note-ancillary-list"></div> <div class="note-attachment-list"></div>
</div>`; </div>`;
export default class AncillariesTypeWidget extends TypeWidget { export default class AttachmentsTypeWidget extends TypeWidget {
static getType() { return "ancillaries"; } static getType() { return "attachments"; }
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$list = this.$widget.find('.note-ancillary-list'); this.$list = this.$widget.find('.note-attachment-list');
super.doRender(); super.doRender();
} }
@ -43,35 +43,35 @@ export default class AncillariesTypeWidget extends TypeWidget {
async doRefresh(note) { async doRefresh(note) {
this.$list.empty(); this.$list.empty();
const ancillaries = await server.get(`notes/${this.noteId}/ancillaries?includeContent=true`); const attachments = await server.get(`notes/${this.noteId}/attachments?includeContent=true`);
if (ancillaries.length === 0) { if (attachments.length === 0) {
this.$list.html("<strong>This note has no ancillaries.</strong>"); this.$list.html("<strong>This note has no attachments.</strong>");
return; return;
} }
for (const ancillary of ancillaries) { for (const attachment of attachments) {
this.$list.append( this.$list.append(
$('<div class="note-ancillary-wrapper">') $('<div class="note-attachment-wrapper">')
.append( .append(
$('<h4>').append($('<span class="ancillary-name">').text(ancillary.name)) $('<h4>').append($('<span class="attachment-name">').text(attachment.name))
) )
.append( .append(
$('<table class="ancillary-details">') $('<table class="attachment-details">')
.append( .append(
$('<tr>') $('<tr>')
.append($('<th>').text('Length:')) .append($('<th>').text('Length:'))
.append($('<td>').text(ancillary.contentLength)) .append($('<td>').text(attachment.contentLength))
.append($('<th>').text('MIME:')) .append($('<th>').text('MIME:'))
.append($('<td>').text(ancillary.mime)) .append($('<td>').text(attachment.mime))
.append($('<th>').text('Date modified:')) .append($('<th>').text('Date modified:'))
.append($('<td>').text(ancillary.utcDateModified)) .append($('<td>').text(attachment.utcDateModified))
) )
) )
.append( .append(
$('<pre class="ancillary-content">') $('<pre class="attachment-content">')
.text(ancillary.content) .text(attachment.content)
) )
); );
} }

View File

@ -54,10 +54,10 @@ function createNote(req) {
} }
function updateNoteData(req) { function updateNoteData(req) {
const {content, ancillaries} = req.body; const {content, attachments} = req.body;
const {noteId} = req.params; const {noteId} = req.params;
return noteService.updateNoteData(noteId, content, ancillaries); return noteService.updateNoteData(noteId, content, attachments);
} }
function deleteNote(req) { function deleteNote(req) {
@ -127,7 +127,7 @@ function setNoteTypeMime(req) {
note.save(); note.save();
} }
function getNoteAncillaries(req) { function getNoteAttachments(req) {
const includeContent = req.query.includeContent === 'true'; const includeContent = req.query.includeContent === 'true';
const {noteId} = req.params; const {noteId} = req.params;
@ -137,19 +137,19 @@ function getNoteAncillaries(req) {
throw new NotFoundError(`Note '${noteId}' doesn't exist.`); throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
} }
const noteAncillaries = note.getNoteAncillaries(); const noteAttachments = note.getNoteAttachments();
return noteAncillaries.map(ancillary => { return noteAttachments.map(attachment => {
const pojo = ancillary.getPojo(); const pojo = attachment.getPojo();
if (includeContent && utils.isStringNote(null, ancillary.mime)) { if (includeContent && utils.isStringNote(null, attachment.mime)) {
pojo.content = ancillary.getContent()?.toString(); pojo.content = attachment.getContent()?.toString();
pojo.contentLength = pojo.content.length; pojo.contentLength = pojo.content.length;
const MAX_ANCILLARY_LENGTH = 1_000_000; const MAX_ATTACHMENT_LENGTH = 1_000_000;
if (pojo.content.length > MAX_ANCILLARY_LENGTH) { if (pojo.content.length > MAX_ATTACHMENT_LENGTH) {
pojo.content = pojo.content.substring(0, MAX_ANCILLARY_LENGTH); pojo.content = pojo.content.substring(0, MAX_ATTACHMENT_LENGTH);
} }
} }
@ -157,7 +157,7 @@ function getNoteAncillaries(req) {
}); });
} }
function saveNoteAncillary(req) { function saveNoteAttachment(req) {
const {noteId, name} = req.params; const {noteId, name} = req.params;
const {mime, content} = req.body; const {mime, content} = req.body;
@ -167,7 +167,7 @@ function saveNoteAncillary(req) {
throw new NotFoundError(`Note '${noteId}' doesn't exist.`); throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
} }
note.saveNoteAncillary(name, mime, content); note.saveNoteAttachment(name, mime, content);
} }
function getRelationMap(req) { function getRelationMap(req) {
@ -384,6 +384,6 @@ module.exports = {
getDeleteNotesPreview, getDeleteNotesPreview,
uploadModifiedFile, uploadModifiedFile,
forceSaveNoteRevision, forceSaveNoteRevision,
getNoteAncillaries, getNoteAttachments,
saveNoteAncillary saveNoteAttachment
}; };

View File

@ -113,9 +113,9 @@ function forceNoteSync(req) {
entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId); entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId);
} }
for (const noteAncillaryId of sql.getColumn("SELECT noteAncillaryId FROM note_ancillaries WHERE noteId = ?", [noteId])) { for (const noteAttachmentId of sql.getColumn("SELECT noteAttachmentId FROM note_attachments WHERE noteId = ?", [noteId])) {
sql.execute(`UPDATE note_ancillaries SET utcDateModified = ? WHERE noteAncillaryId = ?`, [now, noteAncillaryId]); sql.execute(`UPDATE note_attachments SET utcDateModified = ? WHERE noteAttachmentId = ?`, [now, noteAttachmentId]);
entityChangesService.moveEntityChangeToTop('note_ancillaries', noteAncillaryId); entityChangesService.moveEntityChangeToTop('note_attachments', noteAttachmentId);
} }
log.info(`Forcing note sync for ${noteId}`); log.info(`Forcing note sync for ${noteId}`);

View File

@ -126,8 +126,8 @@ function register(app) {
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);
apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime); apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime);
apiRoute(GET, '/api/notes/:noteId/ancillaries', notesApiRoute.getNoteAncillaries); apiRoute(GET, '/api/notes/:noteId/attachments', notesApiRoute.getNoteAttachments);
apiRoute(PUT, '/api/notes/:noteId/ancillaries/:name', notesApiRoute.saveNoteAncillary); apiRoute(PUT, '/api/notes/:noteId/attachments/:name', notesApiRoute.saveNoteAttachment);
apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions); apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions);
apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions); apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions);
apiRoute(GET, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision); apiRoute(GET, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision);

View File

@ -215,21 +215,21 @@ class ConsistencyChecks {
}); });
this.findAndFixIssues(` this.findAndFixIssues(`
SELECT noteAncillaryId, note_ancillaries.noteId AS noteId SELECT noteAttachmentId, note_attachments.noteId AS noteId
FROM note_ancillaries FROM note_attachments
LEFT JOIN notes USING (noteId) LEFT JOIN notes USING (noteId)
WHERE notes.noteId IS NULL WHERE notes.noteId IS NULL
AND note_ancillaries.isDeleted = 0`, AND note_attachments.isDeleted = 0`,
({noteAncillaryId, noteId}) => { ({noteAttachmentId, noteId}) => {
if (this.autoFix) { if (this.autoFix) {
const noteAncillary = becca.getNoteAncillary(noteAncillaryId); const noteAttachment = becca.getNoteAttachment(noteAttachmentId);
noteAncillary.markAsDeleted(); noteAttachment.markAsDeleted();
this.reloadNeeded = false; this.reloadNeeded = false;
logFix(`Note ancillary '${noteAncillaryId}' has been deleted since it references missing note '${noteId}'`); logFix(`Note attachment '${noteAttachmentId}' has been deleted since it references missing note '${noteId}'`);
} else { } else {
logError(`Note ancillary '${noteAncillaryId}' references missing note '${noteId}'`); logError(`Note attachment '${noteAttachmentId}' references missing note '${noteId}'`);
} }
}); });
} }
@ -341,22 +341,22 @@ class ConsistencyChecks {
}); });
this.findAndFixIssues(` this.findAndFixIssues(`
SELECT noteAncillaryId, SELECT noteAttachmentId,
note_ancillaries.noteId AS noteId note_attachments.noteId AS noteId
FROM note_ancillaries FROM note_attachments
JOIN notes USING (noteId) JOIN notes USING (noteId)
WHERE notes.isDeleted = 1 WHERE notes.isDeleted = 1
AND note_ancillaries.isDeleted = 0`, AND note_attachments.isDeleted = 0`,
({noteAncillaryId, noteId}) => { ({noteAttachmentId, noteId}) => {
if (this.autoFix) { if (this.autoFix) {
const noteAncillary = becca.getNoteAncillary(noteAncillaryId); const noteAttachment = becca.getNoteAttachment(noteAttachmentId);
noteAncillary.markAsDeleted(); noteAttachment.markAsDeleted();
this.reloadNeeded = false; this.reloadNeeded = false;
logFix(`Note ancillary '${noteAncillaryId}' has been deleted since associated note '${noteId}' is deleted.`); logFix(`Note attachment '${noteAttachmentId}' has been deleted since associated note '${noteId}' is deleted.`);
} else { } else {
logError(`Note ancillary '${noteAncillaryId}' is not deleted even though associated note '${noteId}' is deleted.`) logError(`Note attachment '${noteAttachmentId}' is not deleted even though associated note '${noteId}' is deleted.`)
} }
}); });
} }
@ -657,7 +657,7 @@ class ConsistencyChecks {
findEntityChangeIssues() { findEntityChangeIssues() {
this.runEntityChangeChecks("notes", "noteId"); this.runEntityChangeChecks("notes", "noteId");
this.runEntityChangeChecks("note_revisions", "noteRevisionId"); this.runEntityChangeChecks("note_revisions", "noteRevisionId");
this.runEntityChangeChecks("note_ancillaries", "noteAncillaryId"); this.runEntityChangeChecks("note_attachments", "noteAttachmentId");
this.runEntityChangeChecks("blobs", "blobId"); this.runEntityChangeChecks("blobs", "blobId");
this.runEntityChangeChecks("branches", "branchId"); this.runEntityChangeChecks("branches", "branchId");
this.runEntityChangeChecks("attributes", "attributeId"); this.runEntityChangeChecks("attributes", "attributeId");
@ -754,7 +754,7 @@ class ConsistencyChecks {
return `${tableName}: ${count}`; return `${tableName}: ${count}`;
} }
const tables = [ "notes", "note_revisions", "note_ancillaries", "branches", "attributes", "etapi_tokens" ]; const tables = [ "notes", "note_revisions", "note_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(", ")}`);
} }

View File

@ -149,7 +149,7 @@ function fillAllEntityChanges() {
fillEntityChanges("notes", "noteId"); fillEntityChanges("notes", "noteId");
fillEntityChanges("branches", "branchId"); fillEntityChanges("branches", "branchId");
fillEntityChanges("note_revisions", "noteRevisionId"); fillEntityChanges("note_revisions", "noteRevisionId");
fillEntityChanges("note_ancillaries", "noteAncillaryId"); fillEntityChanges("note_attachments", "noteAttachmentId");
fillEntityChanges("blobs", "blobId"); fillEntityChanges("blobs", "blobId");
fillEntityChanges("attributes", "attributeId"); fillEntityChanges("attributes", "attributeId");
fillEntityChanges("etapi_tokens", "etapiTokenId"); fillEntityChanges("etapi_tokens", "etapiTokenId");

View File

@ -170,19 +170,19 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
meta.dataFileName = getDataFileName(note.type, note.mime, baseFileName, existingFileNames); meta.dataFileName = getDataFileName(note.type, note.mime, baseFileName, existingFileNames);
} }
const ancillaries = note.getNoteAncillaries(); const attachments = note.getNoteAttachments();
if (ancillaries.length > 0) { if (attachments.length > 0) {
meta.ancillaries = ancillaries meta.attachments = attachments
.filter(ancillary => ["canvasSvg", "mermaidSvg"].includes(ancillary.name)) .filter(attachment => ["canvasSvg", "mermaidSvg"].includes(attachment.name))
.map(ancillary => ({ .map(attachment => ({
name: ancillary.name, name: attachment.name,
mime: ancillary.mime, mime: attachment.mime,
dataFileName: getDataFileName( dataFileName: getDataFileName(
null, null,
ancillary.mime, attachment.mime,
baseFileName + "_" + ancillary.name, baseFileName + "_" + attachment.name,
existingFileNames existingFileNames
) )
})); }));
@ -337,12 +337,12 @@ ${markdownContent}`;
taskContext.increaseProgressCount(); taskContext.increaseProgressCount();
for (const ancillaryMeta of noteMeta.ancillaries || []) { for (const attachmentMeta of noteMeta.attachments || []) {
const noteAncillary = note.getNoteAncillaryByName(ancillaryMeta.name); const noteAttachment = note.getNoteAttachmentByName(attachmentMeta.name);
const content = noteAncillary.getContent(); const content = noteAttachment.getContent();
archive.append(content, { archive.append(content, {
name: filePathPrefix + ancillaryMeta.dataFileName, name: filePathPrefix + attachmentMeta.dataFileName,
date: dateUtils.parseDateTime(note.utcDateModified) date: dateUtils.parseDateTime(note.utcDateModified)
}); });
} }

View File

@ -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_attachment.js"); const BNoteAttachment = require("../../becca/entities/bnote_attachment.js");
/** /**
* @param {TaskContext} taskContext * @param {TaskContext} taskContext
@ -65,7 +65,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
}; };
let parent; let parent;
let ancillaryMeta = false; let attachmentMeta = false;
for (const segment of pathSegments) { for (const segment of pathSegments) {
if (!cursor || !cursor.children || cursor.children.length === 0) { if (!cursor || !cursor.children || cursor.children.length === 0) {
@ -77,10 +77,10 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
if (!cursor) { if (!cursor) {
for (const file of parent.children) { for (const file of parent.children) {
for (const ancillary of file.ancillaries || []) { for (const attachment of file.attachments || []) {
if (ancillary.dataFileName === segment) { if (attachment.dataFileName === segment) {
cursor = file; cursor = file;
ancillaryMeta = ancillary; attachmentMeta = attachment;
break; break;
} }
} }
@ -95,7 +95,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
return { return {
parentNoteMeta: parent, parentNoteMeta: parent,
noteMeta: cursor, noteMeta: cursor,
ancillaryMeta attachmentMeta
}; };
} }
@ -370,7 +370,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
} }
function saveNote(filePath, content) { function saveNote(filePath, content) {
const {parentNoteMeta, noteMeta, ancillaryMeta} = getMeta(filePath); const {parentNoteMeta, noteMeta, attachmentMeta} = getMeta(filePath);
if (noteMeta?.noImport) { if (noteMeta?.noImport) {
return; return;
@ -378,14 +378,14 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
const noteId = getNoteId(noteMeta, filePath); const noteId = getNoteId(noteMeta, filePath);
if (ancillaryMeta) { if (attachmentMeta) {
const noteAncillary = new BNoteAncillary({ const noteAttachment = new BNoteAttachment({
noteId, noteId,
name: ancillaryMeta.name, name: attachmentMeta.name,
mime: ancillaryMeta.mime mime: attachmentMeta.mime
}); });
noteAncillary.setContent(content); noteAttachment.setContent(content);
return; return;
} }

View File

@ -4,27 +4,27 @@ const log = require("./log");
/** /**
* @param {BNote} note * @param {BNote} note
*/ */
function protectNoteAncillaries(note) { function protectNoteAttachments(note) {
for (const noteAncillary of note.getNoteAncillaries()) { for (const noteAttachment of note.getNoteAttachments()) {
if (note.isProtected !== noteAncillary.isProtected) { if (note.isProtected !== noteAttachment.isProtected) {
if (!protectedSession.isProtectedSessionAvailable()) { if (!protectedSession.isProtectedSessionAvailable()) {
log.error("Protected session is not available to fix note ancillaries."); log.error("Protected session is not available to fix note attachments.");
return; return;
} }
try { try {
const content = noteAncillary.getContent(); const content = noteAttachment.getContent();
noteAncillary.isProtected = note.isProtected; noteAttachment.isProtected = note.isProtected;
// this will force de/encryption // this will force de/encryption
noteAncillary.setContent(content); noteAttachment.setContent(content);
noteAncillary.save(); noteAttachment.save();
} }
catch (e) { catch (e) {
log.error(`Could not un/protect note ancillary ID = ${noteAncillary.noteAncillaryId}`); log.error(`Could not un/protect note attachment ID = ${noteAttachment.noteAttachmentId}`);
throw e; throw e;
} }
@ -33,5 +33,5 @@ function protectNoteAncillaries(note) {
} }
module.exports = { module.exports = {
protectNoteAncillaries protectNoteAttachments
} }

View File

@ -114,7 +114,7 @@ function eraseEntity(entityChange, instanceId) {
"branches", "branches",
"attributes", "attributes",
"note_revisions", "note_revisions",
"note_ancillaries", "note_attachments",
"blobs", "blobs",
]; ];