@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
80 lines (79 loc) • 3.88 kB
JavaScript
import { getRelation } from '@directus/utils';
import { cloneDeep } from 'lodash-es';
import { fetchAllowedFields } from '../../../permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js';
import { parseFilterKey } from '../../../utils/parse-filter-key.js';
export async function convertWildcards(options, context) {
const fields = cloneDeep(options.fields);
const fieldsInCollection = Object.entries(context.schema.collections[options.collection].fields).map(([name]) => name);
let allowedFields = fieldsInCollection;
if (options.accountability && options.accountability.admin === false) {
allowedFields = await fetchAllowedFields({
collection: options.collection,
action: 'read',
accountability: options.accountability,
}, context);
}
if (!allowedFields || allowedFields.length === 0)
return [];
// In case of full read permissions
if (allowedFields[0] === '*')
allowedFields = fieldsInCollection;
for (let index = 0; index < fields.length; index++) {
const fieldKey = fields[index];
if (fieldKey.includes('*') === false)
continue;
if (fieldKey === '*') {
const aliases = Object.keys(options.alias ?? {});
// Set to all fields in collection
if (allowedFields.includes('*')) {
fields.splice(index, 1, ...fieldsInCollection, ...aliases);
}
else {
// Set to all allowed fields
const allowedAliases = aliases.filter((fieldKey) => {
const { fieldName } = parseFilterKey(options.alias[fieldKey]);
return allowedFields.includes(fieldName);
});
fields.splice(index, 1, ...allowedFields, ...allowedAliases);
}
}
// Swap *.* case for *,<relational-field>.*,<another-relational>.*
if (fieldKey.includes('.') && fieldKey.split('.')[0] === '*') {
const parts = fieldKey.split('.');
let relationalFields = [];
if (allowedFields.includes('*')) {
relationalFields = context.schema.relations.reduce((acc, relation) => {
if (relation.collection === options.collection && !acc.includes(relation.field)) {
acc.push(relation.field);
}
if (relation.related_collection === options.collection && !acc.includes(relation.meta.one_field)) {
acc.push(relation.meta.one_field);
}
return acc;
}, []);
}
else {
relationalFields = allowedFields.filter((fieldKey) => getRelation(context.schema.relations, options.collection, fieldKey) !== undefined);
}
if (options.backlink === false) {
relationalFields = relationalFields.filter((relationField) => getRelation(context.schema.relations, options.collection, relationField) !== context.parentRelation);
}
const nonRelationalFields = allowedFields.filter((fieldKey) => relationalFields.includes(fieldKey) === false);
const aliasFields = Object.keys(options.alias ?? {}).map((fieldKey) => {
const name = options.alias[fieldKey];
if (relationalFields.includes(name)) {
return `${fieldKey}.${parts.slice(1).join('.')}`;
}
return fieldKey;
});
fields.splice(index, 1, ...[
...relationalFields.map((relationalField) => {
return `${relationalField}.${parts.slice(1).join('.')}`;
}),
...nonRelationalFields,
...aliasFields,
]);
}
}
return fields;
}