mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
blob WIP
This commit is contained in:
parent
eee05a4d01
commit
b6efc954bd
@ -1,6 +1,6 @@
|
|||||||
CREATE TABLE IF NOT EXISTS "note_attachments"
|
CREATE TABLE IF NOT EXISTS "attachments"
|
||||||
(
|
(
|
||||||
noteAttachmentId TEXT not null primary key,
|
attachmentId TEXT not null primary key,
|
||||||
parentId TEXT not null,
|
parentId TEXT not null,
|
||||||
role TEXT not null,
|
role TEXT not null,
|
||||||
mime TEXT not null,
|
mime TEXT not null,
|
||||||
@ -11,5 +11,5 @@ CREATE TABLE IF NOT EXISTS "note_attachments"
|
|||||||
isDeleted INT not null,
|
isDeleted INT not null,
|
||||||
deleteId TEXT DEFAULT NULL);
|
deleteId TEXT DEFAULT NULL);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IDX_note_attachments_parentId_role
|
CREATE UNIQUE INDEX IDX_attachments_parentId_role
|
||||||
on note_attachments (parentId, role);
|
on attachments (parentId, role);
|
@ -35,34 +35,26 @@ CREATE TABLE IF NOT EXISTS "notes" (
|
|||||||
`isProtected` INT NOT NULL DEFAULT 0,
|
`isProtected` INT NOT NULL DEFAULT 0,
|
||||||
`type` TEXT NOT NULL DEFAULT 'text',
|
`type` TEXT NOT NULL DEFAULT 'text',
|
||||||
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
||||||
|
`blobId` TEXT DEFAULT NULL,
|
||||||
`isDeleted` INT NOT NULL DEFAULT 0,
|
`isDeleted` INT NOT NULL DEFAULT 0,
|
||||||
`deleteId` TEXT DEFAULT NULL,
|
`deleteId` TEXT DEFAULT NULL,
|
||||||
`dateCreated` TEXT NOT NULL,
|
`dateCreated` TEXT NOT NULL,
|
||||||
`dateModified` TEXT NOT NULL,
|
`dateModified` TEXT NOT NULL,
|
||||||
`utcDateCreated` TEXT NOT NULL,
|
`utcDateCreated` TEXT NOT NULL,
|
||||||
`utcDateModified` TEXT NOT NULL,
|
`utcDateModified` TEXT NOT NULL
|
||||||
PRIMARY KEY(`noteId`));
|
PRIMARY KEY(`noteId`));
|
||||||
CREATE TABLE IF NOT EXISTS "note_contents" (
|
|
||||||
`noteId` TEXT NOT NULL,
|
|
||||||
`content` TEXT NULL DEFAULT NULL,
|
|
||||||
`dateModified` TEXT NOT NULL,
|
|
||||||
`utcDateModified` TEXT NOT NULL,
|
|
||||||
PRIMARY KEY(`noteId`)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
||||||
`noteId` TEXT NOT NULL,
|
`noteId` TEXT NOT NULL,
|
||||||
type TEXT DEFAULT '' NOT NULL,
|
type TEXT DEFAULT '' NOT NULL,
|
||||||
mime TEXT DEFAULT '' NOT NULL,
|
mime TEXT DEFAULT '' NOT NULL,
|
||||||
`title` TEXT NOT NULL,
|
`title` TEXT NOT NULL,
|
||||||
`isProtected` INT NOT NULL DEFAULT 0,
|
`isProtected` INT NOT NULL DEFAULT 0,
|
||||||
|
`blobId` TEXT DEFAULT NULL,
|
||||||
`utcDateLastEdited` TEXT NOT NULL,
|
`utcDateLastEdited` TEXT NOT NULL,
|
||||||
`utcDateCreated` TEXT NOT NULL,
|
`utcDateCreated` TEXT NOT NULL,
|
||||||
`utcDateModified` TEXT NOT NULL,
|
`utcDateModified` TEXT NOT NULL,
|
||||||
`dateLastEdited` TEXT NOT NULL,
|
`dateLastEdited` TEXT NOT NULL,
|
||||||
`dateCreated` TEXT NOT NULL);
|
`dateCreated` TEXT NOT NULL);
|
||||||
CREATE TABLE IF NOT EXISTS "note_revision_contents" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
|
||||||
`content` TEXT,
|
|
||||||
`utcDateModified` TEXT NOT NULL);
|
|
||||||
CREATE TABLE IF NOT EXISTS "options"
|
CREATE TABLE IF NOT EXISTS "options"
|
||||||
(
|
(
|
||||||
name TEXT not null PRIMARY KEY,
|
name TEXT not null PRIMARY KEY,
|
||||||
@ -112,18 +104,17 @@ 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_attachments"
|
CREATE TABLE IF NOT EXISTS "attachments"
|
||||||
(
|
(
|
||||||
noteAttachmentId TEXT not null primary key,
|
attachmentId TEXT not null primary key,
|
||||||
noteId TEXT not null,
|
parentId TEXT not null,
|
||||||
name TEXT not null,
|
role TEXT not null,
|
||||||
mime TEXT not null,
|
mime TEXT not null,
|
||||||
|
title TEXT not null,
|
||||||
isProtected INT not null DEFAULT 0,
|
isProtected INT not null DEFAULT 0,
|
||||||
|
blobId TEXT not null,
|
||||||
utcDateModified TEXT not null,
|
utcDateModified TEXT not null,
|
||||||
isDeleted INT not null,
|
isDeleted INT not null,
|
||||||
`deleteId` TEXT DEFAULT NULL);
|
deleteId TEXT DEFAULT NULL);
|
||||||
|
CREATE UNIQUE INDEX IDX_attachments_parentId_role
|
||||||
CREATE INDEX IDX_note_attachments_name
|
on attachments (parentId, role);
|
||||||
on note_attachments (name);
|
|
||||||
CREATE UNIQUE INDEX IDX_note_attachments_noteId_name
|
|
||||||
on note_attachments (noteId, name);
|
|
||||||
|
@ -121,12 +121,12 @@ class Becca {
|
|||||||
return row ? new BNoteRevision(row) : null;
|
return row ? new BNoteRevision(row) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {BNoteAttachment|null} */
|
/** @returns {BAttachment|null} */
|
||||||
getNoteAttachment(noteAttachmentId) {
|
getAttachment(attachmentId) {
|
||||||
const row = sql.getRow("SELECT * FROM note_attachments WHERE noteAttachmentId = ?", [noteAttachmentId]);
|
const row = sql.getRow("SELECT * FROM attachments WHERE attachmentId = ?", [attachmentId]);
|
||||||
|
|
||||||
const BNoteAttachment = require("./entities/bnote_attachment"); // avoiding circular dependency problems
|
const BAttachment = require("./entities/battachment"); // avoiding circular dependency problems
|
||||||
return row ? new BNoteAttachment(row) : null;
|
return row ? new BAttachment(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_attachments') {
|
} else if (entityName === 'attachments') {
|
||||||
return this.getNoteAttachment(entityId);
|
return this.getAttachment(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g,
|
const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g,
|
||||||
|
@ -9,31 +9,31 @@ const entityChangesService = require('../../services/entity_changes');
|
|||||||
const AbstractBeccaEntity = require("./abstract_becca_entity");
|
const AbstractBeccaEntity = require("./abstract_becca_entity");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NoteAttachment represent data related/attached to the note. Conceptually similar to attributes, but intended for
|
* Attachment 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 BNoteAttachment extends AbstractBeccaEntity {
|
class BAttachment extends AbstractBeccaEntity {
|
||||||
static get entityName() { return "note_attachments"; }
|
static get entityName() { return "attachments"; }
|
||||||
static get primaryKeyName() { return "noteAttachmentId"; }
|
static get primaryKeyName() { return "attachmentId"; }
|
||||||
static get hashedProperties() { return ["noteAttachmentId", "parentId", "role", "mime", "title", "utcDateModified"]; }
|
static get hashedProperties() { return ["attachmentId", "parentId", "role", "mime", "title", "utcDateModified"]; }
|
||||||
|
|
||||||
constructor(row) {
|
constructor(row) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (!row.parentId?.trim()) {
|
if (!row.parentId?.trim()) {
|
||||||
throw new Error("'noteId' must be given to initialize a NoteAttachment entity");
|
throw new Error("'noteId' must be given to initialize a Attachment entity");
|
||||||
} else if (!row.role?.trim()) {
|
} else if (!row.role?.trim()) {
|
||||||
throw new Error("'role' must be given to initialize a NoteAttachment entity");
|
throw new Error("'role' must be given to initialize a Attachment entity");
|
||||||
} else if (!row.mime?.trim()) {
|
} else if (!row.mime?.trim()) {
|
||||||
throw new Error("'mime' must be given to initialize a NoteAttachment entity");
|
throw new Error("'mime' must be given to initialize a Attachment entity");
|
||||||
} else if (!row.title?.trim()) {
|
} else if (!row.title?.trim()) {
|
||||||
throw new Error("'title' must be given to initialize a NoteAttachment entity");
|
throw new Error("'title' must be given to initialize a Attachment 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.noteAttachmentId = row.noteAttachmentId || `${this.noteId}_${this.name}`; // FIXME
|
this.attachmentId = row.attachmentId || `${this.noteId}_${this.name}`; // FIXME
|
||||||
/** @type {string} either noteId or noteRevisionId to which this attachment belongs */
|
/** @type {string} either noteId or noteRevisionId to which this attachment belongs */
|
||||||
this.parentId = row.parentId;
|
this.parentId = row.parentId;
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
@ -59,14 +59,14 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
|||||||
|
|
||||||
/** @returns {*} */
|
/** @returns {*} */
|
||||||
getContent(silentNotFoundError = false) {
|
getContent(silentNotFoundError = false) {
|
||||||
const res = sql.getRow(`SELECT content FROM note_attachment_contents WHERE noteAttachmentId = ?`, [this.noteAttachmentId]);
|
const res = sql.getRow(`SELECT content FROM attachment_contents WHERE attachmentId = ?`, [this.attachmentId]);
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
if (silentNotFoundError) {
|
if (silentNotFoundError) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error(`Cannot find note attachment content for noteAttachmentId=${this.noteAttachmentId}`);
|
throw new Error(`Cannot find note attachment content for attachmentId=${this.attachmentId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,10 +93,10 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
|||||||
|
|
||||||
setContent(content) {
|
setContent(content) {
|
||||||
sql.transactional(() => {
|
sql.transactional(() => {
|
||||||
this.save(); // also explicitly save note_attachment to update contentCheckSum
|
this.save(); // also explicitly save attachment to update contentCheckSum
|
||||||
|
|
||||||
const pojo = {
|
const pojo = {
|
||||||
noteAttachmentId: this.noteAttachmentId,
|
attachmentId: this.attachmentId,
|
||||||
content: content,
|
content: content,
|
||||||
utcDateModified: dateUtils.utcNowDateTime()
|
utcDateModified: dateUtils.utcNowDateTime()
|
||||||
};
|
};
|
||||||
@ -105,15 +105,15 @@ class BNoteAttachment 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 noteAttachmentId=${this.noteAttachmentId} since we're out of protected session.`);
|
throw new Error(`Cannot update content of attachmentId=${this.attachmentId} since we're out of protected session.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sql.upsert("note_attachment_contents", "noteAttachmentId", pojo);
|
sql.upsert("attachment_contents", "attachmentId", pojo);
|
||||||
|
|
||||||
entityChangesService.addEntityChange({
|
entityChangesService.addEntityChange({
|
||||||
entityName: 'note_attachment_contents',
|
entityName: 'attachment_contents',
|
||||||
entityId: this.noteAttachmentId,
|
entityId: this.attachmentId,
|
||||||
hash: this.contentCheckSum, // FIXME
|
hash: this.contentCheckSum, // FIXME
|
||||||
isErased: false,
|
isErased: false,
|
||||||
utcDateChanged: pojo.utcDateModified,
|
utcDateChanged: pojo.utcDateModified,
|
||||||
@ -123,7 +123,7 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
calculateCheckSum(content) {
|
calculateCheckSum(content) {
|
||||||
return utils.hash(`${this.noteAttachmentId}|${content.toString()}`);
|
return utils.hash(`${this.attachmentId}|${content.toString()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeSaving() {
|
beforeSaving() {
|
||||||
@ -131,7 +131,7 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
|||||||
throw new Error(`Name must be alphanumerical, "${this.name}" given.`);
|
throw new Error(`Name must be alphanumerical, "${this.name}" given.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.noteAttachmentId = `${this.noteId}_${this.name}`; // FIXME
|
this.attachmentId = `${this.noteId}_${this.name}`; // FIXME
|
||||||
|
|
||||||
super.beforeSaving();
|
super.beforeSaving();
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
|||||||
|
|
||||||
getPojo() {
|
getPojo() {
|
||||||
return {
|
return {
|
||||||
noteAttachmentId: this.noteAttachmentId,
|
attachmentId: this.attachmentId,
|
||||||
parentId: this.parentId,
|
parentId: this.parentId,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
mime: this.mime,
|
mime: this.mime,
|
||||||
@ -159,4 +159,4 @@ class BNoteAttachment extends AbstractBeccaEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BNoteAttachment;
|
module.exports = BAttachment;
|
@ -198,8 +198,8 @@ class BBranch extends AbstractBeccaEntity {
|
|||||||
relation.markAsDeleted(deleteId);
|
relation.markAsDeleted(deleteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const noteAttachment of note.getNoteAttachments()) {
|
for (const attachment of note.getAttachments()) {
|
||||||
noteAttachment.markAsDeleted(deleteId);
|
attachment.markAsDeleted(deleteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
note.markAsDeleted(deleteId);
|
note.markAsDeleted(deleteId);
|
||||||
|
@ -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 BNoteAttachment = require("./bnote_attachment");
|
const BAttachment = require("./battachment");
|
||||||
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 {BNoteAttachment[]} */
|
/** @returns {BAttachment[]} */
|
||||||
getNoteAttachments() {
|
getAttachments() {
|
||||||
return sql.getRows("SELECT * FROM note_attachments WHERE noteId = ? AND isDeleted = 0", [this.noteId])
|
return sql.getRows("SELECT * FROM attachments WHERE noteId = ? AND isDeleted = 0", [this.noteId])
|
||||||
.map(row => new BNoteAttachment(row));
|
.map(row => new BAttachment(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {BNoteAttachment|undefined} */
|
/** @returns {BAttachment|undefined} */
|
||||||
getNoteAttachmentByName(name) {
|
getAttachmentByName(name) {
|
||||||
return sql.getRows("SELECT * FROM note_attachments WHERE noteId = ? AND name = ? AND isDeleted = 0", [this.noteId, name])
|
return sql.getRows("SELECT * FROM attachments WHERE noteId = ? AND name = ? AND isDeleted = 0", [this.noteId, name])
|
||||||
.map(row => new BNoteAttachment(row))
|
.map(row => new BAttachment(row))
|
||||||
[0];
|
[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1502,21 +1502,21 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {BNoteAttachment}
|
* @returns {BAttachment}
|
||||||
*/
|
*/
|
||||||
saveNoteAttachment(name, mime, content) {
|
saveAttachment(name, mime, content) {
|
||||||
let noteAttachment = this.getNoteAttachmentByName(name);
|
let attachment = this.getAttachmentByName(name);
|
||||||
|
|
||||||
noteAttachment = new BNoteAttachment({
|
attachment = new BAttachment({
|
||||||
noteId: this.noteId,
|
noteId: this.noteId,
|
||||||
name,
|
name,
|
||||||
mime,
|
mime,
|
||||||
isProtected: this.isProtected
|
isProtected: this.isProtected
|
||||||
});
|
});
|
||||||
|
|
||||||
noteAttachment.setContent(content);
|
attachment.setContent(content);
|
||||||
|
|
||||||
return noteAttachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeSaving() {
|
beforeSaving() {
|
||||||
|
@ -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 BNoteAttachment = require("./entities/bnote_attachment");
|
const BAttachment = require("./entities/battachment");
|
||||||
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_attachments": BNoteAttachment,
|
"attachments": BAttachment,
|
||||||
"recent_notes": BRecentNote,
|
"recent_notes": BRecentNote,
|
||||||
"etapi_tokens": BEtapiToken,
|
"etapi_tokens": BEtapiToken,
|
||||||
"options": BOption
|
"options": BOption
|
||||||
|
@ -34,7 +34,7 @@ async function processEntityChanges(entityChanges) {
|
|||||||
|
|
||||||
loadResults.addOption(ec.entity.name);
|
loadResults.addOption(ec.entity.name);
|
||||||
}
|
}
|
||||||
else if (['etapi_tokens', 'note_attachments'].includes(ec.entityName)) {
|
else if (['etapi_tokens', 'attachments'].includes(ec.entityName)) {
|
||||||
// NOOP
|
// NOOP
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -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="showNoteAttachments" class="dropdown-item"><kbd data-command="showNoteAttachments"></kbd> Note attachments</a>
|
<a data-trigger-command="showAttachments" class="dropdown-item"><kbd data-command="showAttachments"></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>
|
||||||
|
@ -127,7 +127,7 @@ function setNoteTypeMime(req) {
|
|||||||
note.save();
|
note.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteAttachments(req) {
|
function getAttachments(req) {
|
||||||
const includeContent = req.query.includeContent === 'true';
|
const includeContent = req.query.includeContent === 'true';
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
|
|
||||||
@ -137,9 +137,9 @@ function getNoteAttachments(req) {
|
|||||||
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
|
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteAttachments = note.getNoteAttachments();
|
const attachments = note.getAttachments();
|
||||||
|
|
||||||
return noteAttachments.map(attachment => {
|
return attachments.map(attachment => {
|
||||||
const pojo = attachment.getPojo();
|
const pojo = attachment.getPojo();
|
||||||
|
|
||||||
if (includeContent && utils.isStringNote(null, attachment.mime)) {
|
if (includeContent && utils.isStringNote(null, attachment.mime)) {
|
||||||
@ -157,7 +157,7 @@ function getNoteAttachments(req) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveNoteAttachment(req) {
|
function saveAttachment(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 saveNoteAttachment(req) {
|
|||||||
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
|
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
note.saveNoteAttachment(name, mime, content);
|
note.saveAttachment(name, mime, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRelationMap(req) {
|
function getRelationMap(req) {
|
||||||
@ -384,6 +384,6 @@ module.exports = {
|
|||||||
getDeleteNotesPreview,
|
getDeleteNotesPreview,
|
||||||
uploadModifiedFile,
|
uploadModifiedFile,
|
||||||
forceSaveNoteRevision,
|
forceSaveNoteRevision,
|
||||||
getNoteAttachments,
|
getAttachments,
|
||||||
saveNoteAttachment
|
saveAttachment
|
||||||
};
|
};
|
||||||
|
@ -113,9 +113,9 @@ function forceNoteSync(req) {
|
|||||||
entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId);
|
entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const noteAttachmentId of sql.getColumn("SELECT noteAttachmentId FROM note_attachments WHERE noteId = ?", [noteId])) {
|
for (const attachmentId of sql.getColumn("SELECT attachmentId FROM attachments WHERE noteId = ?", [noteId])) {
|
||||||
sql.execute(`UPDATE note_attachments SET utcDateModified = ? WHERE noteAttachmentId = ?`, [now, noteAttachmentId]);
|
sql.execute(`UPDATE attachments SET utcDateModified = ? WHERE attachmentId = ?`, [now, attachmentId]);
|
||||||
entityChangesService.moveEntityChangeToTop('note_attachments', noteAttachmentId);
|
entityChangesService.moveEntityChangeToTop('attachments', attachmentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info(`Forcing note sync for ${noteId}`);
|
log.info(`Forcing note sync for ${noteId}`);
|
||||||
|
@ -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/attachments', notesApiRoute.getNoteAttachments);
|
apiRoute(GET, '/api/notes/:noteId/attachments', notesApiRoute.getAttachments);
|
||||||
apiRoute(PUT, '/api/notes/:noteId/attachments/:name', notesApiRoute.saveNoteAttachment);
|
apiRoute(PUT, '/api/notes/:noteId/attachments/:name', notesApiRoute.saveAttachment);
|
||||||
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);
|
||||||
|
@ -4,9 +4,9 @@ const log = require("./log");
|
|||||||
/**
|
/**
|
||||||
* @param {BNote} note
|
* @param {BNote} note
|
||||||
*/
|
*/
|
||||||
function protectNoteAttachments(note) {
|
function protectAttachments(note) {
|
||||||
for (const noteAttachment of note.getNoteAttachments()) {
|
for (const attachment of note.getAttachments()) {
|
||||||
if (note.isProtected !== noteAttachment.isProtected) {
|
if (note.isProtected !== attachment.isProtected) {
|
||||||
if (!protectedSession.isProtectedSessionAvailable()) {
|
if (!protectedSession.isProtectedSessionAvailable()) {
|
||||||
log.error("Protected session is not available to fix note attachments.");
|
log.error("Protected session is not available to fix note attachments.");
|
||||||
|
|
||||||
@ -14,17 +14,17 @@ function protectNoteAttachments(note) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = noteAttachment.getContent();
|
const content = attachment.getContent();
|
||||||
|
|
||||||
noteAttachment.isProtected = note.isProtected;
|
attachment.isProtected = note.isProtected;
|
||||||
|
|
||||||
// this will force de/encryption
|
// this will force de/encryption
|
||||||
noteAttachment.setContent(content);
|
attachment.setContent(content);
|
||||||
|
|
||||||
noteAttachment.save();
|
attachment.save();
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
log.error(`Could not un/protect note attachment ID = ${noteAttachment.noteAttachmentId}`);
|
log.error(`Could not un/protect note attachment ID = ${attachment.attachmentId}`);
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -33,5 +33,5 @@ function protectNoteAttachments(note) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
protectNoteAttachments
|
protectAttachments
|
||||||
}
|
}
|
@ -214,24 +214,25 @@ class ConsistencyChecks {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
// FIXME
|
||||||
SELECT noteAttachmentId, note_attachments.noteId AS noteId
|
// this.findAndFixIssues(`
|
||||||
FROM note_attachments
|
// SELECT attachmentId, attachments.parentId AS noteId
|
||||||
LEFT JOIN notes ON notes.noteId = note_attachments.parentId
|
// FROM attachments
|
||||||
WHERE notes.noteId IS NULL
|
// LEFT JOIN notes ON notes.noteId = attachments.parentId
|
||||||
AND note_attachments.isDeleted = 0`,
|
// WHERE notes.noteId IS NULL
|
||||||
({noteAttachmentId, noteId}) => {
|
// AND attachments.isDeleted = 0`,
|
||||||
if (this.autoFix) {
|
// ({attachmentId, noteId}) => {
|
||||||
const noteAttachment = becca.getNoteAttachment(noteAttachmentId);
|
// if (this.autoFix) {
|
||||||
noteAttachment.markAsDeleted();
|
// const attachment = becca.getAttachment(attachmentId);
|
||||||
|
// attachment.markAsDeleted();
|
||||||
this.reloadNeeded = false;
|
//
|
||||||
|
// this.reloadNeeded = false;
|
||||||
logFix(`Note attachment '${noteAttachmentId}' has been deleted since it references missing note '${noteId}'`);
|
//
|
||||||
} else {
|
// logFix(`Note attachment '${attachmentId}' has been deleted since it references missing note '${noteId}'`);
|
||||||
logError(`Note attachment '${noteAttachmentId}' references missing note '${noteId}'`);
|
// } else {
|
||||||
}
|
// logError(`Note attachment '${attachmentId}' references missing note '${noteId}'`);
|
||||||
});
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
findExistencyIssues() {
|
findExistencyIssues() {
|
||||||
@ -341,22 +342,22 @@ class ConsistencyChecks {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
this.findAndFixIssues(`
|
||||||
SELECT noteAttachmentId,
|
SELECT attachmentId,
|
||||||
note_attachments.noteId AS noteId
|
attachments.parentId AS noteId
|
||||||
FROM note_attachments
|
FROM attachments
|
||||||
JOIN notes USING (noteId)
|
JOIN notes ON notes.noteId = attachments.parentId
|
||||||
WHERE notes.isDeleted = 1
|
WHERE notes.isDeleted = 1
|
||||||
AND note_attachments.isDeleted = 0`,
|
AND attachments.isDeleted = 0`,
|
||||||
({noteAttachmentId, noteId}) => {
|
({attachmentId, noteId}) => {
|
||||||
if (this.autoFix) {
|
if (this.autoFix) {
|
||||||
const noteAttachment = becca.getNoteAttachment(noteAttachmentId);
|
const attachment = becca.getAttachment(attachmentId);
|
||||||
noteAttachment.markAsDeleted();
|
attachment.markAsDeleted();
|
||||||
|
|
||||||
this.reloadNeeded = false;
|
this.reloadNeeded = false;
|
||||||
|
|
||||||
logFix(`Note attachment '${noteAttachmentId}' has been deleted since associated note '${noteId}' is deleted.`);
|
logFix(`Note attachment '${attachmentId}' has been deleted since associated note '${noteId}' is deleted.`);
|
||||||
} else {
|
} else {
|
||||||
logError(`Note attachment '${noteAttachmentId}' is not deleted even though associated note '${noteId}' is deleted.`)
|
logError(`Note attachment '${attachmentId}' is not deleted even though associated note '${noteId}' is deleted.`)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -657,7 +658,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_attachments", "noteAttachmentId");
|
this.runEntityChangeChecks("attachments", "attachmentId");
|
||||||
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 +755,7 @@ class ConsistencyChecks {
|
|||||||
return `${tableName}: ${count}`;
|
return `${tableName}: ${count}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tables = [ "notes", "note_revisions", "note_attachments", "branches", "attributes", "etapi_tokens" ];
|
const tables = [ "notes", "note_revisions", "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(", ")}`);
|
||||||
}
|
}
|
||||||
|
@ -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_attachments", "noteAttachmentId");
|
fillEntityChanges("attachments", "attachmentId");
|
||||||
fillEntityChanges("blobs", "blobId");
|
fillEntityChanges("blobs", "blobId");
|
||||||
fillEntityChanges("attributes", "attributeId");
|
fillEntityChanges("attributes", "attributeId");
|
||||||
fillEntityChanges("etapi_tokens", "etapiTokenId");
|
fillEntityChanges("etapi_tokens", "etapiTokenId");
|
||||||
|
@ -170,7 +170,7 @@ 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 attachments = note.getNoteAttachments();
|
const attachments = note.getAttachments();
|
||||||
|
|
||||||
if (attachments.length > 0) {
|
if (attachments.length > 0) {
|
||||||
meta.attachments = attachments
|
meta.attachments = attachments
|
||||||
@ -339,8 +339,8 @@ ${markdownContent}`;
|
|||||||
|
|
||||||
for (const attachmentMeta of noteMeta.attachments || []) {
|
for (const attachmentMeta of noteMeta.attachments || []) {
|
||||||
// FIXME
|
// FIXME
|
||||||
const noteAttachment = note.getNoteAttachmentByName(attachmentMeta.name);
|
const attachment = note.getAttachmentByName(attachmentMeta.name);
|
||||||
const content = noteAttachment.getContent();
|
const content = attachment.getContent();
|
||||||
|
|
||||||
archive.append(content, {
|
archive.append(content, {
|
||||||
name: filePathPrefix + attachmentMeta.dataFileName,
|
name: filePathPrefix + attachmentMeta.dataFileName,
|
||||||
|
@ -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 BNoteAttachment = require("../../becca/entities/bnote_attachment");
|
const BAttachment = require("../../becca/entities/battachment");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {TaskContext} taskContext
|
* @param {TaskContext} taskContext
|
||||||
@ -379,14 +379,14 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
|||||||
const noteId = getNoteId(noteMeta, filePath);
|
const noteId = getNoteId(noteMeta, filePath);
|
||||||
|
|
||||||
if (attachmentMeta) {
|
if (attachmentMeta) {
|
||||||
const noteAttachment = new BNoteAttachment({
|
const attachment = new BAttachment({
|
||||||
parentId: noteId,
|
parentId: noteId,
|
||||||
title: attachmentMeta.title,
|
title: attachmentMeta.title,
|
||||||
role: attachmentMeta.role,
|
role: attachmentMeta.role,
|
||||||
mime: attachmentMeta.mime
|
mime: attachmentMeta.mime
|
||||||
});
|
});
|
||||||
|
|
||||||
noteAttachment.setContent(content);
|
attachment.setContent(content);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ function eraseEntity(entityChange, instanceId) {
|
|||||||
"branches",
|
"branches",
|
||||||
"attributes",
|
"attributes",
|
||||||
"note_revisions",
|
"note_revisions",
|
||||||
"note_attachments",
|
"attachments",
|
||||||
"blobs",
|
"blobs",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ const ORDERING = {
|
|||||||
"blobs": 0,
|
"blobs": 0,
|
||||||
"note_reordering": 2,
|
"note_reordering": 2,
|
||||||
"note_revisions": 2,
|
"note_revisions": 2,
|
||||||
"note_attachments": 3,
|
"attachments": 3,
|
||||||
"notes": 1,
|
"notes": 1,
|
||||||
"options": 0
|
"options": 0
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user