note cache fixes for created notes

This commit is contained in:
zadam 2020-05-13 23:06:13 +02:00
parent 7992f32d34
commit a287bb59ea
4 changed files with 71 additions and 46 deletions

View File

@ -11,6 +11,7 @@ import Component from "../widgets/component.js";
import keyboardActionsService from "./keyboard_actions.js"; import keyboardActionsService from "./keyboard_actions.js";
import MobileScreenSwitcherExecutor from "../widgets/mobile_widgets/mobile_screen_switcher.js"; import MobileScreenSwitcherExecutor from "../widgets/mobile_widgets/mobile_screen_switcher.js";
import MainTreeExecutors from "./main_tree_executors.js"; import MainTreeExecutors from "./main_tree_executors.js";
import protectedSessionHolder from "./protected_session_holder.js";
class AppContext extends Component { class AppContext extends Component {
constructor(isMainWindow) { constructor(isMainWindow) {
@ -110,6 +111,8 @@ const appContext = new AppContext(window.glob.isMainWindow);
// we should save all outstanding changes before the page/app is closed // we should save all outstanding changes before the page/app is closed
$(window).on('beforeunload', () => { $(window).on('beforeunload', () => {
protectedSessionHolder.resetSessionCookie();
appContext.triggerEvent('beforeUnload'); appContext.triggerEvent('beforeUnload');
}); });

View File

@ -12,15 +12,19 @@ setInterval(() => {
resetProtectedSession(); resetProtectedSession();
} }
}, 5000); }, 10000);
function setProtectedSessionId(id) { function setProtectedSessionId(id) {
// using session cookie so that it disappears after browser/tab is closed // using session cookie so that it disappears after browser/tab is closed
utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, id); utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, id);
} }
function resetProtectedSession() { function resetSessionCookie() {
utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, null); utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, null);
}
function resetProtectedSession() {
resetSessionCookie();
// most secure solution - guarantees nothing remained in memory // most secure solution - guarantees nothing remained in memory
// since this expires because user doesn't use the app, it shouldn't be disruptive // since this expires because user doesn't use the app, it shouldn't be disruptive
@ -47,8 +51,9 @@ function touchProtectedSessionIfNecessary(note) {
export default { export default {
setProtectedSessionId, setProtectedSessionId,
resetSessionCookie,
resetProtectedSession, resetProtectedSession,
isProtectedSessionAvailable, isProtectedSessionAvailable,
touchProtectedSession, touchProtectedSession,
touchProtectedSessionIfNecessary touchProtectedSessionIfNecessary
}; };

View File

@ -109,11 +109,17 @@ async function addImagesToNote(images, note, content) {
const {note: imageNote, url} = await imageService.saveImage(note.noteId, buffer, filename, true); const {note: imageNote, url} = await imageService.saveImage(note.noteId, buffer, filename, true);
await new Attribute({
noteId: imageNote.noteId,
type: 'label',
name: 'hideInAutocomplete'
}).save();
await new Attribute({ await new Attribute({
noteId: note.noteId, noteId: note.noteId,
type: 'relation', type: 'relation',
value: imageNote.noteId, name: 'imageLink',
name: 'imageLink' value: imageNote.noteId
}).save(); }).save();
console.log(`Replacing ${imageId} with ${url}`); console.log(`Replacing ${imageId} with ${url}`);
@ -155,4 +161,4 @@ module.exports = {
addClipping, addClipping,
openNote, openNote,
handshake handshake
}; };

View File

@ -1,7 +1,6 @@
const sql = require('./sql'); const sql = require('./sql');
const sqlInit = require('./sql_init'); const sqlInit = require('./sql_init');
const eventService = require('./events'); const eventService = require('./events');
const repository = require('./repository');
const protectedSessionService = require('./protected_session'); const protectedSessionService = require('./protected_session');
const utils = require('./utils'); const utils = require('./utils');
const hoistedNoteService = require('./hoisted_note'); const hoistedNoteService = require('./hoisted_note');
@ -14,9 +13,6 @@ let branches
/** @type {Object.<String, Attribute>} */ /** @type {Object.<String, Attribute>} */
let attributes; let attributes;
/** @type {Object.<String, Attribute[]>} */
let noteAttributeCache = {};
let childParentToBranch = {}; let childParentToBranch = {};
class Note { class Note {
@ -28,7 +24,7 @@ class Note {
/** @param {boolean} */ /** @param {boolean} */
this.isProtected = !!row.isProtected; this.isProtected = !!row.isProtected;
/** @param {boolean} */ /** @param {boolean} */
this.isDecrypted = false; this.isDecrypted = !row.isProtected || !!row.isContentAvailable;
/** @param {Note[]} */ /** @param {Note[]} */
this.parents = []; this.parents = [];
/** @param {Note[]} */ /** @param {Note[]} */
@ -45,6 +41,10 @@ class Note {
/** @param {string|null} */ /** @param {string|null} */
this.fulltextCache = null; this.fulltextCache = null;
if (protectedSessionService.isProtectedSessionAvailable()) {
decryptProtectedNote(this);
}
} }
/** @return {Attribute[]} */ /** @return {Attribute[]} */
@ -114,6 +114,12 @@ class Note {
return this.hasAttribute('label', 'archived'); return this.hasAttribute('label', 'archived');
} }
get isHideInAutocompleteOrArchived() {
return this.attributes.find(attr =>
attr.type === 'label'
&& ["archived", "hideInAutocomplete"].includes(attr.name));
}
get hasInheritableOwnedArchivedLabel() { get hasInheritableOwnedArchivedLabel() {
return !!this.ownedAttributes.find(attr => attr.type === 'label' && attr.name === 'archived' && attr.isInheritable); return !!this.ownedAttributes.find(attr => attr.type === 'label' && attr.name === 'archived' && attr.isInheritable);
} }
@ -126,6 +132,11 @@ class Note {
get fulltext() { get fulltext() {
if (!this.fulltextCache) { if (!this.fulltextCache) {
if (this.isHideInAutocompleteOrArchived) {
this.fulltextCache = " "; // can't be empty
return this.fulltextCache;
}
this.fulltextCache = this.title.toLowerCase(); this.fulltextCache = this.title.toLowerCase();
for (const attr of this.attributes) { for (const attr of this.attributes) {
@ -193,6 +204,21 @@ class Branch {
/** @param {string} */ /** @param {string} */
this.prefix = row.prefix; this.prefix = row.prefix;
if (this.branchId === 'root') {
return;
}
const childNote = notes[this.noteId];
const parentNote = this.parentNote;
if (!childNote) {
console.log(`Cannot find child note ${this.noteId} of a branch ${this.branchId}`);
return;
}
childNote.parents.push(parentNote);
parentNote.children.push(childNote);
childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this; childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this;
} }
@ -222,6 +248,8 @@ class Attribute {
this.value = row.value; this.value = row.value;
/** @param {boolean} */ /** @param {boolean} */
this.isInheritable = !!row.isInheritable; this.isInheritable = !!row.isInheritable;
notes[this.noteId].ownedAttributes.push(this);
} }
get isAffectingSubtree() { get isAffectingSubtree() {
@ -264,42 +292,21 @@ async function load() {
attributes = await getMappedRows(`SELECT attributeId, noteId, type, name, value, isInheritable FROM attributes WHERE isDeleted = 0`, attributes = await getMappedRows(`SELECT attributeId, noteId, type, name, value, isInheritable FROM attributes WHERE isDeleted = 0`,
row => new Attribute(row)); row => new Attribute(row));
for (const attr of Object.values(attributes)) {
notes[attr.noteId].ownedAttributes.push(attr);
}
for (const branch of Object.values(branches)) {
if (branch.branchId === 'root') {
continue;
}
const childNote = notes[branch.noteId];
const parentNote = branch.parentNote;
if (!childNote) {
console.log(`Cannot find child note ${branch.noteId} of a branch ${branch.branchId}`);
continue;
}
childNote.parents.push(parentNote);
parentNote.children.push(childNote);
}
if (protectedSessionService.isProtectedSessionAvailable()) {
await decryptProtectedNotes();
}
loaded = true; loaded = true;
loadedPromiseResolve(); loadedPromiseResolve();
} }
async function decryptProtectedNotes() { function decryptProtectedNote(note) {
for (const note of notes) { if (note.isProtected && !note.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
if (note.isProtected && !note.isDecrypted) { note.title = protectedSessionService.decryptString(note.title);
note.title = protectedSessionService.decryptString(note.title);
note.isDecrypted = true; note.isDecrypted = true;
} }
}
async function decryptProtectedNotes() {
for (const note of Object.values(notes)) {
decryptProtectedNote(note);
} }
} }
@ -770,11 +777,17 @@ eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_DELETED
// we can assume we have protected session since we managed to update // we can assume we have protected session since we managed to update
note.title = entity.title; note.title = entity.title;
note.isDecrypted = true; note.isProtected = entity.isProtected;
note.isDecrypted = !entity.isProtected || !!entity.isContentAvailable;
note.fulltextCache = null; note.fulltextCache = null;
decryptProtectedNote(note);
} }
else { else {
notes[noteId] = new Note(entity); const note = new Note(entity);
notes[noteId] = note;
decryptProtectedNote(note);
} }
} }
else if (entityName === 'branches') { else if (entityName === 'branches') {
@ -848,8 +861,6 @@ eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_DELETED
attributes[attributeId] = attr; attributes[attributeId] = attr;
if (note) { if (note) {
note.ownedAttributes.push(attr);
if (attr.isAffectingSubtree) { if (attr.isAffectingSubtree) {
note.invalidateSubtreeCaches(); note.invalidateSubtreeCaches();
} }