diff --git a/src/routes/api/etapi.js b/src/routes/api/etapi.js index 87dc660db..a2e73b9f5 100644 --- a/src/routes/api/etapi.js +++ b/src/routes/api/etapi.js @@ -3,6 +3,12 @@ const utils = require("../../services/utils"); const noteService = require("../../services/notes"); const attributeService = require("../../services/attributes"); const Branch = require("../../becca/entities/branch"); +const cls = require("../../services/cls.js"); +const sql = require("../../services/sql.js"); +const log = require("../../services/log.js"); +const entityChangesService = require("../../services/entity_changes.js"); +const sqlInit = require("../../services/sql_init.js"); +const passwordService = require("../../services/password.js"); const GENERIC_CODE = "GENERIC"; @@ -29,8 +35,43 @@ function sendAttributeNotFoundError(res, attributeId) { return sendError(res, 404, "ATTRIBUTE_NOT_FOUND",`Attribute ${attributeId} not found`); } +// TODO: +// * add date/month/year functions + +function checkEtapiAuth(req, res, next) { + if (false) { + sendError(res, 401, "NOT_AUTHENTICATED", "Not authenticated"); + } + else { + next(); + } +} + function register(router) { - router.get('/etapi/notes/:noteId', (req, res, next) => { + function route(method, path, routeHandler) { + router[method](path, checkEtapiAuth, (req, res, next) => { + try { + cls.namespace.bindEmitter(req); + cls.namespace.bindEmitter(res); + + cls.init(() => { + cls.set('sourceId', "etapi"); + cls.set('localNowDateTime', req.headers['trilium-local-now-datetime']); + + const cb = () => routeHandler(req, res, next); + + return sql.transactional(cb); + }); + } + catch (e) { + log.error(`${method} ${path} threw exception: ` + e.stack); + + res.status(500).send(e.message); + } + }); + } + + route('get', '/etapi/notes/:noteId', (req, res, next) => { const {noteId} = req.params; const note = becca.getNote(noteId); @@ -41,7 +82,7 @@ function register(router) { res.json(mapNoteToPojo(note)); }); - router.get('/etapi/notes/:noteId/content', (req, res, next) => { + route('get', '/etapi/notes/:noteId/content', (req, res, next) => { const {noteId} = req.params; const note = becca.getNote(noteId); @@ -59,7 +100,7 @@ function register(router) { res.send(note.getContent()); }); - router.get('/etapi/branches/:branchId', (req, res, next) => { + route('get', '/etapi/branches/:branchId', (req, res, next) => { const {branchId} = req.params; const branch = becca.getBranch(branchId); @@ -70,7 +111,7 @@ function register(router) { res.json(mapBranchToPojo(branch)); }); - router.get('/etapi/attributes/:attributeId', (req, res, next) => { + route('get', '/etapi/attributes/:attributeId', (req, res, next) => { const {attributeId} = req.params; const attribute = becca.getAttribute(attributeId); @@ -81,7 +122,7 @@ function register(router) { res.json(mapAttributeToPojo(attribute)); }); - router.post('/etapi/notes', (req, res, next) => { + route('post' ,'/etapi/notes', (req, res, next) => { const params = req.body; if (!becca.getNote(params.parentNoteId)) { @@ -101,7 +142,7 @@ function register(router) { } }); - router.post('/etapi/branches', (req, res, next) => { + route('post' ,'/etapi/branches', (req, res, next) => { const params = req.body; if (!becca.getNote(params.noteId)) { @@ -132,7 +173,7 @@ function register(router) { } }); - router.post('/etapi/attributes', (req, res, next) => { + route('post' ,'/etapi/attributes', (req, res, next) => { const params = req.body; if (!becca.getNote(params.noteId)) { diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js index d6d856725..969370eaa 100644 --- a/src/services/backend_script_api.js +++ b/src/services/backend_script_api.js @@ -134,18 +134,18 @@ function BackendScriptApi(currentNote, apiParams) { this.getNoteWithLabel = attributeService.getNoteWithLabel; /** - * If there's no branch between note and parent note, create one. Otherwise do nothing. + * If there's no branch between note and parent note, create one. Otherwise, do nothing. * * @method * @param {string} noteId * @param {string} parentNoteId - * @param {string} prefix - if branch will be create between note and parent note, set this prefix + * @param {string} prefix - if branch will be created between note and parent note, set this prefix * @returns {void} */ this.ensureNoteIsPresentInParent = cloningService.ensureNoteIsPresentInParent; /** - * If there's a branch between note and parent note, remove it. Otherwise do nothing. + * If there's a branch between note and parent note, remove it. Otherwise, do nothing. * * @method * @param {string} noteId diff --git a/test-etapi/create-note.http b/test-etapi/create-note.http new file mode 100644 index 000000000..9b51a62e5 --- /dev/null +++ b/test-etapi/create-note.http @@ -0,0 +1,39 @@ +POST {{triliumHost}}/etapi/notes +Content-Type: application/json + +{ + "parentNoteId": "root", + "title": "Hello", + "type": "text", + "content": "Hi there!" +} + +> {% + client.test("Request executed successfully", function() { + client.assert(response.status === 200, "Response status is not 200"); + }); + + client.global.set("createdNoteId", response.body.note.noteId); + client.global.set("createdBranchId", response.body.note.branchId); +%} + +### + +POST {{triliumHost}}/etapi/attributes +Content-Type: application/json + +{ + "noteId": "{{createdNoteId}}", + "type": "label", + "name": "mylabel", + "value": "val", + "isInheritable": "true" +} + +> {% + client.test("Request executed successfully", function() { + client.assert(response.status === 200, "Response status is not 200"); + }); + + client.global.set("createdAttributeId", response.body.attributeId); +%} diff --git a/test-etapi/http-client.env.json b/test-etapi/http-client.env.json new file mode 100644 index 000000000..8ede0719c --- /dev/null +++ b/test-etapi/http-client.env.json @@ -0,0 +1,5 @@ +{ + "dev": { + "triliumHost": "http://localhost:37740" + } +}