@directus/api 20.0.0-rc.0 → 20.0.0

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.
Files changed (291) hide show
  1. package/dist/app.js +9 -4
  2. package/dist/auth/drivers/ldap.js +4 -4
  3. package/dist/auth/drivers/local.js +4 -4
  4. package/dist/auth/drivers/oauth2.js +4 -4
  5. package/dist/auth/drivers/openid.js +4 -2
  6. package/dist/cache.js +0 -3
  7. package/dist/cli/commands/bootstrap/index.js +2 -8
  8. package/dist/cli/commands/init/index.js +10 -9
  9. package/dist/cli/utils/defaults.d.ts +11 -4
  10. package/dist/cli/utils/defaults.js +1 -7
  11. package/dist/constants.d.ts +9 -1
  12. package/dist/constants.js +10 -0
  13. package/dist/controllers/auth.js +16 -5
  14. package/dist/controllers/permissions.js +2 -14
  15. package/dist/controllers/roles.js +1 -22
  16. package/dist/controllers/{access.d.ts → tus.d.ts} +1 -0
  17. package/dist/controllers/tus.js +72 -0
  18. package/dist/controllers/users.js +55 -0
  19. package/dist/database/helpers/fn/types.d.ts +1 -2
  20. package/dist/database/helpers/fn/types.js +1 -1
  21. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  22. package/dist/database/helpers/geometry/dialects/mssql.js +2 -4
  23. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  24. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  25. package/dist/database/helpers/geometry/dialects/oracle.js +3 -5
  26. package/dist/database/helpers/geometry/types.d.ts +1 -1
  27. package/dist/database/helpers/geometry/types.js +2 -4
  28. package/dist/database/index.js +1 -2
  29. package/dist/database/migrations/20240701A-add-tus-data.js +12 -0
  30. package/dist/database/{run-ast/types.d.ts → run-ast.d.ts} +9 -3
  31. package/dist/database/run-ast.js +450 -0
  32. package/dist/flows.js +4 -3
  33. package/dist/middleware/authenticate.js +7 -2
  34. package/dist/middleware/cache.js +1 -1
  35. package/dist/middleware/check-ip.d.ts +2 -0
  36. package/dist/middleware/check-ip.js +37 -0
  37. package/dist/middleware/get-permissions.d.ts +3 -0
  38. package/dist/middleware/get-permissions.js +10 -0
  39. package/dist/middleware/respond.js +1 -1
  40. package/dist/services/activity.js +10 -22
  41. package/dist/services/assets.d.ts +3 -2
  42. package/dist/services/assets.js +5 -10
  43. package/dist/services/authentication.js +26 -32
  44. package/dist/services/authorization.d.ts +17 -0
  45. package/dist/services/authorization.js +456 -0
  46. package/dist/services/collections.js +17 -18
  47. package/dist/services/fields.d.ts +1 -0
  48. package/dist/services/fields.js +24 -53
  49. package/dist/services/files/lib/extract-metadata.d.ts +3 -0
  50. package/dist/services/files/lib/extract-metadata.js +32 -0
  51. package/dist/services/files/utils/get-metadata.d.ts +5 -0
  52. package/dist/services/files/utils/get-metadata.js +107 -0
  53. package/dist/services/files.d.ts +4 -6
  54. package/dist/services/files.js +24 -140
  55. package/dist/services/graphql/index.d.ts +3 -3
  56. package/dist/services/graphql/index.js +22 -126
  57. package/dist/services/graphql/subscription.js +4 -2
  58. package/dist/services/import-export.js +4 -18
  59. package/dist/services/index.d.ts +2 -3
  60. package/dist/services/index.js +2 -3
  61. package/dist/services/items.js +44 -115
  62. package/dist/services/meta.js +23 -60
  63. package/dist/services/payload.d.ts +10 -9
  64. package/dist/services/payload.js +3 -18
  65. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +7 -5
  66. package/dist/services/{permissions.js → permissions/index.js} +54 -30
  67. package/dist/{permissions → services/permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  68. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  69. package/dist/services/relations.d.ts +6 -0
  70. package/dist/services/relations.js +29 -26
  71. package/dist/services/roles.d.ts +12 -4
  72. package/dist/services/roles.js +424 -57
  73. package/dist/services/server.js +6 -0
  74. package/dist/services/shares.d.ts +2 -0
  75. package/dist/services/shares.js +8 -12
  76. package/dist/services/specifications.d.ts +2 -2
  77. package/dist/services/specifications.js +27 -39
  78. package/dist/services/tus/data-store.d.ts +36 -0
  79. package/dist/services/tus/data-store.js +214 -0
  80. package/dist/services/tus/index.d.ts +2 -0
  81. package/dist/services/tus/index.js +2 -0
  82. package/dist/services/tus/lockers.d.ts +36 -0
  83. package/dist/services/tus/lockers.js +83 -0
  84. package/dist/services/tus/server.d.ts +8 -0
  85. package/dist/services/tus/server.js +80 -0
  86. package/dist/services/tus/utils/wait-timeout.d.ts +1 -0
  87. package/dist/services/tus/utils/wait-timeout.js +13 -0
  88. package/dist/services/users.d.ts +5 -1
  89. package/dist/services/users.js +161 -78
  90. package/dist/services/utils.js +7 -11
  91. package/dist/services/versions.d.ts +2 -0
  92. package/dist/services/versions.js +10 -34
  93. package/dist/storage/register-locations.js +5 -1
  94. package/dist/telemetry/lib/get-report.js +2 -2
  95. package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
  96. package/dist/telemetry/utils/check-increased-user-limits.js +25 -0
  97. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
  98. package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
  99. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
  100. package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
  101. package/dist/telemetry/utils/get-user-count.d.ts +8 -0
  102. package/dist/telemetry/utils/get-user-count.js +33 -0
  103. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
  104. package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
  105. package/dist/types/ast.d.ts +1 -43
  106. package/dist/types/items.d.ts +0 -11
  107. package/dist/utils/apply-query.d.ts +3 -4
  108. package/dist/utils/apply-query.js +8 -37
  109. package/dist/utils/get-accountability-for-role.js +25 -16
  110. package/dist/utils/get-accountability-for-token.js +16 -17
  111. package/dist/utils/get-ast-from-query.d.ts +13 -0
  112. package/dist/utils/get-ast-from-query.js +297 -0
  113. package/dist/utils/get-cache-key.d.ts +1 -1
  114. package/dist/utils/get-cache-key.js +1 -12
  115. package/dist/utils/get-column.d.ts +1 -2
  116. package/dist/utils/get-column.js +0 -1
  117. package/dist/utils/get-permissions.d.ts +2 -0
  118. package/dist/utils/get-permissions.js +150 -0
  119. package/dist/utils/get-service.js +1 -5
  120. package/dist/utils/merge-permissions-for-share.d.ts +4 -0
  121. package/dist/utils/merge-permissions-for-share.js +109 -0
  122. package/dist/utils/merge-permissions.d.ts +3 -0
  123. package/dist/utils/merge-permissions.js +95 -0
  124. package/dist/utils/reduce-schema.d.ts +6 -4
  125. package/dist/utils/reduce-schema.js +34 -14
  126. package/dist/utils/verify-session-jwt.js +2 -1
  127. package/dist/websocket/authenticate.d.ts +2 -0
  128. package/dist/websocket/authenticate.js +12 -0
  129. package/dist/websocket/controllers/graphql.js +4 -1
  130. package/dist/websocket/controllers/hooks.js +0 -4
  131. package/dist/websocket/controllers/rest.js +2 -0
  132. package/dist/websocket/handlers/subscribe.js +2 -0
  133. package/dist/websocket/utils/items.d.ts +1 -1
  134. package/package.json +35 -33
  135. package/dist/controllers/access.js +0 -148
  136. package/dist/controllers/policies.d.ts +0 -2
  137. package/dist/controllers/policies.js +0 -169
  138. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +0 -16
  139. package/dist/database/get-ast-from-query/get-ast-from-query.js +0 -82
  140. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +0 -13
  141. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +0 -69
  142. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +0 -15
  143. package/dist/database/get-ast-from-query/lib/parse-fields.js +0 -190
  144. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +0 -14
  145. package/dist/database/get-ast-from-query/utils/get-deep-query.js +0 -17
  146. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +0 -2
  147. package/dist/database/get-ast-from-query/utils/get-related-collection.js +0 -13
  148. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +0 -2
  149. package/dist/database/get-ast-from-query/utils/get-relation.js +0 -7
  150. package/dist/database/migrations/20240619A-permissions-policies.js +0 -163
  151. package/dist/database/run-ast/lib/get-db-query.d.ts +0 -4
  152. package/dist/database/run-ast/lib/get-db-query.js +0 -194
  153. package/dist/database/run-ast/lib/parse-current-level.d.ts +0 -7
  154. package/dist/database/run-ast/lib/parse-current-level.js +0 -41
  155. package/dist/database/run-ast/run-ast.d.ts +0 -7
  156. package/dist/database/run-ast/run-ast.js +0 -107
  157. package/dist/database/run-ast/types.js +0 -1
  158. package/dist/database/run-ast/utils/apply-case-when.d.ts +0 -16
  159. package/dist/database/run-ast/utils/apply-case-when.js +0 -26
  160. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +0 -3
  161. package/dist/database/run-ast/utils/apply-parent-filters.js +0 -55
  162. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +0 -10
  163. package/dist/database/run-ast/utils/get-column-pre-processor.js +0 -57
  164. package/dist/database/run-ast/utils/get-field-alias.d.ts +0 -2
  165. package/dist/database/run-ast/utils/get-field-alias.js +0 -4
  166. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +0 -5
  167. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +0 -23
  168. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +0 -3
  169. package/dist/database/run-ast/utils/merge-with-parent-items.js +0 -87
  170. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +0 -3
  171. package/dist/database/run-ast/utils/remove-temporary-fields.js +0 -73
  172. package/dist/permissions/cache.d.ts +0 -2
  173. package/dist/permissions/cache.js +0 -23
  174. package/dist/permissions/lib/fetch-permissions.d.ts +0 -10
  175. package/dist/permissions/lib/fetch-permissions.js +0 -55
  176. package/dist/permissions/lib/fetch-policies.d.ts +0 -7
  177. package/dist/permissions/lib/fetch-policies.js +0 -28
  178. package/dist/permissions/lib/fetch-roles-tree.d.ts +0 -3
  179. package/dist/permissions/lib/fetch-roles-tree.js +0 -28
  180. package/dist/permissions/lib/with-app-minimal-permissions.js +0 -10
  181. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +0 -7
  182. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +0 -56
  183. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +0 -3
  184. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +0 -16
  185. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +0 -8
  186. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +0 -24
  187. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +0 -9
  188. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +0 -31
  189. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +0 -16
  190. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +0 -27
  191. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +0 -10
  192. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +0 -23
  193. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
  194. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
  195. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
  196. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
  197. package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
  198. package/dist/permissions/modules/fetch-global-access/types.js +0 -1
  199. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
  200. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
  201. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +0 -12
  202. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +0 -32
  203. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +0 -4
  204. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +0 -29
  205. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +0 -4
  206. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +0 -49
  207. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +0 -3
  208. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +0 -56
  209. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +0 -4
  210. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +0 -8
  211. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +0 -9
  212. package/dist/permissions/modules/process-ast/lib/inject-cases.js +0 -93
  213. package/dist/permissions/modules/process-ast/process-ast.d.ts +0 -9
  214. package/dist/permissions/modules/process-ast/process-ast.js +0 -39
  215. package/dist/permissions/modules/process-ast/types.d.ts +0 -24
  216. package/dist/permissions/modules/process-ast/types.js +0 -1
  217. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +0 -2
  218. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +0 -7
  219. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +0 -12
  220. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +0 -30
  221. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +0 -15
  222. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +0 -50
  223. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +0 -3
  224. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +0 -9
  225. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +0 -3
  226. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +0 -24
  227. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +0 -1
  228. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +0 -3
  229. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +0 -5
  230. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +0 -7
  231. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +0 -2
  232. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +0 -3
  233. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +0 -2
  234. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +0 -3
  235. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +0 -3
  236. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +0 -16
  237. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +0 -2
  238. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +0 -12
  239. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +0 -2
  240. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +0 -28
  241. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +0 -5
  242. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +0 -12
  243. package/dist/permissions/modules/process-payload/process-payload.d.ts +0 -13
  244. package/dist/permissions/modules/process-payload/process-payload.js +0 -77
  245. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +0 -12
  246. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +0 -11
  247. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +0 -9
  248. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +0 -33
  249. package/dist/permissions/modules/validate-access/validate-access.d.ts +0 -14
  250. package/dist/permissions/modules/validate-access/validate-access.js +0 -28
  251. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +0 -1
  252. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +0 -8
  253. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +0 -5
  254. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +0 -10
  255. package/dist/permissions/types.d.ts +0 -6
  256. package/dist/permissions/types.js +0 -1
  257. package/dist/permissions/utils/create-default-accountability.d.ts +0 -2
  258. package/dist/permissions/utils/create-default-accountability.js +0 -11
  259. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +0 -8
  260. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +0 -27
  261. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +0 -9
  262. package/dist/permissions/utils/fetch-dynamic-variable-context.js +0 -43
  263. package/dist/permissions/utils/filter-policies-by-ip.d.ts +0 -2
  264. package/dist/permissions/utils/filter-policies-by-ip.js +0 -15
  265. package/dist/permissions/utils/get-unaliased-field-key.d.ts +0 -5
  266. package/dist/permissions/utils/get-unaliased-field-key.js +0 -17
  267. package/dist/permissions/utils/process-permissions.d.ts +0 -7
  268. package/dist/permissions/utils/process-permissions.js +0 -9
  269. package/dist/permissions/utils/with-cache.d.ts +0 -10
  270. package/dist/permissions/utils/with-cache.js +0 -25
  271. package/dist/services/access.d.ts +0 -10
  272. package/dist/services/access.js +0 -43
  273. package/dist/services/policies.d.ts +0 -12
  274. package/dist/services/policies.js +0 -87
  275. package/dist/telemetry/utils/check-user-limits.d.ts +0 -5
  276. package/dist/telemetry/utils/check-user-limits.js +0 -19
  277. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +0 -17
  278. package/dist/utils/fetch-user-count/fetch-access-lookup.js +0 -22
  279. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +0 -16
  280. package/dist/utils/fetch-user-count/fetch-access-roles.js +0 -37
  281. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +0 -6
  282. package/dist/utils/fetch-user-count/fetch-active-users.js +0 -3
  283. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +0 -12
  284. package/dist/utils/fetch-user-count/fetch-user-count.js +0 -57
  285. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +0 -20
  286. package/dist/utils/fetch-user-count/get-user-count-query.js +0 -17
  287. package/dist/utils/validate-user-count-integrity.d.ts +0 -13
  288. package/dist/utils/validate-user-count-integrity.js +0 -29
  289. /package/dist/database/migrations/{20240619A-permissions-policies.d.ts → 20240701A-add-tus-data.d.ts} +0 -0
  290. /package/dist/{utils → services/files/utils}/parse-image-metadata.d.ts +0 -0
  291. /package/dist/{utils → services/files/utils}/parse-image-metadata.js +0 -0
@@ -9,7 +9,6 @@ import { parse as wktToGeoJSON } from 'wellknown';
9
9
  import { getHelpers } from '../database/helpers/index.js';
10
10
  import getDatabase from '../database/index.js';
11
11
  import { generateHash } from '../utils/generate-hash.js';
12
- import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
13
12
  /**
14
13
  * Process a given payload for a collection to ensure the special fields (hash, uuid, date etc) are
15
14
  * handled correctly.
@@ -318,7 +317,6 @@ export class PayloadService {
318
317
  return relation.collection === this.collection;
319
318
  });
320
319
  const revisions = [];
321
- let userIntegrityCheckFlags = UserIntegrityCheckFlag.None;
322
320
  const nestedActionEvents = [];
323
321
  const payload = cloneDeep(data);
324
322
  // Only process related records that are actually in the payload
@@ -364,7 +362,6 @@ export class PayloadService {
364
362
  if (Object.keys(fieldsToUpdate).length > 0) {
365
363
  await service.updateOne(relatedPrimaryKey, relatedRecord, {
366
364
  onRevisionCreate: (pk) => revisions.push(pk),
367
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
368
365
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
369
366
  emitEvents: opts?.emitEvents,
370
367
  mutationTracker: opts?.mutationTracker,
@@ -374,7 +371,6 @@ export class PayloadService {
374
371
  else {
375
372
  relatedPrimaryKey = await service.createOne(relatedRecord, {
376
373
  onRevisionCreate: (pk) => revisions.push(pk),
377
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
378
374
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
379
375
  emitEvents: opts?.emitEvents,
380
376
  mutationTracker: opts?.mutationTracker,
@@ -383,7 +379,7 @@ export class PayloadService {
383
379
  // Overwrite the nested object with just the primary key, so the parent level can be saved correctly
384
380
  payload[relation.field] = relatedPrimaryKey;
385
381
  }
386
- return { payload, revisions, nestedActionEvents, userIntegrityCheckFlags };
382
+ return { payload, revisions, nestedActionEvents };
387
383
  }
388
384
  /**
389
385
  * Save/update all nested related m2o items inside the payload
@@ -392,7 +388,6 @@ export class PayloadService {
392
388
  const payload = cloneDeep(data);
393
389
  // All the revisions saved on this level
394
390
  const revisions = [];
395
- let userIntegrityCheckFlags = UserIntegrityCheckFlag.None;
396
391
  const nestedActionEvents = [];
397
392
  // Many to one relations that exist on the current collection
398
393
  const relations = this.schema.relations.filter((relation) => {
@@ -429,7 +424,6 @@ export class PayloadService {
429
424
  if (Object.keys(fieldsToUpdate).length > 0) {
430
425
  await service.updateOne(relatedPrimaryKey, relatedRecord, {
431
426
  onRevisionCreate: (pk) => revisions.push(pk),
432
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
433
427
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
434
428
  emitEvents: opts?.emitEvents,
435
429
  mutationTracker: opts?.mutationTracker,
@@ -439,7 +433,6 @@ export class PayloadService {
439
433
  else {
440
434
  relatedPrimaryKey = await service.createOne(relatedRecord, {
441
435
  onRevisionCreate: (pk) => revisions.push(pk),
442
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
443
436
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
444
437
  emitEvents: opts?.emitEvents,
445
438
  mutationTracker: opts?.mutationTracker,
@@ -448,14 +441,13 @@ export class PayloadService {
448
441
  // Overwrite the nested object with just the primary key, so the parent level can be saved correctly
449
442
  payload[relation.field] = relatedPrimaryKey;
450
443
  }
451
- return { payload, revisions, nestedActionEvents, userIntegrityCheckFlags };
444
+ return { payload, revisions, nestedActionEvents };
452
445
  }
453
446
  /**
454
447
  * Recursively save/update all nested related o2m items
455
448
  */
456
449
  async processO2M(data, parent, opts) {
457
450
  const revisions = [];
458
- let userIntegrityCheckFlags = UserIntegrityCheckFlag.None;
459
451
  const nestedActionEvents = [];
460
452
  const relations = this.schema.relations.filter((relation) => {
461
453
  return relation.related_collection === this.collection;
@@ -524,7 +516,6 @@ export class PayloadService {
524
516
  }
525
517
  savedPrimaryKeys.push(...(await service.upsertMany(recordsToUpsert, {
526
518
  onRevisionCreate: (pk) => revisions.push(pk),
527
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
528
519
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
529
520
  emitEvents: opts?.emitEvents,
530
521
  mutationTracker: opts?.mutationTracker,
@@ -549,7 +540,6 @@ export class PayloadService {
549
540
  if (relation.meta.one_deselect_action === 'delete') {
550
541
  // There's no revision for a deletion
551
542
  await service.deleteByQuery(query, {
552
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
553
543
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
554
544
  emitEvents: opts?.emitEvents,
555
545
  mutationTracker: opts?.mutationTracker,
@@ -558,7 +548,6 @@ export class PayloadService {
558
548
  else {
559
549
  await service.updateByQuery(query, { [relation.field]: null }, {
560
550
  onRevisionCreate: (pk) => revisions.push(pk),
561
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
562
551
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
563
552
  emitEvents: opts?.emitEvents,
564
553
  mutationTracker: opts?.mutationTracker,
@@ -601,7 +590,6 @@ export class PayloadService {
601
590
  }
602
591
  await service.createMany(createPayload, {
603
592
  onRevisionCreate: (pk) => revisions.push(pk),
604
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
605
593
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
606
594
  emitEvents: opts?.emitEvents,
607
595
  mutationTracker: opts?.mutationTracker,
@@ -615,7 +603,6 @@ export class PayloadService {
615
603
  [relation.field]: parent || payload[currentPrimaryKeyField],
616
604
  }, {
617
605
  onRevisionCreate: (pk) => revisions.push(pk),
618
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
619
606
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
620
607
  emitEvents: opts?.emitEvents,
621
608
  mutationTracker: opts?.mutationTracker,
@@ -641,7 +628,6 @@ export class PayloadService {
641
628
  };
642
629
  if (relation.meta.one_deselect_action === 'delete') {
643
630
  await service.deleteByQuery(query, {
644
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
645
631
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
646
632
  emitEvents: opts?.emitEvents,
647
633
  mutationTracker: opts?.mutationTracker,
@@ -650,7 +636,6 @@ export class PayloadService {
650
636
  else {
651
637
  await service.updateByQuery(query, { [relation.field]: null }, {
652
638
  onRevisionCreate: (pk) => revisions.push(pk),
653
- onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
654
639
  bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
655
640
  emitEvents: opts?.emitEvents,
656
641
  mutationTracker: opts?.mutationTracker,
@@ -659,7 +644,7 @@ export class PayloadService {
659
644
  }
660
645
  }
661
646
  }
662
- return { revisions, nestedActionEvents, userIntegrityCheckFlags };
647
+ return { revisions, nestedActionEvents };
663
648
  }
664
649
  /**
665
650
  * Transforms the input partial payload to match the output structure, to have consistency
@@ -1,10 +1,12 @@
1
- import type { Item, ItemPermissions, PrimaryKey, Query } from '@directus/types';
2
- import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
3
- import type { QueryOptions } from './items.js';
4
- import { ItemsService } from './items.js';
1
+ import type { Item, ItemPermissions, PermissionsAction, PrimaryKey, Query } from '@directus/types';
2
+ import type Keyv from 'keyv';
3
+ import type { AbstractServiceOptions, MutationOptions } from '../../types/index.js';
4
+ import type { QueryOptions } from '../items.js';
5
+ import { ItemsService } from '../items.js';
5
6
  export declare class PermissionsService extends ItemsService {
7
+ systemCache: Keyv<any>;
6
8
  constructor(options: AbstractServiceOptions);
7
- private clearCaches;
9
+ getAllowedFields(action: PermissionsAction, collection?: string): Record<string, string[]>;
8
10
  readByQuery(query: Query, opts?: QueryOptions): Promise<Partial<Item>[]>;
9
11
  createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
10
12
  createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
@@ -1,17 +1,32 @@
1
1
  import { ForbiddenError } from '@directus/errors';
2
- import { clearSystemCache } from '../cache.js';
3
- import { withAppMinimalPermissions } from '../permissions/lib/with-app-minimal-permissions.js';
4
- import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
5
- import { ItemsService } from './items.js';
2
+ import { clearSystemCache, getCache } from '../../cache.js';
3
+ import { AuthorizationService } from '../authorization.js';
4
+ import { ItemsService } from '../items.js';
5
+ import { withAppMinimalPermissions } from './lib/with-app-minimal-permissions.js';
6
6
  export class PermissionsService extends ItemsService {
7
+ systemCache;
7
8
  constructor(options) {
8
9
  super('directus_permissions', options);
10
+ const { systemCache } = getCache();
11
+ this.systemCache = systemCache;
9
12
  }
10
- async clearCaches(opts) {
11
- await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
12
- if (this.cache && opts?.autoPurgeCache !== false) {
13
- await this.cache.clear();
13
+ getAllowedFields(action, collection) {
14
+ const results = this.accountability?.permissions?.filter((permission) => {
15
+ let matchesCollection = true;
16
+ if (collection) {
17
+ matchesCollection = permission.collection === collection;
18
+ }
19
+ const matchesAction = permission.action === action;
20
+ return collection ? matchesCollection && matchesAction : matchesAction;
21
+ }) ?? [];
22
+ const fieldsPerCollection = {};
23
+ for (const result of results) {
24
+ const { collection, fields } = result;
25
+ if (!fieldsPerCollection[collection])
26
+ fieldsPerCollection[collection] = [];
27
+ fieldsPerCollection[collection].push(...(fields ?? []));
14
28
  }
29
+ return fieldsPerCollection;
15
30
  }
16
31
  async readByQuery(query, opts) {
17
32
  const result = (await super.readByQuery(query, opts));
@@ -19,32 +34,50 @@ export class PermissionsService extends ItemsService {
19
34
  }
20
35
  async createOne(data, opts) {
21
36
  const res = await super.createOne(data, opts);
22
- await this.clearCaches(opts);
37
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
38
+ if (this.cache && opts?.autoPurgeCache !== false) {
39
+ await this.cache.clear();
40
+ }
23
41
  return res;
24
42
  }
25
43
  async createMany(data, opts) {
26
44
  const res = await super.createMany(data, opts);
27
- await this.clearCaches(opts);
45
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
46
+ if (this.cache && opts?.autoPurgeCache !== false) {
47
+ await this.cache.clear();
48
+ }
28
49
  return res;
29
50
  }
30
51
  async updateBatch(data, opts) {
31
52
  const res = await super.updateBatch(data, opts);
32
- await this.clearCaches(opts);
53
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
54
+ if (this.cache && opts?.autoPurgeCache !== false) {
55
+ await this.cache.clear();
56
+ }
33
57
  return res;
34
58
  }
35
59
  async updateMany(keys, data, opts) {
36
60
  const res = await super.updateMany(keys, data, opts);
37
- await this.clearCaches(opts);
61
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
62
+ if (this.cache && opts?.autoPurgeCache !== false) {
63
+ await this.cache.clear();
64
+ }
38
65
  return res;
39
66
  }
40
67
  async upsertMany(payloads, opts) {
41
68
  const res = await super.upsertMany(payloads, opts);
42
- await this.clearCaches(opts);
69
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
70
+ if (this.cache && opts?.autoPurgeCache !== false) {
71
+ await this.cache.clear();
72
+ }
43
73
  return res;
44
74
  }
45
75
  async deleteMany(keys, opts) {
46
76
  const res = await super.deleteMany(keys, opts);
47
- await this.clearCaches(opts);
77
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
78
+ if (this.cache && opts?.autoPurgeCache !== false) {
79
+ await this.cache.clear();
80
+ }
48
81
  return res;
49
82
  }
50
83
  async getItemPermissions(collection, primaryKey) {
@@ -82,25 +115,16 @@ export class PermissionsService extends ItemsService {
82
115
  updateAction = 'create';
83
116
  }
84
117
  }
118
+ const authorizationService = new AuthorizationService({
119
+ knex: this.knex,
120
+ accountability: this.accountability,
121
+ schema: this.schema,
122
+ });
85
123
  await Promise.all(Object.keys(itemPermissions).map((key) => {
86
124
  const action = key;
87
125
  const checkAction = action === 'update' ? updateAction : action;
88
- if (!this.accountability) {
89
- itemPermissions[action].access = true;
90
- return Promise.resolve();
91
- }
92
- const opts = {
93
- accountability: this.accountability,
94
- action: checkAction,
95
- collection,
96
- };
97
- if (primaryKey) {
98
- opts.primaryKeys = [primaryKey];
99
- }
100
- return validateAccess(opts, {
101
- schema: this.schema,
102
- knex: this.knex,
103
- })
126
+ return authorizationService
127
+ .checkAccess(checkAction, collection, primaryKey)
104
128
  .then(() => (itemPermissions[action].access = true))
105
129
  .catch(() => { });
106
130
  }));
@@ -1,2 +1,2 @@
1
1
  import type { Accountability, Permission, Query } from '@directus/types';
2
- export declare function withAppMinimalPermissions(accountability: Pick<Accountability, 'app'> | null, permissions: Permission[], filter: Query['filter']): Permission[];
2
+ export declare function withAppMinimalPermissions(accountability: Accountability | null, permissions: Permission[], filter: Query['filter']): Permission[];
@@ -0,0 +1,13 @@
1
+ import { appAccessMinimalPermissions } from '@directus/system-data';
2
+ import { filterItems } from '../../../utils/filter-items.js';
3
+ import { mergePermissions } from '../../../utils/merge-permissions.js';
4
+ export function withAppMinimalPermissions(accountability, permissions, filter) {
5
+ if (accountability?.app === true) {
6
+ const filteredAppMinimalPermissions = filterItems(appAccessMinimalPermissions.map((permission) => ({
7
+ ...permission,
8
+ role: accountability.role,
9
+ })), filter);
10
+ return mergePermissions('or', permissions, filteredAppMinimalPermissions);
11
+ }
12
+ return permissions;
13
+ }
@@ -5,8 +5,10 @@ import type { Knex } from 'knex';
5
5
  import type { Helpers } from '../database/helpers/index.js';
6
6
  import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
7
7
  import { ItemsService, type QueryOptions } from './items.js';
8
+ import { PermissionsService } from './permissions/index.js';
8
9
  export declare class RelationsService {
9
10
  knex: Knex;
11
+ permissionsService: PermissionsService;
10
12
  schemaInspector: SchemaInspector;
11
13
  accountability: Accountability | null;
12
14
  schema: SchemaOverview;
@@ -30,6 +32,10 @@ export declare class RelationsService {
30
32
  * Delete an existing relationship
31
33
  */
32
34
  deleteOne(collection: string, field: string, opts?: MutationOptions): Promise<void>;
35
+ /**
36
+ * Whether or not the current user has read access to relations
37
+ */
38
+ private get hasReadAccess();
33
39
  /**
34
40
  * Combine raw schema foreign key information with Directus relations meta rows to form final
35
41
  * Relation objects
@@ -6,15 +6,14 @@ import { clearSystemCache, getCache } from '../cache.js';
6
6
  import { getHelpers } from '../database/helpers/index.js';
7
7
  import getDatabase, { getSchemaInspector } from '../database/index.js';
8
8
  import emitter from '../emitter.js';
9
- import { fetchAllowedFieldMap } from '../permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js';
10
- import { fetchAllowedFields } from '../permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js';
11
- import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
12
9
  import { getDefaultIndexName } from '../utils/get-default-index-name.js';
13
10
  import { getSchema } from '../utils/get-schema.js';
14
11
  import { transaction } from '../utils/transaction.js';
15
12
  import { ItemsService } from './items.js';
13
+ import { PermissionsService } from './permissions/index.js';
16
14
  export class RelationsService {
17
15
  knex;
16
+ permissionsService;
18
17
  schemaInspector;
19
18
  accountability;
20
19
  schema;
@@ -23,6 +22,7 @@ export class RelationsService {
23
22
  helpers;
24
23
  constructor(options) {
25
24
  this.knex = options.knex || getDatabase();
25
+ this.permissionsService = new PermissionsService(options);
26
26
  this.schemaInspector = options.knex ? createInspector(options.knex) : getSchemaInspector();
27
27
  this.schema = options.schema;
28
28
  this.accountability = options.accountability || null;
@@ -37,15 +37,8 @@ export class RelationsService {
37
37
  this.helpers = getHelpers(this.knex);
38
38
  }
39
39
  async readAll(collection, opts) {
40
- if (this.accountability) {
41
- await validateAccess({
42
- accountability: this.accountability,
43
- action: 'read',
44
- collection: 'directus_relations',
45
- }, {
46
- knex: this.knex,
47
- schema: this.schema,
48
- });
40
+ if (this.accountability && this.accountability.admin !== true && this.hasReadAccess === false) {
41
+ throw new ForbiddenError();
49
42
  }
50
43
  const metaReadQuery = {
51
44
  limit: -1,
@@ -71,17 +64,18 @@ export class RelationsService {
71
64
  }
72
65
  async readOne(collection, field) {
73
66
  if (this.accountability && this.accountability.admin !== true) {
74
- await validateAccess({
75
- accountability: this.accountability,
76
- action: 'read',
77
- collection: 'directus_relations',
78
- }, {
79
- schema: this.schema,
80
- knex: this.knex,
67
+ if (this.hasReadAccess === false) {
68
+ throw new ForbiddenError();
69
+ }
70
+ const permissions = this.accountability.permissions?.find((permission) => {
71
+ return permission.action === 'read' && permission.collection === collection;
81
72
  });
82
- const allowedFields = await fetchAllowedFields({ collection, action: 'read', accountability: this.accountability }, { schema: this.schema, knex: this.knex });
83
- if (allowedFields.includes('*') === false && allowedFields.includes(field) === false) {
73
+ if (!permissions || !permissions.fields)
84
74
  throw new ForbiddenError();
75
+ if (permissions.fields.includes('*') === false) {
76
+ const allowedFields = permissions.fields;
77
+ if (allowedFields.includes(field) === false)
78
+ throw new ForbiddenError();
85
79
  }
86
80
  }
87
81
  const metaRow = await this.relationsItemService.readByQuery({
@@ -363,6 +357,14 @@ export class RelationsService {
363
357
  }
364
358
  }
365
359
  }
360
+ /**
361
+ * Whether or not the current user has read access to relations
362
+ */
363
+ get hasReadAccess() {
364
+ return !!this.accountability?.permissions?.find((permission) => {
365
+ return permission.collection === 'directus_relations' && permission.action === 'read';
366
+ });
367
+ }
366
368
  /**
367
369
  * Combine raw schema foreign key information with Directus relations meta rows to form final
368
370
  * Relation objects
@@ -411,11 +413,12 @@ export class RelationsService {
411
413
  async filterForbidden(relations) {
412
414
  if (this.accountability === null || this.accountability?.admin === true)
413
415
  return relations;
414
- const allowedFields = await fetchAllowedFieldMap({
415
- accountability: this.accountability,
416
- action: 'read',
417
- }, { schema: this.schema, knex: this.knex });
418
- const allowedCollections = Object.keys(allowedFields);
416
+ const allowedCollections = this.accountability.permissions
417
+ ?.filter((permission) => {
418
+ return permission.action === 'read';
419
+ })
420
+ .map(({ collection }) => collection) ?? [];
421
+ const allowedFields = this.permissionsService.getAllowedFields('read');
419
422
  relations = toArray(relations);
420
423
  return relations.filter((relation) => {
421
424
  let collectionsAllowed = true;
@@ -1,10 +1,18 @@
1
- import type { Item, PrimaryKey } from '@directus/types';
1
+ import type { Item, PrimaryKey, Query } from '@directus/types';
2
2
  import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
3
3
  import { ItemsService } from './items.js';
4
4
  export declare class RolesService extends ItemsService {
5
5
  constructor(options: AbstractServiceOptions);
6
+ private checkForOtherAdminRoles;
7
+ private checkForOtherAdminUsers;
8
+ private isIpAccessValid;
9
+ private assertValidIpAccess;
10
+ private getRoleAccessType;
11
+ createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
12
+ createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
13
+ updateOne(key: PrimaryKey, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
14
+ updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
6
15
  updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
7
- deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
8
- private validateRoleNesting;
9
- private clearCaches;
16
+ updateByQuery(query: Query, data: Partial<Item>, opts?: MutationOptions | undefined): Promise<PrimaryKey[]>;
17
+ deleteMany(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
10
18
  }