Fix the order of preset application and payload validation (#23346)

Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>
This commit is contained in:
Hannes Küttner
2024-08-14 14:11:51 +02:00
committed by GitHub
parent 2d81ffa9a5
commit 51ecd31312
3 changed files with 35 additions and 6 deletions

View File

@@ -0,0 +1,5 @@
---
'@directus/api': patch
---
Ensured payload validation accounts for preset data

View File

@@ -288,3 +288,27 @@ test('Merges and applies defaults from presets', async () => {
'field-c': 2,
});
});
test('Checks validation rules against payload with defaults', async () => {
const schema = { collections: { 'collection-a': { fields: {} } } } as unknown as SchemaOverview;
const acc = { admin: false } as unknown as Accountability;
vi.mocked(fetchPermissions).mockResolvedValue([
{ fields: ['field-a'], validation: { 'field-a': { _eq: 2 } }, presets: { 'field-a': 1 } } as unknown as Permission,
{ fields: [], validation: null, presets: { 'field-a': 2 } } as unknown as Permission,
]);
const payloadWithPresets = await processPayload(
{
accountability: acc,
action: 'read',
collection: 'collection-a',
payload: {},
},
{ schema } as Context,
);
expect(payloadWithPresets).toEqual({
'field-a': 2,
});
});

View File

@@ -84,6 +84,10 @@ export async function processPayload(options: ProcessPayloadOptions, context: Co
fieldValidationRules.push(field.validation);
}
const presets = (permissions ?? []).map((permission) => permission.presets);
const payloadWithPresets = assign({}, ...presets, options.payload);
const validationRules = [...fieldValidationRules, ...permissionValidationRules].filter((rule): rule is Filter => {
if (rule === null) return false;
if (Object.keys(rule).length === 0) return false;
@@ -94,7 +98,7 @@ export async function processPayload(options: ProcessPayloadOptions, context: Co
const validationErrors: InstanceType<typeof FailedValidationError>[] = [];
validationErrors.push(
...validatePayload({ _and: validationRules }, options.payload)
...validatePayload({ _and: validationRules }, payloadWithPresets)
.map((error) =>
error.details.map((details) => new FailedValidationError(joiValidationErrorItemToErrorExtensions(details))),
)
@@ -104,9 +108,5 @@ export async function processPayload(options: ProcessPayloadOptions, context: Co
if (validationErrors.length > 0) throw validationErrors;
}
if (!permissions) return options.payload;
const presets = permissions.map((permission) => permission.presets);
return assign({}, ...presets, options.payload);
return payloadWithPresets;
}