From a23854e3ff5beec3a0216130788a5a3a50d55200 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sat, 19 Jan 2019 14:49:22 -0500 Subject: [PATCH] feat: new hook type: `response` Used in authentication middleware. Instead of firing an action hook, it now fires a response hook. Response hooks are invoked serially, and if headers are sent from one of the hook listeners, all subsequent hook methods are not called. Response hooks should only be used in situations where res.send (or other like methods) are invoked. Existing plugin hooks that pass in res purely for data retrieval purposes have not changed). fixes nodebb/nodebb-plugin-write-api#101 --- src/middleware/user.js | 5 ++--- src/plugins/hooks.js | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/middleware/user.js b/src/middleware/user.js index 1ae72c6260..366e4fdc9d 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -19,9 +19,8 @@ module.exports = function (middleware) { if (req.loggedIn) { return next(); } - - if (plugins.hasListeners('action:middleware.authenticate')) { - return plugins.fireHook('action:middleware.authenticate', { + if (plugins.hasListeners('response:middleware.authenticate')) { + return plugins.fireHook('response:middleware.authenticate', { req: req, res: res, next: function (err) { diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index fc460fa260..905694093f 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -110,6 +110,9 @@ module.exports = function (Plugins) { case 'static': fireStaticHook(hook, hookList, params, done); break; + case 'response': + fireResponseHook(hook, hookList, params, done); + break; default: winston.warn('[plugins] Unknown hookType: ' + hookType + ', hook : ' + hook); callback(); @@ -184,6 +187,28 @@ module.exports = function (Plugins) { }, callback); } + function fireResponseHook(hook, hookList, params, callback) { + if (!Array.isArray(hookList) || !hookList.length) { + return callback(); + } + async.eachSeries(hookList, function (hookObj, next) { + if (typeof hookObj.method !== 'function') { + if (global.env === 'development') { + winston.warn('[plugins] Expected method for hook \'' + hook + '\' in plugin \'' + hookObj.id + '\' not found, skipping.'); + } + return next(); + } + + // Skip remaining hooks if headers have been sent + if (params.res.headersSent) { + return next(); + } + + hookObj.method(params); + next(); + }, callback); + } + Plugins.hasListeners = function (hook) { return !!(Plugins.loadedHooks[hook] && Plugins.loadedHooks[hook].length > 0); };