1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-21 13:47:39 +02:00

Merge branch 'master' of github.com:Unleash/unleash

This commit is contained in:
Ivar Conradi Østhus 2018-01-23 09:08:48 +01:00
commit 75dfc96176
7 changed files with 96 additions and 21 deletions

View File

@ -22,6 +22,16 @@ unleash.start({
}); });
``` ```
Additionally, you can trigger the admin interfact to prompt the user to sign in by configuring your middleware to return a `401` status on
protected routes. The response body must contain a `message` and a `path` used to redirect the user to the proper login route.
```json
{
"message": "You must be logged in to use Unleash",
"path": "/custom/login"
}
```
Examples on custom authentication hooks: Examples on custom authentication hooks:
- [google-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/google-auth-hook.js) - [google-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/google-auth-hook.js)
- [basic-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/basic-auth-hook.js) - [basic-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/basic-auth-hook.js)

View File

@ -51,12 +51,20 @@ class FeatureToggleStore {
.then(this.rowToFeature); .then(this.rowToFeature);
} }
hasFeatureName(name) { hasFeature(name) {
return this.db return this.db
.first('name') .first('name', 'archived')
.from(TABLE) .from(TABLE)
.where({ name }) .where({ name })
.then(n => !!n); .then(row => {
if (!row) {
throw new NotFoundError('No feature toggle found');
}
return {
name: row.name,
archived: row.archived === 1,
};
});
} }
getArchivedFeatures() { getArchivedFeatures() {

View File

@ -23,12 +23,7 @@ const handleErrors = (req, res, error) => {
case NameExistsError: case NameExistsError:
return res return res
.status(403) .status(403)
.json([ .json([{ msg: error.message }])
{
msg:
'A feature with this name already exists. Try re-activating it from the archive.',
},
])
.end(); .end();
case ValidationError: case ValidationError:
return res return res
@ -97,13 +92,15 @@ module.exports.router = function(config) {
function validateUniqueName(req) { function validateUniqueName(req) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
featureToggleStore.hasFeatureName(req.body.name).then(hasName => { featureToggleStore
if (hasName) { .hasFeature(req.body.name)
reject(new NameExistsError('Feature name already exist')); .then(definition => {
} else { const msg = definition.archived
resolve(req); ? 'An archived toggle with that name already exist'
} : 'A toggle with that name already exist';
}); reject(new NameExistsError(msg));
})
.catch(() => resolve(req));
}); });
} }

View File

@ -81,6 +81,56 @@ test('should require at least one strategy when creating a feature toggle', t =>
.expect(400); .expect(400);
}); });
test('should be allowed to use new toggle name', t => {
t.plan(0);
const { request, base } = getSetup();
return request
.post(`${base}/api/admin/features/validate`)
.send({ name: 'new.name' })
.set('Content-Type', 'application/json')
.expect(201);
});
test('should not be allowed to reuse active toggle name', t => {
t.plan(1);
const { request, featureToggleStore, base } = getSetup();
featureToggleStore.addFeature({
name: 'ts',
strategies: [{ name: 'default' }],
});
return request
.post(`${base}/api/admin/features/validate`)
.send({ name: 'ts' })
.set('Content-Type', 'application/json')
.expect(403)
.expect(res => {
t.true(res.body[0].msg === 'A toggle with that name already exist');
});
});
test('should not be allowed to reuse archived toggle name', t => {
t.plan(1);
const { request, featureToggleStore, base } = getSetup();
featureToggleStore.addArchivedFeature({
name: 'ts.archived',
strategies: [{ name: 'default' }],
});
return request
.post(`${base}/api/admin/features/validate`)
.send({ name: 'ts.archived' })
.set('Content-Type', 'application/json')
.expect(403)
.expect(res => {
t.true(
res.body[0].msg ===
'An archived toggle with that name already exist'
);
});
});
test('should require at least one strategy when updating a feature toggle', t => { test('should require at least one strategy when updating a feature toggle', t => {
t.plan(0); t.plan(0);
const { request, featureToggleStore, base } = getSetup(); const { request, featureToggleStore, base } = getSetup();

View File

@ -83,7 +83,7 @@
"prometheus-gc-stats": "^0.5.0", "prometheus-gc-stats": "^0.5.0",
"response-time": "^2.3.2", "response-time": "^2.3.2",
"serve-favicon": "^2.3.0", "serve-favicon": "^2.3.0",
"unleash-frontend": "^3.0.0-alpha.5", "unleash-frontend": "^3.0.0-alpha.6",
"yallist": "^3.0.2", "yallist": "^3.0.2",
"yargs": "^10.0.3" "yargs": "^10.0.3"
}, },

View File

@ -12,8 +12,18 @@ module.exports = () => {
return Promise.reject(); return Promise.reject();
} }
}, },
hasFeature: name => {
const toggle = _features.find(f => f.name === name);
const archived = _archive.find(f => f.name === name);
if (toggle) {
return Promise.resolve({ name, archived: false });
} else if (archived) {
return Promise.resolve({ name, archived: true });
} else {
return Promise.reject();
}
},
getFeatures: () => Promise.resolve(_features), getFeatures: () => Promise.resolve(_features),
hasFeatureName: () => Promise.resolve(false),
addFeature: feature => _features.push(feature), addFeature: feature => _features.push(feature),
getArchivedFeatures: () => Promise.resolve(_archive), getArchivedFeatures: () => Promise.resolve(_archive),
addArchivedFeature: feature => _archive.push(feature), addArchivedFeature: feature => _archive.push(feature),

View File

@ -5775,9 +5775,9 @@ unique-temp-dir@^1.0.0:
os-tmpdir "^1.0.1" os-tmpdir "^1.0.1"
uid2 "0.0.3" uid2 "0.0.3"
unleash-frontend@^3.0.0-alpha.5: unleash-frontend@^3.0.0-alpha.6:
version "3.0.0-alpha.5" version "3.0.0-alpha.6"
resolved "https://registry.yarnpkg.com/unleash-frontend/-/unleash-frontend-3.0.0-alpha.5.tgz#ef4c2bb9e24ba07465b1737098b92b6a036df282" resolved "https://registry.yarnpkg.com/unleash-frontend/-/unleash-frontend-3.0.0-alpha.6.tgz#439a5554a1169082b7ae19544002cad19409a27d"
dependencies: dependencies:
debug "^3.1.0" debug "^3.1.0"
immutable "^3.8.1" immutable "^3.8.1"