mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	converted file, script, search and sender routes
This commit is contained in:
		
							parent
							
								
									aa57a64c61
								
							
						
					
					
						commit
						cfe0ae1eda
					
				| @ -1,16 +1,11 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| const express = require('express'); |  | ||||||
| const router = express.Router(); |  | ||||||
| const sql = require('../../services/sql'); | const sql = require('../../services/sql'); | ||||||
| const auth = require('../../services/auth'); |  | ||||||
| const notes = require('../../services/notes'); | const notes = require('../../services/notes'); | ||||||
| const labels = require('../../services/labels'); | const labels = require('../../services/labels'); | ||||||
| const protected_session = require('../../services/protected_session'); | const protected_session = require('../../services/protected_session'); | ||||||
| const multer = require('multer')(); |  | ||||||
| const wrap = require('express-promise-wrap').wrap; |  | ||||||
| 
 | 
 | ||||||
| router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single('upload'), wrap(async (req, res, next) => { | async function uploadFile(req) { | ||||||
|     const sourceId = req.headers.source_id; |     const sourceId = req.headers.source_id; | ||||||
|     const parentNoteId = req.params.parentNoteId; |     const parentNoteId = req.params.parentNoteId; | ||||||
|     const file = req.file; |     const file = req.file; | ||||||
| @ -20,29 +15,27 @@ router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single( | |||||||
|     const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [parentNoteId]); |     const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [parentNoteId]); | ||||||
| 
 | 
 | ||||||
|     if (!note) { |     if (!note) { | ||||||
|         return res.status(404).send(`Note ${parentNoteId} doesn't exist.`); |         return [404, `Note ${parentNoteId} doesn't exist.`]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await sql.doInTransaction(async () => { |     const {noteId} = await notes.createNewNote(parentNoteId, { | ||||||
|         const noteId = (await notes.createNewNote(parentNoteId, { |         title: originalName, | ||||||
|             title: originalName, |         content: file.buffer, | ||||||
|             content: file.buffer, |         target: 'into', | ||||||
|             target: 'into', |         isProtected: false, | ||||||
|             isProtected: false, |         type: 'file', | ||||||
|             type: 'file', |         mime: file.mimetype | ||||||
|             mime: file.mimetype |     }, req, sourceId); | ||||||
|         }, req, sourceId)).noteId; |  | ||||||
| 
 | 
 | ||||||
|         await labels.createLabel(noteId, "original_file_name", originalName, sourceId); |     await labels.createLabel(noteId, "original_file_name", originalName, sourceId); | ||||||
|         await labels.createLabel(noteId, "file_size", size, sourceId); |     await labels.createLabel(noteId, "file_size", size, sourceId); | ||||||
| 
 | 
 | ||||||
|         res.send({ |     return { | ||||||
|             noteId: noteId |         noteId: noteId | ||||||
|         }); |     }; | ||||||
|     }); | } | ||||||
| })); |  | ||||||
| 
 | 
 | ||||||
| router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, res, next) => { | async function downloadFile(req, res) { | ||||||
|     const noteId = req.params.noteId; |     const noteId = req.params.noteId; | ||||||
|     const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); |     const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); | ||||||
|     const protectedSessionId = req.query.protectedSessionId; |     const protectedSessionId = req.query.protectedSessionId; | ||||||
| @ -69,6 +62,9 @@ router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, re | |||||||
|     res.setHeader('Content-Type', note.mime); |     res.setHeader('Content-Type', note.mime); | ||||||
| 
 | 
 | ||||||
|     res.send(note.content); |     res.send(note.content); | ||||||
| })); | } | ||||||
| 
 | 
 | ||||||
| module.exports = router; | module.exports = { | ||||||
|  |     uploadFile, | ||||||
|  |     downloadFile | ||||||
|  | }; | ||||||
| @ -1,55 +1,56 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| const express = require('express'); |  | ||||||
| const router = express.Router(); |  | ||||||
| const auth = require('../../services/auth'); |  | ||||||
| const wrap = require('express-promise-wrap').wrap; |  | ||||||
| const labels = require('../../services/labels'); | const labels = require('../../services/labels'); | ||||||
| const script = require('../../services/script'); | const script = require('../../services/script'); | ||||||
| const Repository = require('../../services/repository'); | const Repository = require('../../services/repository'); | ||||||
| 
 | 
 | ||||||
| router.post('/exec', auth.checkApiAuth, wrap(async (req, res, next) => { | async function exec(req) { | ||||||
|     const ret = await script.executeScript(req, req.body.script, req.body.params, req.body.startNoteId, req.body.currentNoteId); |     const ret = await script.executeScript(req, req.body.script, req.body.params, req.body.startNoteId, req.body.currentNoteId); | ||||||
| 
 | 
 | ||||||
|     res.send({ |     return { | ||||||
|         executionResult: ret |         executionResult: ret | ||||||
|     }); |     }; | ||||||
| })); | } | ||||||
| 
 | 
 | ||||||
| router.post('/run/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { | async function run(req) { | ||||||
|     const repository = new Repository(req); |     const repository = new Repository(req); | ||||||
|     const note = await repository.getNote(req.params.noteId); |     const note = await repository.getNote(req.params.noteId); | ||||||
| 
 | 
 | ||||||
|     const ret = await script.executeNote(req, note); |     const ret = await script.executeNote(req, note); | ||||||
| 
 | 
 | ||||||
|     res.send({ |     return { | ||||||
|         executionResult: ret |         executionResult: ret | ||||||
|     }); |     }; | ||||||
| })); | } | ||||||
| 
 | 
 | ||||||
| router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => { | async function getStartupBundles(req) { | ||||||
|     const repository = new Repository(req); |     const repository = new Repository(req); | ||||||
|     const notes = await labels.getNotesWithLabel(repository, "run", "frontend_startup"); |     const notes = await labels.getNotesWithLabel(repository, "run", "frontend_startup"); | ||||||
| 
 | 
 | ||||||
|     const scripts = []; |     const bundles = []; | ||||||
| 
 | 
 | ||||||
|     for (const note of notes) { |     for (const note of notes) { | ||||||
|         const bundle = await script.getScriptBundle(note); |         const bundle = await script.getScriptBundle(note); | ||||||
| 
 | 
 | ||||||
|         if (bundle) { |         if (bundle) { | ||||||
|             scripts.push(bundle); |             bundles.push(bundle); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     res.send(scripts); |     return bundles; | ||||||
| })); | } | ||||||
| 
 | 
 | ||||||
| router.get('/bundle/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { | async function getBundle(req) { | ||||||
|     const repository = new Repository(req); |     const repository = new Repository(req); | ||||||
|     const note = await repository.getNote(req.params.noteId); |     const note = await repository.getNote(req.params.noteId); | ||||||
|     const bundle = await script.getScriptBundle(note); |     const bundle = await script.getScriptBundle(note); | ||||||
| 
 | 
 | ||||||
|     res.send(bundle); |     return bundle; | ||||||
| })); | } | ||||||
| 
 | 
 | ||||||
| module.exports = router; | module.exports = { | ||||||
|  |     exec, | ||||||
|  |     run, | ||||||
|  |     getStartupBundles, | ||||||
|  |     getBundle | ||||||
|  | }; | ||||||
| @ -1,25 +1,21 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| const express = require('express'); |  | ||||||
| const router = express.Router(); |  | ||||||
| const auth = require('../../services/auth'); |  | ||||||
| const sql = require('../../services/sql'); | const sql = require('../../services/sql'); | ||||||
| const notes = require('../../services/notes'); | const notes = require('../../services/notes'); | ||||||
| const wrap = require('express-promise-wrap').wrap; |  | ||||||
| const parseFilters = require('../../services/parse_filters'); | const parseFilters = require('../../services/parse_filters'); | ||||||
| const buildSearchQuery = require('../../services/build_search_query'); | const buildSearchQuery = require('../../services/build_search_query'); | ||||||
| 
 | 
 | ||||||
| router.get('/:searchString', auth.checkApiAuth, wrap(async (req, res, next) => { | async function searchNotes(req) { | ||||||
|     const {attrFilters, searchText} = parseFilters(req.params.searchString); |     const {attrFilters, searchText} = parseFilters(req.params.searchString); | ||||||
| 
 | 
 | ||||||
|     const {query, params} = buildSearchQuery(attrFilters, searchText); |     const {query, params} = buildSearchQuery(attrFilters, searchText); | ||||||
| 
 | 
 | ||||||
|     const noteIds = await sql.getColumn(query, params); |     const noteIds = await sql.getColumn(query, params); | ||||||
| 
 | 
 | ||||||
|     res.send(noteIds); |     return noteIds; | ||||||
| })); | } | ||||||
| 
 | 
 | ||||||
| router.post('/:searchString', auth.checkApiAuth, wrap(async (req, res, next) => { | async function saveSearchToNote(req) { | ||||||
|     const noteContent = { |     const noteContent = { | ||||||
|         searchString: req.params.searchString |         searchString: req.params.searchString | ||||||
|     }; |     }; | ||||||
| @ -30,7 +26,10 @@ router.post('/:searchString', auth.checkApiAuth, wrap(async (req, res, next) => | |||||||
|         mime: "application/json" |         mime: "application/json" | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     res.send({ noteId }); |     return { noteId }; | ||||||
| })); | } | ||||||
| 
 | 
 | ||||||
| module.exports = router; | module.exports = { | ||||||
|  |     searchNotes, | ||||||
|  |     saveSearchToNote | ||||||
|  | }; | ||||||
| @ -13,7 +13,7 @@ const password_encryption = require('../../services/password_encryption'); | |||||||
| const options = require('../../services/options'); | const options = require('../../services/options'); | ||||||
| const sync_table = require('../../services/sync_table'); | const sync_table = require('../../services/sync_table'); | ||||||
| 
 | 
 | ||||||
| router.post('/login', wrap(async (req, res, next) => { | async function login(req) { | ||||||
|     const username = req.body.username; |     const username = req.body.username; | ||||||
|     const password = req.body.password; |     const password = req.body.password; | ||||||
| 
 | 
 | ||||||
| @ -21,61 +21,44 @@ router.post('/login', wrap(async (req, res, next) => { | |||||||
|     const isPasswordValid = await password_encryption.verifyPassword(password); |     const isPasswordValid = await password_encryption.verifyPassword(password); | ||||||
| 
 | 
 | ||||||
|     if (!isUsernameValid || !isPasswordValid) { |     if (!isUsernameValid || !isPasswordValid) { | ||||||
|         res.status(401).send("Incorrect username/password"); |         return [401, "Incorrect username/password"]; | ||||||
|     } |     } | ||||||
|     else { |  | ||||||
|         const token = utils.randomSecureToken(); |  | ||||||
| 
 | 
 | ||||||
|         await sql.doInTransaction(async () => { |     const token = utils.randomSecureToken(); | ||||||
|             const apiTokenId = utils.newApiTokenId(); |  | ||||||
| 
 | 
 | ||||||
|             await sql.insert("api_tokens", { |     const apiTokenId = utils.newApiTokenId(); | ||||||
|                 apiTokenId: apiTokenId, |  | ||||||
|                 token: token, |  | ||||||
|                 dateCreated: utils.nowDate(), |  | ||||||
|                 isDeleted: false |  | ||||||
|             }); |  | ||||||
| 
 | 
 | ||||||
|             await sync_table.addApiTokenSync(apiTokenId); |     await sql.insert("api_tokens", { | ||||||
|         }); |         apiTokenId: apiTokenId, | ||||||
|  |         token: token, | ||||||
|  |         dateCreated: utils.nowDate(), | ||||||
|  |         isDeleted: false | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|         res.send({ |     await sync_table.addApiTokenSync(apiTokenId); | ||||||
|             token: token |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| })); |  | ||||||
| 
 | 
 | ||||||
| async function checkSenderToken(req, res, next) { |     return { | ||||||
|     const token = req.headers.authorization; |         token: token | ||||||
| 
 |     }; | ||||||
|     if (await sql.getValue("SELECT COUNT(*) FROM api_tokens WHERE isDeleted = 0 AND token = ?", [token]) === 0) { |  | ||||||
|         res.status(401).send("Not authorized"); |  | ||||||
|     } |  | ||||||
|     else if (await sql.isDbUpToDate()) { |  | ||||||
|         next(); |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         res.status(409).send("Mismatched app versions"); // need better response than that
 |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| router.post('/image', checkSenderToken, multer.single('upload'), wrap(async (req, res, next) => { | async function uploadImage(req) { | ||||||
|     const file = req.file; |     const file = req.file; | ||||||
| 
 | 
 | ||||||
|     if (!["image/png", "image/jpeg", "image/gif"].includes(file.mimetype)) { |     if (!["image/png", "image/jpeg", "image/gif"].includes(file.mimetype)) { | ||||||
|         return res.status(400).send("Unknown image type: " + file.mimetype); |         return [400, "Unknown image type: " + file.mimetype]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']); |     const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']); | ||||||
| 
 | 
 | ||||||
|     const noteId = (await notes.createNewNote(parentNoteId, { |     const {noteId} = await notes.createNewNote(parentNoteId, { | ||||||
|         title: "Sender image", |         title: "Sender image", | ||||||
|         content: "", |         content: "", | ||||||
|         target: 'into', |         target: 'into', | ||||||
|         isProtected: false, |         isProtected: false, | ||||||
|         type: 'text', |         type: 'text', | ||||||
|         mime: 'text/html' |         mime: 'text/html' | ||||||
|     })).noteId; |     }); | ||||||
| 
 | 
 | ||||||
|     const {fileName, imageId} = await image.saveImage(file, null, noteId); |     const {fileName, imageId} = await image.saveImage(file, null, noteId); | ||||||
| 
 | 
 | ||||||
| @ -84,11 +67,9 @@ router.post('/image', checkSenderToken, multer.single('upload'), wrap(async (req | |||||||
|     const content = `<img src="${url}"/>`; |     const content = `<img src="${url}"/>`; | ||||||
| 
 | 
 | ||||||
|     await sql.execute("UPDATE notes SET content = ? WHERE noteId = ?", [content, noteId]); |     await sql.execute("UPDATE notes SET content = ? WHERE noteId = ?", [content, noteId]); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     res.send({}); | async function saveNote(req) { | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| router.post('/note', checkSenderToken, wrap(async (req, res, next) => { |  | ||||||
|     const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']); |     const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']); | ||||||
| 
 | 
 | ||||||
|     await notes.createNewNote(parentNoteId, { |     await notes.createNewNote(parentNoteId, { | ||||||
| @ -99,8 +80,10 @@ router.post('/note', checkSenderToken, wrap(async (req, res, next) => { | |||||||
|         type: 'text', |         type: 'text', | ||||||
|         mime: 'text/html' |         mime: 'text/html' | ||||||
|     }); |     }); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     res.send({}); | module.exports = { | ||||||
| })); |     login, | ||||||
| 
 |     uploadImage, | ||||||
| module.exports = router; |     saveNote | ||||||
|  | }; | ||||||
| @ -92,6 +92,7 @@ function route(method, path, middleware, routeHandler, resultHandler) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const GET = 'get', POST = 'post', PUT = 'put', DELETE = 'delete'; | const GET = 'get', POST = 'post', PUT = 'put', DELETE = 'delete'; | ||||||
|  | const uploadMiddleware = multer.single('upload'); | ||||||
| 
 | 
 | ||||||
| function register(app) { | function register(app) { | ||||||
|     app.use('/', indexRoute); |     app.use('/', indexRoute); | ||||||
| @ -180,10 +181,23 @@ function register(app) { | |||||||
| 
 | 
 | ||||||
|     httpApiRoute(GET, '/api/images/:imageId/:filename', imageRoute.returnImage); |     httpApiRoute(GET, '/api/images/:imageId/:filename', imageRoute.returnImage); | ||||||
|     httpApiRoute(POST, '/api/images', imageRoute.uploadImage); |     httpApiRoute(POST, '/api/images', imageRoute.uploadImage); | ||||||
|     app.use('/api/script', scriptRoute); | 
 | ||||||
|     app.use('/api/sender', senderRoute); |     apiRoute(POST, '/api/script/exec', scriptRoute.exec); | ||||||
|     app.use('/api/files', filesRoute); |     apiRoute(POST, '/api/script/run/:noteId', scriptRoute.run); | ||||||
|     app.use('/api/search', searchRoute); |     apiRoute(GET, '/api/script/startup', scriptRoute.getStartupBundles); | ||||||
|  |     apiRoute(GET, '/api/script/bundle/:noteId', scriptRoute.getBundle); | ||||||
|  | 
 | ||||||
|  |     route(POST, '/api/sender/login', [], senderRoute.login, apiResultHandler); | ||||||
|  |     route(POST, '/api/sender/image', [auth.checkSenderToken], senderRoute.uploadImage, apiResultHandler); | ||||||
|  |     route(POST, '/api/sender/note', [auth.checkSenderToken], senderRoute.saveNote, apiResultHandler); | ||||||
|  | 
 | ||||||
|  |     route(POST, '/api/files/upload/:parentNoteId', [auth.checkApiAuthOrElectron, uploadMiddleware], | ||||||
|  |         filesRoute.uploadFile, apiResultHandler); | ||||||
|  | 
 | ||||||
|  |     route(GET, '/api/files/download/:noteId', [auth.checkApiAuthOrElectron], filesRoute.downloadFile); | ||||||
|  | 
 | ||||||
|  |     apiRoute(GET, '/api/search/:searchString', searchRoute.searchNotes); | ||||||
|  |     apiRoute(POST, '/api/search/:searchString', searchRoute.saveSearchToNote); | ||||||
| 
 | 
 | ||||||
|     app.use('', router); |     app.use('', router); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -72,11 +72,26 @@ async function checkAppNotInitialized(req, res, next) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | async function checkSenderToken(req, res, next) { | ||||||
|  |     const token = req.headers.authorization; | ||||||
|  | 
 | ||||||
|  |     if (await sql.getValue("SELECT COUNT(*) FROM api_tokens WHERE isDeleted = 0 AND token = ?", [token]) === 0) { | ||||||
|  |         res.status(401).send("Not authorized"); | ||||||
|  |     } | ||||||
|  |     else if (await sql.isDbUpToDate()) { | ||||||
|  |         next(); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         res.status(409).send("Mismatched app versions"); // need better response than that
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|     checkAuth, |     checkAuth, | ||||||
|     checkAuthForMigrationPage, |     checkAuthForMigrationPage, | ||||||
|     checkApiAuth, |     checkApiAuth, | ||||||
|     checkApiAuthForMigrationPage, |     checkApiAuthForMigrationPage, | ||||||
|     checkAppNotInitialized, |     checkAppNotInitialized, | ||||||
|     checkApiAuthOrElectron |     checkApiAuthOrElectron, | ||||||
|  |     checkSenderToken | ||||||
| }; | }; | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 azivner
						azivner