diff --git a/src/public/javascripts/services/export.js b/src/public/javascripts/services/export.js index d945bfc1e..7d4180169 100644 --- a/src/public/javascripts/services/export.js +++ b/src/public/javascripts/services/export.js @@ -1,6 +1,7 @@ import treeService from './tree.js'; import protectedSessionHolder from './protected_session_holder.js'; import utils from './utils.js'; +import server from './server.js'; function exportSubTree(noteId) { const url = utils.getHost() + "/api/export/" + noteId + "?protectedSessionId=" diff --git a/src/routes/api/app_info.js b/src/routes/api/app_info.js index ddb392700..b574d14a1 100644 --- a/src/routes/api/app_info.js +++ b/src/routes/api/app_info.js @@ -1,13 +1,11 @@ "use strict"; -const express = require('express'); -const router = express.Router(); const app_info = require('../../services/app_info'); -const auth = require('../../services/auth'); -const wrap = require('express-promise-wrap').wrap; -router.get('', auth.checkApiAuth, wrap(async (req, res, next) => { - res.send(app_info); -})); +async function getAppInfo() { + return app_info; +} -module.exports = router; \ No newline at end of file +module.exports = { + getAppInfo +}; \ No newline at end of file diff --git a/src/routes/api/event_log.js b/src/routes/api/event_log.js index 598bc9f04..9644d4a7a 100644 --- a/src/routes/api/event_log.js +++ b/src/routes/api/event_log.js @@ -1,18 +1,12 @@ "use strict"; -const express = require('express'); -const router = express.Router(); const sql = require('../../services/sql'); -const auth = require('../../services/auth'); -const wrap = require('express-promise-wrap').wrap; -router.get('', auth.checkApiAuth, wrap(async (req, res, next) => { +async function getEventLog() { await deleteOld(); - const result = await sql.getRows("SELECT * FROM event_log ORDER BY dateAdded DESC"); - - res.send(result); -})); + return await sql.getRows("SELECT * FROM event_log ORDER BY dateAdded DESC"); +} async function deleteOld() { const cutoffId = await sql.getValue("SELECT id FROM event_log ORDER BY id DESC LIMIT 1000, 1"); @@ -24,4 +18,6 @@ async function deleteOld() { } } -module.exports = router; \ No newline at end of file +module.exports = { + getEventLog +}; \ No newline at end of file diff --git a/src/routes/api/export.js b/src/routes/api/export.js index 657a3154c..c0a7024ff 100644 --- a/src/routes/api/export.js +++ b/src/routes/api/export.js @@ -1,16 +1,12 @@ "use strict"; -const express = require('express'); -const router = express.Router(); const sql = require('../../services/sql'); const html = require('html'); -const auth = require('../../services/auth'); -const wrap = require('express-promise-wrap').wrap; const tar = require('tar-stream'); const sanitize = require("sanitize-filename"); const Repository = require("../../services/repository"); -router.get('/:noteId/', auth.checkApiAuthOrElectron, wrap(async (req, res, next) => { +async function exportNote(req, res) { const noteId = req.params.noteId; const repo = new Repository(req); @@ -18,7 +14,7 @@ router.get('/:noteId/', auth.checkApiAuthOrElectron, wrap(async (req, res, next) const pack = tar.pack(); - const name = await exportNote(branchId, '', pack, repo); + const name = await exportNoteInner(branchId, '', pack, repo); pack.finalize(); @@ -26,9 +22,9 @@ router.get('/:noteId/', auth.checkApiAuthOrElectron, wrap(async (req, res, next) res.setHeader('Content-Type', 'application/tar'); pack.pipe(res); -})); +} -async function exportNote(branchId, directory, pack, repo) { +async function exportNoteInner(branchId, directory, pack, repo) { const branch = await sql.getRow("SELECT * FROM branches WHERE branchId = ?", [branchId]); const note = await repo.getEntity("SELECT notes.* FROM notes WHERE noteId = ?", [branch.noteId]); @@ -55,7 +51,7 @@ async function exportNote(branchId, directory, pack, repo) { if (children.length > 0) { for (const child of children) { - await exportNote(child.branchId, childFileName + "/", pack, repo); + await exportNoteInner(child.branchId, childFileName + "/", pack, repo); } } @@ -77,4 +73,6 @@ async function getMetadata(note) { }; } -module.exports = router; \ No newline at end of file +module.exports = { + exportNote +}; \ No newline at end of file diff --git a/src/routes/api/import.js b/src/routes/api/import.js index dcc2dc5e3..6d57f880d 100644 --- a/src/routes/api/import.js +++ b/src/routes/api/import.js @@ -90,7 +90,7 @@ async function parseImportFile(file) { }); } -router.post('/:parentNoteId', auth.checkApiAuthOrElectron, multer.single('upload'), wrap(async (req, res, next) => { +async function importTar(req, res) { const sourceId = req.headers.source_id; const parentNoteId = req.params.parentNoteId; const file = req.file; @@ -103,12 +103,10 @@ router.post('/:parentNoteId', auth.checkApiAuthOrElectron, multer.single('upload const files = await parseImportFile(file); - await sql.doInTransaction(async () => { - await importNotes(files, parentNoteId, sourceId); - }); + await importNotes(files, parentNoteId, sourceId); res.send({}); -})); +} async function importNotes(files, parentNoteId, sourceId) { for (const file of files) { @@ -136,4 +134,6 @@ async function importNotes(files, parentNoteId, sourceId) { } } -module.exports = router; \ No newline at end of file +module.exports = { + importTar +}; \ No newline at end of file diff --git a/src/routes/api/recent_notes.js b/src/routes/api/recent_notes.js index 601176b89..610708703 100644 --- a/src/routes/api/recent_notes.js +++ b/src/routes/api/recent_notes.js @@ -1,38 +1,9 @@ "use strict"; -const express = require('express'); -const router = express.Router(); const sql = require('../../services/sql'); -const auth = require('../../services/auth'); const utils = require('../../services/utils'); const sync_table = require('../../services/sync_table'); const options = require('../../services/options'); -const wrap = require('express-promise-wrap').wrap; - -router.get('', auth.checkApiAuth, wrap(async (req, res, next) => { - res.send(await getRecentNotes()); -})); - -router.put('/:branchId/:notePath', auth.checkApiAuth, wrap(async (req, res, next) => { - const branchId = req.params.branchId; - const notePath = req.params.notePath; - const sourceId = req.headers.source_id; - - await sql.doInTransaction(async () => { - await sql.replace('recent_notes', { - branchId: branchId, - notePath: notePath, - dateAccessed: utils.nowDate(), - isDeleted: 0 - }); - - await sync_table.addRecentNoteSync(branchId, sourceId); - - await options.setOption('start_note_path', notePath, sourceId); - }); - - res.send(await getRecentNotes()); -})); async function getRecentNotes() { return await sql.getRows(` @@ -49,4 +20,27 @@ async function getRecentNotes() { LIMIT 200`); } -module.exports = router; \ No newline at end of file + +async function addRecentNote(req) { + const branchId = req.params.branchId; + const notePath = req.params.notePath; + const sourceId = req.headers.source_id; + + await sql.replace('recent_notes', { + branchId: branchId, + notePath: notePath, + dateAccessed: utils.nowDate(), + isDeleted: 0 + }); + + await sync_table.addRecentNoteSync(branchId, sourceId); + + await options.setOption('start_note_path', notePath, sourceId); + + return await getRecentNotes(); +} + +module.exports = { + getRecentNotes, + addRecentNote +}; \ No newline at end of file diff --git a/src/routes/routes.js b/src/routes/routes.js index fef767357..e6db21329 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -3,6 +3,7 @@ const loginRoute = require('./login'); const logoutRoute = require('./logout'); const migrationRoute = require('./migration'); const setupRoute = require('./setup'); +const multer = require('multer')(); // API routes const treeApiRoute = require('./api/tree'); @@ -39,17 +40,13 @@ 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 result = await cls.init(async () => { - cls.namespace.set('sourceId', req.headers.source_id); - - return await sql.doInTransaction(async () => { - return await handler(req, res, next); - }); - }); - +function apiRoute(method, path, routeHandler) { + route({ + method, + path, + middleware: [auth.checkApiAuth], + routeHandler, + resultHandler: (res, result) => { // if it's an array and first element is integer then we consider this to be [statusCode, response] format if (Array.isArray(result) && result.length > 0 && Number.isInteger(result[0])) { const [statusCode, response] = result; @@ -67,12 +64,38 @@ function apiRoute(method, path, handler) { res.status(200).send(result); } } + }); +} + +// API routes requiring HTTP protocol. This means we ignore route return value and make an electron auth exception +function httpApiRoute(method, path, routeHandler) { + route({ + method, + path, + middleware: [auth.checkApiAuth, multer.single('upload')], + routeHandler + }) +} + +function route({ method, path, middleware, routeHandler, resultHandler }) { + router[method](path, ...middleware, async (req, res, next) => { + try { + const result = await cls.init(async () => { + cls.namespace.set('sourceId', req.headers.source_id); + + return await sql.doInTransaction(async () => { + return await routeHandler(req, res, next); + }); + }); + + if (resultHandler) { + resultHandler(res, result); + } + } catch (e) { log.info(`${method} ${path} threw exception: ` + e.stack); - res.send(500); - - next(e); + res.sendStatus(500); } }); } @@ -146,12 +169,16 @@ function register(app) { apiRoute(PUT, '/api/sync/labels', syncApiRoute.updateLabel); apiRoute(PUT, '/api/sync/api_tokens', syncApiRoute.updateApiToken); - app.use('/api/login', loginApiRoute); - app.use('/api/event-log', eventLogRoute); - app.use('/api/recent-notes', recentNotesRoute); - app.use('/api/app-info', appInfoRoute); - app.use('/api/export', exportRoute); - app.use('/api/import', importRoute); + apiRoute(GET, '/api/event-log', eventLogRoute.getEventLog); + + apiRoute(GET, '/api/recent-notes', recentNotesRoute.getRecentNotes); + apiRoute(PUT, '/api/recent-notes/:branchId/:notePath', recentNotesRoute.addRecentNote); + apiRoute(GET, '/api/app-info', appInfoRoute.getAppInfo); + + httpApiRoute(GET, '/api/export/:noteId', exportRoute.exportNote); + + httpApiRoute(POST, '/api/import/:parentNoteId', importRoute.importTar); + app.use('/api/setup', setupApiRoute); app.use('/api/sql', sqlRoute); app.use('/api/anonymization', anonymizationRoute); @@ -166,6 +193,7 @@ function register(app) { app.use('/api/migration', migrationApiRoute); + app.use('/api/login', loginApiRoute); } module.exports = {