mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-23 00:16:25 +01:00
feat: ability to upsert single legal values (#9056)
This commit is contained in:
parent
7893d3fbd3
commit
20fda186b5
@ -20,9 +20,10 @@ import {
|
|||||||
} from '../../types';
|
} from '../../types';
|
||||||
import type { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType';
|
import type { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType';
|
||||||
import type EventService from '../events/event-service';
|
import type EventService from '../events/event-service';
|
||||||
import { contextSchema } from '../../services/context-schema';
|
import { contextSchema, legalValueSchema } from '../../services/context-schema';
|
||||||
import { NameExistsError } from '../../error';
|
import { NameExistsError } from '../../error';
|
||||||
import { nameSchema } from '../../schema/feature-schema';
|
import { nameSchema } from '../../schema/feature-schema';
|
||||||
|
import type { LegalValueSchema } from '../../openapi';
|
||||||
|
|
||||||
class ContextService {
|
class ContextService {
|
||||||
private eventService: EventService;
|
private eventService: EventService;
|
||||||
@ -126,7 +127,6 @@ class ContextService {
|
|||||||
);
|
);
|
||||||
const value = await contextSchema.validateAsync(updatedContextField);
|
const value = await contextSchema.validateAsync(updatedContextField);
|
||||||
|
|
||||||
// update
|
|
||||||
await this.contextFieldStore.update(value);
|
await this.contextFieldStore.update(value);
|
||||||
|
|
||||||
const { createdAt, sortOrder, ...previousContextField } = contextField;
|
const { createdAt, sortOrder, ...previousContextField } = contextField;
|
||||||
@ -140,6 +140,45 @@ class ContextService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateContextFieldLegalValue(
|
||||||
|
contextFieldLegalValue: { name: string; legalValue: LegalValueSchema },
|
||||||
|
auditUser: IAuditUser,
|
||||||
|
): Promise<void> {
|
||||||
|
const contextField = await this.contextFieldStore.get(
|
||||||
|
contextFieldLegalValue.name,
|
||||||
|
);
|
||||||
|
const validatedLegalValue = await legalValueSchema.validateAsync(
|
||||||
|
contextFieldLegalValue.legalValue,
|
||||||
|
);
|
||||||
|
|
||||||
|
const legalValues = contextField.legalValues
|
||||||
|
? [...contextField.legalValues]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const existingIndex = legalValues.findIndex(
|
||||||
|
(legalvalue) => legalvalue.value === validatedLegalValue.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingIndex !== -1) {
|
||||||
|
legalValues[existingIndex] = validatedLegalValue;
|
||||||
|
} else {
|
||||||
|
legalValues.push(validatedLegalValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newContextField = { ...contextField, legalValues };
|
||||||
|
|
||||||
|
await this.contextFieldStore.update(newContextField);
|
||||||
|
|
||||||
|
await this.eventService.storeEvent({
|
||||||
|
type: CONTEXT_FIELD_UPDATED,
|
||||||
|
createdBy: auditUser.username,
|
||||||
|
createdByUserId: auditUser.id,
|
||||||
|
ip: auditUser.ip,
|
||||||
|
preData: contextField,
|
||||||
|
data: newContextField,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async deleteContextField(
|
async deleteContextField(
|
||||||
name: string,
|
name: string,
|
||||||
auditUser: IAuditUser,
|
auditUser: IAuditUser,
|
||||||
|
@ -151,6 +151,59 @@ test('should update a context field with new legal values', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should add and update a single context field with new legal values', async () => {
|
||||||
|
expect.assertions(1);
|
||||||
|
|
||||||
|
// non existent context
|
||||||
|
await request
|
||||||
|
.post(`${base}/api/admin/context/doesntexist/legalValues`)
|
||||||
|
.send({
|
||||||
|
value: 'local',
|
||||||
|
description: 'Local environment',
|
||||||
|
})
|
||||||
|
.set('Content-Type', 'application/json')
|
||||||
|
.expect(404);
|
||||||
|
|
||||||
|
// invalid schema
|
||||||
|
await request
|
||||||
|
.post(`${base}/api/admin/context/environment/legal-values`)
|
||||||
|
.send({
|
||||||
|
valueInvalid: 'invalid schema',
|
||||||
|
description: 'Local environment',
|
||||||
|
})
|
||||||
|
.set('Content-Type', 'application/json')
|
||||||
|
.expect(400);
|
||||||
|
|
||||||
|
// add a new context field legal value
|
||||||
|
await request
|
||||||
|
.post(`${base}/api/admin/context/environment/legal-values`)
|
||||||
|
.send({
|
||||||
|
value: 'newvalue',
|
||||||
|
description: 'new description',
|
||||||
|
})
|
||||||
|
.set('Content-Type', 'application/json')
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
// update existing context field legal value description
|
||||||
|
await request
|
||||||
|
.post(`${base}/api/admin/context/environment/legal-values`)
|
||||||
|
.send({
|
||||||
|
value: 'newvalue',
|
||||||
|
description: 'updated description',
|
||||||
|
})
|
||||||
|
.set('Content-Type', 'application/json')
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
const { body } = await request.get(`${base}/api/admin/context/environment`);
|
||||||
|
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
name: 'environment',
|
||||||
|
legalValues: [
|
||||||
|
{ value: 'newvalue', description: 'updated description' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('should not delete a unknown context field', () => {
|
test('should not delete a unknown context field', () => {
|
||||||
expect.assertions(0);
|
expect.assertions(0);
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ import {
|
|||||||
import type { UpdateContextFieldSchema } from '../../openapi/spec/update-context-field-schema';
|
import type { UpdateContextFieldSchema } from '../../openapi/spec/update-context-field-schema';
|
||||||
import type { CreateContextFieldSchema } from '../../openapi/spec/create-context-field-schema';
|
import type { CreateContextFieldSchema } from '../../openapi/spec/create-context-field-schema';
|
||||||
import { extractUserIdFromUser } from '../../util';
|
import { extractUserIdFromUser } from '../../util';
|
||||||
|
import type { LegalValueSchema } from '../../openapi';
|
||||||
|
|
||||||
interface ContextParam {
|
interface ContextParam {
|
||||||
contextField: string;
|
contextField: string;
|
||||||
@ -168,6 +169,25 @@ export class ContextController extends Controller {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route({
|
||||||
|
method: 'post',
|
||||||
|
path: '/:contextField/legal-values',
|
||||||
|
handler: this.updateContextFieldLegalValue,
|
||||||
|
permission: UPDATE_CONTEXT_FIELD,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['Context'],
|
||||||
|
summary: 'Add or update legal value for the context field',
|
||||||
|
description: `Endpoint that allows adding or updating a single custom context field legal value. If the legal value already exists, it will be updated with the new description`,
|
||||||
|
operationId: 'updateContextFieldLegalValue',
|
||||||
|
requestBody: createRequestSchema('legalValueSchema'),
|
||||||
|
responses: {
|
||||||
|
200: emptyResponse,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
this.route({
|
this.route({
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
path: '/:contextField',
|
path: '/:contextField',
|
||||||
@ -271,6 +291,20 @@ export class ContextController extends Controller {
|
|||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateContextFieldLegalValue(
|
||||||
|
req: IAuthRequest<ContextParam, void, LegalValueSchema>,
|
||||||
|
res: Response,
|
||||||
|
): Promise<void> {
|
||||||
|
const name = req.params.contextField;
|
||||||
|
const legalValue = req.body;
|
||||||
|
|
||||||
|
await this.contextService.updateContextFieldLegalValue(
|
||||||
|
{ name, legalValue },
|
||||||
|
req.audit,
|
||||||
|
);
|
||||||
|
res.status(200).end();
|
||||||
|
}
|
||||||
|
|
||||||
async deleteContextField(
|
async deleteContextField(
|
||||||
req: IAuthRequest<ContextParam>,
|
req: IAuthRequest<ContextParam>,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
@ -3,7 +3,7 @@ import { nameType } from '../routes/util';
|
|||||||
|
|
||||||
export const nameSchema = joi.object().keys({ name: nameType });
|
export const nameSchema = joi.object().keys({ name: nameType });
|
||||||
|
|
||||||
const legalValueSchema = joi.object().keys({
|
export const legalValueSchema = joi.object().keys({
|
||||||
value: joi.string().min(1).max(100).required(),
|
value: joi.string().min(1).max(100).required(),
|
||||||
description: joi.string().allow('').allow(null).optional(),
|
description: joi.string().allow('').allow(null).optional(),
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user