mirror of
https://github.com/directus/directus.git
synced 2026-01-29 14:48:02 -05:00
* Move permissions extraction to accountability
* Fix permissions retrieval for public user
* Fetch user / role context in permissions middleware
* Remove unnecessary parseFilter
* Rename schemaCache to systemCache
* Add permissions caching
* Add system cache invalidation on permission changes
* Improve caching perf by reducing scope
* Add note to docs
* Clarify compatibility with conditional fields/filters
* Fix lint warning
* Allow nested vars in system-filter-input
* Add custom getter function that resolves arrays
* Add is-dynamic-variable util
* Export new util
* Cleanup parse filter
* Fix build
* Move debounce up to use-items
* Remove unused prop
* 🧹
* Fix input pattern usage w/ vars
* Remove debounce from search-input, increase throttle
108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
import { uniq } from 'lodash';
|
|
import { SchemaOverview } from '../types';
|
|
import { Accountability, PermissionsAction } from '@directus/shared/types';
|
|
|
|
/**
|
|
* Reduces the schema based on the included permissions. The resulting object is the schema structure, but with only
|
|
* the allowed collections/fields/relations included based on the permissions.
|
|
* @param schema The full project schema
|
|
* @param actions Array of permissions actions (crud)
|
|
* @returns Reduced schema
|
|
*/
|
|
export function reduceSchema(
|
|
schema: SchemaOverview,
|
|
accountability: Accountability | null,
|
|
actions: PermissionsAction[] = ['create', 'read', 'update', 'delete']
|
|
): SchemaOverview {
|
|
const reduced: SchemaOverview = {
|
|
collections: {},
|
|
relations: [],
|
|
};
|
|
|
|
const allowedFieldsInCollection =
|
|
accountability?.permissions
|
|
?.filter((permission) => actions.includes(permission.action))
|
|
.reduce((acc, permission) => {
|
|
if (!acc[permission.collection]) {
|
|
acc[permission.collection] = [];
|
|
}
|
|
|
|
if (permission.fields) {
|
|
acc[permission.collection] = uniq([...acc[permission.collection], ...permission.fields]);
|
|
}
|
|
|
|
return acc;
|
|
}, {} as { [collection: string]: string[] }) ?? {};
|
|
|
|
for (const [collectionName, collection] of Object.entries(schema.collections)) {
|
|
if (
|
|
accountability?.permissions?.some(
|
|
(permission) => permission.collection === collectionName && actions.includes(permission.action)
|
|
)
|
|
) {
|
|
const fields: SchemaOverview['collections'][string]['fields'] = {};
|
|
|
|
for (const [fieldName, field] of Object.entries(schema.collections[collectionName].fields)) {
|
|
if (
|
|
allowedFieldsInCollection[collectionName]?.includes('*') ||
|
|
allowedFieldsInCollection[collectionName]?.includes(fieldName)
|
|
) {
|
|
fields[fieldName] = field;
|
|
}
|
|
}
|
|
|
|
reduced.collections[collectionName] = {
|
|
...collection,
|
|
fields,
|
|
};
|
|
}
|
|
}
|
|
|
|
reduced.relations = schema.relations.filter((relation) => {
|
|
let collectionsAllowed = true;
|
|
let fieldsAllowed = true;
|
|
|
|
if (Object.keys(allowedFieldsInCollection).includes(relation.collection) === false) {
|
|
collectionsAllowed = false;
|
|
}
|
|
|
|
if (
|
|
relation.related_collection &&
|
|
Object.keys(allowedFieldsInCollection).includes(relation.related_collection) === false
|
|
) {
|
|
collectionsAllowed = false;
|
|
}
|
|
|
|
if (
|
|
relation.meta?.one_allowed_collections &&
|
|
relation.meta.one_allowed_collections.every((collection) =>
|
|
Object.keys(allowedFieldsInCollection).includes(collection)
|
|
) === false
|
|
) {
|
|
collectionsAllowed = false;
|
|
}
|
|
|
|
if (
|
|
!allowedFieldsInCollection[relation.collection] ||
|
|
(allowedFieldsInCollection[relation.collection].includes('*') === false &&
|
|
allowedFieldsInCollection[relation.collection].includes(relation.field) === false)
|
|
) {
|
|
fieldsAllowed = false;
|
|
}
|
|
|
|
if (
|
|
relation.related_collection &&
|
|
relation.meta?.one_field &&
|
|
(!allowedFieldsInCollection[relation.related_collection] ||
|
|
(allowedFieldsInCollection[relation.related_collection].includes('*') === false &&
|
|
allowedFieldsInCollection[relation.related_collection].includes(relation.meta?.one_field) === false))
|
|
) {
|
|
fieldsAllowed = false;
|
|
}
|
|
|
|
return collectionsAllowed && fieldsAllowed;
|
|
});
|
|
|
|
return reduced;
|
|
}
|