UNPKG

@mvp-rockets/namma-generator

Version:

A generator to generate mvp-rockets projects

300 lines (273 loc) 9.99 kB
/* eslint max-classes-per-file: ["error", 4] */ /* eslint-disable block-scoped-var */ /* eslint-disable no-var */ /* eslint-disable no-use-before-define */ /* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable no-new */ /* eslint-disable max-classes-per-file */ const async = require('async'); const { ApiError, logError, whenResult } = require('lib'); const { HTTP_CONSTANT } = require('@mvp-rockets/namma-lib'); const AutoImportApis = require('./utils/autoimport'); const { defaultTransaction = false } = require('config/config'); const TokenVerifier = require('lib/token-verifier'); const cls = require('cls-hooked'); class Route { constructor() { this.handlers = {}; this.app = { get() { }, post() { }, put() { }, delete() { } }; } setApp(app) { this.app = app; new AutoImportApis({ includes: ['resources'] }); } withSecurity() { return new PreRequestHandler(new RestHandler(this, this.app), security); } withOutSecurity() { return new PreRequestHandler(new RestHandler(this, this.app), (req, res, next) => { next(null, { status: true }); }); } getHandler(url, method) { if (!this.handlers[url]) { return { status: false, message: `${url} not registered ` }; } if (!this.handlers[url][method]) { return { status: false, message: `${url} not registered for ${method}` }; } return { status: true, handler: this.handlers[url][method] }; } addToCache(url, restHandler) { const existingHandler = this.handlers[url]; let exists = false; if (existingHandler) { const handlerForGivenMethod = existingHandler[restHandler.method]; if (handlerForGivenMethod) { handlerForGivenMethod.push(restHandler); exists = true; } else { existingHandler[restHandler.method] = [restHandler]; exists = false; } } else { this.handlers[url] = {}; this.handlers[url][restHandler.method] = [restHandler]; exists = false; } return { alreadyExist: exists }; } bind(restHandler) { var self = this; var result = this.addToCache(restHandler.url, restHandler); if (!result.alreadyExist) { var self = this; var result = self.getHandler(restHandler.url, restHandler.method); const handlersForUrl = result.handler; var restHandler = handlersForUrl[0]; this.bindToRouter(restHandler.url, restHandler.method, restHandler.preRequestHandler.securityCheck, (req, res, next) => { self.execute(restHandler.transaction, restHandler.url, restHandler.method, req, res, (error, result) => { if (error) next(error, result); else { res.set('Cache-Control', 'no-cache, no-store, must-revalidate, max-age=0'); res.set('Pragma', 'no-cache'); res.set('Expires', 0); res.send(result); } }); }); } } bindToRouter(url, method, auth, next) { if (method === 'Get') { this.app.get(url, auth, next); } else if (method === 'Post') { this.app.post(url, auth, next); } else if (method === 'Put') { this.app.put(url, auth, next); } else if (method === 'Delete') { this.app.delete(url, auth, next); } } execute(transaction, url, method, req, res, next) { const self = this; const result = self.getHandler(url, method); if (!result.status) { next(result.message); } else { const handlersForUrl = result.handler; async.detect(handlersForUrl, (handler, callback) => { handler.preRequestHandler.filterFunction(req, res, callback); }, async (err, selectedHandler) => { if (err) { next(err); return; } const { functionToBeCalled } = selectedHandler; if (transaction) { try { const { sequelize } = require('./models'); await sequelize .transaction(async (t1) => { const result1 = await functionToBeCalled(req, res); result1.matchWith({ Ok: ({ value }) => { next(null, value); }, Error: ({ value }) => { throw value; } }); const appliedFn = async.applyEach(selectedHandler.postRequestHandler.nextSteps, result1); appliedFn((error) => { if (error) { logError('Failed in route', error); } }); }); } catch (error) { next(error); } } else { const result1 = await functionToBeCalled(req, res); result1.matchWith({ Ok: ({ value }) => { next(null, value); }, Error: ({ value }) => { // FIXME: throw value? next(value); } }); const appliedFn = async.applyEach(selectedHandler.postRequestHandler.nextSteps, result1); appliedFn((error) => { if (error) { logError('Failed in route', error); } }); } } ); } } } class RestHandler { constructor(peopplRoute, app) { this.peopplRoute = peopplRoute; this.app = app; } setPreRequestHandler(preRequestHandler) { this.preRequestHandler = preRequestHandler; } get(url, functionToBeCalled) { this.url = url; this.functionToBeCalled = functionToBeCalled; this.method = 'Get'; this.postRequestHandler = new PostRequestHandler(this); return this.postRequestHandler; } post(url, functionToBeCalled) { this.url = url; this.functionToBeCalled = functionToBeCalled; this.method = 'Post'; this.postRequestHandler = new PostRequestHandler(this); return this.postRequestHandler; } delete(url, functionToBeCalled) { this.url = url; this.functionToBeCalled = functionToBeCalled; this.method = 'Delete'; this.postRequestHandler = new PostRequestHandler(this); return this.postRequestHandler; } put(url, functionToBeCalled) { this.url = url; this.functionToBeCalled = functionToBeCalled; this.method = 'Put'; this.postRequestHandler = new PostRequestHandler(this); return this.postRequestHandler; } bind(transaction) { this.transaction = transaction; this.peopplRoute.bind(this); } } class PreRequestHandler { constructor(restHandler, securityCheck) { this.securityCheck = securityCheck; this.restHandler = restHandler; } authorize(filterFunction) { this.filterFunction = filterFunction; this.restHandler.setPreRequestHandler(this); return this.restHandler; } noAuth() { this.filterFunction = (req, res, next) => next(null, true); this.restHandler.setPreRequestHandler(this); return this.restHandler; } } class PostRequestHandler { constructor(restHandler) { this.restHandler = restHandler; this.nextSteps = []; } then(nextStep) { this.nextSteps.push(nextStep); return this; } bind() { this.restHandler.bind(defaultTransaction); } bindWithTransaction() { this.restHandler.bind(true); } bindWithOutTransaction() { this.restHandler.bind(false); } } async function security(req, res, next) { const clientToken = req.body.token || req.query.token || req.headers['x-access-token']; if (clientToken) { const response = await TokenVerifier.verify({ clientToken, type: 'google' }); whenResult( (decoded) => { req.decoded = decoded; const namespace = cls.getNamespace(config.clsNameSpace); namespace.run(() => { namespace.set('userId', decoded.id); namespace.set('sessionId', decoded?.sessionId); }); next(); }, (error) => { logError('token verification failed', error); next(new ApiError('unauthorized', 'Failed to authenticate token.', HTTP_CONSTANT.UNAUTHORIZED)); } )(response); } else { logError('No Token provided', +req.originalUrl); next(new ApiError('Forbidden', 'No token provided.', HTTP_CONSTANT.FORBIDDEN)); } } module.exports = new Route();