mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	changes in backend script running
This commit is contained in:
		| @@ -32,6 +32,17 @@ class Note extends Entity { | ||||
|         return this.repository.getEntities("SELECT * FROM attributes WHERE noteId = ? AND isDeleted = 0", [this.noteId]); | ||||
|     } | ||||
|  | ||||
|     // WARNING: this doesn't take into account the possibility to have multi-valued attributes! | ||||
|     async getAttributeMap() { | ||||
|         const map = {}; | ||||
|  | ||||
|         for (const attr of await this.getAttributes()) { | ||||
|             map[attr.name] = attr.value; | ||||
|         } | ||||
|  | ||||
|         return map; | ||||
|     } | ||||
|  | ||||
|     async getAttribute(name) { | ||||
|         return this.repository.getEntity("SELECT * FROM attributes WHERE noteId = ? AND name = ?", [this.noteId, name]); | ||||
|     } | ||||
|   | ||||
| @@ -4,7 +4,6 @@ const express = require('express'); | ||||
| const router = express.Router(); | ||||
| const auth = require('../../services/auth'); | ||||
| const wrap = require('express-promise-wrap').wrap; | ||||
| const notes = require('../../services/notes'); | ||||
| const attributes = require('../../services/attributes'); | ||||
| const script = require('../../services/script'); | ||||
| const Repository = require('../../services/repository'); | ||||
| @@ -24,13 +23,15 @@ router.post('/job', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| })); | ||||
|  | ||||
| router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
|     const noteIds = await attributes.getNoteIdsWithAttribute("run_on_startup"); | ||||
|     const noteIds = await attributes.getNoteIdsWithAttribute("run", "frontend_startup"); | ||||
|     const repository = new Repository(req); | ||||
|  | ||||
|     const scripts = []; | ||||
|  | ||||
|     for (const noteId of noteIds) { | ||||
|         scripts.push(await getNoteWithSubtreeScript(noteId, repository)); | ||||
|         const note = await repository.getNote(noteId); | ||||
|  | ||||
|         scripts.push(await script.getNoteScript(note)); | ||||
|     } | ||||
|  | ||||
|     res.send(scripts); | ||||
| @@ -38,55 +39,9 @@ router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
|  | ||||
| router.get('/subtree/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
|     const repository = new Repository(req); | ||||
|     const noteId = req.params.noteId; | ||||
|     const note = await repository.getNote(req.params.noteId); | ||||
|  | ||||
|     res.send(await getNoteWithSubtreeScript(noteId, repository)); | ||||
|     res.send(await script.getNoteScript(note, repository)); | ||||
| })); | ||||
|  | ||||
| async function getNoteWithSubtreeScript(noteId, repository) { | ||||
|     const note = await repository.getNote(noteId); | ||||
|  | ||||
|     let noteScript = note.content; | ||||
|  | ||||
|     if (note.isJavaScript()) { | ||||
|         // last \r\n is necessary if script contains line comment on its last line | ||||
|         noteScript = "(async function() {" + noteScript + "\r\n})()"; | ||||
|     } | ||||
|  | ||||
|     const subTreeScripts = await getSubTreeScripts(noteId, [noteId], repository, note.isJavaScript()); | ||||
|  | ||||
|     return subTreeScripts + noteScript; | ||||
| } | ||||
|  | ||||
| async function getSubTreeScripts(parentId, includedNoteIds, repository, isJavaScript) { | ||||
|     const children = await repository.getEntities(` | ||||
|                                       SELECT notes.*  | ||||
|                                       FROM notes JOIN note_tree USING(noteId) | ||||
|                                       WHERE note_tree.isDeleted = 0 AND notes.isDeleted = 0 | ||||
|                                            AND note_tree.parentNoteId = ? AND (notes.type = 'code' OR notes.type = 'file') | ||||
|                                            AND (notes.mime = 'application/javascript'  | ||||
|                                                 OR notes.mime = 'application/x-javascript'  | ||||
|                                                 OR notes.mime = 'text/html')`, [parentId]); | ||||
|  | ||||
|     let script = "\r\n"; | ||||
|  | ||||
|     for (const child of children) { | ||||
|         if (includedNoteIds.includes(child.noteId)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         includedNoteIds.push(child.noteId); | ||||
|  | ||||
|         script += await getSubTreeScripts(child.noteId, includedNoteIds, repository); | ||||
|  | ||||
|         if (!isJavaScript && child.isJavaScript()) { | ||||
|             child.content = '<script>' + child.content + '</script>'; | ||||
|         } | ||||
|  | ||||
|         script += child.content + "\r\n"; | ||||
|     } | ||||
|  | ||||
|     return script; | ||||
| } | ||||
|  | ||||
| module.exports = router; | ||||
| @@ -11,7 +11,8 @@ const BUILTIN_ATTRIBUTES = [ | ||||
|     'calendar_root', | ||||
|     'hide_in_autocomplete', | ||||
|     'exclude_from_export', | ||||
|     'run' | ||||
|     'run', | ||||
|     'manual_transaction_handling' | ||||
| ]; | ||||
|  | ||||
| async function getNoteAttributeMap(noteId) { | ||||
|   | ||||
| @@ -19,7 +19,7 @@ async function runNotesWithAttribute(runAttrValue) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| setTimeout(() => runNotesWithAttribute('on_startup'), 10 * 1000); | ||||
| setTimeout(() => runNotesWithAttribute('backend_startup'), 10 * 1000); | ||||
|  | ||||
| setInterval(() => runNotesWithAttribute('hourly'), 3600 * 1000); | ||||
|  | ||||
|   | ||||
| @@ -6,11 +6,10 @@ async function executeNote(note) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const ctx = new ScriptContext(); | ||||
|     const manualTransactionHandling = (await note.getAttributeMap()).manual_transaction_handling !== undefined; | ||||
|     const noteScript = await getNoteScript(note); | ||||
|  | ||||
|     return await sql.doInTransaction(async () => { | ||||
|         return await (function() { return eval(`const api = this; (async function() {${note.content}\n\r})()`); }.call(ctx)); | ||||
|     }); | ||||
|     return await executeJob(noteScript, [], manualTransactionHandling); | ||||
| } | ||||
|  | ||||
| async function executeScript(dataKey, script, params) { | ||||
| @@ -84,8 +83,38 @@ function getParams(params) { | ||||
|     }).join(","); | ||||
| } | ||||
|  | ||||
| async function getNoteScript(note) { | ||||
|     const subTreeScripts = await getSubTreeScripts(note, [note.noteId]); | ||||
|  | ||||
|     // last \r\n is necessary if script contains line comment on its last line | ||||
|     return "async function() {" + subTreeScripts + note.content + "\r\n}"; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param includedNoteIds - if multiple child note scripts reference same dependency (child note), | ||||
|  *                          it will be included just once | ||||
|  */ | ||||
| async function getSubTreeScripts(parent, includedNoteIds) { | ||||
|     let script = "\r\n"; | ||||
|  | ||||
|     for (const child of await parent.getChildren()) { | ||||
|         if (!child.isJavaScript() || includedNoteIds.includes(child.noteId)) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         includedNoteIds.push(child.noteId); | ||||
|  | ||||
|         script += await getSubTreeScripts(child.noteId, includedNoteIds); | ||||
|  | ||||
|         script += child.content + "\r\n"; | ||||
|     } | ||||
|  | ||||
|     return script; | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     executeNote, | ||||
|     executeScript, | ||||
|     setJob | ||||
|     setJob, | ||||
|     getNoteScript | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user