mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	initial work on new router model
This commit is contained in:
		| @@ -5,100 +5,88 @@ const router = express.Router(); | ||||
| const auth = require('../../services/auth'); | ||||
| const sql = require('../../services/sql'); | ||||
| const notes = require('../../services/notes'); | ||||
| const log = require('../../services/log'); | ||||
| const utils = require('../../services/utils'); | ||||
| const protected_session = require('../../services/protected_session'); | ||||
| const tree = require('../../services/tree'); | ||||
| const sync_table = require('../../services/sync_table'); | ||||
| const wrap = require('express-promise-wrap').wrap; | ||||
|  | ||||
| router.get('/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function getNote(req) { | ||||
|     const noteId = req.params.noteId; | ||||
|  | ||||
|     const detail = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); | ||||
|     const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); | ||||
|  | ||||
|     if (!detail) { | ||||
|         log.info("Note " + noteId + " has not been found."); | ||||
|  | ||||
|         return res.status(404).send({}); | ||||
|     if (!note) { | ||||
|         return [404, "Note " + noteId + " has not been found."]; | ||||
|     } | ||||
|  | ||||
|     protected_session.decryptNote(req, detail); | ||||
|     protected_session.decryptNote(req, note); | ||||
|  | ||||
|     if (detail.type === 'file') { | ||||
|     if (note.type === 'file') { | ||||
|         // no need to transfer (potentially large) file payload for this request | ||||
|         detail.content = null; | ||||
|         note.content = null; | ||||
|     } | ||||
|  | ||||
|     res.send(detail); | ||||
| })); | ||||
|     return note; | ||||
| } | ||||
|  | ||||
| router.post('/:parentNoteId/children', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function createNote(req) { | ||||
|     const sourceId = req.headers.source_id; | ||||
|     const parentNoteId = req.params.parentNoteId; | ||||
|     const newNote = req.body; | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     const { noteId, branchId, note } = await notes.createNewNote(parentNoteId, newNote, req, sourceId); | ||||
|  | ||||
|         res.send({ | ||||
|     return { | ||||
|         'noteId': noteId, | ||||
|         'branchId': branchId, | ||||
|         'note': note | ||||
|         }); | ||||
|     }); | ||||
| })); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| router.put('/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function updateNote(req) { | ||||
|     const note = req.body; | ||||
|     const noteId = req.params.noteId; | ||||
|     const sourceId = req.headers.source_id; | ||||
|     const dataKey = protected_session.getDataKey(req); | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     await notes.updateNote(noteId, note, dataKey, sourceId); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|     res.send({}); | ||||
| })); | ||||
|  | ||||
| router.put('/:noteId/sort', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function sortNotes(req) { | ||||
|     const noteId = req.params.noteId; | ||||
|     const sourceId = req.headers.source_id; | ||||
|     const dataKey = protected_session.getDataKey(req); | ||||
|  | ||||
|     await tree.sortNotesAlphabetically(noteId, dataKey, sourceId); | ||||
| } | ||||
|  | ||||
|     res.send({}); | ||||
| })); | ||||
|  | ||||
| router.put('/:noteId/protect-sub-tree/:isProtected', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function protectBranch(req) { | ||||
|     const noteId = req.params.noteId; | ||||
|     const isProtected = !!parseInt(req.params.isProtected); | ||||
|     const dataKey = protected_session.getDataKey(req); | ||||
|     const sourceId = req.headers.source_id; | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     await notes.protectNoteRecursively(noteId, dataKey, isProtected, sourceId); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|     res.send({}); | ||||
| })); | ||||
|  | ||||
| router.put(/\/(.*)\/type\/(.*)\/mime\/(.*)/, auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function setNoteTypeMime(req) { | ||||
|     const noteId = req.params[0]; | ||||
|     const type = req.params[1]; | ||||
|     const mime = req.params[2]; | ||||
|     const sourceId = req.headers.source_id; | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     await sql.execute("UPDATE notes SET type = ?, mime = ?, dateModified = ? WHERE noteId = ?", | ||||
|         [type, mime, utils.nowDate(), noteId]); | ||||
|  | ||||
|     await sync_table.addNoteSync(noteId, sourceId); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|     res.send({}); | ||||
| })); | ||||
|  | ||||
| module.exports = router; | ||||
| module.exports = { | ||||
|     getNote, | ||||
|     updateNote, | ||||
|     createNote, | ||||
|     sortNotes, | ||||
|     protectBranch, | ||||
|     setNoteTypeMime | ||||
| }; | ||||
| @@ -1,17 +1,13 @@ | ||||
| "use strict"; | ||||
|  | ||||
| const express = require('express'); | ||||
| const router = express.Router(); | ||||
| const sql = require('../../services/sql'); | ||||
| const options = require('../../services/options'); | ||||
| const utils = require('../../services/utils'); | ||||
| const auth = require('../../services/auth'); | ||||
| const config = require('../../services/config'); | ||||
| const protected_session = require('../../services/protected_session'); | ||||
| const sync_table = require('../../services/sync_table'); | ||||
| const wrap = require('express-promise-wrap').wrap; | ||||
|  | ||||
| router.get('/', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function getTree(req) { | ||||
|     const branches = await sql.getRows(` | ||||
|       SELECT  | ||||
|         branchId, | ||||
| @@ -27,15 +23,13 @@ router.get('/', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
|       ORDER BY  | ||||
|         notePosition`); | ||||
|  | ||||
|     let notes = [{ | ||||
|     const notes = [{ | ||||
|         noteId: 'root', | ||||
|         title: 'root', | ||||
|         isProtected: false, | ||||
|         type: 'none', | ||||
|         mime: 'none' | ||||
|     }]; | ||||
|  | ||||
|     notes = notes.concat(await sql.getRows(` | ||||
|     }].concat(await sql.getRows(` | ||||
|       SELECT  | ||||
|         notes.noteId, | ||||
|         notes.title, | ||||
| @@ -58,15 +52,15 @@ router.get('/', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
|         note.isProtected = !!note.isProtected; | ||||
|     }); | ||||
|  | ||||
|     res.send({ | ||||
|     return { | ||||
|         instanceName: config.General ? config.General.instanceName : null, | ||||
|         branches: branches, | ||||
|         notes: notes, | ||||
|         start_note_path: await options.getOption('start_note_path') | ||||
|     }); | ||||
| })); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| router.put('/:branchId/set-prefix', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function setPrefix(req) { | ||||
|     const branchId = req.params.branchId; | ||||
|     const sourceId = req.headers.source_id; | ||||
|     const prefix = utils.isEmptyOrWhitespace(req.body.prefix) ? null : req.body.prefix; | ||||
| @@ -77,7 +71,10 @@ router.put('/:branchId/set-prefix', auth.checkApiAuth, wrap(async (req, res, nex | ||||
|         await sync_table.addBranchSync(branchId, sourceId); | ||||
|     }); | ||||
|  | ||||
|     res.send({}); | ||||
| })); | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| module.exports = router; | ||||
| module.exports = { | ||||
|     getTree, | ||||
|     setPrefix | ||||
| }; | ||||
|   | ||||
| @@ -15,15 +15,17 @@ const wrap = require('express-promise-wrap').wrap; | ||||
|  * for not deleted note trees. There may be multiple deleted note-parent note relationships. | ||||
|  */ | ||||
|  | ||||
| router.put('/:branchId/move-to/:parentNoteId', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function moveBranchToParent(req) { | ||||
|     const branchId = req.params.branchId; | ||||
|     const parentNoteId = req.params.parentNoteId; | ||||
|     const sourceId = req.headers.source_id; | ||||
|  | ||||
|     const noteToMove = await tree.getBranch(branchId); | ||||
|  | ||||
|     if (!await tree.validateParentChild(res, parentNoteId, noteToMove.noteId, branchId)) { | ||||
|         return; | ||||
|     const validationResult = await tree.validateParentChild(parentNoteId, noteToMove.noteId, branchId); | ||||
|  | ||||
|     if (!validationResult.success) { | ||||
|         return [400, validationResult]; | ||||
|     } | ||||
|  | ||||
|     const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [parentNoteId]); | ||||
| @@ -31,17 +33,15 @@ router.put('/:branchId/move-to/:parentNoteId', auth.checkApiAuth, wrap(async (re | ||||
|  | ||||
|     const now = utils.nowDate(); | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     await sql.execute("UPDATE branches SET parentNoteId = ?, notePosition = ?, dateModified = ? WHERE branchId = ?", | ||||
|         [parentNoteId, newNotePos, now, branchId]); | ||||
|  | ||||
|     await sync_table.addBranchSync(branchId, sourceId); | ||||
|     }); | ||||
|  | ||||
|     res.send({ success: true }); | ||||
| })); | ||||
|     return { success: true }; | ||||
| } | ||||
|  | ||||
| router.put('/:branchId/move-before/:beforeBranchId', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function moveBranchBeforeNote(req) { | ||||
|     const branchId = req.params.branchId; | ||||
|     const beforeBranchId = req.params.beforeBranchId; | ||||
|     const sourceId = req.headers.source_id; | ||||
| @@ -49,11 +49,12 @@ router.put('/:branchId/move-before/:beforeBranchId', auth.checkApiAuth, wrap(asy | ||||
|     const noteToMove = await tree.getBranch(branchId); | ||||
|     const beforeNote = await tree.getBranch(beforeBranchId); | ||||
|  | ||||
|     if (!await tree.validateParentChild(res, beforeNote.parentNoteId, noteToMove.noteId, branchId)) { | ||||
|         return; | ||||
|     const validationResult = await tree.validateParentChild(beforeNote.parentNoteId, noteToMove.noteId, branchId); | ||||
|  | ||||
|     if (!validationResult.success) { | ||||
|         return [400, validationResult]; | ||||
|     } | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     // we don't change dateModified so other changes are prioritized in case of conflict | ||||
|     // also we would have to sync all those modified note trees otherwise hash checks would fail | ||||
|     await sql.execute("UPDATE branches SET notePosition = notePosition + 1 WHERE parentNoteId = ? AND notePosition >= ? AND isDeleted = 0", | ||||
| @@ -65,12 +66,11 @@ router.put('/:branchId/move-before/:beforeBranchId', auth.checkApiAuth, wrap(asy | ||||
|         [beforeNote.parentNoteId, beforeNote.notePosition, utils.nowDate(), branchId]); | ||||
|  | ||||
|     await sync_table.addBranchSync(branchId, sourceId); | ||||
|     }); | ||||
|  | ||||
|     res.send({ success: true }); | ||||
| })); | ||||
|     return { success: true }; | ||||
| } | ||||
|  | ||||
| router.put('/:branchId/move-after/:afterBranchId', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function moveBranchAfterNote(req) { | ||||
|     const branchId = req.params.branchId; | ||||
|     const afterBranchId = req.params.afterBranchId; | ||||
|     const sourceId = req.headers.source_id; | ||||
| @@ -78,11 +78,12 @@ router.put('/:branchId/move-after/:afterBranchId', auth.checkApiAuth, wrap(async | ||||
|     const noteToMove = await tree.getBranch(branchId); | ||||
|     const afterNote = await tree.getBranch(afterBranchId); | ||||
|  | ||||
|     if (!await tree.validateParentChild(res, afterNote.parentNoteId, noteToMove.noteId, branchId)) { | ||||
|         return; | ||||
|     const validationResult = await tree.validateParentChild(afterNote.parentNoteId, noteToMove.noteId, branchId); | ||||
|  | ||||
|     if (!validationResult.success) { | ||||
|         return [400, validationResult]; | ||||
|     } | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     // we don't change dateModified so other changes are prioritized in case of conflict | ||||
|     // also we would have to sync all those modified note trees otherwise hash checks would fail | ||||
|     await sql.execute("UPDATE branches SET notePosition = notePosition + 1 WHERE parentNoteId = ? AND notePosition > ? AND isDeleted = 0", | ||||
| @@ -94,30 +95,26 @@ router.put('/:branchId/move-after/:afterBranchId', auth.checkApiAuth, wrap(async | ||||
|         [afterNote.parentNoteId, afterNote.notePosition + 1, utils.nowDate(), branchId]); | ||||
|  | ||||
|     await sync_table.addBranchSync(branchId, sourceId); | ||||
|     }); | ||||
|  | ||||
|     res.send({ success: true }); | ||||
| })); | ||||
|     return { success: true }; | ||||
| } | ||||
|  | ||||
| router.put('/:branchId/expanded/:expanded', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
| async function setExpanded(req) { | ||||
|     const branchId = req.params.branchId; | ||||
|     const expanded = req.params.expanded; | ||||
|  | ||||
|     await sql.doInTransaction(async () => { | ||||
|     await sql.execute("UPDATE branches SET isExpanded = ? WHERE branchId = ?", [expanded, branchId]); | ||||
|  | ||||
|     // we don't sync expanded label | ||||
|     }); | ||||
| } | ||||
|  | ||||
|     res.send({}); | ||||
| })); | ||||
|  | ||||
| router.delete('/:branchId', auth.checkApiAuth, wrap(async (req, res, next) => { | ||||
|     await sql.doInTransaction(async () => { | ||||
| async function deleteBranch(req) { | ||||
|     await notes.deleteNote(req.params.branchId, req.headers.source_id); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|     res.send({}); | ||||
| })); | ||||
|  | ||||
| module.exports = router; | ||||
| module.exports = { | ||||
|     moveBranchToParent, | ||||
|     moveBranchBeforeNote, | ||||
|     moveBranchAfterNote, | ||||
|     setExpanded, | ||||
|     deleteBranch | ||||
| }; | ||||
| @@ -32,6 +32,39 @@ const senderRoute = require('./api/sender'); | ||||
| const filesRoute = require('./api/file_upload'); | ||||
| const searchRoute = require('./api/search'); | ||||
|  | ||||
| const express = require('express'); | ||||
| const router = express.Router(); | ||||
| const auth = require('../services/auth'); | ||||
| const cls = require('../services/cls'); | ||||
| const sql = require('../services/sql'); | ||||
|  | ||||
| function apiRoute(method, path, handler) { | ||||
|     router[method](path, auth.checkApiAuth, async (req, res, next) => { | ||||
|         try { | ||||
|             const resp = await cls.init(async () => { | ||||
|                 return await sql.doInTransaction(async () => { | ||||
|                     return await handler(req, res, next); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             if (Array.isArray(resp)) { | ||||
|                 res.status(resp[0]).send(resp[1]); | ||||
|             } | ||||
|             else if (resp === undefined) { | ||||
|                 res.status(200); | ||||
|             } | ||||
|             else { | ||||
|                 res.status(200).send(resp); | ||||
|             } | ||||
|         } | ||||
|         catch (e) { | ||||
|             next(e); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| const GET = 'get', POST = 'post', PUT = 'put', DELETE = 'delete'; | ||||
|  | ||||
| function register(app) { | ||||
|     app.use('/', indexRoute); | ||||
|     app.use('/login', loginRoute); | ||||
| @@ -39,9 +72,22 @@ function register(app) { | ||||
|     app.use('/migration', migrationRoute); | ||||
|     app.use('/setup', setupRoute); | ||||
|  | ||||
|     app.use('/api/tree', treeApiRoute); | ||||
|     app.use('/api/notes', notesApiRoute); | ||||
|     app.use('/api/tree', treeChangesApiRoute); | ||||
|     apiRoute(GET, '/api/tree', treeApiRoute.getTree); | ||||
|     apiRoute(PUT, '/api/tree/:branchId/set-prefix', treeApiRoute.setPrefix); | ||||
|  | ||||
|     apiRoute(PUT, '/api/tree/:branchId/move-to/:parentNoteId', treeChangesApiRoute.moveBranchToParent); | ||||
|     apiRoute(PUT, '/api/tree/:branchId/move-before/:beforeBranchId', treeChangesApiRoute.moveBranchBeforeNote); | ||||
|     apiRoute(PUT, '/api/tree/:branchId/move-after/:afterBranchId', treeChangesApiRoute.moveBranchAfterNote); | ||||
|     apiRoute(PUT, '/api/tree/:branchId/expanded/:expanded', treeChangesApiRoute.setExpanded); | ||||
|     apiRoute(DELETE, '/api/tree/:branchId', treeChangesApiRoute.deleteBranch); | ||||
|  | ||||
|     apiRoute(GET, '/api/notes/:noteId', notesApiRoute.getNote); | ||||
|     apiRoute(PUT, '/api/notes/:noteId', notesApiRoute.updateNote); | ||||
|     apiRoute(POST, '/api/notes/:parentNoteId/children', notesApiRoute.createNote); | ||||
|     apiRoute(PUT, '/api/notes/:noteId/sort', notesApiRoute.sortNotes); | ||||
|     apiRoute(PUT, '/api/notes/:noteId/protect-sub-tree/:isProtected', notesApiRoute.protectBranch); | ||||
|     apiRoute(PUT, /\/api\/notes\/(.*)\/type\/(.*)\/mime\/(.*)/, notesApiRoute.setNoteTypeMime); | ||||
|  | ||||
|     app.use('/api/notes', cloningApiRoute); | ||||
|     app.use('/api', labelsRoute); | ||||
|     app.use('/api/notes-revisions', noteRevisionsApiRoute); | ||||
| @@ -65,6 +111,7 @@ function register(app) { | ||||
|     app.use('/api/sender', senderRoute); | ||||
|     app.use('/api/files', filesRoute); | ||||
|     app.use('/api/search', searchRoute); | ||||
|     app.use('', router); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|   | ||||
| @@ -4,28 +4,24 @@ const sql = require('./sql'); | ||||
| const sync_table = require('./sync_table'); | ||||
| const protected_session = require('./protected_session'); | ||||
|  | ||||
| async function validateParentChild(res, parentNoteId, childNoteId, branchId = null) { | ||||
| async function validateParentChild(parentNoteId, childNoteId, branchId = null) { | ||||
|     const existing = await getExistingBranch(parentNoteId, childNoteId); | ||||
|  | ||||
|     if (existing && (branchId === null || existing.branchId !== branchId)) { | ||||
|         res.send({ | ||||
|         return { | ||||
|             success: false, | ||||
|             message: 'This note already exists in the target.' | ||||
|         }); | ||||
|  | ||||
|         return false; | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     if (!await checkTreeCycle(parentNoteId, childNoteId)) { | ||||
|         res.send({ | ||||
|         return { | ||||
|             success: false, | ||||
|             message: 'Moving note here would create cycle.' | ||||
|         }); | ||||
|  | ||||
|         return false; | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|     return { success: true }; | ||||
| } | ||||
|  | ||||
| async function getExistingBranch(parentNoteId, childNoteId) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user