diff --git a/src/app.js b/src/app.js index c78d192da..96a097b1c 100644 --- a/src/app.js +++ b/src/app.js @@ -63,6 +63,8 @@ app.use(favicon(__dirname + '/public/images/app-icons/win/icon.ico')); require('./routes/routes').register(app); +require('./routes/custom').register(app); + // catch 404 and forward to error handler app.use((req, res, next) => { const err = new Error('Router not found for request ' + req.url); diff --git a/src/routes/api/script.js b/src/routes/api/script.js index 72ca8ec92..eea9db665 100644 --- a/src/routes/api/script.js +++ b/src/routes/api/script.js @@ -19,7 +19,7 @@ async function exec(req) { async function run(req) { const note = await repository.getNote(req.params.noteId); - const result = await scriptService.executeNote(note, note); + const result = await scriptService.executeNote(note, { originEntity: note }); return { executionResult: result }; } diff --git a/src/routes/custom.js b/src/routes/custom.js new file mode 100644 index 000000000..8f28a1aeb --- /dev/null +++ b/src/routes/custom.js @@ -0,0 +1,43 @@ +const repository = require('../services/repository'); +const log = require('../services/log'); +const scriptService = require('../services/script'); + +function register(router) { + router.all('/custom/:path*', async (req, res, next) => { + const attrs = await repository.getEntities("SELECT * FROM attributes WHERE isDeleted = 0 AND type = 'label' AND ('customRequestHandler', 'customResourceProvider')"); + + for (const attr of attrs) { + const regex = new RegExp(attr.value); + + try { + const m = regex.match(router.path); + + if (m) { + if (attr.name === 'customRequestHandler') { + const note = await attr.getNote(); + + await scriptService.executeNote(note, { + pathParams: m.slice(1), + req, + res + }); + } + else if (attr.name === 'customResourceProvider') { + + } + + break; + } + } + catch (e) { + log.error(`Testing path for label ${attr.attributeId}, regex=${attr.value} failed with error ` + e.stack); + } + } + + res.send('Hello ' + req.params.path); + }); +} + +module.exports = { + register +}; \ No newline at end of file diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js index b909f346e..f30a84234 100644 --- a/src/services/backend_script_api.js +++ b/src/services/backend_script_api.js @@ -19,13 +19,17 @@ const appInfo = require('./app_info'); * @constructor * @hideconstructor */ -function BackendScriptApi(startNote, currentNote, originEntity) { +function BackendScriptApi(currentNote, apiParams) { /** @property {Note} note where script started executing */ - this.startNote = startNote; + this.startNote = apiParams.startNote; /** @property {Note} note where script is currently executing */ this.currentNote = currentNote; /** @property {Entity} entity whose event triggered this executions */ - this.originEntity = originEntity; + this.originEntity = apiParams.originEntity; + + for (const key in apiParams) { + this[key] = apiParams[key]; + } this.axios = axios; diff --git a/src/services/handlers.js b/src/services/handlers.js index faaba467b..95973be86 100644 --- a/src/services/handlers.js +++ b/src/services/handlers.js @@ -12,7 +12,7 @@ async function runAttachedRelations(note, relationName, originEntity) { const scriptNote = await relation.getTargetNote(); if (scriptNote) { - await scriptService.executeNote(scriptNote, originEntity); + await scriptService.executeNote(scriptNote, { originEntity }); } else { log.error(`Target note ${relation.value} of atttribute ${relation.attributeId} has not been found.`); diff --git a/src/services/scheduler.js b/src/services/scheduler.js index 78e02cd9e..35e3e9ec8 100644 --- a/src/services/scheduler.js +++ b/src/services/scheduler.js @@ -17,7 +17,7 @@ async function runNotesWithLabel(runAttrValue) { AND notes.isDeleted = 0`, [runAttrValue]); for (const note of notes) { - scriptService.executeNote(note, note); + scriptService.executeNote(note, { originEntity: note }); } } diff --git a/src/services/script.js b/src/services/script.js index 628510c6d..21bc81884 100644 --- a/src/services/script.js +++ b/src/services/script.js @@ -5,33 +5,33 @@ const cls = require('./cls'); const sourceIdService = require('./source_id'); const log = require('./log'); -async function executeNote(note, originEntity) { +async function executeNote(note, apiParams) { if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) { return; } const bundle = await getScriptBundle(note); - await executeBundle(bundle, note, originEntity); + await executeBundle(bundle, apiParams); } -async function executeBundle(bundle, startNote, originEntity = null) { - if (!startNote) { +async function executeBundle(bundle, apiParams = {}) { + if (!apiParams.startNote) { // this is the default case, the only exception is when we want to preserve frontend startNote - startNote = bundle.note; + apiParams.startNote = bundle.note; } // last \r\n is necessary if script contains line comment on its last line const script = "async function() {\r\n" + bundle.script + "\r\n}"; - const ctx = new ScriptContext(startNote, bundle.allNotes, originEntity); + const ctx = new ScriptContext(bundle.allNotes, apiParams); try { if (await bundle.note.hasLabel('manualTransactionHandling')) { - return await execute(ctx, script, ''); + return await execute(ctx, script); } else { - return await sql.transactional(async () => await execute(ctx, script, '')); + return await sql.transactional(async () => await execute(ctx, script)); } } catch (e) { @@ -57,11 +57,11 @@ async function executeScript(script, params, startNoteId, currentNoteId, originE return await executeBundle(bundle, startNote, originEntity); } -async function execute(ctx, script, paramsStr) { +async function execute(ctx, script, params = []) { // scripts run as "server" sourceId so clients recognize the changes as "foreign" and update themselves cls.namespace.set('sourceId', sourceIdService.getCurrentSourceId()); - return await (function() { return eval(`const apiContext = this;\r\n(${script}\r\n)(${paramsStr})`); }.call(ctx)); + return await (function() { return eval(`const apiContext = this;\r\n(${script}\r\n)()`); }.call(ctx)); } function getParams(params) { diff --git a/src/services/script_context.js b/src/services/script_context.js index 9d88817cd..e7dd13718 100644 --- a/src/services/script_context.js +++ b/src/services/script_context.js @@ -1,10 +1,10 @@ const utils = require('./utils'); const BackendScriptApi = require('./backend_script_api'); -function ScriptContext(startNote, allNotes, originEntity = null) { +function ScriptContext(allNotes, apiParams = {}) { this.modules = {}; this.notes = utils.toObject(allNotes, note => [note.noteId, note]); - this.apis = utils.toObject(allNotes, note => [note.noteId, new BackendScriptApi(startNote, note, originEntity)]); + this.apis = utils.toObject(allNotes, note => [note.noteId, new BackendScriptApi(note, apiParams)]); this.require = moduleNoteIds => { return moduleName => { const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));