Work on field query validation a bit

This commit is contained in:
rijkvanzanten
2020-07-07 15:54:59 -04:00
parent 15f1f629e4
commit a034e44775
5 changed files with 74 additions and 38 deletions

View File

@@ -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'];

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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
View 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);
}
}