mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
refactored note attachment into note ancillary
This commit is contained in:
parent
78954268ab
commit
37ba76fdd8
@ -4,7 +4,7 @@ UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share'
|
||||
UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL;
|
||||
UPDATE note_revisions SET title = 'title';
|
||||
UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL;
|
||||
UPDATE note_attachment_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' WHERE type = 'label' AND name NOT IN('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'workspaceInbox', 'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteContentChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'inherit', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
|
||||
UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN ('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'workspaceInbox', 'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteContentChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'inherit', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
|
||||
|
@ -1,6 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS "note_attachments"
|
||||
CREATE TABLE IF NOT EXISTS "note_ancillaries"
|
||||
(
|
||||
noteAttachmentId TEXT not null primary key,
|
||||
noteAncillaryId TEXT not null primary key,
|
||||
noteId TEXT not null,
|
||||
name TEXT not null,
|
||||
mime TEXT not null,
|
||||
@ -10,11 +10,11 @@ CREATE TABLE IF NOT EXISTS "note_attachments"
|
||||
isDeleted INT not null,
|
||||
`deleteId` TEXT DEFAULT NULL);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "note_attachment_contents" (`noteAttachmentId` TEXT NOT NULL PRIMARY KEY,
|
||||
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_attachments_name
|
||||
on note_attachments (name);
|
||||
CREATE UNIQUE INDEX IDX_note_attachments_noteId_name
|
||||
on note_attachments (noteId, name);
|
||||
CREATE INDEX IDX_note_ancillaries_name
|
||||
on note_ancillaries (name);
|
||||
CREATE UNIQUE INDEX IDX_note_ancillaries_noteId_name
|
||||
on note_ancillaries (noteId, name);
|
@ -29,11 +29,11 @@ module.exports = async () => {
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
log.info(`Could not create a note attachment for canvas "${note.noteId}" with error: ${e.message} ${e.stack}`);
|
||||
log.info(`Could not create a note ancillary for canvas "${note.noteId}" with error: ${e.message} ${e.stack}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
note.saveNoteAttachment('canvasSvg', 'image/svg+xml', svg);
|
||||
note.saveNoteAncillary('canvasSvg', 'image/svg+xml', svg);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
@ -112,9 +112,9 @@ CREATE TABLE IF NOT EXISTS "recent_notes"
|
||||
notePath TEXT not null,
|
||||
utcDateCreated TEXT not null
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "note_attachments"
|
||||
CREATE TABLE IF NOT EXISTS "note_ancillaries"
|
||||
(
|
||||
noteAttachmentId TEXT not null primary key,
|
||||
noteAncillaryId TEXT not null primary key,
|
||||
noteId TEXT not null,
|
||||
name TEXT not null,
|
||||
mime TEXT not null,
|
||||
@ -123,10 +123,10 @@ CREATE TABLE IF NOT EXISTS "note_attachments"
|
||||
utcDateModified TEXT not null,
|
||||
isDeleted INT not null,
|
||||
`deleteId` TEXT DEFAULT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "note_attachment_contents" (`noteAttachmentId` TEXT NOT NULL PRIMARY KEY,
|
||||
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_attachments_name
|
||||
on note_attachments (name);
|
||||
CREATE UNIQUE INDEX IDX_note_attachments_noteId_name
|
||||
on note_attachments (noteId, name);
|
||||
CREATE INDEX IDX_note_ancillaries_name
|
||||
on note_ancillaries (name);
|
||||
CREATE UNIQUE INDEX IDX_note_ancillaries_noteId_name
|
||||
on note_ancillaries (noteId, name);
|
||||
|
1
package-lock.json
generated
1
package-lock.json
generated
@ -5,6 +5,7 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "trilium",
|
||||
"version": "0.58.7",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0-only",
|
||||
|
@ -122,12 +122,12 @@ class Becca {
|
||||
return row ? new BNoteRevision(row) : null;
|
||||
}
|
||||
|
||||
/** @returns {BNoteAttachment|null} */
|
||||
getNoteAttachment(noteAttachmentId) {
|
||||
const row = sql.getRow("SELECT * FROM note_attachments WHERE noteAttachmentId = ?", [noteAttachmentId]);
|
||||
/** @returns {BNoteAncillary|null} */
|
||||
getNoteAncillary(noteAncillaryId) {
|
||||
const row = sql.getRow("SELECT * FROM note_ancillaries WHERE noteAncillaryId = ?", [noteAncillaryId]);
|
||||
|
||||
const BNoteAttachment = require("./entities/bnote_attachment"); // avoiding circular dependency problems
|
||||
return row ? new BNoteAttachment(row) : null;
|
||||
const BNoteAncillary = require("./entities/bnote_ancillary"); // avoiding circular dependency problems
|
||||
return row ? new BNoteAncillary(row) : null;
|
||||
}
|
||||
|
||||
/** @returns {BOption|null} */
|
||||
@ -152,8 +152,8 @@ class Becca {
|
||||
|
||||
if (entityName === 'note_revisions') {
|
||||
return this.getNoteRevision(entityId);
|
||||
} else if (entityName === 'note_attachments') {
|
||||
return this.getNoteAttachment(entityId);
|
||||
} else if (entityName === 'note_ancillaries') {
|
||||
return this.getNoteAncillary(entityId);
|
||||
}
|
||||
|
||||
const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g,
|
||||
|
@ -198,8 +198,8 @@ class BBranch extends AbstractBeccaEntity {
|
||||
relation.markAsDeleted(deleteId);
|
||||
}
|
||||
|
||||
for (const noteAttachment of note.getNoteAttachments()) {
|
||||
noteAttachment.markAsDeleted(deleteId);
|
||||
for (const noteAncillary of note.getNoteAncillaries()) {
|
||||
noteAncillary.markAsDeleted(deleteId);
|
||||
}
|
||||
|
||||
note.markAsDeleted(deleteId);
|
||||
|
@ -8,7 +8,7 @@ const dateUtils = require('../../services/date_utils');
|
||||
const entityChangesService = require('../../services/entity_changes');
|
||||
const AbstractBeccaEntity = require("./abstract_becca_entity");
|
||||
const BNoteRevision = require("./bnote_revision");
|
||||
const BNoteAttachment = require("./bnote_attachment");
|
||||
const BNoteAncillary = require("./bnote_ancillary");
|
||||
const TaskContext = require("../../services/task_context");
|
||||
const dayjs = require("dayjs");
|
||||
const utc = require('dayjs/plugin/utc');
|
||||
@ -19,7 +19,7 @@ const LABEL = 'label';
|
||||
const RELATION = 'relation';
|
||||
|
||||
/**
|
||||
* Trilium's main entity which can represent text note, image, code note, file attachment etc.
|
||||
* Trilium's main entity which can represent text note, image, code note, file ancillary etc.
|
||||
*
|
||||
* @extends AbstractBeccaEntity
|
||||
*/
|
||||
@ -337,7 +337,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
return this.mime === "application/json";
|
||||
}
|
||||
|
||||
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
|
||||
/** @returns {boolean} true if this note is JavaScript (code or ancillary) */
|
||||
isJavaScript() {
|
||||
return (this.type === "code" || this.type === "file" || this.type === 'launcher')
|
||||
&& (this.mime.startsWith("application/javascript")
|
||||
@ -1136,16 +1136,16 @@ class BNote extends AbstractBeccaEntity {
|
||||
.map(row => new BNoteRevision(row));
|
||||
}
|
||||
|
||||
/** @returns {BNoteAttachment[]} */
|
||||
getNoteAttachments() {
|
||||
return sql.getRows("SELECT * FROM note_attachments WHERE noteId = ? AND isDeleted = 0", [this.noteId])
|
||||
.map(row => new BNoteAttachment(row));
|
||||
/** @returns {BNoteAncillary[]} */
|
||||
getNoteAncillaries() {
|
||||
return sql.getRows("SELECT * FROM note_ancillaries WHERE noteId = ? AND isDeleted = 0", [this.noteId])
|
||||
.map(row => new BNoteAncillary(row));
|
||||
}
|
||||
|
||||
/** @returns {BNoteAttachment|undefined} */
|
||||
getNoteAttachmentByName(name) {
|
||||
return sql.getRows("SELECT * FROM note_attachments WHERE noteId = ? AND name = ? AND isDeleted = 0", [this.noteId, name])
|
||||
.map(row => new BNoteAttachment(row))
|
||||
/** @returns {BNoteAncillary|undefined} */
|
||||
getNoteAncillaryByName(name) {
|
||||
return sql.getRows("SELECT * FROM note_ancillaries WHERE noteId = ? AND name = ? AND isDeleted = 0", [this.noteId, name])
|
||||
.map(row => new BNoteAncillary(row))
|
||||
[0];
|
||||
}
|
||||
|
||||
@ -1479,28 +1479,28 @@ class BNote extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {BNoteAttachment}
|
||||
* @returns {BNoteAncillary}
|
||||
*/
|
||||
saveNoteAttachment(name, mime, content) {
|
||||
let noteAttachment = this.getNoteAttachmentByName(name);
|
||||
saveNoteAncillary(name, mime, content) {
|
||||
let noteAncillary = this.getNoteAncillaryByName(name);
|
||||
|
||||
if (noteAttachment
|
||||
&& noteAttachment.mime === mime
|
||||
&& noteAttachment.contentCheckSum === noteAttachment.calculateCheckSum(content)) {
|
||||
if (noteAncillary
|
||||
&& noteAncillary.mime === mime
|
||||
&& noteAncillary.contentCheckSum === noteAncillary.calculateCheckSum(content)) {
|
||||
|
||||
return noteAttachment; // no change
|
||||
return noteAncillary; // no change
|
||||
}
|
||||
|
||||
noteAttachment = new BNoteAttachment({
|
||||
noteAncillary = new BNoteAncillary({
|
||||
noteId: this.noteId,
|
||||
name,
|
||||
mime,
|
||||
isProtected: this.isProtected
|
||||
});
|
||||
|
||||
noteAttachment.setContent(content);
|
||||
noteAncillary.setContent(content);
|
||||
|
||||
return noteAttachment;
|
||||
return noteAncillary;
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
|
@ -9,29 +9,29 @@ const entityChangesService = require('../../services/entity_changes');
|
||||
const AbstractBeccaEntity = require("./abstract_becca_entity");
|
||||
|
||||
/**
|
||||
* NoteAttachment represent data related/attached to the note. Conceptually similar to attributes, but intended for
|
||||
* NoteAncillary 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.
|
||||
*
|
||||
* @extends AbstractBeccaEntity
|
||||
*/
|
||||
class BNoteAttachment extends AbstractBeccaEntity {
|
||||
static get entityName() { return "note_attachments"; }
|
||||
static get primaryKeyName() { return "noteAttachmentId"; }
|
||||
static get hashedProperties() { return ["noteAttachmentId", "noteId", "name", "content", "utcDateModified"]; }
|
||||
class BNoteAncillary extends AbstractBeccaEntity {
|
||||
static get entityName() { return "note_ancillaries"; }
|
||||
static get primaryKeyName() { return "noteAncillaryId"; }
|
||||
static get hashedProperties() { return ["noteAncillaryId", "noteId", "name", "content", "utcDateModified"]; }
|
||||
|
||||
constructor(row) {
|
||||
super();
|
||||
|
||||
if (!row.noteId) {
|
||||
throw new Error("'noteId' must be given to initialize a NoteAttachment entity");
|
||||
throw new Error("'noteId' must be given to initialize a NoteAncillary entity");
|
||||
}
|
||||
|
||||
if (!row.name) {
|
||||
throw new Error("'name' must be given to initialize a NoteAttachment entity");
|
||||
throw new Error("'name' must be given to initialize a NoteAncillary entity");
|
||||
}
|
||||
|
||||
/** @type {string} needs to be set at the initialization time since it's used in the .setContent() */
|
||||
this.noteAttachmentId = row.noteAttachmentId || `${this.noteId}_${this.name}`;
|
||||
this.noteAncillaryId = row.noteAncillaryId || `${this.noteId}_${this.name}`;
|
||||
/** @type {string} */
|
||||
this.noteId = row.noteId;
|
||||
/** @type {string} */
|
||||
@ -57,14 +57,14 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
||||
|
||||
/** @returns {*} */
|
||||
getContent(silentNotFoundError = false) {
|
||||
const res = sql.getRow(`SELECT content FROM note_attachment_contents WHERE noteAttachmentId = ?`, [this.noteAttachmentId]);
|
||||
const res = sql.getRow(`SELECT content FROM note_ancillary_contents WHERE noteAncillaryId = ?`, [this.noteAncillaryId]);
|
||||
|
||||
if (!res) {
|
||||
if (silentNotFoundError) {
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
throw new Error(`Cannot find note attachment content for noteAttachmentId=${this.noteAttachmentId}`);
|
||||
throw new Error(`Cannot find note ancillary content for noteAncillaryId=${this.noteAncillaryId}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,10 +92,10 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
||||
setContent(content) {
|
||||
sql.transactional(() => {
|
||||
this.contentCheckSum = this.calculateCheckSum(content);
|
||||
this.save(); // also explicitly save note_attachment to update contentCheckSum
|
||||
this.save(); // also explicitly save note_ancillary to update contentCheckSum
|
||||
|
||||
const pojo = {
|
||||
noteAttachmentId: this.noteAttachmentId,
|
||||
noteAncillaryId: this.noteAncillaryId,
|
||||
content: content,
|
||||
utcDateModified: dateUtils.utcNowDateTime()
|
||||
};
|
||||
@ -104,15 +104,15 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
||||
if (protectedSessionService.isProtectedSessionAvailable()) {
|
||||
pojo.content = protectedSessionService.encrypt(pojo.content);
|
||||
} else {
|
||||
throw new Error(`Cannot update content of noteAttachmentId=${this.noteAttachmentId} since we're out of protected session.`);
|
||||
throw new Error(`Cannot update content of noteAncillaryId=${this.noteAncillaryId} since we're out of protected session.`);
|
||||
}
|
||||
}
|
||||
|
||||
sql.upsert("note_attachment_contents", "noteAttachmentId", pojo);
|
||||
sql.upsert("note_ancillary_contents", "noteAncillaryId", pojo);
|
||||
|
||||
entityChangesService.addEntityChange({
|
||||
entityName: 'note_attachment_contents',
|
||||
entityId: this.noteAttachmentId,
|
||||
entityName: 'note_ancillary_contents',
|
||||
entityId: this.noteAncillaryId,
|
||||
hash: this.contentCheckSum,
|
||||
isErased: false,
|
||||
utcDateChanged: pojo.utcDateModified,
|
||||
@ -122,7 +122,7 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
calculateCheckSum(content) {
|
||||
return utils.hash(`${this.noteAttachmentId}|${content.toString()}`);
|
||||
return utils.hash(`${this.noteAncillaryId}|${content.toString()}`);
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
@ -130,7 +130,7 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
||||
throw new Error(`Name must be alphanumerical, "${this.name}" given.`);
|
||||
}
|
||||
|
||||
this.noteAttachmentId = `${this.noteId}_${this.name}`;
|
||||
this.noteAncillaryId = `${this.noteId}_${this.name}`;
|
||||
|
||||
super.beforeSaving();
|
||||
|
||||
@ -139,7 +139,7 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
||||
|
||||
getPojo() {
|
||||
return {
|
||||
noteAttachmentId: this.noteAttachmentId,
|
||||
noteAncillaryId: this.noteAncillaryId,
|
||||
noteId: this.noteId,
|
||||
name: this.name,
|
||||
mime: this.mime,
|
||||
@ -159,4 +159,4 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BNoteAttachment;
|
||||
module.exports = BNoteAncillary;
|
@ -1,6 +1,6 @@
|
||||
const BNote = require('./entities/bnote');
|
||||
const BNoteRevision = require('./entities/bnote_revision');
|
||||
const BNoteAttachment = require("./entities/bnote_attachment");
|
||||
const BNoteAncillary = require("./entities/bnote_ancillary");
|
||||
const BBranch = require('./entities/bbranch');
|
||||
const BAttribute = require('./entities/battribute');
|
||||
const BRecentNote = require('./entities/brecent_note');
|
||||
@ -14,8 +14,8 @@ const ENTITY_NAME_TO_ENTITY = {
|
||||
"note_contents": BNote,
|
||||
"note_revisions": BNoteRevision,
|
||||
"note_revision_contents": BNoteRevision,
|
||||
"note_attachments": BNoteAttachment,
|
||||
"note_attachment_contents": BNoteAttachment,
|
||||
"note_ancillaries": BNoteAncillary,
|
||||
"note_ancillary_contents": BNoteAncillary,
|
||||
"recent_notes": BRecentNote,
|
||||
"etapi_tokens": BEtapiToken,
|
||||
"options": BOption
|
||||
|
@ -801,7 +801,7 @@ class FNote {
|
||||
return labels.length > 0 ? labels[0].value : "";
|
||||
}
|
||||
|
||||
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
|
||||
/** @returns {boolean} true if this note is JavaScript (code or ancillary) */
|
||||
isJavaScript() {
|
||||
return (this.type === "code" || this.type === "file" || this.type === 'launcher')
|
||||
&& (this.mime.startsWith("application/javascript")
|
||||
|
@ -36,7 +36,7 @@ async function processEntityChanges(entityChanges) {
|
||||
|
||||
loadResults.addOption(ec.entity.name);
|
||||
}
|
||||
else if (['etapi_tokens', 'note_attachments', 'note_attachment_contents'].includes(ec.entityName)) {
|
||||
else if (['etapi_tokens', 'note_ancillaries', 'note_ancillary_contents'].includes(ec.entityName)) {
|
||||
// NOOP
|
||||
}
|
||||
else {
|
||||
|
@ -78,9 +78,9 @@ export default class MermaidWidget extends NoteContextAwareWidget {
|
||||
this.$display.html(renderedSvg);
|
||||
|
||||
// not awaiting intentionally
|
||||
// this is pretty hacky since we update attachment on render
|
||||
// this is pretty hacky since we update ancillary on render
|
||||
// but if nothing changed this should not trigger DB write and sync
|
||||
server.put(`notes/${note.noteId}/attachments/mermaidSvg`, {
|
||||
server.put(`notes/${note.noteId}/ancillaries/mermaidSvg`, {
|
||||
mime: 'image/svg+xml',
|
||||
content: renderedSvg
|
||||
});
|
||||
|
@ -284,7 +284,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
||||
|
||||
return {
|
||||
content: JSON.stringify(content),
|
||||
attachments: [
|
||||
ancillaries: [
|
||||
{
|
||||
name: 'canvasSvg',
|
||||
mime: 'image/svg+xml',
|
||||
|
@ -587,7 +587,7 @@ export default class RelationMapTypeWidget extends TypeWidget {
|
||||
}
|
||||
|
||||
getData() {
|
||||
// TODO: save also image as attachment
|
||||
// TODO: save also image as ancillary
|
||||
return {
|
||||
content: JSON.stringify(this.mapData)
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ export default class TypeWidget extends NoteContextAwareWidget {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Object>|*} promise resolving note data. Note data is an object with content and attachments.
|
||||
* @returns {Promise<Object>|*} promise resolving note data. Note data is an object with content and ancillaries.
|
||||
*/
|
||||
getData() {}
|
||||
|
||||
|
@ -54,10 +54,10 @@ function createNote(req) {
|
||||
}
|
||||
|
||||
function updateNoteData(req) {
|
||||
const {content, attachments} = req.body;
|
||||
const {content, ancillaries} = req.body;
|
||||
const {noteId} = req.params;
|
||||
|
||||
return noteService.updateNoteData(noteId, content, attachments);
|
||||
return noteService.updateNoteData(noteId, content, ancillaries);
|
||||
}
|
||||
|
||||
function deleteNote(req) {
|
||||
@ -127,7 +127,7 @@ function setNoteTypeMime(req) {
|
||||
note.save();
|
||||
}
|
||||
|
||||
function saveNoteAttachment(req) {
|
||||
function saveNoteAncillary(req) {
|
||||
const {noteId, name} = req.params;
|
||||
const {mime, content} = req.body;
|
||||
|
||||
@ -137,7 +137,7 @@ function saveNoteAttachment(req) {
|
||||
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
|
||||
}
|
||||
|
||||
note.saveNoteAttachment(name, mime, content);
|
||||
note.saveNoteAncillary(name, mime, content);
|
||||
}
|
||||
|
||||
function getRelationMap(req) {
|
||||
@ -354,5 +354,5 @@ module.exports = {
|
||||
getDeleteNotesPreview,
|
||||
uploadModifiedFile,
|
||||
forceSaveNoteRevision,
|
||||
saveNoteAttachment
|
||||
saveNoteAncillary
|
||||
};
|
||||
|
@ -114,12 +114,12 @@ function forceNoteSync(req) {
|
||||
entityChangesService.moveEntityChangeToTop('note_revision_contents', noteRevisionId);
|
||||
}
|
||||
|
||||
for (const noteAttachmentId of sql.getColumn("SELECT noteAttachmentId FROM note_attachments WHERE noteId = ?", [noteId])) {
|
||||
sql.execute(`UPDATE note_attachments SET utcDateModified = ? WHERE noteAttachmentId = ?`, [now, noteAttachmentId]);
|
||||
entityChangesService.moveEntityChangeToTop('note_attachments', noteAttachmentId);
|
||||
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]);
|
||||
entityChangesService.moveEntityChangeToTop('note_ancillaries', noteAncillaryId);
|
||||
|
||||
sql.execute(`UPDATE note_attachment_contents SET utcDateModified = ? WHERE noteAttachmentId = ?`, [now, noteAttachmentId]);
|
||||
entityChangesService.moveEntityChangeToTop('note_attachment_contents', noteAttachmentId);
|
||||
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}`);
|
||||
|
@ -126,7 +126,7 @@ function register(app) {
|
||||
apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes);
|
||||
apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote);
|
||||
apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime);
|
||||
apiRoute(PUT, '/api/notes/:noteId/attachments/:name', notesApiRoute.saveNoteAttachment);
|
||||
apiRoute(PUT, '/api/notes/:noteId/ancillaries/:name', notesApiRoute.saveNoteAncillary);
|
||||
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);
|
||||
|
@ -200,21 +200,21 @@ class ConsistencyChecks {
|
||||
});
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT noteAttachmentId, note_attachments.noteId AS noteId
|
||||
FROM note_attachments
|
||||
SELECT noteAncillaryId, note_ancillaries.noteId AS noteId
|
||||
FROM note_ancillaries
|
||||
LEFT JOIN notes USING (noteId)
|
||||
WHERE notes.noteId IS NULL
|
||||
AND note_attachments.isDeleted = 0`,
|
||||
({noteAttachmentId, noteId}) => {
|
||||
AND note_ancillaries.isDeleted = 0`,
|
||||
({noteAncillaryId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const noteAttachment = becca.getNoteAttachment(noteAttachmentId);
|
||||
noteAttachment.markAsDeleted();
|
||||
const noteAncillary = becca.getNoteAncillary(noteAncillaryId);
|
||||
noteAncillary.markAsDeleted();
|
||||
|
||||
this.reloadNeeded = false;
|
||||
|
||||
logFix(`Note attachment '${noteAttachmentId}' has been deleted since it references missing note '${noteId}'`);
|
||||
logFix(`Note ancillary '${noteAncillaryId}' has been deleted since it references missing note '${noteId}'`);
|
||||
} else {
|
||||
logError(`Note attachment '${noteAttachmentId}' references missing note '${noteId}'`);
|
||||
logError(`Note ancillary '${noteAncillaryId}' references missing note '${noteId}'`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -326,22 +326,22 @@ class ConsistencyChecks {
|
||||
});
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT noteAttachmentId,
|
||||
note_attachments.noteId AS noteId
|
||||
FROM note_attachments
|
||||
SELECT noteAncillaryId,
|
||||
note_ancillaries.noteId AS noteId
|
||||
FROM note_ancillaries
|
||||
JOIN notes USING (noteId)
|
||||
WHERE notes.isDeleted = 1
|
||||
AND note_attachments.isDeleted = 0`,
|
||||
({noteAttachmentId, noteId}) => {
|
||||
AND note_ancillaries.isDeleted = 0`,
|
||||
({noteAncillaryId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const noteAttachment = becca.getNoteAttachment(noteAttachmentId);
|
||||
noteAttachment.markAsDeleted();
|
||||
const noteAncillary = becca.getNoteAncillary(noteAncillaryId);
|
||||
noteAncillary.markAsDeleted();
|
||||
|
||||
this.reloadNeeded = false;
|
||||
|
||||
logFix(`Note attachment '${noteAttachmentId}' has been deleted since associated note '${noteId}' is deleted.`);
|
||||
logFix(`Note ancillary '${noteAncillaryId}' has been deleted since associated note '${noteId}' is deleted.`);
|
||||
} else {
|
||||
logError(`Note attachment '${noteAttachmentId}' is not deleted even though associated note '${noteId}' is deleted.`)
|
||||
logError(`Note ancillary '${noteAncillaryId}' is not deleted even though associated note '${noteId}' is deleted.`)
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -637,8 +637,8 @@ class ConsistencyChecks {
|
||||
this.runEntityChangeChecks("note_contents", "noteId");
|
||||
this.runEntityChangeChecks("note_revisions", "noteRevisionId");
|
||||
this.runEntityChangeChecks("note_revision_contents", "noteRevisionId");
|
||||
this.runEntityChangeChecks("note_attachments", "noteAttachmentId");
|
||||
this.runEntityChangeChecks("note_attachment_contents", "noteAttachmentId");
|
||||
this.runEntityChangeChecks("note_ancillaries", "noteAncillaryId");
|
||||
this.runEntityChangeChecks("note_ancillary_contents", "noteAncillaryId");
|
||||
this.runEntityChangeChecks("branches", "branchId");
|
||||
this.runEntityChangeChecks("attributes", "attributeId");
|
||||
this.runEntityChangeChecks("etapi_tokens", "etapiTokenId");
|
||||
@ -734,7 +734,7 @@ class ConsistencyChecks {
|
||||
return `${tableName}: ${count}`;
|
||||
}
|
||||
|
||||
const tables = [ "notes", "note_revisions", "note_attachments", "branches", "attributes", "etapi_tokens" ];
|
||||
const tables = [ "notes", "note_revisions", "note_ancillaries", "branches", "attributes", "etapi_tokens" ];
|
||||
|
||||
log.info(`Table counts: ${tables.map(tableName => getTableRowCount(tableName)).join(", ")}`);
|
||||
}
|
||||
|
@ -128,8 +128,8 @@ function fillAllEntityChanges() {
|
||||
fillEntityChanges("branches", "branchId");
|
||||
fillEntityChanges("note_revisions", "noteRevisionId");
|
||||
fillEntityChanges("note_revision_contents", "noteRevisionId");
|
||||
fillEntityChanges("note_attachments", "noteAttachmentId");
|
||||
fillEntityChanges("note_attachment_contents", "noteAttachmentId");
|
||||
fillEntityChanges("note_ancillaries", "noteAncillaryId");
|
||||
fillEntityChanges("note_ancillary_contents", "noteAncillaryId");
|
||||
fillEntityChanges("attributes", "attributeId");
|
||||
fillEntityChanges("etapi_tokens", "etapiTokenId");
|
||||
fillEntityChanges("options", "name", 'isSynced = 1');
|
||||
|
@ -170,19 +170,19 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
||||
meta.dataFileName = getDataFileName(note.type, note.mime, baseFileName, existingFileNames);
|
||||
}
|
||||
|
||||
const attachments = note.getNoteAttachments();
|
||||
const ancillaries = note.getNoteAncillaries();
|
||||
|
||||
if (attachments.length > 0) {
|
||||
meta.attachments = attachments
|
||||
.filter(attachment => ["canvasSvg", "mermaidSvg"].includes(attachment.name))
|
||||
.map(attachment => ({
|
||||
if (ancillaries.length > 0) {
|
||||
meta.ancillaries = ancillaries
|
||||
.filter(ancillary => ["canvasSvg", "mermaidSvg"].includes(ancillary.name))
|
||||
.map(ancillary => ({
|
||||
|
||||
name: attachment.name,
|
||||
mime: attachment.mime,
|
||||
name: ancillary.name,
|
||||
mime: ancillary.mime,
|
||||
dataFileName: getDataFileName(
|
||||
null,
|
||||
attachment.mime,
|
||||
baseFileName + "_" + attachment.name,
|
||||
ancillary.mime,
|
||||
baseFileName + "_" + ancillary.name,
|
||||
existingFileNames
|
||||
)
|
||||
}));
|
||||
@ -234,11 +234,11 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
||||
|
||||
const meta = noteIdToMeta[targetPath[targetPath.length - 1]];
|
||||
|
||||
// for some note types it's more user-friendly to see the attachment (if exists) instead of source note
|
||||
const preferredAttachment = (meta.attachments || []).find(attachment => ['mermaidSvg', 'canvasSvg'].includes(attachment.name));
|
||||
// for some note types it's more user-friendly to see the ancillary (if exists) instead of source note
|
||||
const preferredAncillary = (meta.ancillaries || []).find(ancillary => ['mermaidSvg', 'canvasSvg'].includes(ancillary.name));
|
||||
|
||||
if (preferredAttachment) {
|
||||
url += encodeURIComponent(preferredAttachment.dataFileName);
|
||||
if (preferredAncillary) {
|
||||
url += encodeURIComponent(preferredAncillary.dataFileName);
|
||||
} else {
|
||||
// link can target note which is only "folder-note" and as such will not have a file in an export
|
||||
url += encodeURIComponent(meta.dataFileName || meta.dirFileName);
|
||||
@ -344,12 +344,12 @@ ${markdownContent}`;
|
||||
|
||||
taskContext.increaseProgressCount();
|
||||
|
||||
for (const attachmentMeta of noteMeta.attachments || []) {
|
||||
const noteAttachment = note.getNoteAttachmentByName(attachmentMeta.name);
|
||||
const content = noteAttachment.getContent();
|
||||
for (const ancillaryMeta of noteMeta.ancillaries || []) {
|
||||
const noteAncillary = note.getNoteAncillaryByName(ancillaryMeta.name);
|
||||
const content = noteAncillary.getContent();
|
||||
|
||||
archive.append(content, {
|
||||
name: filePathPrefix + attachmentMeta.dataFileName,
|
||||
name: filePathPrefix + ancillaryMeta.dataFileName,
|
||||
date: dateUtils.parseDateTime(note.utcDateModified)
|
||||
});
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ const treeService = require("../tree");
|
||||
const yauzl = require("yauzl");
|
||||
const htmlSanitizer = require('../html_sanitizer');
|
||||
const becca = require("../../becca/becca");
|
||||
const BNoteAttachment = require("../../becca/entities/bnote_attachment");
|
||||
const BNoteAncillary = require("../../becca/entities/bnote_ancillary");
|
||||
|
||||
/**
|
||||
* @param {TaskContext} taskContext
|
||||
@ -65,7 +65,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
};
|
||||
|
||||
let parent;
|
||||
let attachmentMeta = false;
|
||||
let ancillaryMeta = false;
|
||||
|
||||
for (const segment of pathSegments) {
|
||||
if (!cursor || !cursor.children || cursor.children.length === 0) {
|
||||
@ -77,10 +77,10 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
|
||||
if (!cursor) {
|
||||
for (const file of parent.children) {
|
||||
for (const attachment of file.attachments || []) {
|
||||
if (attachment.dataFileName === segment) {
|
||||
for (const ancillary of file.ancillaries || []) {
|
||||
if (ancillary.dataFileName === segment) {
|
||||
cursor = file;
|
||||
attachmentMeta = attachment;
|
||||
ancillaryMeta = ancillary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -95,7 +95,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
return {
|
||||
parentNoteMeta: parent,
|
||||
noteMeta: cursor,
|
||||
attachmentMeta
|
||||
ancillaryMeta
|
||||
};
|
||||
}
|
||||
|
||||
@ -373,7 +373,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
}
|
||||
|
||||
function saveNote(filePath, content) {
|
||||
const {parentNoteMeta, noteMeta, attachmentMeta} = getMeta(filePath);
|
||||
const {parentNoteMeta, noteMeta, ancillaryMeta} = getMeta(filePath);
|
||||
|
||||
if (noteMeta?.noImport) {
|
||||
return;
|
||||
@ -381,14 +381,14 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
|
||||
const noteId = getNoteId(noteMeta, filePath);
|
||||
|
||||
if (attachmentMeta) {
|
||||
const noteAttachment = new BNoteAttachment({
|
||||
if (ancillaryMeta) {
|
||||
const noteAncillary = new BNoteAncillary({
|
||||
noteId,
|
||||
name: attachmentMeta.name,
|
||||
mime: attachmentMeta.mime
|
||||
name: ancillaryMeta.name,
|
||||
mime: ancillaryMeta.mime
|
||||
});
|
||||
|
||||
noteAttachment.setContent(content);
|
||||
noteAncillary.setContent(content);
|
||||
return;
|
||||
}
|
||||
|
||||
|
37
src/services/note_ancillaries.js
Normal file
37
src/services/note_ancillaries.js
Normal file
@ -0,0 +1,37 @@
|
||||
const protectedSession = require("./protected_session.js");
|
||||
const log = require("./log.js");
|
||||
|
||||
/**
|
||||
* @param {BNote} note
|
||||
*/
|
||||
function protectNoteAncillaries(note) {
|
||||
for (const noteAncillary of note.getNoteAncillaries()) {
|
||||
if (note.isProtected !== noteAncillary.isProtected) {
|
||||
if (!protectedSession.isProtectedSessionAvailable()) {
|
||||
log.error("Protected session is not available to fix note ancillaries.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const content = noteAncillary.getContent();
|
||||
|
||||
noteAncillary.isProtected = note.isProtected;
|
||||
|
||||
// this will force de/encryption
|
||||
noteAncillary.setContent(content);
|
||||
|
||||
noteAncillary.save();
|
||||
}
|
||||
catch (e) {
|
||||
log.error(`Could not un/protect note ancillary ID = ${noteAncillary.noteAncillaryId}`);
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
protectNoteAncillaries
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
const protectedSession = require("./protected_session.js");
|
||||
const log = require("./log.js");
|
||||
|
||||
/**
|
||||
* @param {BNote} note
|
||||
*/
|
||||
function protectNoteAttachments(note) {
|
||||
for (const noteAttachment of note.getNoteAttachments()) {
|
||||
if (note.isProtected !== noteAttachment.isProtected) {
|
||||
if (!protectedSession.isProtectedSessionAvailable()) {
|
||||
log.error("Protected session is not available to fix note attachments.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const content = noteAttachment.getContent();
|
||||
|
||||
noteAttachment.isProtected = note.isProtected;
|
||||
|
||||
// this will force de/encryption
|
||||
noteAttachment.setContent(content);
|
||||
|
||||
noteAttachment.save();
|
||||
}
|
||||
catch (e) {
|
||||
log.error(`Could not un/protect note attachment ID = ${noteAttachment.noteAttachmentId}`);
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
protectNoteAttachments
|
||||
}
|
@ -9,7 +9,7 @@ const protectedSessionService = require('../services/protected_session');
|
||||
const log = require('../services/log');
|
||||
const utils = require('../services/utils');
|
||||
const noteRevisionService = require('../services/note_revisions');
|
||||
const noteAttachmentService = require('../services/note_attachments');
|
||||
const noteAncillarieservice = require('../services/note_ancillaries');
|
||||
const attributeService = require('../services/attributes');
|
||||
const request = require('./request');
|
||||
const path = require('path');
|
||||
@ -18,7 +18,7 @@ const becca = require('../becca/becca');
|
||||
const BBranch = require('../becca/entities/bbranch');
|
||||
const BNote = require('../becca/entities/bnote');
|
||||
const BAttribute = require('../becca/entities/battribute');
|
||||
const BNoteAttachment = require("../becca/entities/bnote_attachment");
|
||||
const BNoteAncillary = require("../becca/entities/bnote_ancillary");
|
||||
const dayjs = require("dayjs");
|
||||
const htmlSanitizer = require("./html_sanitizer");
|
||||
const ValidationError = require("../errors/validation_error");
|
||||
@ -302,7 +302,7 @@ function protectNote(note, protect) {
|
||||
}
|
||||
|
||||
noteRevisionService.protectNoteRevisions(note);
|
||||
noteAttachmentService.protectNoteAttachments(note);
|
||||
noteAncillarieservice.protectNoteAncillaries(note);
|
||||
}
|
||||
catch (e) {
|
||||
log.error(`Could not un/protect note ID = ${note.noteId}`);
|
||||
@ -593,7 +593,7 @@ function saveNoteRevisionIfNeeded(note) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateNoteData(noteId, content, attachments = []) {
|
||||
function updateNoteData(noteId, content, ancillaries = []) {
|
||||
const note = becca.getNote(noteId);
|
||||
|
||||
if (!note.isContentAvailable()) {
|
||||
@ -606,8 +606,8 @@ function updateNoteData(noteId, content, attachments = []) {
|
||||
|
||||
note.setContent(content);
|
||||
|
||||
for (const {name, mime, content} of attachments) {
|
||||
note.saveNoteAttachment(name, mime, content);
|
||||
for (const {name, mime, content} of ancillaries) {
|
||||
note.saveNoteAncillary(name, mime, content);
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,14 +675,14 @@ function undeleteBranch(branchId, deleteId, taskContext) {
|
||||
new BAttribute(attribute).save({skipValidation: true});
|
||||
}
|
||||
|
||||
const noteAttachments = sql.getRows(`
|
||||
SELECT * FROM note_attachments
|
||||
const noteAncillaries = sql.getRows(`
|
||||
SELECT * FROM note_ancillaries
|
||||
WHERE isDeleted = 1
|
||||
AND deleteId = ?
|
||||
AND noteId = ?`, [deleteId, note.noteId]);
|
||||
|
||||
for (const noteAttachment of noteAttachments) {
|
||||
new BNoteAttachment(noteAttachment).save();
|
||||
for (const noteAncillary of noteAncillaries) {
|
||||
new BNoteAncillary(noteAncillary).save();
|
||||
}
|
||||
|
||||
const childBranchIds = sql.getColumn(`
|
||||
@ -737,7 +737,7 @@ function runOcr(note, buffer) {
|
||||
try {
|
||||
const plainText = textExtractingService.ocrTextFromBuffer(buffer);
|
||||
|
||||
note.saveNoteAttachment('plainText', 'text/plain', plainText);
|
||||
note.saveNoteAncillary('plainText', 'text/plain', plainText);
|
||||
}
|
||||
catch (e) {
|
||||
log.error(`OCR on note '${note.noteId}' failed with error '${e.message}', stack ${e.stack}`);
|
||||
@ -780,10 +780,10 @@ function eraseNotes(noteIdsToErase) {
|
||||
|
||||
noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase);
|
||||
|
||||
const noteAttachmentIdsToErase = sql.getManyRows(`SELECT noteAttachmentId FROM note_attachments WHERE noteId IN (???)`, noteIdsToErase)
|
||||
.map(row => row.noteAttachmentId);
|
||||
const noteAncillaryIdsToErase = sql.getManyRows(`SELECT noteAncillaryId FROM note_ancillaries WHERE noteId IN (???)`, noteIdsToErase)
|
||||
.map(row => row.noteAncillaryId);
|
||||
|
||||
eraseNoteAttachments(noteAttachmentIdsToErase);
|
||||
eraseNoteAncillaries(noteAncillaryIdsToErase);
|
||||
|
||||
log.info(`Erased notes: ${JSON.stringify(noteIdsToErase)}`);
|
||||
}
|
||||
@ -820,18 +820,18 @@ function eraseAttributes(attributeIdsToErase) {
|
||||
log.info(`Erased attributes: ${JSON.stringify(attributeIdsToErase)}`);
|
||||
}
|
||||
|
||||
function eraseNoteAttachments(noteAttachmentIdsToErase) {
|
||||
if (noteAttachmentIdsToErase.length === 0) {
|
||||
function eraseNoteAncillaries(noteAncillaryIdsToErase) {
|
||||
if (noteAncillaryIdsToErase.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Removing note attachments: ${JSON.stringify(noteAttachmentIdsToErase)}`);
|
||||
log.info(`Removing note ancillaries: ${JSON.stringify(noteAncillaryIdsToErase)}`);
|
||||
|
||||
sql.executeMany(`DELETE FROM note_attachments WHERE noteAttachmentId IN (???)`, noteAttachmentIdsToErase);
|
||||
sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_attachments' AND entityId IN (???)`, noteAttachmentIdsToErase);
|
||||
sql.executeMany(`DELETE FROM note_ancillaries WHERE noteAncillaryId IN (???)`, noteAncillaryIdsToErase);
|
||||
sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_ancillaries' AND entityId IN (???)`, noteAncillaryIdsToErase);
|
||||
|
||||
sql.executeMany(`DELETE FROM note_attachment_contents WHERE noteAttachmentId IN (???)`, noteAttachmentIdsToErase);
|
||||
sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_attachment_contents' AND entityId IN (???)`, noteAttachmentIdsToErase);
|
||||
sql.executeMany(`DELETE FROM note_ancillary_contents WHERE noteAncillaryId IN (???)`, noteAncillaryIdsToErase);
|
||||
sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_ancillary_contents' AND entityId IN (???)`, noteAncillaryIdsToErase);
|
||||
}
|
||||
|
||||
function eraseDeletedEntities(eraseEntitiesAfterTimeInSeconds = null) {
|
||||
@ -968,16 +968,16 @@ function duplicateSubtreeInner(origNote, origBranch, newParentNoteId, noteIdMapp
|
||||
attr.save();
|
||||
}
|
||||
|
||||
for (const noteAttachment of origNote.getNoteAttachments()) {
|
||||
const duplNoteAttachment = new BNoteAttachment({
|
||||
...noteAttachment,
|
||||
noteAttachmentId: undefined,
|
||||
for (const noteAncillary of origNote.getNoteAncillaries()) {
|
||||
const duplNoteAncillary = new BNoteAncillary({
|
||||
...noteAncillary,
|
||||
noteAncillaryId: undefined,
|
||||
noteId: newNote.noteId
|
||||
});
|
||||
|
||||
duplNoteAttachment.save();
|
||||
duplNoteAncillary.save();
|
||||
|
||||
duplNoteAttachment.setContent(noteAttachment.getContent());
|
||||
duplNoteAncillary.setContent(noteAncillary.getContent());
|
||||
}
|
||||
|
||||
for (const childBranch of origNote.getChildBranches()) {
|
||||
|
@ -50,7 +50,7 @@ class NoteContentFulltextExp extends Expression {
|
||||
|
||||
for (const row of sql.iterateRows(`
|
||||
SELECT noteId, 'plainText' as type, mime, content, isProtected
|
||||
FROM note_attachments JOIN note_attachment_contents USING (noteAttachmentId)
|
||||
FROM note_ancillaries JOIN note_ancillary_contents USING (noteAncillaryId)
|
||||
WHERE name IN ('plainText') AND isDeleted = 0`)) {
|
||||
|
||||
if (!resultNoteSet.hasNoteId(row.noteId)) {
|
||||
|
@ -321,7 +321,7 @@ function getEntityChangeRow(entityName, entityId) {
|
||||
throw new Error(`Entity ${entityName} ${entityId} not found.`);
|
||||
}
|
||||
|
||||
if (['note_contents', 'note_revision_contents', 'note_attachment_contents'].includes(entityName) && entity.content !== null) {
|
||||
if (['note_contents', 'note_revision_contents', 'note_ancillary_contents'].includes(entityName) && entity.content !== null) {
|
||||
if (typeof entity.content === 'string') {
|
||||
entity.content = Buffer.from(entity.content, 'UTF-8');
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ function updateNormalEntity(remoteEntityChange, remoteEntityRow, instanceId) {
|
||||
|| localEntityChange.utcDateChanged < remoteEntityChange.utcDateChanged
|
||||
|| localEntityChange.hash !== remoteEntityChange.hash // sync error, we should still update
|
||||
) {
|
||||
if (['note_contents', 'note_revision_contents', 'note_attachment_contents'].includes(remoteEntityChange.entityName)) {
|
||||
if (['note_contents', 'note_revision_contents', 'note_ancillary_contents'].includes(remoteEntityChange.entityName)) {
|
||||
remoteEntityRow.content = handleContent(remoteEntityRow.content);
|
||||
}
|
||||
|
||||
@ -116,8 +116,8 @@ function eraseEntity(entityChange, instanceId) {
|
||||
"attributes",
|
||||
"note_revisions",
|
||||
"note_revision_contents",
|
||||
"note_attachments",
|
||||
"note_attachment_contents"
|
||||
"note_ancillaries",
|
||||
"note_ancillary_contents"
|
||||
];
|
||||
|
||||
if (!entityNames.includes(entityName)) {
|
||||
|
@ -96,7 +96,7 @@ async function extractTextFromPdf(note, buffer) {
|
||||
|
||||
strings = strings.filter(str => str?.trim());
|
||||
|
||||
note.saveNoteAttachment('plainText', 'text/plain', strings.join(" "));
|
||||
note.saveNoteAncillary('plainText', 'text/plain', strings.join(" "));
|
||||
}
|
||||
catch (e) {
|
||||
log.info(`Extracting text from PDF on note '${note.noteId}' failed with error '${e.message}', stack ${e.stack}`);
|
||||
@ -126,4 +126,4 @@ async function ocrTextFromBuffer(buffer) {
|
||||
module.exports = {
|
||||
ocrTextFromBuffer,
|
||||
extractTextFromPdf
|
||||
};
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user