diff --git a/package-lock.json b/package-lock.json index ab5939714..5de5daa81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "trilium", - "version": "0.40.3", + "version": "0.40.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1208,9 +1208,9 @@ "optional": true }, "bowser": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.7.0.tgz", - "integrity": "sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w==" + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", + "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==" }, "boxen": { "version": "4.2.0", @@ -2165,9 +2165,9 @@ "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=" }, "dayjs": { - "version": "1.8.20", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.20.tgz", - "integrity": "sha512-mH0MCDxw6UCGJYxVN78h8ugWycZAO8thkj3bW6vApL5tS0hQplIDdAQcmbvl7n35H0AKdCJQaArTrIQw2xt4Qg==" + "version": "1.8.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.21.tgz", + "integrity": "sha512-1kbWK0hziklUHkGgiKr7xm59KwAg/K3Tp7H/8X+f58DnNCwY3pKYjOCJpIlVs125FRBukGVZdKZojC073D0IeQ==" }, "debug": { "version": "4.1.1", @@ -2669,9 +2669,9 @@ "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" }, "electron": { - "version": "9.0.0-beta.2", - "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.2.tgz", - "integrity": "sha512-WkRkUh5gE5B+b9XdTDvC67VvG118J0+wURcBpcXlBZJ9k+oqn0qcX+D3NG1WitXjcrAdV18cx5taUOat8zxAeA==", + "version": "9.0.0-beta.3", + "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.3.tgz", + "integrity": "sha512-se2XiC3sc6o8EUL/uE7bOknW7/gh37mQ+7uX8idugfYyK1oCISfr5CqtVXOMNTwMtx0opdFQ1HFC+W2ckNiPXg==", "dev": true, "requires": { "@electron/get": "^1.0.1", @@ -3790,9 +3790,9 @@ } }, "file-type": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-14.1.2.tgz", - "integrity": "sha512-9NI4+QzDlEPB6OETc/FcJt8i8vNT396VweRwEwLcE07MnorWkZDopNuc+MeoYA7ArbzoK044JbaDExWys8deTQ==", + "version": "14.1.3", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-14.1.3.tgz", + "integrity": "sha512-fTTNfpY1QxlpKCrA5bRxZL/6f7+6jUCJkOCCzFkAI+tmLu5lfX+4Zo22GG1orRhVH7Dx0fHtMFXq0++NDjKn/w==", "requires": { "readable-web-to-node-stream": "^2.0.0", "strtok3": "^6.0.0", @@ -4712,9 +4712,9 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "helmet": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.21.2.tgz", - "integrity": "sha512-okUo+MeWgg00cKB8Csblu8EXgcIoDyb5ZS/3u0W4spCimeVuCUvVZ6Vj3O2VJ1Sxpyb8jCDvzu0L1KKT11pkIg==", + "version": "3.21.3", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.21.3.tgz", + "integrity": "sha512-8OjGNdpG3WQhPO71fSy2fT4X3FSNutU1LDeAf+YS+Vil6r+fE7w8per5mNed6egGYbZl3QhKXgFzMYSwys+YQw==", "requires": { "depd": "2.0.0", "dns-prefetch-control": "0.2.0", @@ -4723,7 +4723,7 @@ "feature-policy": "0.3.0", "frameguard": "3.1.0", "helmet-crossdomain": "0.4.0", - "helmet-csp": "2.9.4", + "helmet-csp": "2.9.5", "hide-powered-by": "1.1.0", "hpkp": "2.0.0", "hsts": "2.2.0", @@ -4746,11 +4746,11 @@ "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==" }, "helmet-csp": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.9.4.tgz", - "integrity": "sha512-qUgGx8+yk7Xl8XFEGI4MFu1oNmulxhQVTlV8HP8tV3tpfslCs30OZz/9uQqsWPvDISiu/NwrrCowsZBhFADYqg==", + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.9.5.tgz", + "integrity": "sha512-w9nps5adqFQwgktVPDbXkARmZot/nr8aegzQas9AXdBSwBFBBefPpDSTV0wtgHlAUdDwY6MZo7qAl9yts3ppJg==", "requires": { - "bowser": "^2.7.0", + "bowser": "2.9.0", "camelize": "1.0.0", "content-security-policy-builder": "2.1.0", "dasherize": "2.0.0" diff --git a/package.json b/package.json index 42939d540..42170b04e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "commonmark": "0.29.1", "cookie-parser": "1.4.4", "csurf": "1.11.0", - "dayjs": "1.8.20", + "dayjs": "1.8.21", "debug": "4.1.1", "ejs": "2.7.4", "electron-debug": "3.0.1", @@ -37,9 +37,9 @@ "electron-window-state": "5.0.3", "express": "4.17.1", "express-session": "1.17.0", - "file-type": "14.1.2", + "file-type": "14.1.3", "fs-extra": "8.1.0", - "helmet": "3.21.2", + "helmet": "3.21.3", "html": "1.0.0", "html2plaintext": "2.1.2", "http-proxy-agent": "4.0.1", @@ -75,7 +75,7 @@ "ws": "7.2.1" }, "devDependencies": { - "electron": "9.0.0-beta.2", + "electron": "9.0.0-beta.3", "electron-builder": "22.3.2", "electron-packager": "14.2.1", "electron-rebuild": "1.10.0", diff --git a/src/public/javascripts/services/frontend_script_api.js b/src/public/javascripts/services/frontend_script_api.js index f813d3a13..da2bd014a 100644 --- a/src/public/javascripts/services/frontend_script_api.js +++ b/src/public/javascripts/services/frontend_script_api.js @@ -305,9 +305,32 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain this.setupElementTooltip = noteTooltipService.setupElementTooltip; /** + * @deprecated use protectNote and protectSubtree instead * @method */ - this.protectActiveNote = protectedSessionService.protectNoteAndSendToServer; + this.protectActiveNote = async () => { + const activeNote = appContext.tabManager.getActiveTabNote(); + + await protectedSessionService.protectNote(activeNote.noteId, true, false); + }; + + /** + * @method + * @param {string} noteId + * @param {boolean} protect - true to protect note, false to unprotect + */ + this.protectNote = async (noteId, protect) => { + await protectedSessionService.protectNote(noteId, protect, false); + }; + + /** + * @method + * @param {string} noteId + * @param {boolean} protect - true to protect subtree, false to unprotect + */ + this.protectSubTree = async (noteId, protect) => { + await protectedSessionService.protectNote(noteId, protect, true); + }; /** * Returns date-note for today. If it doesn't exist, it is automatically created. diff --git a/src/public/javascripts/services/protected_session.js b/src/public/javascripts/services/protected_session.js index 918533eb7..1e2cba0f5 100644 --- a/src/public/javascripts/services/protected_session.js +++ b/src/public/javascripts/services/protected_session.js @@ -68,46 +68,10 @@ async function enterProtectedSessionOnServer(password) { }); } -async function protectNoteAndSendToServer() { - if (!appContext.tabManager.getActiveTabNote() || appContext.tabManager.getActiveTabNote().isProtected) { - return; - } - +async function protectNote(noteId, protect, includingSubtree) { await enterProtectedSession(); - const note = appContext.tabManager.getActiveTabNote(); - note.isProtected = true; - - await appContext.tabManager.getActiveTabContext().saveNote(); -} - -async function unprotectNoteAndSendToServer() { - const activeNote = appContext.tabManager.getActiveTabNote(); - - if (!activeNote.isProtected) { - toastService.showAndLogError(`Note ${activeNote.noteId} is not protected`); - - return; - } - - if (!protectedSessionHolder.isProtectedSessionAvailable()) { - console.log("Unprotecting notes outside of protected session is not allowed."); - // the reason is that it's not easy to handle even with enterProtectedSession, - // because we would first have to make sure the note is loaded and only then unprotect - // we used to have a bug where we would overwrite the previous note with unprotected content. - - return; - } - - activeNote.isProtected = false; - - await appContext.tabManager.getActiveTabContext().saveNote(); -} - -async function protectSubtree(noteId, protect) { - await enterProtectedSession(); - - await server.put('notes/' + noteId + "/protect/" + (protect ? 1 : 0)); + await server.put(`notes/${noteId}/protect/${protect ? 1 : 0}?subtree=${includingSubtree ? 1 : 0}`); } function makeToast(message, protectingLabel, text) { @@ -140,10 +104,8 @@ ws.subscribeToMessages(async message => { }); export default { - protectSubtree, + protectNote, enterProtectedSession, leaveProtectedSession, - protectNoteAndSendToServer, - unprotectNoteAndSendToServer, setupProtectedSession }; \ No newline at end of file diff --git a/src/public/javascripts/services/tab_manager.js b/src/public/javascripts/services/tab_manager.js index 3049429fe..10756a0ca 100644 --- a/src/public/javascripts/services/tab_manager.js +++ b/src/public/javascripts/services/tab_manager.js @@ -90,11 +90,12 @@ export default class TabManager extends Component { await this.tabsUpdate.allowUpdateWithoutChange(async () => { for (const tab of filteredTabs) { const tabContext = this.openEmptyTab(tab.tabId); - await tabContext.setNote(tab.notePath); if (tab.active) { this.activateTab(tabContext.tabId); } + + await tabContext.setNote(tab.notePath); } }); } diff --git a/src/public/javascripts/widgets/note_detail.js b/src/public/javascripts/widgets/note_detail.js index ea02709b2..dfdbd2b17 100644 --- a/src/public/javascripts/widgets/note_detail.js +++ b/src/public/javascripts/widgets/note_detail.js @@ -151,16 +151,14 @@ export default class NoteDetailWidget extends TabAwareWidget { } async getWidgetType() { - const note = this.note; - - if (!note) { + if (!this.note) { return "empty"; } - let type = note.type; + let type = this.note.type; if (type === 'text' && !this.tabContext.autoBookDisabled - && note.hasChildren() + && this.note.hasChildren() && utils.isDesktop()) { const noteComplement = await this.tabContext.getNoteComplement(); @@ -170,7 +168,7 @@ export default class NoteDetailWidget extends TabAwareWidget { } } - if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) { + if (this.note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) { type = 'protected-session'; } diff --git a/src/public/javascripts/widgets/note_tree.js b/src/public/javascripts/widgets/note_tree.js index 1192bf680..3d2f5e32b 100644 --- a/src/public/javascripts/widgets/note_tree.js +++ b/src/public/javascripts/widgets/note_tree.js @@ -804,11 +804,11 @@ export default class NoteTreeWidget extends TabAwareWidget { } protectSubtreeCommand({node}) { - protectedSessionService.protectSubtree(node.data.noteId, true); + protectedSessionService.protectNote(node.data.noteId, true, true); } unprotectSubtreeCommand({node}) { - protectedSessionService.protectSubtree(node.data.noteId, false); + protectedSessionService.protectNote(node.data.noteId, false, true); } duplicateNoteCommand({node}) { diff --git a/src/public/javascripts/widgets/protected_note_switch.js b/src/public/javascripts/widgets/protected_note_switch.js index f396f5fc5..ab691b44d 100644 --- a/src/public/javascripts/widgets/protected_note_switch.js +++ b/src/public/javascripts/widgets/protected_note_switch.js @@ -21,10 +21,10 @@ export default class ProtectedNoteSwitchWidget extends TabAwareWidget { this.$widget = $(TPL); this.$protectButton = this.$widget.find(".protect-button"); - this.$protectButton.on('click', protectedSessionService.protectNoteAndSendToServer); + this.$protectButton.on('click', () => protectedSessionService.protectNote(this.noteId, true, false)); this.$unprotectButton = this.$widget.find(".unprotect-button"); - this.$unprotectButton.on('click', protectedSessionService.unprotectNoteAndSendToServer); + this.$unprotectButton.on('click', () => protectedSessionService.protectNote(this.noteId, false, false)); return this.$widget; } @@ -33,6 +33,12 @@ export default class ProtectedNoteSwitchWidget extends TabAwareWidget { this.$protectButton.toggleClass("active", note.isProtected); this.$protectButton.prop("disabled", note.isProtected); this.$unprotectButton.toggleClass("active", !note.isProtected); - this.$unprotectButton.prop("disabled", !note.isProtected || !protectedSessionHolder.isProtectedSessionAvailable()); + this.$unprotectButton.prop("disabled", !note.isProtected); + } + + async entitiesReloadedEvent({loadResults}) { + if (loadResults.isNoteReloaded(this.noteId)) { + this.refresh(); + } } } \ No newline at end of file diff --git a/src/public/javascripts/widgets/type_widgets/render.js b/src/public/javascripts/widgets/type_widgets/render.js index 37633afeb..8f95dbea0 100644 --- a/src/public/javascripts/widgets/type_widgets/render.js +++ b/src/public/javascripts/widgets/type_widgets/render.js @@ -32,7 +32,7 @@ export default class RenderTypeWidget extends TypeWidget { const renderNotesFound = await renderService.render(note, this.$noteDetailRenderContent); - console.log("render", this.$noteDetailRenderContent); + console.trace("render"); if (!renderNotesFound) { this.$noteDetailRenderHelp.show(); diff --git a/src/public/javascripts/widgets/type_widgets/type_widget.js b/src/public/javascripts/widgets/type_widgets/type_widget.js index e42329286..6bedc0bd3 100644 --- a/src/public/javascripts/widgets/type_widgets/type_widget.js +++ b/src/public/javascripts/widgets/type_widgets/type_widget.js @@ -16,10 +16,11 @@ export default class TypeWidget extends TabAwareWidget { */ doRefresh(note) {} - refresh() { - const widgetType = this.constructor.getType(); + async refresh() { + const thisWidgetType = this.constructor.getType(); + const noteWidgetType = await this.noteDetailWidget.getWidgetType(); - if (widgetType !== this.noteDetailWidget.type) { + if (thisWidgetType !== noteWidgetType) { this.toggle(false); this.cleanup(); diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js index 102b8e928..fde86bb32 100644 --- a/src/routes/api/notes.js +++ b/src/routes/api/notes.js @@ -83,14 +83,15 @@ async function sortNotes(req) { await treeService.sortNotesAlphabetically(noteId); } -async function protectSubtree(req) { +async function protectNote(req) { const noteId = req.params.noteId; const note = await repository.getNote(noteId); const protect = !!parseInt(req.params.isProtected); + const includingSubTree = !!parseInt(req.query.subtree); const taskContext = new TaskContext(utils.randomString(10), 'protect-notes', {protect}); - await noteService.protectNoteRecursively(note, protect, taskContext); + await noteService.protectNoteRecursively(note, protect, includingSubTree, taskContext); taskContext.taskSucceeded(); } @@ -183,7 +184,7 @@ module.exports = { undeleteNote, createNote, sortNotes, - protectSubtree, + protectNote, setNoteTypeMime, getRelationMap, changeTitle, diff --git a/src/routes/routes.js b/src/routes/routes.js index 1e6c0ce74..53a01e3a1 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -134,7 +134,7 @@ function register(app) { apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote); apiRoute(POST, '/api/notes/:parentNoteId/children', notesApiRoute.createNote); apiRoute(PUT, '/api/notes/:noteId/sort', notesApiRoute.sortNotes); - apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectSubtree); + apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote); apiRoute(PUT, /\/api\/notes\/(.*)\/type\/(.*)\/mime\/(.*)/, notesApiRoute.setNoteTypeMime); apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions); apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions); diff --git a/src/services/notes.js b/src/services/notes.js index 068ad0536..383398af5 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -186,13 +186,15 @@ async function createTextNote(parentNoteId, title, content = "", params = {}) { return await createNewNote(params); } -async function protectNoteRecursively(note, protect, taskContext) { +async function protectNoteRecursively(note, protect, includingSubTree, taskContext) { await protectNote(note, protect); taskContext.increaseProgressCount(); - for (const child of await note.getChildNotes()) { - await protectNoteRecursively(child, protect, taskContext); + if (includingSubTree) { + for (const child of await note.getChildNotes()) { + await protectNoteRecursively(child, protect, taskContext); + } } }