Skip to content

Commit

Permalink
feat: ability to upsert single legal values (#9056)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Jan 3, 2025
1 parent 7893d3f commit 20fda18
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 3 deletions.
43 changes: 41 additions & 2 deletions src/lib/features/context/context-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import {
} from '../../types';
import type { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType';
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 { nameSchema } from '../../schema/feature-schema';
import type { LegalValueSchema } from '../../openapi';

class ContextService {
private eventService: EventService;
Expand Down Expand Up @@ -126,7 +127,6 @@ class ContextService {
);
const value = await contextSchema.validateAsync(updatedContextField);

// update
await this.contextFieldStore.update(value);

const { createdAt, sortOrder, ...previousContextField } = contextField;
Expand All @@ -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(
name: string,
auditUser: IAuditUser,
Expand Down
53 changes: 53 additions & 0 deletions src/lib/features/context/context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,59 @@ test('should update a context field with new legal values', () => {
.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', () => {
expect.assertions(0);

Expand Down
34 changes: 34 additions & 0 deletions src/lib/features/context/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
import type { UpdateContextFieldSchema } from '../../openapi/spec/update-context-field-schema';
import type { CreateContextFieldSchema } from '../../openapi/spec/create-context-field-schema';
import { extractUserIdFromUser } from '../../util';
import type { LegalValueSchema } from '../../openapi';

interface ContextParam {
contextField: string;
Expand Down Expand Up @@ -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({
method: 'delete',
path: '/:contextField',
Expand Down Expand Up @@ -271,6 +291,20 @@ export class ContextController extends Controller {
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(
req: IAuthRequest<ContextParam>,
res: Response,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/services/context-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { nameType } from '../routes/util';

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(),
description: joi.string().allow('').allow(null).optional(),
});
Expand Down

0 comments on commit 20fda18

Please sign in to comment.