mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-04 00:18:01 +01:00
Fix/validate context (#1282)
* fix: add context guards * fix: change error message * fix: remove console log
This commit is contained in:
parent
37352804df
commit
8ecacfb89c
@ -196,7 +196,12 @@ class FeatureController extends Controller {
|
|||||||
const projectId = await this.service.getProjectId(featureName);
|
const projectId = await this.service.getProjectId(featureName);
|
||||||
const value = await featureSchema.validateAsync(updatedFeature);
|
const value = await featureSchema.validateAsync(updatedFeature);
|
||||||
|
|
||||||
await this.service.updateFeatureToggle(projectId, value, userName);
|
await this.service.updateFeatureToggle(
|
||||||
|
projectId,
|
||||||
|
value,
|
||||||
|
userName,
|
||||||
|
featureName,
|
||||||
|
);
|
||||||
|
|
||||||
await this.service.removeAllStrategiesForEnv(featureName);
|
await this.service.removeAllStrategiesForEnv(featureName);
|
||||||
|
|
||||||
|
@ -178,16 +178,22 @@ export default class ProjectFeaturesController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateFeature(
|
async updateFeature(
|
||||||
req: IAuthRequest<ProjectParam, any, FeatureToggleDTO, any>,
|
req: IAuthRequest<
|
||||||
|
{ projectId: string; featureName: string },
|
||||||
|
any,
|
||||||
|
FeatureToggleDTO,
|
||||||
|
any
|
||||||
|
>,
|
||||||
res: Response,
|
res: Response,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { projectId } = req.params;
|
const { projectId, featureName } = req.params;
|
||||||
const data = req.body;
|
const data = req.body;
|
||||||
const userName = extractUsername(req);
|
const userName = extractUsername(req);
|
||||||
const created = await this.featureService.updateFeatureToggle(
|
const created = await this.featureService.updateFeatureToggle(
|
||||||
projectId,
|
projectId,
|
||||||
data,
|
data,
|
||||||
userName,
|
userName,
|
||||||
|
featureName,
|
||||||
);
|
);
|
||||||
res.status(200).json(created);
|
res.status(200).json(created);
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ class FeatureToggleService {
|
|||||||
const id = await this.featureToggleStore.getProjectId(featureName);
|
const id = await this.featureToggleStore.getProjectId(featureName);
|
||||||
if (id !== projectId) {
|
if (id !== projectId) {
|
||||||
throw new InvalidOperationError(
|
throw new InvalidOperationError(
|
||||||
'You can not change the projectId for an activation strategy.',
|
'Project id does not match the project that the feature belongs to',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,6 +162,7 @@ class FeatureToggleService {
|
|||||||
project,
|
project,
|
||||||
newDocument,
|
newDocument,
|
||||||
createdBy,
|
createdBy,
|
||||||
|
featureName,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (featureToggle.stale !== newDocument.stale) {
|
if (featureToggle.stale !== newDocument.stale) {
|
||||||
@ -559,8 +560,10 @@ class FeatureToggleService {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
updatedFeature: FeatureToggleDTO,
|
updatedFeature: FeatureToggleDTO,
|
||||||
userName: string,
|
userName: string,
|
||||||
|
featureName: string,
|
||||||
): Promise<FeatureToggle> {
|
): Promise<FeatureToggle> {
|
||||||
const featureName = updatedFeature.name;
|
await this.validateFeatureContext({ featureName, projectId });
|
||||||
|
|
||||||
this.logger.info(`${userName} updates feature toggle ${featureName}`);
|
this.logger.info(`${userName} updates feature toggle ${featureName}`);
|
||||||
|
|
||||||
const featureData = await featureMetadataSchema.validateAsync(
|
const featureData = await featureMetadataSchema.validateAsync(
|
||||||
@ -569,10 +572,11 @@ class FeatureToggleService {
|
|||||||
|
|
||||||
const preData = await this.featureToggleStore.get(featureName);
|
const preData = await this.featureToggleStore.get(featureName);
|
||||||
|
|
||||||
const featureToggle = await this.featureToggleStore.update(
|
const featureToggle = await this.featureToggleStore.update(projectId, {
|
||||||
projectId,
|
...featureData,
|
||||||
featureData,
|
name: featureName,
|
||||||
);
|
});
|
||||||
|
|
||||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||||
|
|
||||||
await this.eventStore.store(
|
await this.eventStore.store(
|
||||||
|
@ -732,7 +732,6 @@ test('should hit validate and tags endpoint if legacy api is disabled', async ()
|
|||||||
await appWithDisabledLegacyFeatures.request
|
await appWithDisabledLegacyFeatures.request
|
||||||
.get(`/api/admin/features/${feature.name}/tags`)
|
.get(`/api/admin/features/${feature.name}/tags`)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
console.log(res.body);
|
|
||||||
expect(res.body.tags[0].value).toBe('TeamGreen');
|
expect(res.body.tags[0].value).toBe('TeamGreen');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1914,3 +1914,72 @@ test(`a feature's variants should be sorted by name in increasing order`, async
|
|||||||
expect(res.body.variants[2].name).toBe('z');
|
expect(res.body.variants[2].name).toBe('z');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should validate context when calling update with PUT', async () => {
|
||||||
|
const name = 'new.toggle.validate.context';
|
||||||
|
await app.request
|
||||||
|
.post('/api/admin/projects/default/features')
|
||||||
|
.send({ name, description: 'some', type: 'release' })
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
await app.request
|
||||||
|
.put(`/api/admin/projects/another-project/features/${name}`)
|
||||||
|
.send({ name, description: 'updated', type: 'kill-switch' })
|
||||||
|
.expect((res) => {
|
||||||
|
expect(res.body.name).toBe('InvalidOperationError');
|
||||||
|
})
|
||||||
|
.expect(403);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should validate context when calling update with PATCH', async () => {
|
||||||
|
const name = 'new.toggle.validate.context2';
|
||||||
|
await app.request
|
||||||
|
.post('/api/admin/projects/default/features')
|
||||||
|
.send({ name, description: 'some', type: 'release' })
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
await app.request
|
||||||
|
.patch(`/api/admin/projects/another-project/features/${name}`)
|
||||||
|
.send([])
|
||||||
|
.expect((res) => {
|
||||||
|
expect(res.body.name).toBe('InvalidOperationError');
|
||||||
|
})
|
||||||
|
.expect(403);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not update project with PUT', async () => {
|
||||||
|
const name = 'new.toggle.validate.update.project.put';
|
||||||
|
await app.request
|
||||||
|
.post('/api/admin/projects/default/features')
|
||||||
|
.send({ name, description: 'some', type: 'release' })
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
await app.request
|
||||||
|
.put(`/api/admin/projects/default/features/${name}`)
|
||||||
|
.send({
|
||||||
|
name,
|
||||||
|
description: 'updated',
|
||||||
|
type: 'kill-switch',
|
||||||
|
project: 'new-project',
|
||||||
|
})
|
||||||
|
.expect((res) => {
|
||||||
|
expect(res.body.project).toBe('default');
|
||||||
|
})
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not update project with PATCH', async () => {
|
||||||
|
const name = 'new.toggle.validate.update.project.patch';
|
||||||
|
await app.request
|
||||||
|
.post('/api/admin/projects/default/features')
|
||||||
|
.send({ name, description: 'some', type: 'release' })
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
await app.request
|
||||||
|
.patch(`/api/admin/projects/default/features/${name}`)
|
||||||
|
.send([{ op: 'replace', path: '/project', value: 'new-project' }])
|
||||||
|
.expect((res) => {
|
||||||
|
expect(res.body.project).toBe('default');
|
||||||
|
})
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
@ -111,3 +111,41 @@ test('Should be able to get strategy by id', async () => {
|
|||||||
const fetchedConfig = await service.getStrategy(createdConfig.id);
|
const fetchedConfig = await service.getStrategy(createdConfig.id);
|
||||||
expect(fetchedConfig).toEqual(createdConfig);
|
expect(fetchedConfig).toEqual(createdConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should ignore name in the body when updating feature toggle', async () => {
|
||||||
|
const featureName = 'body-name-update';
|
||||||
|
const projectId = 'default';
|
||||||
|
|
||||||
|
const userName = 'strategy';
|
||||||
|
const secondFeatureName = 'body-name-update2';
|
||||||
|
|
||||||
|
await service.createFeatureToggle(
|
||||||
|
projectId,
|
||||||
|
{
|
||||||
|
name: featureName,
|
||||||
|
description: 'First toggle',
|
||||||
|
},
|
||||||
|
userName,
|
||||||
|
);
|
||||||
|
|
||||||
|
await service.createFeatureToggle(
|
||||||
|
projectId,
|
||||||
|
{
|
||||||
|
name: secondFeatureName,
|
||||||
|
description: 'Second toggle',
|
||||||
|
},
|
||||||
|
userName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const update = {
|
||||||
|
name: secondFeatureName,
|
||||||
|
description: "I'm changed",
|
||||||
|
};
|
||||||
|
|
||||||
|
await service.updateFeatureToggle(projectId, update, userName, featureName);
|
||||||
|
const featureOne = await service.getFeature(featureName);
|
||||||
|
const featureTwo = await service.getFeature(secondFeatureName);
|
||||||
|
|
||||||
|
expect(featureOne.description).toBe(`I'm changed`);
|
||||||
|
expect(featureTwo.description).toBe('Second toggle');
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user