mirror of
https://github.com/directus/directus.git
synced 2026-01-29 14:48:02 -05:00
Work on field query validation a bit
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { Transformation } from './types/assets';
|
||||
import { Collection } from './types/collection';
|
||||
|
||||
export const SYSTEM_ASSET_WHITELIST: Transformation[] = [
|
||||
{
|
||||
@@ -38,3 +37,5 @@ export const SYSTEM_ASSET_WHITELIST: Transformation[] = [
|
||||
];
|
||||
|
||||
export const ASSET_GENERATION_QUERY_KEYS = ['key', 'w', 'h', 'f'];
|
||||
|
||||
export const FIELD_SPECIAL_ALIAS_TYPES = ['alias', 'o2m', 'm2m', 'file-info'];
|
||||
|
||||
@@ -26,6 +26,13 @@ const sanitizeQuery: RequestHandler = (req, res, next) => {
|
||||
|
||||
if (req.query.limit) {
|
||||
query.limit = sanitizeLimit(req.query.limit);
|
||||
} else {
|
||||
/** @todo is this the right place to set these defaults? */
|
||||
query.limit = 100;
|
||||
}
|
||||
|
||||
if (req.query.limit == '-1') {
|
||||
delete query.limit;
|
||||
}
|
||||
|
||||
if (req.query.offset) {
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
import { RequestHandler } from 'express';
|
||||
import { Query } from '../types/query';
|
||||
import { hasFields } from '../services/schema';
|
||||
import asyncHandler from 'express-async-handler';
|
||||
import { InvalidQueryException } from '../exceptions';
|
||||
import hasFields from '../utils/has-fields';
|
||||
|
||||
const validateQuery: RequestHandler = asyncHandler(async (req, res, next) => {
|
||||
if (!req.collection) return next();
|
||||
@@ -35,25 +35,27 @@ async function validateParams(collection: string, query: Query) {
|
||||
}
|
||||
|
||||
async function validateFields(collection: string, query: Query) {
|
||||
const fieldsToCheck = new Set<string>();
|
||||
|
||||
if (query.fields) {
|
||||
/** @todo support relationships in here */
|
||||
// query.fields.forEach((field) => fieldsToCheck.add(field));
|
||||
}
|
||||
|
||||
if (query.sort) {
|
||||
query.sort.forEach((sort) => fieldsToCheck.add(sort.column));
|
||||
}
|
||||
|
||||
/** @todo swap with more efficient schemaInspector version */
|
||||
const fieldsExist = await hasFields(collection, Array.from(fieldsToCheck));
|
||||
|
||||
Array.from(fieldsToCheck).forEach((field, index) => {
|
||||
const exists = fieldsExist[index];
|
||||
if (exists === false)
|
||||
throw new InvalidQueryException(`Field ${field} doesn't exist in ${collection}.`);
|
||||
});
|
||||
/**
|
||||
* @todo combine this with permissions (?)
|
||||
*/
|
||||
/**
|
||||
* @todo use /utils/has-fields
|
||||
*/
|
||||
// const fieldsToCheck = new Set<string>();
|
||||
// if (query.fields) {
|
||||
// /** @todo support relationships in here */
|
||||
// query.fields.forEach((field) => fieldsToCheck.add(field));
|
||||
// }
|
||||
// if (query.sort) {
|
||||
// query.sort.forEach((sort) => fieldsToCheck.add(sort.column));
|
||||
// }
|
||||
// /** @todo swap with more efficient schemaInspector version */
|
||||
// const fieldsExist = await hasFields(collection, Array.from(fieldsToCheck));
|
||||
// Array.from(fieldsToCheck).forEach((field, index) => {
|
||||
// const exists = fieldsExist[index];
|
||||
// if (exists === false)
|
||||
// throw new InvalidQueryException(`Field ${field} doesn't exist in ${collection}.`);
|
||||
// });
|
||||
}
|
||||
|
||||
async function validateMeta(query: Query) {
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import database from '../database';
|
||||
|
||||
/** @TODO replace this with schema inspector */
|
||||
|
||||
export const hasCollection = async (collection: string) => {
|
||||
return await database.schema.hasTable(collection);
|
||||
};
|
||||
|
||||
export const hasField = async (collection: string, field: string) => {
|
||||
return await database.schema.hasColumn(collection, field);
|
||||
};
|
||||
|
||||
export const hasFields = async (collection: string, fields: string[]) => {
|
||||
const columns = await database(collection).columnInfo();
|
||||
const fieldNames = Object.keys(columns);
|
||||
return fields.map((fieldKey) => fieldNames.includes(fieldKey));
|
||||
};
|
||||
43
src/utils/has-fields.ts
Normal file
43
src/utils/has-fields.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import database, { schemaInspector } from '../database';
|
||||
import { FIELD_SPECIAL_ALIAS_TYPES } from '../constants';
|
||||
import { uniq } from 'lodash';
|
||||
|
||||
export default async function hasFields(fields: { collection: string; field: string }[]) {
|
||||
const fieldsObject: { [collection: string]: string[] } = {};
|
||||
|
||||
fields.forEach(({ field, collection }) => {
|
||||
if (fieldsObject.hasOwnProperty(collection) === false) {
|
||||
fieldsObject[collection] = [];
|
||||
}
|
||||
|
||||
fieldsObject[collection].push(field);
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(fieldsObject).map(([collection, fields]) =>
|
||||
collectionHasFields(collection, fields)
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function collectionHasFields(collection: string, fieldKeys: string[]) {
|
||||
const [columns, fields] = await Promise.all([
|
||||
schemaInspector.columns(collection),
|
||||
database
|
||||
.select('field')
|
||||
.from('directus_fields')
|
||||
.where({ collection })
|
||||
.whereIn('field', fieldKeys)
|
||||
.whereIn('special', FIELD_SPECIAL_ALIAS_TYPES),
|
||||
]);
|
||||
|
||||
const existingFields = uniq([
|
||||
...columns.map(({ column }) => column),
|
||||
...fields.map(({ field }) => field),
|
||||
]);
|
||||
|
||||
for (const key of fieldKeys) {
|
||||
if (existingFields.includes(key) === false) throw new Error(key);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user