mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	note cache fixes for created notes
This commit is contained in:
		| @@ -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'); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -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 | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -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(); | ||||||
|                 } |                 } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user