@directus/api 26.0.0 → 26.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,9 +4,10 @@ import { FailedValidationError, joiValidationErrorItemToErrorExtensions } from '
4
4
  import { assign, difference, uniq } from 'lodash-es';
5
5
  import { fetchPermissions } from '../../lib/fetch-permissions.js';
6
6
  import { fetchPolicies } from '../../lib/fetch-policies.js';
7
- import { isFieldNullable } from './lib/is-field-nullable.js';
8
- import { fetchDynamicVariableData } from '../../utils/fetch-dynamic-variable-data.js';
9
7
  import { extractRequiredDynamicVariableContext } from '../../utils/extract-required-dynamic-variable-context.js';
8
+ import { fetchDynamicVariableData } from '../../utils/fetch-dynamic-variable-data.js';
9
+ import { contextHasDynamicVariables } from '../process-ast/utils/context-has-dynamic-variables.js';
10
+ import { isFieldNullable } from './lib/is-field-nullable.js';
10
11
  /**
11
12
  * @note this only validates the top-level fields. The expectation is that this function is called
12
13
  * for each level of nested insert separately
@@ -14,8 +15,9 @@ import { extractRequiredDynamicVariableContext } from '../../utils/extract-requi
14
15
  export async function processPayload(options, context) {
15
16
  let permissions;
16
17
  let permissionValidationRules = [];
17
- const policies = await fetchPolicies(options.accountability, context);
18
+ let policies = [];
18
19
  if (!options.accountability.admin) {
20
+ policies = await fetchPolicies(options.accountability, context);
19
21
  permissions = await fetchPermissions({ action: options.action, policies, collections: [options.collection], accountability: options.accountability }, context);
20
22
  if (permissions.length === 0) {
21
23
  throw new ForbiddenError({
@@ -55,14 +57,18 @@ export async function processPayload(options, context) {
55
57
  },
56
58
  });
57
59
  }
58
- const permissionContext = extractRequiredDynamicVariableContext(field.validation);
59
- const filterContext = await fetchDynamicVariableData({
60
- accountability: options.accountability,
61
- policies,
62
- dynamicVariableContext: permissionContext,
63
- }, context);
64
- const validationFilter = parseFilter(field.validation, options.accountability, filterContext);
65
- fieldValidationRules.push(validationFilter);
60
+ if (field.validation) {
61
+ const permissionContext = extractRequiredDynamicVariableContext(field.validation);
62
+ const filterContext = contextHasDynamicVariables(permissionContext)
63
+ ? await fetchDynamicVariableData({
64
+ accountability: options.accountability,
65
+ policies,
66
+ dynamicVariableContext: permissionContext,
67
+ }, context)
68
+ : undefined;
69
+ const validationFilter = parseFilter(field.validation, options.accountability, filterContext);
70
+ fieldValidationRules.push(validationFilter);
71
+ }
66
72
  }
67
73
  const presets = (permissions ?? []).map((permission) => permission.presets);
68
74
  const payloadWithPresets = assign({}, ...presets, options.payload);
@@ -23,7 +23,9 @@ export async function fetchDynamicVariableData(options, context) {
23
23
  });
24
24
  });
25
25
  }
26
- if (options.accountability.roles.length > 0 && (options.dynamicVariableContext.$CURRENT_ROLES?.size ?? 0) > 0) {
26
+ if (options.accountability.roles &&
27
+ options.accountability.roles.length > 0 &&
28
+ (options.dynamicVariableContext.$CURRENT_ROLES?.size ?? 0) > 0) {
27
29
  contextData['$CURRENT_ROLES'] = await fetchContextData('$CURRENT_ROLES', options.dynamicVariableContext, { roles: options.accountability.roles }, async (fields) => {
28
30
  const rolesService = new RolesService(context);
29
31
  return await rolesService.readMany(options.accountability.roles, {
@@ -360,29 +360,26 @@ export function applyFilter(knex, schema, rootQuery, rootFilter, collection, ali
360
360
  pkField = knex.raw(getHelpers(knex).schema.castA2oPrimaryKey(), [pkField]);
361
361
  }
362
362
  const childKey = Object.keys(value)?.[0];
363
- const subQueryBuilder = (filter, cases) => (subQueryKnex) => {
364
- const field = relation.field;
365
- const collection = relation.collection;
366
- const column = `${collection}.${field}`;
367
- subQueryKnex
368
- .select({ [field]: column })
369
- .from(collection)
370
- .whereNotNull(column);
371
- applyQuery(knex, relation.collection, subQueryKnex, { filter }, schema, cases, permissions);
372
- };
373
- const { cases: subCases } = getCases(relation.collection, permissions, []);
374
- if (childKey === '_none') {
375
- dbQuery[logical].whereNotIn(pkField, subQueryBuilder(Object.values(value)[0], subCases));
376
- continue;
377
- }
378
- else if (childKey === '_some') {
379
- dbQuery[logical].whereIn(pkField, subQueryBuilder(Object.values(value)[0], subCases));
380
- continue;
381
- }
382
- else {
383
- // Add implicit _some behavior when no operator is provided
384
- dbQuery[logical].whereIn(pkField, subQueryBuilder(value, subCases));
385
- continue;
363
+ if (childKey === '_none' || childKey === '_some') {
364
+ const subQueryBuilder = (filter, cases) => (subQueryKnex) => {
365
+ const field = relation.field;
366
+ const collection = relation.collection;
367
+ const column = `${collection}.${field}`;
368
+ subQueryKnex
369
+ .select({ [field]: column })
370
+ .from(collection)
371
+ .whereNotNull(column);
372
+ applyQuery(knex, relation.collection, subQueryKnex, { filter }, schema, cases, permissions);
373
+ };
374
+ const { cases: subCases } = getCases(relation.collection, permissions, []);
375
+ if (childKey === '_none') {
376
+ dbQuery[logical].whereNotIn(pkField, subQueryBuilder(Object.values(value)[0], subCases));
377
+ continue;
378
+ }
379
+ else if (childKey === '_some') {
380
+ dbQuery[logical].whereIn(pkField, subQueryBuilder(Object.values(value)[0], subCases));
381
+ continue;
382
+ }
386
383
  }
387
384
  }
388
385
  if (filterPath.includes('_none') || filterPath.includes('_some')) {
@@ -631,7 +628,8 @@ export function applySearch(knex, schema, dbQuery, searchQuery, collection, alia
631
628
  dbQuery.andWhere(function (queryBuilder) {
632
629
  let needsFallbackCondition = true;
633
630
  fields.forEach(([name, field]) => {
634
- const whenCases = (caseMap[name] ?? []).map((caseIndex) => cases[caseIndex]);
631
+ // only account for when cases when full access is not given
632
+ const whenCases = allowedFields.has('*') ? [] : (caseMap[name] ?? []).map((caseIndex) => cases[caseIndex]);
635
633
  const fieldType = getFieldType(field);
636
634
  if (fieldType !== null) {
637
635
  needsFallbackCondition = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/api",
3
- "version": "26.0.0",
3
+ "version": "26.0.1",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "keywords": [
6
6
  "directus",
@@ -150,29 +150,29 @@
150
150
  "ws": "8.18.1",
151
151
  "zod": "3.24.2",
152
152
  "zod-validation-error": "3.4.0",
153
- "@directus/app": "13.8.0",
154
- "@directus/constants": "13.0.1",
153
+ "@directus/app": "13.8.1",
155
154
  "@directus/errors": "2.0.1",
155
+ "@directus/constants": "13.0.1",
156
156
  "@directus/env": "5.0.3",
157
157
  "@directus/extensions": "3.0.4",
158
+ "@directus/extensions-registry": "3.0.4",
159
+ "@directus/memory": "3.0.3",
158
160
  "@directus/extensions-sdk": "13.0.4",
159
161
  "@directus/format-title": "12.0.1",
160
- "@directus/memory": "3.0.3",
161
- "@directus/pressure": "3.0.3",
162
- "@directus/extensions-registry": "3.0.4",
163
- "@directus/storage": "12.0.0",
164
- "@directus/storage-driver-azure": "12.0.3",
165
162
  "@directus/schema": "13.0.1",
166
163
  "@directus/specs": "11.1.0",
164
+ "@directus/pressure": "3.0.3",
165
+ "@directus/storage": "12.0.0",
167
166
  "@directus/storage-driver-cloudinary": "12.0.3",
167
+ "@directus/storage-driver-azure": "12.0.3",
168
+ "@directus/storage-driver-gcs": "12.0.3",
168
169
  "@directus/storage-driver-local": "12.0.0",
169
170
  "@directus/storage-driver-s3": "12.0.3",
170
- "@directus/storage-driver-gcs": "12.0.3",
171
+ "@directus/system-data": "3.1.0",
171
172
  "@directus/storage-driver-supabase": "3.0.3",
172
173
  "@directus/utils": "13.0.3",
173
- "@directus/system-data": "3.1.0",
174
174
  "@directus/validation": "2.0.3",
175
- "directus": "11.6.0"
175
+ "directus": "11.6.1"
176
176
  },
177
177
  "devDependencies": {
178
178
  "@directus/tsconfig": "3.0.0",