diff --git a/README.md b/README.md index f455f60..01f4565 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ npm i yemot-router2 # **Changelog**
-5.0.0 - 5.1.1 +5.0.0 - 5.1.2 **5.0.0** גרסה 5 כוללת שינויים רבים, כולל שינויים שוברים, ושכתוב משמעותי של הAPI הפנימי. @@ -50,6 +50,10 @@ npm i yemot-router2 **5.1.1** תוקן באג שבו ניתוק מחוץ לפונקציה (לדוגמה השמעת id_list_message, יציאה מהשלוחה ואז ניתוק) היה מפעיל את הפונקציה. + +**5.1.2** +תוקנה התמיכה בבקשות POST (ההגדרה api_url_post=yes בשלוחה), שבהן הפרמטרים נשלחים בbody ולא בquery +נוסף פרוקסי שמיירט נסיון גישה לreq.query בבקשות POST או לreq.body בבקשות GET, ומציג הסבר מפורט לתיקון.
diff --git a/exemple.js b/exemple.js index 95abe07..404bd33 100644 --- a/exemple.js +++ b/exemple.js @@ -51,6 +51,8 @@ router.get('/', async (call) => { call.go_to_folder('/1'); }); +app.use(express.urlencoded({ extended: true })); // A must if you want to use post requests (api_url_post=yes) + app.use('/', router); const port = 3000; diff --git a/lib/call.js b/lib/call.js index 5058288..1e619f4 100644 --- a/lib/call.js +++ b/lib/call.js @@ -52,14 +52,16 @@ class Call { await this.blockRunningUntilNextRequest(); - if (!this.req.query[valName]) { + const values = this.req.method === 'POST' ? this.req.body : this.req.query; + if (!values[valName]) { await sendResp(); } }; await sendResp(); - return this.req.query[valName] ?? false; + const values = this.req.method === 'POST' ? this.req.body : this.req.query; + return values[valName] ?? false; } go_to_folder (folder) { @@ -131,17 +133,20 @@ class Call { this.req = req; this.res = res; this.query = req.query; + this.body = req.body; this.params = req.params; - this.did = this.query.ApiDID; - this.phone = this.query.ApiPhone; - this.callId = this.query.ApiCallId; - this.real_did = this.query.ApiRealDID; - this.extension = this.query.ApiExtension; + const values = this.req.method === 'POST' ? this.req.body : this.req.query; - const queryToCopy = Object.keys(this.query).filter((key) => key.startsWith('Api')); + this.did = values.ApiDID; + this.phone = values.ApiPhone; + this.callId = values.ApiCallId; + this.real_did = values.ApiRealDID; + this.extension = values.ApiExtension; + + const queryToCopy = Object.keys(values).filter((key) => key.startsWith('Api')); for (const key of queryToCopy) { - this[key] = this.query[key]; + this[key] = values[key]; } } diff --git a/lib/yemot_router.js b/lib/yemot_router.js index 7379810..abdefba 100644 --- a/lib/yemot_router.js +++ b/lib/yemot_router.js @@ -4,7 +4,7 @@ const Router = require('express').Router; const EventEmitter = require('events'); const colors = require('colors'); -function shiftDuplicatedFromQuery (query) { +function shiftDuplicatedValues (query) { /** אם ערך מסויים יש כמה פעמים, שייקבע רק האחרון **/ for (const key of Object.keys(query)) { const iterator = query[key]; @@ -75,46 +75,78 @@ function YemotRouter (options = {}) { } return new Proxy(Router(), { - get: function (target, prop) { - if (['get', 'post', 'all', 'add_fn'].includes(prop)) { + get: function (target, propName) { + if (['get', 'post', 'all', 'add_fn'].includes(propName)) { return (path, fn) => { - target[prop === 'add_fn' ? 'all' : prop](path, (req, res, next) => { - if (prop === 'add_fn') { + target[propName === 'add_fn' ? 'all' : propName](path, (req, res, next) => { + if (propName === 'add_fn') { console.warn('[warning] add_fn is deprecated, use get/post/all instead'); } + + if (req.method === 'POST' && !req.body) { + throw new Error('YemotRouter: it look you use api_url_post=yes, but you didn\'t include express.urlencoded({ extended: true }) middleware! (https://expressjs.com/en/4x/api.html#express.urlencoded)'); + } + + const values = req.method === 'POST' ? req.body : req.query; const requiredValues = ['ApiPhone', 'ApiDID', 'ApiExtension', 'ApiCallId']; - if (requiredValues.some((key) => !Object.prototype.hasOwnProperty.call(req.query, key))) { + if (requiredValues.some((key) => !Object.prototype.hasOwnProperty.call(values, key))) { return res.json({ message: 'request is not valid yemot request' }); } - req.query = shiftDuplicatedFromQuery(req.query); + if (req.method === 'POST') { + req.body = shiftDuplicatedValues(req.body); + } else { + req.query = shiftDuplicatedValues(req.query); + } - const callId = req.query.ApiCallId; + const callId = values.ApiCallId; let isNewCall = false; let currentCall = activeCalls[callId]; if (!currentCall) { isNewCall = true; - if (req.query.hangup === 'yes') { + if (values.hangup === 'yes') { logger(callId, '👋 call is hangup (outside the function)'); return res.json({ message: 'hangup' }); } currentCall = new Call(callId, eventsEmitter, ops); activeCalls[callId] = currentCall; - logger(callId, `📞 new call - from ${req.query.ApiPhone}`); + logger(callId, `📞 new call - from ${values.ApiPhone}`); } currentCall.setReqValues(req, res); + if (req.method === 'POST') { + const _query = req.query; + const proxy = new Proxy(_query, { + get: function (target, propName) { + console.warn(`[${req.path}] You are trying to access the '${propName}' property on the request query string object, but you have set the 'api_url_post=yes' option. This means that the yemot values will be in the request body object, not the request query object.\nPlease update your code accordingly - instead of call.req.query.propName, use call.req.body.propName.`); + return target[propName]; + } + }); + req.query = proxy; + currentCall.query = proxy; + } else { + const _body = req.body; + const proxy = new Proxy(_body, { + get: function (target, propName) { + if (!target[propName]) console.warn(`[${req.path}] If you do not use the api_url_post=yes option, the values will be in the call.req.query object, not the call.req.body object.\nPlease update your code accordingly - instead of call.req.body.propName, use call.req.query.propName, or use the api_url_post=yes option.`); + return target[propName]; + } + }); + req.body = proxy; + currentCall.body = proxy; + } + if (isNewCall) { makeNewCall(fn, callId, currentCall); } else { - eventsEmitter.emit(callId, req.query.hangup === 'yes'); + eventsEmitter.emit(callId, values.hangup === 'yes'); } }); }; } else { - return target[prop]; + return target[propName]; } } });