UNPKG

payload

Version:

Node, React, Headless CMS and Application Framework built on Next.js

151 lines (150 loc) 6.09 kB
// @ts-strict-ignore import { fieldAffectsData, fieldIsVirtual } from '../../fields/config/types.js'; import { getEntityPolicies } from '../../utilities/getEntityPolicies.js'; import isolateObjectProperty from '../../utilities/isolateObjectProperty.js'; import { getLocalizedPaths } from '../getLocalizedPaths.js'; import { validateQueryPaths } from './validateQueryPaths.js'; /** * Validate the Payload key / value / operator */ export async function validateSearchParam({ collectionConfig, errors, fields, globalConfig, operator, overrideAccess, parentIsLocalized, path: incomingPath, policies, req, val, versionFields }) { // Replace GraphQL nested field double underscore formatting let sanitizedPath; if (incomingPath === '_id') { sanitizedPath = 'id'; } else { sanitizedPath = incomingPath.replace(/__/g, '.'); } let paths = []; const { slug } = collectionConfig || globalConfig; const blockPolicies = {}; if (globalConfig && !policies.globals[slug]) { policies.globals[slug] = await getEntityPolicies({ type: 'global', blockPolicies, entity: globalConfig, operations: [ 'read' ], req }); } if (sanitizedPath !== 'id') { paths = getLocalizedPaths({ collectionSlug: collectionConfig?.slug, fields, globalSlug: globalConfig?.slug, incomingPath: sanitizedPath, locale: req.locale, overrideAccess, parentIsLocalized, payload: req.payload }); } const promises = []; // Sanitize relation.otherRelation.id to relation.otherRelation if (paths.at(-1)?.path === 'id') { const previousField = paths.at(-2)?.field; if (previousField && (previousField.type === 'relationship' || previousField.type === 'upload') && typeof previousField.relationTo === 'string') { paths.pop(); } } promises.push(...paths.map(async ({ collectionSlug, field, invalid, path }, i)=>{ if (invalid) { errors.push({ path }); return; } if (fieldIsVirtual(field)) { errors.push({ path }); } if (!overrideAccess && fieldAffectsData(field)) { if (collectionSlug) { if (!policies.collections[collectionSlug]) { policies.collections[collectionSlug] = await getEntityPolicies({ type: 'collection', blockPolicies, entity: req.payload.collections[collectionSlug].config, operations: [ 'read' ], req: isolateObjectProperty(req, 'transactionID') }); } if ([ 'hash', 'salt' ].includes(incomingPath) && collectionConfig.auth && !collectionConfig.auth?.disableLocalStrategy) { errors.push({ path: incomingPath }); } } let fieldPath = path; // remove locale from end of path if (path.endsWith(`.${req.locale}`)) { fieldPath = path.slice(0, -(req.locale.length + 1)); } // remove ".value" from ends of polymorphic relationship paths if ((field.type === 'relationship' || field.type === 'upload') && Array.isArray(field.relationTo)) { fieldPath = fieldPath.replace('.value', ''); } const entityType = globalConfig ? 'globals' : 'collections'; const entitySlug = collectionSlug || globalConfig.slug; const segments = fieldPath.split('.'); let fieldAccess; if (versionFields) { fieldAccess = policies[entityType][entitySlug]; if (segments[0] === 'parent' || segments[0] === 'version') { segments.shift(); } } else { fieldAccess = policies[entityType][entitySlug].fields; } segments.forEach((segment)=>{ if (fieldAccess[segment]) { if ('fields' in fieldAccess[segment]) { fieldAccess = fieldAccess[segment].fields; } else if ('blocks' in fieldAccess[segment] || 'blockReferences' in fieldAccess[segment]) { fieldAccess = fieldAccess[segment]; } else { fieldAccess = fieldAccess[segment]; } } }); if (!fieldAccess?.read?.permission) { errors.push({ path: fieldPath }); } } if (i > 1) { // Remove top collection and reverse array // to work backwards from top const pathsToQuery = paths.slice(1).reverse(); pathsToQuery.forEach(({ collectionSlug: pathCollectionSlug, path: subPath }, pathToQueryIndex)=>{ // On the "deepest" collection, // validate query of the relationship if (pathToQueryIndex === 0) { promises.push(validateQueryPaths({ collectionConfig: req.payload.collections[pathCollectionSlug].config, errors, globalConfig: undefined, overrideAccess, policies, req, where: { [subPath]: { [operator]: val } } })); } }); } })); await Promise.all(promises); } //# sourceMappingURL=validateSearchParams.js.map