mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 07:03:38 +00:00
add util for throwing standardized validationerror
This commit is contained in:
parent
9a4028d6e3
commit
f1015c3094
@ -45,7 +45,7 @@ const COMPONENT_FIELDS = ['__component'];
|
||||
const STATIC_FIELDS = [ID_ATTRIBUTE];
|
||||
|
||||
const throwInvalidParam = ({ key }) => {
|
||||
throw new ValidationError(`Invalid param ${key}`);
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
};
|
||||
|
||||
module.exports = ({ action, ability, model }) => {
|
||||
|
||||
@ -39,12 +39,12 @@ const createContentAPIValidators = () => {
|
||||
const nonWritableAttributes = getNonWritableAttributes(schema);
|
||||
|
||||
const transforms = [
|
||||
// Remove non writable attributes
|
||||
// non writable attributes
|
||||
traverseEntity(visitors.throwRestrictedFields(nonWritableAttributes), { schema }),
|
||||
];
|
||||
|
||||
if (auth) {
|
||||
// Remove restricted relations
|
||||
// restricted relations
|
||||
transforms.push(traverseEntity(visitors.throwRestrictedRelations(auth), { schema }));
|
||||
}
|
||||
|
||||
|
||||
5
packages/core/utils/src/validate/utils.ts
Normal file
5
packages/core/utils/src/validate/utils.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { ValidationError } from '../errors';
|
||||
|
||||
export const throwInvalidParam = ({ key }: { key: string }) => {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
};
|
||||
@ -10,7 +10,7 @@ import { throwPassword, throwPrivate, throwDynamicZones, throwMorphToRelations }
|
||||
import { isOperator } from '../operators';
|
||||
|
||||
import type { Model } from '../types';
|
||||
import { ValidationError } from '../errors';
|
||||
import { throwInvalidParam } from './utils';
|
||||
|
||||
const { traverseQueryFilters, traverseQuerySort, traverseQueryFields } = traversals;
|
||||
|
||||
@ -20,30 +20,30 @@ const throwPasswords = (schema: Model) => async (entity: Data) => {
|
||||
|
||||
const defaultValidateFilters = curry((schema: Model, filters: unknown) => {
|
||||
return pipeAsync(
|
||||
// Remove keys that are not attributes or valid operators
|
||||
// keys that are not attributes or valid operators
|
||||
traverseQueryFilters(
|
||||
({ key, attribute }) => {
|
||||
const isAttribute = !!attribute;
|
||||
|
||||
if (!isAttribute && !isOperator(key) && key !== 'id') {
|
||||
throw new ValidationError(`invalid key ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
},
|
||||
{ schema }
|
||||
),
|
||||
// Remove dynamic zones from filters
|
||||
// dynamic zones from filters
|
||||
traverseQueryFilters(throwDynamicZones, { schema }),
|
||||
// Remove morpTo relations from filters
|
||||
// morpTo relations from filters
|
||||
traverseQueryFilters(throwMorphToRelations, { schema }),
|
||||
// Remove passwords from filters
|
||||
// passwords from filters
|
||||
traverseQueryFilters(throwPassword, { schema }),
|
||||
// Remove private from filters
|
||||
// private from filters
|
||||
traverseQueryFilters(throwPrivate, { schema }),
|
||||
// Remove empty objects
|
||||
// empty objects
|
||||
traverseQueryFilters(
|
||||
({ key, value }) => {
|
||||
if (isObject(value) && isEmpty(value)) {
|
||||
throw new ValidationError(`invalid key ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
},
|
||||
{ schema }
|
||||
@ -53,7 +53,7 @@ const defaultValidateFilters = curry((schema: Model, filters: unknown) => {
|
||||
|
||||
const defaultValidateSort = curry((schema: Model, sort: unknown) => {
|
||||
return pipeAsync(
|
||||
// Remove non attribute keys
|
||||
// non attribute keys
|
||||
traverseQuerySort(
|
||||
({ key, attribute }) => {
|
||||
// ID is not an attribute per se, so we need to make
|
||||
@ -63,24 +63,24 @@ const defaultValidateSort = curry((schema: Model, sort: unknown) => {
|
||||
}
|
||||
|
||||
if (!attribute) {
|
||||
throw new ValidationError(`invalid key ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
},
|
||||
{ schema }
|
||||
),
|
||||
// Remove dynamic zones from sort
|
||||
// dynamic zones from sort
|
||||
traverseQuerySort(throwDynamicZones, { schema }),
|
||||
// Remove morpTo relations from sort
|
||||
// morpTo relations from sort
|
||||
traverseQuerySort(throwMorphToRelations, { schema }),
|
||||
// Remove private from sort
|
||||
// private from sort
|
||||
traverseQuerySort(throwPrivate, { schema }),
|
||||
// Remove passwords from filters
|
||||
// passwords from filters
|
||||
traverseQuerySort(throwPassword, { schema }),
|
||||
// Remove keys for empty non-scalar values
|
||||
// keys for empty non-scalar values
|
||||
traverseQuerySort(
|
||||
({ key, attribute, value }) => {
|
||||
if (!isScalarAttribute(attribute) && isEmpty(value)) {
|
||||
throw new ValidationError(`invalid key ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
},
|
||||
{ schema }
|
||||
@ -90,21 +90,21 @@ const defaultValidateSort = curry((schema: Model, sort: unknown) => {
|
||||
|
||||
const defaultValidateFields = curry((schema: Model, fields: unknown) => {
|
||||
return pipeAsync(
|
||||
// Only keep scalar attributes
|
||||
// Only allow scalar attributes
|
||||
traverseQueryFields(
|
||||
({ key, attribute }) => {
|
||||
if (key === 'id') {
|
||||
return;
|
||||
}
|
||||
if (isNil(attribute) || !isScalarAttribute(attribute)) {
|
||||
throw new ValidationError(`invalid key ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
},
|
||||
{ schema }
|
||||
),
|
||||
// Remove private fields
|
||||
// private fields
|
||||
traverseQueryFields(throwPrivate, { schema }),
|
||||
// Remove password fields
|
||||
// password fields
|
||||
traverseQueryFields(throwPassword, { schema })
|
||||
)(fields);
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { isArray, isNil, toPath } from 'lodash/fp';
|
||||
import type { Visitor } from '../../traverse/factory';
|
||||
import { ValidationError } from '../../errors';
|
||||
import { throwInvalidParam } from '../utils';
|
||||
|
||||
export default (allowedFields: string[] | null = null): Visitor =>
|
||||
({ key, path: { attribute: path } }) => {
|
||||
@ -66,8 +66,8 @@ export default (allowedFields: string[] | null = null): Visitor =>
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove otherwise
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
// throw otherwise
|
||||
throwInvalidParam({ key });
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { isDynamicZoneAttribute } from '../../content-types';
|
||||
import { ValidationError } from '../../errors';
|
||||
import { throwInvalidParam } from '../utils';
|
||||
import type { Visitor } from '../../traverse/factory';
|
||||
|
||||
const visitor: Visitor = ({ key, attribute }) => {
|
||||
if (isDynamicZoneAttribute(attribute)) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { isMorphToRelationalAttribute } from '../../content-types';
|
||||
import { ValidationError } from '../../errors';
|
||||
import { throwInvalidParam } from '../utils';
|
||||
import type { Visitor } from '../../traverse/factory';
|
||||
|
||||
const visitor: Visitor = ({ key, attribute }) => {
|
||||
if (isMorphToRelationalAttribute(attribute)) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { ValidationError } from '../../errors';
|
||||
import { throwInvalidParam } from '../utils';
|
||||
import type { Visitor } from '../../traverse/factory';
|
||||
|
||||
const visitor: Visitor = ({ key, attribute }) => {
|
||||
if (attribute?.type === 'password') {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { isPrivateAttribute } from '../../content-types';
|
||||
import { ValidationError } from '../../errors';
|
||||
import { throwInvalidParam } from '../utils';
|
||||
import type { Visitor } from '../../traverse/factory';
|
||||
|
||||
const visitor: Visitor = ({ schema, key, attribute }) => {
|
||||
@ -10,7 +10,7 @@ const visitor: Visitor = ({ schema, key, attribute }) => {
|
||||
const isPrivate = attribute.private === true || isPrivateAttribute(schema, key);
|
||||
|
||||
if (isPrivate) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { isArray } from 'lodash/fp';
|
||||
import type { Visitor } from '../../traverse/factory';
|
||||
import { ValidationError } from '../../errors';
|
||||
import { throwInvalidParam } from '../utils';
|
||||
|
||||
export default (restrictedFields: string[] | null = null): Visitor =>
|
||||
({ key, path: { attribute: path } }) => {
|
||||
// Remove all fields
|
||||
// all fields
|
||||
if (restrictedFields === null) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
|
||||
// Ignore invalid formats
|
||||
@ -14,16 +14,16 @@ export default (restrictedFields: string[] | null = null): Visitor =>
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove if an exact match was found
|
||||
// if an exact match was found
|
||||
if (restrictedFields.includes(path as string)) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
|
||||
// Remove nested matches
|
||||
// nested matches
|
||||
const isRestrictedNested = restrictedFields.some((allowedPath) =>
|
||||
path?.toString().startsWith(`${allowedPath}.`)
|
||||
);
|
||||
if (isRestrictedNested) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as contentTypeUtils from '../../content-types';
|
||||
import { ValidationError } from '../../errors';
|
||||
import { throwInvalidParam } from '../utils';
|
||||
import type { Visitor } from '../../traverse/factory';
|
||||
|
||||
const ACTIONS_TO_VERIFY = ['find'];
|
||||
@ -31,9 +31,9 @@ export default (auth: unknown): Visitor =>
|
||||
}
|
||||
}
|
||||
|
||||
// If the new value is empty, remove the relation completely
|
||||
// If the new value is empty
|
||||
if (newMorphValue.length === 0) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
} else {
|
||||
set(key, newMorphValue);
|
||||
}
|
||||
@ -44,9 +44,9 @@ export default (auth: unknown): Visitor =>
|
||||
|
||||
const isAllowed = await hasAccessToSomeScopes(scopes, auth);
|
||||
|
||||
// If the authenticated user don't have access to any of the scopes, then remove the field
|
||||
// If the authenticated user don't have access to any of the scopes
|
||||
if (!isAllowed) {
|
||||
throw new ValidationError(`Invalid parameter ${key}`);
|
||||
throwInvalidParam({ key });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user