1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00
unleash.unleash/lib/routes/admin-api/feature.js
ivaosthu ccaab0c47b fix: LogProvider as option injected to unleash.
Instead of instructing users to do static calls
in to Unleash, she should instead be allwed to
specify the log provider as an option to Unleash.

This commit introduces the "getLogger" option,
a function responsible for creating a logger.
2020-02-20 08:34:24 +01:00

185 lines
5.6 KiB
JavaScript

'use strict';
const Controller = require('../controller');
const joi = require('joi');
const {
FEATURE_CREATED,
FEATURE_UPDATED,
FEATURE_ARCHIVED,
} = require('../../event-type');
const NameExistsError = require('../../error/name-exists-error');
const { handleErrors } = require('./util');
const extractUser = require('../../extract-user');
const {
UPDATE_FEATURE,
DELETE_FEATURE,
CREATE_FEATURE,
} = require('../../permissions');
const { featureShema, nameSchema } = require('./feature-schema');
const version = 1;
class FeatureController extends Controller {
constructor(config) {
super(config);
this.featureToggleStore = config.stores.featureToggleStore;
this.eventStore = config.stores.eventStore;
this.logger = config.getLogger('/admin-api/feature.js');
this.get('/', this.getAllToggles);
this.post('/', this.createToggle, CREATE_FEATURE);
this.get('/:featureName', this.getToggle);
this.put('/:featureName', this.updateToggle, UPDATE_FEATURE);
this.delete('/:featureName', this.deleteToggle, DELETE_FEATURE);
this.post('/validate', this.validate);
this.post('/:featureName/toggle', this.toggle, UPDATE_FEATURE);
this.post('/:featureName/toggle/on', this.toggleOn, UPDATE_FEATURE);
this.post('/:featureName/toggle/off', this.toggleOff, UPDATE_FEATURE);
}
async getAllToggles(req, res) {
const features = await this.featureToggleStore.getFeatures();
res.json({ version, features });
}
async getToggle(req, res) {
try {
const name = req.params.featureName;
const feature = await this.featureToggleStore.getFeature(name);
res.json(feature).end();
} catch (err) {
res.status(404).json({ error: 'Could not find feature' });
}
}
async validate(req, res) {
const name = req.body.name;
try {
await joi.validate({ name }, nameSchema);
await this.validateUniqueName(name);
res.status(201).end();
} catch (error) {
handleErrors(res, this.logger, error);
}
}
// TODO: cleanup this validation
async validateUniqueName(name) {
let msg;
try {
const definition = await this.featureToggleStore.hasFeature(name);
msg = definition.archived
? 'An archived toggle with that name already exist'
: 'A toggle with that name already exist';
} catch (error) {
// No conflict, everything ok!
return;
}
// Interntional throw here!
throw new NameExistsError(msg);
}
async createToggle(req, res) {
const toggleName = req.body.name;
const userName = extractUser(req);
try {
await this.validateUniqueName(toggleName);
const featureToggle = await joi.validate(req.body, featureShema);
await this.eventStore.store({
type: FEATURE_CREATED,
createdBy: userName,
data: featureToggle,
});
res.status(201).end();
} catch (error) {
handleErrors(res, this.logger, error);
}
}
async updateToggle(req, res) {
const featureName = req.params.featureName;
const userName = extractUser(req);
const updatedFeature = req.body;
updatedFeature.name = featureName;
try {
await this.featureToggleStore.getFeature(featureName);
await joi.validate(updatedFeature, featureShema);
await this.eventStore.store({
type: FEATURE_UPDATED,
createdBy: userName,
data: updatedFeature,
});
res.status(200).end();
} catch (error) {
handleErrors(res, this.logger, error);
}
}
// Kept to keep backward compatability
async toggle(req, res) {
try {
const name = req.params.featureName;
const feature = await this.featureToggleStore.getFeature(name);
const enabled = !feature.enabled;
this._toggle(enabled, req, res);
} catch (error) {
handleErrors(res, this.logger, error);
}
}
async toggleOn(req, res) {
this._toggle(true, req, res);
}
async toggleOff(req, res) {
this._toggle(false, req, res);
}
async _toggle(enabled, req, res) {
const featureName = req.params.featureName;
const userName = extractUser(req);
try {
const feature = await this.featureToggleStore.getFeature(
featureName
);
feature.enabled = enabled;
await this.eventStore.store({
type: FEATURE_UPDATED,
createdBy: userName,
data: feature,
});
res.json(feature).end();
} catch (error) {
handleErrors(res, this.logger, error);
}
}
async deleteToggle(req, res) {
const featureName = req.params.featureName;
const userName = extractUser(req);
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(res, this.logger, error);
}
}
}
module.exports = FeatureController;