mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
fix loading of string content saved as binary
This commit is contained in:
parent
8d2958738f
commit
75c6afd1c3
@ -2,8 +2,7 @@
|
||||
|
||||
const sql = require("../services/sql");
|
||||
const NoteSet = require("../services/search/note_set");
|
||||
const BAttachment = require("./entities/battachment.js");
|
||||
const NotFoundError = require("../errors/not_found_error.js");
|
||||
const NotFoundError = require("../errors/not_found_error");
|
||||
|
||||
/**
|
||||
* Becca is a backend cache of all notes, branches and attributes. There's a similar frontend cache Froca.
|
||||
@ -148,7 +147,7 @@ class Becca {
|
||||
getRevision(revisionId) {
|
||||
const row = sql.getRow("SELECT * FROM revisions WHERE revisionId = ?", [revisionId]);
|
||||
|
||||
const BRevision = require("./entities/brevision.js"); // avoiding circular dependency problems
|
||||
const BRevision = require("./entities/brevision"); // avoiding circular dependency problems
|
||||
return row ? new BRevision(row) : null;
|
||||
}
|
||||
|
||||
@ -186,8 +185,8 @@ class Becca {
|
||||
}
|
||||
|
||||
/** @returns {BBlob|null} */
|
||||
getBlob(blobId) {
|
||||
const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?", [blobId]);
|
||||
getBlob(entity) {
|
||||
const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?", [entity.blobId]);
|
||||
|
||||
const BBlob = require("./entities/bblob"); // avoiding circular dependency problems
|
||||
return row ? new BBlob(row) : null;
|
||||
@ -217,8 +216,6 @@ class Becca {
|
||||
return this.getRevision(entityId);
|
||||
} else if (entityName === 'attachments') {
|
||||
return this.getAttachment(entityId);
|
||||
} else if (entityName === 'blobs') {
|
||||
return this.getBlob(entityId);
|
||||
}
|
||||
|
||||
const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g,
|
||||
@ -247,7 +244,7 @@ class Becca {
|
||||
getRevisionsFromQuery(query, params = []) {
|
||||
const rows = sql.getRows(query, params);
|
||||
|
||||
const BRevision = require("./entities/brevision.js"); // avoiding circular dependency problems
|
||||
const BRevision = require("./entities/brevision"); // avoiding circular dependency problems
|
||||
return rows.map(row => new BRevision(row));
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,8 @@ const eventService = require("../../services/events");
|
||||
const dateUtils = require("../../services/date_utils");
|
||||
const cls = require("../../services/cls");
|
||||
const log = require("../../services/log");
|
||||
const protectedSessionService = require("../../services/protected_session.js");
|
||||
const protectedSessionService = require("../../services/protected_session");
|
||||
const blobService = require("../../services/blob");
|
||||
|
||||
let becca = null;
|
||||
|
||||
@ -246,36 +247,13 @@ class AbstractBeccaEntity {
|
||||
throw new Error(`Cannot find content for ${this.constructor.primaryKeyName} '${this[this.constructor.primaryKeyName]}', blobId '${this.blobId}'`);
|
||||
}
|
||||
|
||||
let content = row.content;
|
||||
|
||||
if (this.isProtected) {
|
||||
if (protectedSessionService.isProtectedSessionAvailable()) {
|
||||
content = content === null ? null : protectedSessionService.decrypt(content);
|
||||
} else {
|
||||
content = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hasStringContent()) {
|
||||
return content === null
|
||||
? ""
|
||||
: content.toString("utf-8");
|
||||
} else {
|
||||
// see https://github.com/zadam/trilium/issues/3523
|
||||
// IIRC a zero-sized buffer can be returned as null from the database
|
||||
if (content === null) {
|
||||
// this will force de/encryption
|
||||
content = Buffer.alloc(0);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
return blobService.processContent(row.content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the entity as (soft) deleted. It will be completely erased later.
|
||||
*
|
||||
* This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
|
||||
* This is a low-level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
|
||||
*
|
||||
* @param [deleteId=null]
|
||||
*/
|
||||
|
@ -4,8 +4,8 @@ const utils = require('../../services/utils');
|
||||
const dateUtils = require('../../services/date_utils');
|
||||
const AbstractBeccaEntity = require("./abstract_becca_entity");
|
||||
const sql = require("../../services/sql");
|
||||
const protectedSessionService = require("../../services/protected_session.js");
|
||||
const log = require("../../services/log.js");
|
||||
const protectedSessionService = require("../../services/protected_session");
|
||||
const log = require("../../services/log");
|
||||
|
||||
const attachmentRoleToNoteTypeMapping = {
|
||||
'image': 'image'
|
||||
|
@ -148,8 +148,6 @@ function register(router) {
|
||||
// (e.g. branchIds are not seen in UI), that we export "note export" instead.
|
||||
const branch = note.getParentBranches()[0];
|
||||
|
||||
console.log(note.getParentBranches());
|
||||
|
||||
zipExportService.exportToZip(taskContext, branch, format, res);
|
||||
});
|
||||
|
||||
|
@ -367,7 +367,7 @@ class Froca {
|
||||
|
||||
// we don't want to keep large payloads forever in memory, so we clean that up quite quickly
|
||||
// this cache is more meant to share the data between different components within one business transaction (e.g. loading of the note into the tab context and all the components)
|
||||
// this is also a workaround for missing invalidation after change
|
||||
// if the blob is updated within the cache lifetime, it should be invalidated by froca_updater
|
||||
this.blobPromises[key].then(
|
||||
() => setTimeout(() => this.blobPromises[key] = null, 1000)
|
||||
);
|
||||
|
@ -354,7 +354,7 @@ class NoteListRenderer {
|
||||
$content.append($renderedContent);
|
||||
$content.addClass(`type-${type}`);
|
||||
} catch (e) {
|
||||
console.log(`Caught error while rendering note ${note.noteId} of type ${note.type}: ${e.message}, stack: ${e.stack}`);
|
||||
console.log(`Caught error while rendering note '${note.noteId}' of type '${note.type}': ${e.message}, stack: ${e.stack}`);
|
||||
|
||||
$content.append("rendering error");
|
||||
}
|
||||
|
@ -295,13 +295,16 @@ async function openDialog($dialog, closeActDialog = true) {
|
||||
function isHtmlEmpty(html) {
|
||||
if (!html) {
|
||||
return true;
|
||||
} else if (typeof html !== 'string') {
|
||||
logError(`Got object of type '${typeof html}' where string was expected.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
html = html.toLowerCase();
|
||||
|
||||
return !html.includes('<img')
|
||||
&& !html.includes('<section')
|
||||
// line below will actually attempt to load images so better to check for images first
|
||||
// the line below will actually attempt to load images so better to check for images first
|
||||
&& $("<div>").html(html).text().trim().length === 0;
|
||||
}
|
||||
|
||||
@ -579,7 +582,6 @@ export default {
|
||||
sleep,
|
||||
escapeRegExp,
|
||||
formatNoteSize,
|
||||
escapeRegExp,
|
||||
areObjectsEqual,
|
||||
copyHtmlToClipboard
|
||||
};
|
||||
|
@ -665,12 +665,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
const branch = froca.getBranch(node.data.branchId);
|
||||
|
||||
if (!note) {
|
||||
console.log(`Node update not possible because note ${node.data.noteId} was not found.`);
|
||||
console.log(`Node update not possible because note '${node.data.noteId}' was not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!branch) {
|
||||
console.log(`Node update not possible because branch ${node.data.branchId} was not found.`);
|
||||
} else if (!branch) {
|
||||
console.log(`Node update not possible because branch '${node.data.branchId}' was not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
const becca = require("../../becca/becca");
|
||||
const blobService = require("../../services/blob.js");
|
||||
const blobService = require("../../services/blob");
|
||||
const ValidationError = require("../../errors/validation_error");
|
||||
|
||||
function getAttachmentBlob(req) {
|
||||
|
@ -10,7 +10,7 @@ const { Readable } = require('stream');
|
||||
const chokidar = require('chokidar');
|
||||
const ws = require('../../services/ws');
|
||||
const becca = require("../../becca/becca");
|
||||
const ValidationError = require("../../errors/validation_error.js");
|
||||
const ValidationError = require("../../errors/validation_error");
|
||||
|
||||
function updateFile(req) {
|
||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||
|
@ -1,5 +1,5 @@
|
||||
const becca = require("../../becca/becca.js");
|
||||
const sql = require("../../services/sql.js");
|
||||
const becca = require("../../becca/becca");
|
||||
const sql = require("../../services/sql");
|
||||
|
||||
function getRelationMap(req) {
|
||||
const {relationMapNoteId, noteIds} = req.body;
|
||||
|
@ -7,7 +7,7 @@ const sql = require('../../services/sql');
|
||||
const cls = require('../../services/cls');
|
||||
const path = require('path');
|
||||
const becca = require("../../becca/becca");
|
||||
const blobService = require("../../services/blob.js");
|
||||
const blobService = require("../../services/blob");
|
||||
|
||||
function getRevisionBlob(req) {
|
||||
const preview = req.query.preview === 'true';
|
||||
|
@ -1,7 +1,7 @@
|
||||
const assetPath = require("../services/asset_path.js");
|
||||
const assetPath = require("../services/asset_path");
|
||||
const path = require("path");
|
||||
const express = require("express");
|
||||
const env = require("../services/env.js");
|
||||
const env = require("../services/env");
|
||||
|
||||
const persistentCacheStatic = (root, options) => {
|
||||
if (!env.isDev()) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
const session = require("express-session");
|
||||
const sessionSecret = require("../services/session_secret.js");
|
||||
const dataDir = require("../services/data_dir.js");
|
||||
const sessionSecret = require("../services/session_secret");
|
||||
const dataDir = require("../services/data_dir");
|
||||
const FileStore = require('session-file-store')(session);
|
||||
|
||||
const sessionParser = session({
|
||||
|
@ -1,5 +1,6 @@
|
||||
const becca = require('../becca/becca');
|
||||
const NotFoundError = require("../errors/not_found_error");
|
||||
const protectedSessionService = require("./protected_session");
|
||||
|
||||
function getBlobPojo(entityName, entityId, opts = {}) {
|
||||
opts.preview = !!opts.preview;
|
||||
@ -10,19 +11,47 @@ function getBlobPojo(entityName, entityId, opts = {}) {
|
||||
throw new NotFoundError(`Entity ${entityName} '${entityId}' was not found.`);
|
||||
}
|
||||
|
||||
const blob = becca.getBlob(entity.blobId);
|
||||
const blob = becca.getBlob(entity);
|
||||
|
||||
const pojo = blob.getPojo();
|
||||
|
||||
if (!entity.hasStringContent()) {
|
||||
pojo.content = null;
|
||||
} else if (opts.preview && pojo.content.length > 10000) {
|
||||
pojo.content = `${pojo.content.substr(0, 10000)}\r\n\r\n... and ${pojo.content.length - 10000} more characters.`;
|
||||
} else {
|
||||
pojo.content = processContent(pojo.content, entity.isProtected, true);
|
||||
|
||||
if (opts.preview && pojo.content.length > 10000) {
|
||||
pojo.content = `${pojo.content.substr(0, 10000)}\r\n\r\n... and ${pojo.content.length - 10000} more characters.`;
|
||||
}
|
||||
}
|
||||
|
||||
return pojo;
|
||||
}
|
||||
|
||||
function processContent(content, isProtected, isStringContent) {
|
||||
if (isProtected) {
|
||||
if (protectedSessionService.isProtectedSessionAvailable()) {
|
||||
content = content === null ? null : protectedSessionService.decrypt(content);
|
||||
} else {
|
||||
content = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (isStringContent) {
|
||||
return content === null ? "" : content.toString("utf-8");
|
||||
} else {
|
||||
// see https://github.com/zadam/trilium/issues/3523
|
||||
// IIRC a zero-sized buffer can be returned as null from the database
|
||||
if (content === null) {
|
||||
// this will force de/encryption
|
||||
content = Buffer.alloc(0);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getBlobPojo
|
||||
getBlobPojo,
|
||||
processContent
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
const log = require("./log");
|
||||
const revisionService = require("./revisions.js");
|
||||
const revisionService = require("./revisions");
|
||||
const becca = require("../becca/becca");
|
||||
const cloningService = require("./cloning");
|
||||
const branchService = require("./branches");
|
||||
|
@ -13,7 +13,6 @@ const revisionService = require('./revisions.js');
|
||||
const becca = require("../becca/becca");
|
||||
const utils = require("../services/utils");
|
||||
const {sanitizeAttributeName} = require("./sanitize_attribute_name");
|
||||
const {note} = require("../../spec/search/becca_mocking.js");
|
||||
const noteTypes = require("../services/note_types").getNoteTypeNames();
|
||||
|
||||
class ConsistencyChecks {
|
||||
|
@ -187,8 +187,6 @@ function importHtml(taskContext, file, parentNote) {
|
||||
function importAttachment(taskContext, file, parentNote) {
|
||||
const mime = mimeService.getMime(file.originalname) || file.mimetype;
|
||||
|
||||
console.log("mime", mime);
|
||||
|
||||
if (mime.startsWith("image/")) {
|
||||
imageService.saveImageToAttachment(parentNote.noteId, file.buffer, file.originalname, taskContext.data.shrinkImages);
|
||||
|
||||
|
@ -21,7 +21,7 @@ const htmlSanitizer = require("./html_sanitizer");
|
||||
const ValidationError = require("../errors/validation_error");
|
||||
const noteTypesService = require("./note_types");
|
||||
const fs = require("fs");
|
||||
const ws = require("./ws.js");
|
||||
const ws = require("./ws");
|
||||
|
||||
/** @param {BNote} parentNote */
|
||||
function getNewNotePosition(parentNote) {
|
||||
|
@ -8,7 +8,6 @@ const shareRoot = require("./share_root");
|
||||
const contentRenderer = require("./content_renderer");
|
||||
const assetPath = require("../services/asset_path");
|
||||
const appPath = require("../services/app_path");
|
||||
const utils = require("../services/utils.js");
|
||||
|
||||
function getSharedSubTreeRoot(note) {
|
||||
if (note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user