Skip to content

Commit 12ad97a

Browse files
authored
Fixes create/update duplicate Switcher key - allow moving Switcher (#540)
1 parent 864a54a commit 12ad97a

File tree

5 files changed

+84
-23
lines changed

5 files changed

+84
-23
lines changed

src/routers/config.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,11 @@ router.delete('/config/:id', auth, [
129129
});
130130

131131
router.patch('/config/:id', auth, [
132-
check('id').isMongoId()
132+
check('id').isMongoId(),
133+
check('key').optional().isLength({ min: 3, max: 50 }),
134+
check('group').optional().isMongoId(),
133135
], validate, verifyInputUpdateParameters([
134-
'key', 'description', 'relay', 'disable_metrics'
136+
'key', 'description', 'group', 'relay', 'disable_metrics'
135137
]), async (req, res) => {
136138
try {
137139
const config = await Services.updateConfig(req.params.id, req.body, req.admin);

src/services/config.js

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ export async function populateAdmin(configs) {
5959
}
6060

6161
export async function createConfig(args, admin) {
62+
args.key = formatInput(args.key, { toUpper: true, autoUnderscore: true });
63+
6264
// validates account plan permissions
6365
const group = await getGroupConfigById(args.group);
6466
await checkSwitcher(group);
@@ -70,7 +72,7 @@ export async function createConfig(args, admin) {
7072
});
7173

7274
if (config) {
73-
throw new BadRequestError(`Config ${args.key} already exists`);
75+
throw new BadRequestError(`Config ${config.key} already exists`);
7476
}
7577

7678
config = new Config({
@@ -79,8 +81,6 @@ export async function createConfig(args, admin) {
7981
owner: admin._id
8082
});
8183

82-
config.key = formatInput(config.key, { toUpper: true, autoUnderscore: true });
83-
8484
// validates permissions
8585
config = await verifyOwnership(admin, config, group.domain, ActionTypes.CREATE, RouterTypes.CONFIG);
8686

@@ -112,19 +112,12 @@ export async function updateConfig(id, args, admin) {
112112

113113
// validates existing switcher key
114114
if (args.key) {
115-
const duplicatedKey = await getConfig({
116-
key: args.key,
117-
group: config.group,
118-
domain: config.domain
119-
});
120-
121-
if (duplicatedKey) {
122-
throw new BadRequestError(`Config ${args.key} already exists`);
123-
}
115+
args = await updateConfigKey(args, config);
116+
}
124117

125-
// resets permission cache
126-
permissionCache.permissionReset(config.domain, ActionTypes.ALL, RouterTypes.CONFIG, config.group);
127-
permissionCache.permissionReset(config.domain, ActionTypes.ALL, RouterTypes.CONFIG, config.key);
118+
// validates existing group
119+
if (args.group) {
120+
await getGroupConfigById(args.group);
128121
}
129122

130123
// validates existing environment
@@ -139,13 +132,32 @@ export async function updateConfig(id, args, admin) {
139132
config.updatedBy = admin.email;
140133
const updates = Object.keys(args);
141134
updates.forEach((update) => config[update] = args[update]);
142-
config.key = formatInput(config.key, { toUpper: true, autoUnderscore: true });
135+
143136
await config.save();
144137
updateDomainVersion(config.domain);
145138

146139
return config;
147140
}
148141

142+
async function updateConfigKey(args, config) {
143+
args.key = formatInput(args.key, { toUpper: true, autoUnderscore: true });
144+
145+
const duplicatedKey = await getConfig({
146+
key: args.key,
147+
domain: config.domain
148+
});
149+
150+
if (duplicatedKey) {
151+
throw new BadRequestError(`Config ${duplicatedKey.key} already exists`);
152+
}
153+
154+
// resets permission cache
155+
permissionCache.permissionReset(config.domain, ActionTypes.ALL, RouterTypes.CONFIG, config.group);
156+
permissionCache.permissionReset(config.domain, ActionTypes.ALL, RouterTypes.CONFIG, config.key);
157+
158+
return args;
159+
}
160+
149161
export async function updateConfigRelay(id, args, admin) {
150162
let config = await getConfigById(id);
151163
isRelayValid(args);

tests/config.test.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
adminMasterAccountToken,
1616
domainId,
1717
groupConfigId,
18+
groupConfigId2,
1819
configId1,
1920
config1Document,
2021
configId2,
@@ -52,7 +53,7 @@ describe('Testing configuration insertion', () => {
5253
.post('/config/create')
5354
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
5455
.send({
55-
key: 'NEW_CONFIG',
56+
key: 'new_config', // case insensitive - it will be converted to uppercase
5657
description: 'Description of my new Config',
5758
group: groupConfigId
5859
}).expect(400);
@@ -277,7 +278,7 @@ describe('Testing update info', () => {
277278
const response = await request(app)
278279
.patch('/config/' + configId1)
279280
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
280-
.send({ key: 'NEWKEY' }).expect(400);
281+
.send({ key: 'newkey' }).expect(400);
281282

282283
expect(response.body.error).toEqual('Config NEWKEY already exists');
283284
});
@@ -324,6 +325,41 @@ describe('Testing update info', () => {
324325
});
325326
});
326327

328+
describe('Testing moving Config from GroupConfig to another', () => {
329+
beforeAll(setupDatabase);
330+
331+
test('CONFIG_SUITE - Should move Config to a different GroupConfig', async () => {
332+
await request(app)
333+
.patch('/config/' + configId1)
334+
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
335+
.send({
336+
group: groupConfigId2
337+
}).expect(200);
338+
339+
// DB validation - verify flag updated
340+
const config = await Config.findById(configId1).lean().exec();
341+
expect(config).not.toBeNull();
342+
expect(config.group).toEqual(groupConfigId2);
343+
});
344+
345+
test('CONFIG_SUITE - Should NOT move Config to a different GroupConfig - GroupConfig not found', async () => {
346+
await request(app)
347+
.patch('/config/' + configId1)
348+
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
349+
.send({
350+
group: new mongoose.Types.ObjectId()
351+
}).expect(404);
352+
353+
await request(app)
354+
.patch('/config/' + configId1)
355+
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
356+
.send({
357+
group: 'INVALID_VALUE_ID'
358+
}).expect(422);
359+
});
360+
361+
});
362+
327363
describe('Testing Environment status change', () => {
328364
beforeAll(setupDatabase);
329365

tests/fixtures/db_api.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ export const groupConfigDocument = {
122122
domain: domainId
123123
};
124124

125+
export const groupConfigId2 = new mongoose.Types.ObjectId();
126+
export const groupConfig2Document = {
127+
_id: groupConfigId2,
128+
name: 'Group Test 2',
129+
description: 'Test Group 2',
130+
activated: new Map().set(EnvType.DEFAULT, true),
131+
owner: adminMasterAccountId,
132+
domain: domainId
133+
};
134+
125135
export const configId1 = new mongoose.Types.ObjectId();
126136
export const config1Document = {
127137
_id: configId1,
@@ -265,6 +275,7 @@ export const setupDatabase = async () => {
265275
await new Environment(environment3).save();
266276
await new Domain(domainDocument).save();
267277
await new GroupConfig(groupConfigDocument).save();
278+
await new GroupConfig(groupConfig2Document).save();
268279
await new Config(config1Document).save();
269280
await new Config(config2Document).save();
270281
await new ConfigStrategy(configStrategyDocument).save();

tests/group-config.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ describe('Testing fetch Group info', () => {
9292
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
9393
.send().expect(200);
9494

95-
expect(response.body.length).toEqual(1);
95+
expect(response.body.length).toBeGreaterThan(0);
9696

9797
expect(String(response.body[0]._id)).toEqual(String(groupConfigDocument._id));
9898
expect(response.body[0].name).toEqual(groupConfigDocument.name);
@@ -119,7 +119,7 @@ describe('Testing fetch Group info', () => {
119119
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
120120
.send().expect(200);
121121

122-
expect(response.body.length).toEqual(2);
122+
expect(response.body.length).toBeGreaterThan(1);
123123

124124
// Query filter tests
125125
response = await request(app)
@@ -134,7 +134,7 @@ describe('Testing fetch Group info', () => {
134134
.set('Authorization', `Bearer ${adminMasterAccountToken}`)
135135
.send().expect(200);
136136

137-
expect(response.body.length).toEqual(2);
137+
expect(response.body.length).toBeGreaterThan(1);
138138
});
139139

140140
test('GROUP_SUITE - Should get Group Config information - only fields (name, activated.default)', async () => {

0 commit comments

Comments
 (0)