mirror of
https://github.com/directus/directus.git
synced 2026-02-18 07:11:21 -05:00
Add fields permissions
This commit is contained in:
@@ -1,16 +1,24 @@
|
||||
import { AST, NestedCollectionAST } from '../types/ast';
|
||||
import { uniq } from 'lodash';
|
||||
import { uniq, pick } from 'lodash';
|
||||
import database, { schemaInspector } from './index';
|
||||
import { Filter, Query } from '../types';
|
||||
import { QueryBuilder } from 'knex';
|
||||
|
||||
export default async function runAST(ast: AST, query = ast.query) {
|
||||
const toplevelFields: string[] = [];
|
||||
const tempFields: string[] = [];
|
||||
const nestedCollections: NestedCollectionAST[] = [];
|
||||
const primaryKeyField = await schemaInspector.primary(ast.name);
|
||||
const columnsInCollection = (await schemaInspector.columns(ast.name)).map(
|
||||
({ column }) => column
|
||||
);
|
||||
|
||||
for (const child of ast.children) {
|
||||
if (child.type === 'field') {
|
||||
toplevelFields.push(child.name);
|
||||
if (columnsInCollection.includes(child.name)) {
|
||||
toplevelFields.push(child.name);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -24,7 +32,12 @@ export default async function runAST(ast: AST, query = ast.query) {
|
||||
nestedCollections.push(child);
|
||||
}
|
||||
|
||||
let dbQuery = database.select(toplevelFields).from(ast.name);
|
||||
/** Always fetch primary key in case there's a nested relation that needs it */
|
||||
if (toplevelFields.includes(primaryKeyField) === false) {
|
||||
tempFields.push(primaryKeyField);
|
||||
}
|
||||
|
||||
let dbQuery = database.select([...toplevelFields, ...tempFields]).from(ast.name);
|
||||
|
||||
if (query.filter) {
|
||||
applyFilter(dbQuery, query.filter);
|
||||
@@ -74,8 +87,18 @@ export default async function runAST(ast: AST, query = ast.query) {
|
||||
const m2o = isM2O(batch);
|
||||
|
||||
let batchQuery: Query = {};
|
||||
let tempField: string = null;
|
||||
|
||||
if (m2o) {
|
||||
// Make sure we always fetch the nested items primary key field to ensure we have the key to match the item by
|
||||
const toplevelFields = batch.children
|
||||
.filter(({ type }) => type === 'field')
|
||||
.map(({ name }) => name);
|
||||
if (toplevelFields.includes(batch.relation.primary_one) === false) {
|
||||
tempField = batch.relation.primary_one;
|
||||
batch.children.push({ type: 'field', name: batch.relation.primary_one });
|
||||
}
|
||||
|
||||
batchQuery = {
|
||||
...batch.query,
|
||||
filter: {
|
||||
@@ -88,6 +111,17 @@ export default async function runAST(ast: AST, query = ast.query) {
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// o2m
|
||||
// Make sure we always fetch the related m2o field to ensure we have the foreign key to
|
||||
// match the items by
|
||||
const toplevelFields = batch.children
|
||||
.filter(({ type }) => type === 'field')
|
||||
.map(({ name }) => name);
|
||||
if (toplevelFields.includes(batch.relation.field_many) === false) {
|
||||
tempField = batch.relation.field_many;
|
||||
batch.children.push({ type: 'field', name: batch.relation.field_many });
|
||||
}
|
||||
|
||||
batchQuery = {
|
||||
...batch.query,
|
||||
filter: {
|
||||
@@ -103,34 +137,53 @@ export default async function runAST(ast: AST, query = ast.query) {
|
||||
|
||||
results = results.map((record) => {
|
||||
if (m2o) {
|
||||
const nestedResult =
|
||||
nestedResults.find((nestedRecord) => {
|
||||
return nestedRecord[batch.relation.primary_one] === record[batch.fieldKey];
|
||||
}) || null;
|
||||
|
||||
if (tempField && nestedResult) {
|
||||
delete nestedResult[tempField];
|
||||
}
|
||||
|
||||
return {
|
||||
...record,
|
||||
[batch.fieldKey]:
|
||||
nestedResults.find((nestedRecord) => {
|
||||
return (
|
||||
nestedRecord[batch.relation.primary_one] === record[batch.fieldKey]
|
||||
);
|
||||
}) || null,
|
||||
[batch.fieldKey]: nestedResult,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
// o2m
|
||||
const newRecord = {
|
||||
...record,
|
||||
[batch.fieldKey]: nestedResults.filter((nestedRecord) => {
|
||||
/**
|
||||
* @todo
|
||||
* pull the name ID from somewhere real
|
||||
*/
|
||||
return (
|
||||
nestedRecord[batch.relation.field_many] === record.id ||
|
||||
nestedRecord[batch.relation.field_many]?.id === record.id
|
||||
);
|
||||
}),
|
||||
[batch.fieldKey]: nestedResults
|
||||
.filter((nestedRecord) => {
|
||||
/**
|
||||
* @todo
|
||||
* pull the name ID from somewhere real
|
||||
*/
|
||||
return (
|
||||
nestedRecord[batch.relation.field_many] === record.id ||
|
||||
nestedRecord[batch.relation.field_many]?.id === record.id
|
||||
);
|
||||
})
|
||||
.map((nestedRecord) => {
|
||||
if (tempField) {
|
||||
delete nestedRecord[tempField];
|
||||
}
|
||||
|
||||
return nestedRecord;
|
||||
}),
|
||||
};
|
||||
|
||||
return newRecord;
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
const nestedCollectionKeys = nestedCollections.map(({ fieldKey }) => fieldKey);
|
||||
|
||||
return results.map((result) =>
|
||||
pick(result, uniq([...nestedCollectionKeys, ...toplevelFields]))
|
||||
);
|
||||
}
|
||||
|
||||
function isM2O(child: NestedCollectionAST) {
|
||||
@@ -143,31 +196,29 @@ function applyFilter(dbQuery: QueryBuilder, filter: Filter) {
|
||||
for (const [key, value] of Object.entries(filter)) {
|
||||
if (key.startsWith('_') === false) {
|
||||
let operator = Object.keys(value)[0];
|
||||
operator = operator.slice(1);
|
||||
operator = operator.toLowerCase();
|
||||
|
||||
const compareValue = Object.values(value)[0];
|
||||
|
||||
if (operator === 'eq') {
|
||||
if (operator === '_eq') {
|
||||
dbQuery.where({ [key]: compareValue });
|
||||
}
|
||||
|
||||
if (operator === 'neq') {
|
||||
if (operator === '_neq') {
|
||||
dbQuery.whereNot({ [key]: compareValue });
|
||||
}
|
||||
|
||||
if (operator === 'in') {
|
||||
if (operator === '_in') {
|
||||
let value = compareValue;
|
||||
if (typeof value === 'string') value = value.split(',');
|
||||
|
||||
dbQuery.whereIn(key, value as string[]);
|
||||
}
|
||||
|
||||
if (operator === 'null') {
|
||||
if (operator === '_null') {
|
||||
dbQuery.whereNull(key);
|
||||
}
|
||||
|
||||
if (operator === 'nnull') {
|
||||
if (operator === '_nnull') {
|
||||
dbQuery.whereNotNull(key);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user