From e285f39bcbeb5e6d6a1b8dcda56bc5c700713cb9 Mon Sep 17 00:00:00 2001 From: ivaosthu Date: Fri, 30 Nov 2018 11:11:12 +0100 Subject: [PATCH] chore(modernize): Admin FeatureController --- lib/routes/admin-api/feature.js | 195 ++++++++++++++++++-------------- lib/routes/admin-api/index.js | 4 +- lib/routes/controller.js | 8 ++ 3 files changed, 117 insertions(+), 90 deletions(-) diff --git a/lib/routes/admin-api/feature.js b/lib/routes/admin-api/feature.js index c20d7edc14..f24592778e 100644 --- a/lib/routes/admin-api/feature.js +++ b/lib/routes/admin-api/feature.js @@ -1,6 +1,6 @@ 'use strict'; -const { Router } = require('express'); +const Controller = require('../controller'); const joi = require('joi'); const logger = require('../../logger')('/admin-api/feature.js'); @@ -71,28 +71,54 @@ function validateStrategy(featureToggle) { const version = 1; -module.exports.router = function(config) { - const { featureToggleStore, eventStore } = config.stores; - const router = Router(); +class FeatureController extends Controller { + constructor({ featureToggleStore, eventStore }) { + super(); + this.featureToggleStore = featureToggleStore; + this.eventStore = eventStore; - router.get('/', (req, res) => { - featureToggleStore - .getFeatures() - .then(features => res.json({ version, features })); - }); + this.get('/', this.getAllToggles); + this.post('/', this.createToggle); + this.get('/:featureName', this.getToggle); + this.put('/:featureName', this.updateToggle); + this.delete('/:featureName', this.deleteToggle); + this.post('/validate', this.validate); + this.post('/:featureName/toggle', this.toggle); + } - router.get('/:featureName', (req, res) => { - featureToggleStore - .getFeature(req.params.featureName) - .then(feature => res.json(feature).end()) - .catch(() => - res.status(404).json({ error: 'Could not find feature' }) + async getAllToggles(req, res) { + const features = await this.featureToggleStore.getFeatures(); + res.json({ version, features }); + } + + async getToggle(req, res) { + try { + const featureName = req.params.featureName; + const feature = await this.featureToggleStore.getFeature( + featureName ); - }); + res.json(feature).end(); + } catch (err) { + res.status(404).json({ error: 'Could not find feature' }); + } + } - function validateUniqueName(req) { + async validate(req, res) { + req.checkBody('name', 'Name is required').notEmpty(); + req.checkBody('name', 'Name must be URL friendly').isUrlFriendlyName(); + + try { + await validateRequest(req); + await this.validateUniqueName(req); + res.status(201).end(); + } catch (error) { + handleErrors(req, res, error); + } + } + + validateUniqueName(req) { return new Promise((resolve, reject) => { - featureToggleStore + this.featureToggleStore .hasFeature(req.body.name) .then(definition => { const msg = definition.archived @@ -104,94 +130,87 @@ module.exports.router = function(config) { }); } - router.post('/validate', (req, res) => { - req.checkBody('name', 'Name is required').notEmpty(); - req.checkBody('name', 'Name must be URL friendly').isUrlFriendlyName(); - - validateRequest(req) - .then(validateUniqueName) - .then(() => res.status(201).end()) - .catch(error => handleErrors(req, res, error)); - }); - - router.post('/', (req, res) => { + async createToggle(req, res) { req.checkBody('name', 'Name is required').notEmpty(); req.checkBody('name', 'Name must be URL friendly').isUrlFriendlyName(); const userName = extractUser(req); - validateRequest(req) - .then(validateUniqueName) - .then(_req => _req.body) - .then(validateStrategy) - .then(featureToggle => - eventStore.store({ - type: FEATURE_CREATED, - createdBy: userName, - data: featureToggle, - }) - ) - .then(() => res.status(201).end()) - .catch(error => handleErrors(req, res, error)); - }); + try { + await validateRequest(req); + await this.validateUniqueName(req); + const featureToggle = await validateStrategy(req.body); + await this.eventStore.store({ + type: FEATURE_CREATED, + createdBy: userName, + data: featureToggle, + }); + res.status(201).end(); + } catch (error) { + handleErrors(req, res, error); + } + } - router.put('/:featureName', (req, res) => { + async updateToggle(req, res) { const featureName = req.params.featureName; const userName = extractUser(req); const updatedFeature = req.body; updatedFeature.name = featureName; - featureToggleStore - .getFeature(featureName) - .then(() => validateStrategy(updatedFeature)) - .then(() => - eventStore.store({ - type: FEATURE_UPDATED, - createdBy: userName, - data: updatedFeature, - }) - ) - .then(() => res.status(200).end()) - .catch(error => handleErrors(req, res, error)); - }); + try { + await this.featureToggleStore.getFeature(featureName); + await validateStrategy(updatedFeature); + await this.eventStore.store({ + type: FEATURE_UPDATED, + createdBy: userName, + data: updatedFeature, + }); + res.status(200).end(); + } catch (error) { + handleErrors(req, res, error); + } + } - router.post('/:featureName/toggle', (req, res) => { + async toggle(req, res) { const featureName = req.params.featureName; const userName = extractUser(req); - featureToggleStore - .getFeature(featureName) - .then(feature => { - feature.enabled = !feature.enabled; - return eventStore.store({ - type: FEATURE_UPDATED, - createdBy: userName, - data: feature, - }); - }) - .then(() => res.status(200).end()) - .catch(error => handleErrors(req, res, error)); - }); + try { + const feature = await this.featureToggleStore.getFeature( + featureName + ); - router.delete('/:featureName', (req, res) => { + feature.enabled = !feature.enabled; + await this.eventStore.store({ + type: FEATURE_UPDATED, + createdBy: userName, + data: feature, + }); + res.status(200).end(); + } catch (error) { + handleErrors(req, res, error); + } + } + + async deleteToggle(req, res) { const featureName = req.params.featureName; const userName = extractUser(req); - featureToggleStore - .getFeature(featureName) - .then(() => - eventStore.store({ - type: FEATURE_ARCHIVED, - createdBy: userName, - data: { - name: featureName, - }, - }) - ) - .then(() => res.status(200).end()) - .catch(error => handleErrors(req, res, error)); - }); + try { + await this.featureToggleStore.getFeature(featureName); + await this.eventStore.store({ + type: FEATURE_ARCHIVED, + createdBy: userName, + data: { + name: featureName, + }, + }); + res.status(200).end(); + } catch (error) { + handleErrors(req, res, error); + } + } +} - return router; -}; +module.exports = FeatureController; diff --git a/lib/routes/admin-api/index.js b/lib/routes/admin-api/index.js index f789a8f415..912e0ca869 100644 --- a/lib/routes/admin-api/index.js +++ b/lib/routes/admin-api/index.js @@ -1,7 +1,7 @@ 'use strict'; const Controller = require('../controller'); -const features = require('./feature.js'); +const FeatureController = require('./feature.js'); const ArchiveController = require('./archive.js'); const EventController = require('./event.js'); const strategies = require('./strategy'); @@ -16,7 +16,7 @@ class AdminApi extends Controller { const stores = config.stores; this.app.get('/', this.index); - this.app.use('/features', features.router(config)); + this.app.use('/features', new FeatureController(stores).router()); this.app.use('/archive', new ArchiveController(stores).router()); this.app.use('/strategies', strategies.router(config)); this.app.use('/events', new EventController(stores).router()); diff --git a/lib/routes/controller.js b/lib/routes/controller.js index 5787a82ab1..8c95a51bda 100644 --- a/lib/routes/controller.js +++ b/lib/routes/controller.js @@ -18,6 +18,14 @@ class Controller { this.app.post(path, handler.bind(this)); } + put(path, handler) { + this.app.put(path, handler.bind(this)); + } + + delete(path, handler) { + this.app.delete(path, handler.bind(this)); + } + router() { return this.app; }