@directus/api 21.0.0-rc.0 → 21.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 (285) hide show
  1. package/dist/app.js +5 -5
  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.d.ts +0 -1
  7. package/dist/cache.js +7 -25
  8. package/dist/cli/commands/bootstrap/index.js +2 -8
  9. package/dist/cli/commands/init/index.js +10 -9
  10. package/dist/cli/utils/defaults.d.ts +11 -4
  11. package/dist/cli/utils/defaults.js +1 -7
  12. package/dist/constants.d.ts +1 -1
  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/tus.js +27 -13
  17. package/dist/controllers/users.js +55 -0
  18. package/dist/database/helpers/fn/types.d.ts +1 -2
  19. package/dist/database/helpers/fn/types.js +1 -1
  20. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  21. package/dist/database/helpers/geometry/dialects/mssql.js +2 -4
  22. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  23. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  24. package/dist/database/helpers/geometry/dialects/oracle.js +3 -5
  25. package/dist/database/helpers/geometry/types.d.ts +1 -1
  26. package/dist/database/helpers/geometry/types.js +2 -4
  27. package/dist/database/index.js +11 -8
  28. package/dist/database/migrations/20240305A-change-useragent-type.js +1 -1
  29. package/dist/database/migrations/20240716A-update-files-date-fields.js +33 -0
  30. package/dist/database/{run-ast/types.d.ts → run-ast.d.ts} +9 -3
  31. package/dist/database/run-ast.js +458 -0
  32. package/dist/flows.js +4 -3
  33. package/dist/logger/index.js +1 -1
  34. package/dist/middleware/authenticate.js +7 -2
  35. package/dist/middleware/cache.js +1 -1
  36. package/dist/middleware/check-ip.d.ts +2 -0
  37. package/dist/middleware/check-ip.js +37 -0
  38. package/dist/middleware/error-handler.d.ts +2 -2
  39. package/dist/middleware/error-handler.js +54 -51
  40. package/dist/middleware/get-permissions.d.ts +3 -0
  41. package/dist/middleware/get-permissions.js +10 -0
  42. package/dist/middleware/respond.js +1 -1
  43. package/dist/services/activity.js +10 -22
  44. package/dist/services/assets.d.ts +3 -2
  45. package/dist/services/assets.js +7 -15
  46. package/dist/services/authentication.js +18 -18
  47. package/dist/services/authorization.d.ts +17 -0
  48. package/dist/services/authorization.js +456 -0
  49. package/dist/services/collections.js +17 -18
  50. package/dist/services/fields.d.ts +4 -0
  51. package/dist/services/fields.js +53 -58
  52. package/dist/services/files/lib/get-sharp-instance.d.ts +2 -0
  53. package/dist/services/files/lib/get-sharp-instance.js +10 -0
  54. package/dist/services/files/utils/get-metadata.js +7 -6
  55. package/dist/services/files.js +8 -10
  56. package/dist/services/graphql/index.d.ts +3 -3
  57. package/dist/services/graphql/index.js +22 -126
  58. package/dist/services/graphql/subscription.js +4 -2
  59. package/dist/services/import-export.js +4 -18
  60. package/dist/services/index.d.ts +2 -3
  61. package/dist/services/index.js +2 -3
  62. package/dist/services/items.js +44 -115
  63. package/dist/services/mail/index.d.ts +1 -1
  64. package/dist/services/mail/index.js +9 -1
  65. package/dist/services/meta.js +23 -60
  66. package/dist/services/notifications.js +6 -14
  67. package/dist/services/payload.d.ts +10 -9
  68. package/dist/services/payload.js +3 -18
  69. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +7 -5
  70. package/dist/services/{permissions.js → permissions/index.js} +54 -30
  71. package/dist/{permissions → services/permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  72. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  73. package/dist/services/relations.d.ts +9 -1
  74. package/dist/services/relations.js +56 -31
  75. package/dist/services/roles.d.ts +12 -4
  76. package/dist/services/roles.js +424 -57
  77. package/dist/services/shares.d.ts +2 -0
  78. package/dist/services/shares.js +8 -12
  79. package/dist/services/specifications.d.ts +2 -2
  80. package/dist/services/specifications.js +27 -39
  81. package/dist/services/tus/data-store.js +4 -5
  82. package/dist/services/tus/server.d.ts +1 -1
  83. package/dist/services/tus/server.js +9 -2
  84. package/dist/services/users.d.ts +5 -1
  85. package/dist/services/users.js +161 -78
  86. package/dist/services/utils.js +7 -11
  87. package/dist/services/versions.d.ts +2 -0
  88. package/dist/services/versions.js +10 -34
  89. package/dist/telemetry/lib/get-report.js +2 -2
  90. package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
  91. package/dist/telemetry/utils/check-increased-user-limits.js +25 -0
  92. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
  93. package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
  94. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
  95. package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
  96. package/dist/telemetry/utils/get-user-count.d.ts +8 -0
  97. package/dist/telemetry/utils/get-user-count.js +33 -0
  98. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
  99. package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
  100. package/dist/types/ast.d.ts +1 -43
  101. package/dist/types/items.d.ts +0 -11
  102. package/dist/utils/apply-query.d.ts +3 -4
  103. package/dist/utils/apply-query.js +16 -39
  104. package/dist/utils/get-accountability-for-role.js +25 -16
  105. package/dist/utils/get-accountability-for-token.js +16 -17
  106. package/dist/utils/get-ast-from-query.d.ts +13 -0
  107. package/dist/utils/get-ast-from-query.js +297 -0
  108. package/dist/utils/get-cache-key.d.ts +1 -1
  109. package/dist/utils/get-cache-key.js +1 -12
  110. package/dist/utils/get-column.d.ts +1 -2
  111. package/dist/utils/get-column.js +0 -1
  112. package/dist/utils/get-permissions.d.ts +2 -0
  113. package/dist/utils/get-permissions.js +150 -0
  114. package/dist/utils/get-schema.js +3 -3
  115. package/dist/utils/get-service.js +1 -5
  116. package/dist/utils/merge-permissions-for-share.d.ts +4 -0
  117. package/dist/utils/merge-permissions-for-share.js +109 -0
  118. package/dist/utils/merge-permissions.d.ts +3 -0
  119. package/dist/utils/merge-permissions.js +95 -0
  120. package/dist/utils/reduce-schema.d.ts +6 -4
  121. package/dist/utils/reduce-schema.js +32 -16
  122. package/dist/websocket/authenticate.d.ts +2 -0
  123. package/dist/websocket/authenticate.js +12 -0
  124. package/dist/websocket/controllers/graphql.js +4 -1
  125. package/dist/websocket/controllers/hooks.js +0 -4
  126. package/dist/websocket/controllers/rest.js +2 -0
  127. package/dist/websocket/handlers/subscribe.js +2 -0
  128. package/dist/websocket/utils/items.d.ts +1 -1
  129. package/package.json +36 -37
  130. package/dist/controllers/access.d.ts +0 -2
  131. package/dist/controllers/access.js +0 -148
  132. package/dist/controllers/policies.d.ts +0 -2
  133. package/dist/controllers/policies.js +0 -169
  134. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +0 -16
  135. package/dist/database/get-ast-from-query/get-ast-from-query.js +0 -82
  136. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +0 -13
  137. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +0 -69
  138. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +0 -15
  139. package/dist/database/get-ast-from-query/lib/parse-fields.js +0 -190
  140. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +0 -14
  141. package/dist/database/get-ast-from-query/utils/get-deep-query.js +0 -17
  142. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +0 -2
  143. package/dist/database/get-ast-from-query/utils/get-related-collection.js +0 -13
  144. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +0 -2
  145. package/dist/database/get-ast-from-query/utils/get-relation.js +0 -7
  146. package/dist/database/migrations/20240710A-permissions-policies.js +0 -169
  147. package/dist/database/run-ast/lib/get-db-query.d.ts +0 -4
  148. package/dist/database/run-ast/lib/get-db-query.js +0 -208
  149. package/dist/database/run-ast/lib/parse-current-level.d.ts +0 -7
  150. package/dist/database/run-ast/lib/parse-current-level.js +0 -41
  151. package/dist/database/run-ast/run-ast.d.ts +0 -7
  152. package/dist/database/run-ast/run-ast.js +0 -107
  153. package/dist/database/run-ast/types.js +0 -1
  154. package/dist/database/run-ast/utils/apply-case-when.d.ts +0 -16
  155. package/dist/database/run-ast/utils/apply-case-when.js +0 -26
  156. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +0 -3
  157. package/dist/database/run-ast/utils/apply-parent-filters.js +0 -55
  158. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +0 -10
  159. package/dist/database/run-ast/utils/get-column-pre-processor.js +0 -57
  160. package/dist/database/run-ast/utils/get-field-alias.d.ts +0 -2
  161. package/dist/database/run-ast/utils/get-field-alias.js +0 -4
  162. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +0 -5
  163. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +0 -23
  164. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +0 -3
  165. package/dist/database/run-ast/utils/merge-with-parent-items.js +0 -87
  166. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +0 -3
  167. package/dist/database/run-ast/utils/remove-temporary-fields.js +0 -73
  168. package/dist/permissions/cache.d.ts +0 -2
  169. package/dist/permissions/cache.js +0 -23
  170. package/dist/permissions/lib/fetch-permissions.d.ts +0 -10
  171. package/dist/permissions/lib/fetch-permissions.js +0 -55
  172. package/dist/permissions/lib/fetch-policies.d.ts +0 -7
  173. package/dist/permissions/lib/fetch-policies.js +0 -28
  174. package/dist/permissions/lib/fetch-roles-tree.d.ts +0 -3
  175. package/dist/permissions/lib/fetch-roles-tree.js +0 -28
  176. package/dist/permissions/lib/with-app-minimal-permissions.js +0 -10
  177. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +0 -7
  178. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +0 -56
  179. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +0 -3
  180. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +0 -16
  181. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +0 -8
  182. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +0 -24
  183. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +0 -9
  184. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +0 -31
  185. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +0 -16
  186. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +0 -27
  187. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +0 -10
  188. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +0 -23
  189. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
  190. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
  191. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
  192. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
  193. package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
  194. package/dist/permissions/modules/fetch-global-access/types.js +0 -1
  195. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
  196. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
  197. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +0 -12
  198. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +0 -32
  199. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +0 -4
  200. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +0 -29
  201. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +0 -4
  202. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +0 -49
  203. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +0 -3
  204. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +0 -56
  205. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +0 -4
  206. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +0 -8
  207. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +0 -9
  208. package/dist/permissions/modules/process-ast/lib/inject-cases.js +0 -93
  209. package/dist/permissions/modules/process-ast/process-ast.d.ts +0 -9
  210. package/dist/permissions/modules/process-ast/process-ast.js +0 -39
  211. package/dist/permissions/modules/process-ast/types.d.ts +0 -24
  212. package/dist/permissions/modules/process-ast/types.js +0 -1
  213. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +0 -2
  214. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +0 -7
  215. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +0 -12
  216. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +0 -30
  217. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +0 -15
  218. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +0 -50
  219. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +0 -3
  220. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +0 -9
  221. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +0 -3
  222. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +0 -34
  223. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +0 -1
  224. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +0 -3
  225. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +0 -5
  226. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +0 -7
  227. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +0 -2
  228. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +0 -3
  229. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +0 -2
  230. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +0 -3
  231. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +0 -3
  232. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +0 -16
  233. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +0 -2
  234. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +0 -12
  235. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +0 -2
  236. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +0 -28
  237. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +0 -5
  238. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +0 -12
  239. package/dist/permissions/modules/process-payload/process-payload.d.ts +0 -13
  240. package/dist/permissions/modules/process-payload/process-payload.js +0 -77
  241. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +0 -12
  242. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +0 -11
  243. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +0 -9
  244. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +0 -33
  245. package/dist/permissions/modules/validate-access/validate-access.d.ts +0 -14
  246. package/dist/permissions/modules/validate-access/validate-access.js +0 -28
  247. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +0 -1
  248. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +0 -8
  249. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +0 -5
  250. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +0 -10
  251. package/dist/permissions/types.d.ts +0 -6
  252. package/dist/permissions/types.js +0 -1
  253. package/dist/permissions/utils/create-default-accountability.d.ts +0 -2
  254. package/dist/permissions/utils/create-default-accountability.js +0 -11
  255. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +0 -8
  256. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +0 -27
  257. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +0 -9
  258. package/dist/permissions/utils/fetch-dynamic-variable-context.js +0 -43
  259. package/dist/permissions/utils/filter-policies-by-ip.d.ts +0 -2
  260. package/dist/permissions/utils/filter-policies-by-ip.js +0 -15
  261. package/dist/permissions/utils/get-unaliased-field-key.d.ts +0 -5
  262. package/dist/permissions/utils/get-unaliased-field-key.js +0 -17
  263. package/dist/permissions/utils/process-permissions.d.ts +0 -7
  264. package/dist/permissions/utils/process-permissions.js +0 -9
  265. package/dist/permissions/utils/with-cache.d.ts +0 -10
  266. package/dist/permissions/utils/with-cache.js +0 -25
  267. package/dist/services/access.d.ts +0 -10
  268. package/dist/services/access.js +0 -43
  269. package/dist/services/policies.d.ts +0 -12
  270. package/dist/services/policies.js +0 -87
  271. package/dist/telemetry/utils/check-user-limits.d.ts +0 -5
  272. package/dist/telemetry/utils/check-user-limits.js +0 -19
  273. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +0 -17
  274. package/dist/utils/fetch-user-count/fetch-access-lookup.js +0 -22
  275. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +0 -16
  276. package/dist/utils/fetch-user-count/fetch-access-roles.js +0 -37
  277. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +0 -6
  278. package/dist/utils/fetch-user-count/fetch-active-users.js +0 -3
  279. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +0 -12
  280. package/dist/utils/fetch-user-count/fetch-user-count.js +0 -57
  281. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +0 -20
  282. package/dist/utils/fetch-user-count/get-user-count-query.js +0 -17
  283. package/dist/utils/validate-user-count-integrity.d.ts +0 -13
  284. package/dist/utils/validate-user-count-integrity.js +0 -29
  285. /package/dist/database/migrations/{20240710A-permissions-policies.d.ts → 20240716A-update-files-date-fields.d.ts} +0 -0
@@ -1,41 +0,0 @@
1
- import { parseFilterKey } from '../../../utils/parse-filter-key.js';
2
- export async function parseCurrentLevel(schema, collection, children, query) {
3
- const primaryKeyField = schema.collections[collection].primary;
4
- const columnsInCollection = Object.keys(schema.collections[collection].fields);
5
- const columnsToSelectInternal = [];
6
- const nestedCollectionNodes = [];
7
- for (const child of children) {
8
- if (child.type === 'field' || child.type === 'functionField') {
9
- const { fieldName } = parseFilterKey(child.name);
10
- if (columnsInCollection.includes(fieldName)) {
11
- columnsToSelectInternal.push(child.fieldKey);
12
- }
13
- continue;
14
- }
15
- if (!child.relation)
16
- continue;
17
- if (child.type === 'm2o') {
18
- columnsToSelectInternal.push(child.relation.field);
19
- }
20
- if (child.type === 'a2o') {
21
- columnsToSelectInternal.push(child.relation.field);
22
- columnsToSelectInternal.push(child.relation.meta.one_collection_field);
23
- }
24
- nestedCollectionNodes.push(child);
25
- }
26
- const isAggregate = (query.group || (query.aggregate && Object.keys(query.aggregate).length > 0)) ?? false;
27
- /** Always fetch primary key in case there's a nested relation that needs it. Aggregate payloads
28
- * can't have nested relational fields
29
- */
30
- if (isAggregate === false && columnsToSelectInternal.includes(primaryKeyField) === false) {
31
- columnsToSelectInternal.push(primaryKeyField);
32
- }
33
- /** Make sure select list has unique values */
34
- const columnsToSelect = [...new Set(columnsToSelectInternal)];
35
- const fieldNodes = columnsToSelect.map((column) => children.find((childNode) => (childNode.type === 'field' || childNode.type === 'functionField') && childNode.fieldKey === column) ?? {
36
- type: 'field',
37
- name: column,
38
- fieldKey: column,
39
- });
40
- return { fieldNodes, nestedCollectionNodes, primaryKeyField };
41
- }
@@ -1,7 +0,0 @@
1
- import type { Item, SchemaOverview } from '@directus/types';
2
- import type { AST, NestedCollectionNode } from '../../types/ast.js';
3
- import type { RunASTOptions } from './types.js';
4
- /**
5
- * Execute a given AST using Knex. Returns array of items based on requested AST.
6
- */
7
- export declare function runAst(originalAST: AST | NestedCollectionNode, schema: SchemaOverview, options?: RunASTOptions): Promise<null | Item | Item[]>;
@@ -1,107 +0,0 @@
1
- import { useEnv } from '@directus/env';
2
- import { cloneDeep, merge } from 'lodash-es';
3
- import { PayloadService } from '../../services/payload.js';
4
- import getDatabase from '../index.js';
5
- import { getDBQuery } from './lib/get-db-query.js';
6
- import { parseCurrentLevel } from './lib/parse-current-level.js';
7
- import { applyParentFilters } from './utils/apply-parent-filters.js';
8
- import { mergeWithParentItems } from './utils/merge-with-parent-items.js';
9
- import { removeTemporaryFields } from './utils/remove-temporary-fields.js';
10
- /**
11
- * Execute a given AST using Knex. Returns array of items based on requested AST.
12
- */
13
- export async function runAst(originalAST, schema, options) {
14
- const ast = cloneDeep(originalAST);
15
- const knex = options?.knex || getDatabase();
16
- if (ast.type === 'a2o') {
17
- const results = {};
18
- for (const collection of ast.names) {
19
- results[collection] = await run(collection, ast.children[collection], ast.query[collection], ast.cases[collection] ?? []);
20
- }
21
- return results;
22
- }
23
- else {
24
- return await run(ast.name, ast.children, options?.query || ast.query, ast.cases);
25
- }
26
- async function run(collection, children, query, cases) {
27
- const env = useEnv();
28
- // Retrieve the database columns to select in the current AST
29
- const { fieldNodes, primaryKeyField, nestedCollectionNodes } = await parseCurrentLevel(schema, collection, children, query);
30
- const o2mNodes = nestedCollectionNodes.filter((node) => node.type === 'o2m');
31
- // The actual knex query builder instance. This is a promise that resolves with the raw items from the db
32
- const dbQuery = getDBQuery(schema, knex, collection, fieldNodes, o2mNodes, query, cases);
33
- const rawItems = await dbQuery;
34
- if (!rawItems)
35
- return null;
36
- // Run the items through the special transforms
37
- const payloadService = new PayloadService(collection, { knex, schema });
38
- let items = await payloadService.processValues('read', rawItems, query.alias ?? {});
39
- if (!items || (Array.isArray(items) && items.length === 0))
40
- return items;
41
- // Apply the `_in` filters to the nested collection batches
42
- const nestedNodes = applyParentFilters(schema, nestedCollectionNodes, items);
43
- for (const nestedNode of nestedNodes) {
44
- let nestedItems = [];
45
- if (nestedNode.type === 'o2m') {
46
- let hasMore = true;
47
- let batchCount = 0;
48
- // If a nested node has a whenCase it indicates that the user might not be able to access the field for all items.
49
- // In that case the queried item includes a flag under the fieldKey that is populated in the db and indicates
50
- // if the user has access to that field for that specific item.
51
- const hasWhenCase = nestedNode.whenCase && nestedNode.whenCase.length > 0;
52
- let fieldAllowed = true;
53
- if (hasWhenCase) {
54
- // Extract flag and remove field from item, so it can be populated with the actual items
55
- if (Array.isArray(items)) {
56
- fieldAllowed = [];
57
- for (const item of items) {
58
- fieldAllowed.push(!!item[nestedNode.fieldKey]);
59
- delete item[nestedNode.fieldKey];
60
- }
61
- }
62
- else {
63
- fieldAllowed = !!items[nestedNode.fieldKey];
64
- delete items[nestedNode.fieldKey];
65
- }
66
- }
67
- while (hasMore) {
68
- const node = merge({}, nestedNode, {
69
- query: {
70
- limit: env['RELATIONAL_BATCH_SIZE'],
71
- offset: batchCount * env['RELATIONAL_BATCH_SIZE'],
72
- page: null,
73
- },
74
- });
75
- nestedItems = (await runAst(node, schema, { knex, nested: true }));
76
- if (nestedItems) {
77
- items = mergeWithParentItems(schema, nestedItems, items, nestedNode, fieldAllowed);
78
- }
79
- if (!nestedItems || nestedItems.length < env['RELATIONAL_BATCH_SIZE']) {
80
- hasMore = false;
81
- }
82
- batchCount++;
83
- }
84
- }
85
- else {
86
- const node = merge({}, nestedNode, {
87
- query: { limit: -1 },
88
- });
89
- nestedItems = (await runAst(node, schema, { knex, nested: true }));
90
- if (nestedItems) {
91
- // Merge all fetched nested records with the parent items
92
- items = mergeWithParentItems(schema, nestedItems, items, nestedNode, true);
93
- }
94
- }
95
- }
96
- // During the fetching of data, we have to inject a couple of required fields for the child nesting
97
- // to work (primary / foreign keys) even if they're not explicitly requested. After all fetching
98
- // and nesting is done, we parse through the output structure, and filter out all non-requested
99
- // fields
100
- // The field allowed flags injected in `getDBQuery` are already removed while processing the nested nodes in
101
- // the previous step.
102
- if (options?.nested !== true && options?.stripNonRequested !== false) {
103
- items = removeTemporaryFields(schema, items, originalAST, primaryKeyField);
104
- }
105
- return items;
106
- }
107
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,16 +0,0 @@
1
- import type { Filter, SchemaOverview } from '@directus/types';
2
- import type { Knex } from 'knex';
3
- import type { AliasMap } from '../../../utils/get-column-path.js';
4
- export interface ApplyCaseWhenOptions {
5
- column: Knex.Raw;
6
- columnCases: Filter[];
7
- table: string;
8
- cases: Filter[];
9
- aliasMap: AliasMap;
10
- alias?: string;
11
- }
12
- export interface ApplyCaseWhenContext {
13
- knex: Knex;
14
- schema: SchemaOverview;
15
- }
16
- export declare function applyCaseWhen({ columnCases, table, aliasMap, cases, column, alias }: ApplyCaseWhenOptions, { knex, schema }: ApplyCaseWhenContext): Knex.Raw;
@@ -1,26 +0,0 @@
1
- import { applyFilter } from '../../../utils/apply-query.js';
2
- export function applyCaseWhen({ columnCases, table, aliasMap, cases, column, alias }, { knex, schema }) {
3
- const caseQuery = knex.queryBuilder();
4
- applyFilter(knex, schema, caseQuery, { _or: columnCases }, table, aliasMap, cases);
5
- const compiler = knex.client.queryCompiler(caseQuery);
6
- const sqlParts = [];
7
- // Only empty filters, so no where was generated, skip it
8
- if (!compiler.grouped.where)
9
- return column;
10
- for (const statement of compiler.grouped.where) {
11
- const val = compiler[statement.type](statement);
12
- if (val) {
13
- if (sqlParts.length > 0) {
14
- sqlParts.push(statement.bool);
15
- }
16
- sqlParts.push(val);
17
- }
18
- }
19
- const sql = sqlParts.join(' ');
20
- const bindings = caseQuery.toSQL().bindings;
21
- const result = knex.raw(`(CASE WHEN ${sql} THEN ?? END)`, [...bindings, column]);
22
- if (alias) {
23
- return knex.raw(result + ' AS ??', [alias]);
24
- }
25
- return result;
26
- }
@@ -1,3 +0,0 @@
1
- import type { Item, SchemaOverview } from '@directus/types';
2
- import type { NestedCollectionNode } from '../../../types/ast.js';
3
- export declare function applyParentFilters(schema: SchemaOverview, nestedCollectionNodes: NestedCollectionNode[], parentItem: Item | Item[]): NestedCollectionNode[];
@@ -1,55 +0,0 @@
1
- import { toArray } from '@directus/utils';
2
- import { isNil, merge, uniq } from 'lodash-es';
3
- export function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
4
- const parentItems = toArray(parentItem);
5
- for (const nestedNode of nestedCollectionNodes) {
6
- if (!nestedNode.relation)
7
- continue;
8
- if (nestedNode.type === 'm2o') {
9
- const foreignField = schema.collections[nestedNode.relation.related_collection].primary;
10
- const foreignIds = uniq(parentItems.map((res) => res[nestedNode.relation.field])).filter((id) => !isNil(id));
11
- merge(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
12
- }
13
- else if (nestedNode.type === 'o2m') {
14
- const relatedM2OisFetched = !!nestedNode.children.find((child) => {
15
- return child.type === 'field' && child.name === nestedNode.relation.field;
16
- });
17
- if (relatedM2OisFetched === false) {
18
- nestedNode.children.push({
19
- type: 'field',
20
- name: nestedNode.relation.field,
21
- fieldKey: nestedNode.relation.field,
22
- whenCase: [],
23
- });
24
- }
25
- if (nestedNode.relation.meta?.sort_field) {
26
- nestedNode.children.push({
27
- type: 'field',
28
- name: nestedNode.relation.meta.sort_field,
29
- fieldKey: nestedNode.relation.meta.sort_field,
30
- whenCase: [],
31
- });
32
- }
33
- const foreignField = nestedNode.relation.field;
34
- const foreignIds = uniq(parentItems.map((res) => res[nestedNode.parentKey])).filter((id) => !isNil(id));
35
- merge(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
36
- }
37
- else if (nestedNode.type === 'a2o') {
38
- const keysPerCollection = {};
39
- for (const parentItem of parentItems) {
40
- const collection = parentItem[nestedNode.relation.meta.one_collection_field];
41
- if (!keysPerCollection[collection])
42
- keysPerCollection[collection] = [];
43
- keysPerCollection[collection].push(parentItem[nestedNode.relation.field]);
44
- }
45
- for (const relatedCollection of nestedNode.names) {
46
- const foreignField = nestedNode.relatedKey[relatedCollection];
47
- const foreignIds = uniq(keysPerCollection[relatedCollection]);
48
- merge(nestedNode, {
49
- query: { [relatedCollection]: { filter: { [foreignField]: { _in: foreignIds } }, limit: foreignIds.length } },
50
- });
51
- }
52
- }
53
- }
54
- return nestedCollectionNodes;
55
- }
@@ -1,10 +0,0 @@
1
- import type { Filter, SchemaOverview } from '@directus/types';
2
- import type { Knex } from 'knex';
3
- import type { FieldNode, FunctionFieldNode, M2ONode } from '../../../types/ast.js';
4
- import type { AliasMap } from '../../../utils/get-column-path.js';
5
- interface NodePreProcessOptions {
6
- /** Don't assign an alias to the column but instead return the column as is */
7
- noAlias?: boolean;
8
- }
9
- export declare function getColumnPreprocessor(knex: Knex, schema: SchemaOverview, table: string, cases: Filter[], aliasMap: AliasMap): (fieldNode: FieldNode | FunctionFieldNode | M2ONode, options?: NodePreProcessOptions) => Knex.Raw<string>;
10
- export {};
@@ -1,57 +0,0 @@
1
- import { joinFilterWithCases } from '../../../utils/apply-query.js';
2
- import { getColumn } from '../../../utils/get-column.js';
3
- import { parseFilterKey } from '../../../utils/parse-filter-key.js';
4
- import { getHelpers } from '../../helpers/index.js';
5
- import { applyCaseWhen } from './apply-case-when.js';
6
- import { getNodeAlias } from './get-field-alias.js';
7
- export function getColumnPreprocessor(knex, schema, table, cases, aliasMap) {
8
- const helpers = getHelpers(knex);
9
- return function (fieldNode, options) {
10
- // Don't assign an alias to the column expression if the field has a whenCase
11
- // (since the alias will be assigned in applyCaseWhen) or if the noAlias option is set
12
- const hasWhenCase = fieldNode.whenCase && fieldNode.whenCase.length > 0;
13
- const noAlias = options?.noAlias || hasWhenCase;
14
- const alias = getNodeAlias(fieldNode);
15
- const rawColumnAlias = noAlias ? false : alias;
16
- let field;
17
- if (fieldNode.type === 'field' || fieldNode.type === 'functionField') {
18
- const { fieldName } = parseFilterKey(fieldNode.name);
19
- field = schema.collections[table].fields[fieldName];
20
- }
21
- else {
22
- field = schema.collections[fieldNode.relation.collection].fields[fieldNode.relation.field];
23
- }
24
- let column;
25
- if (field?.type?.startsWith('geometry')) {
26
- column = helpers.st.asText(table, field.field, rawColumnAlias);
27
- }
28
- else if (fieldNode.type === 'functionField') {
29
- // Include the field cases in the functionField query filter
30
- column = getColumn(knex, table, fieldNode.name, rawColumnAlias, schema, {
31
- query: {
32
- ...fieldNode.query,
33
- filter: joinFilterWithCases(fieldNode.query.filter, fieldNode.cases),
34
- },
35
- cases: fieldNode.cases,
36
- });
37
- }
38
- else {
39
- column = getColumn(knex, table, fieldNode.name, rawColumnAlias, schema);
40
- }
41
- if (hasWhenCase) {
42
- const columnCases = [];
43
- for (const index of fieldNode.whenCase) {
44
- columnCases.push(cases[index]);
45
- }
46
- column = applyCaseWhen({
47
- column,
48
- columnCases,
49
- aliasMap,
50
- cases,
51
- table,
52
- alias,
53
- }, { knex, schema });
54
- }
55
- return column;
56
- };
57
- }
@@ -1,2 +0,0 @@
1
- import type { FieldNode, FunctionFieldNode, M2ONode, O2MNode } from '../../../types/index.js';
2
- export declare function getNodeAlias(node: FieldNode | FunctionFieldNode | M2ONode | O2MNode): string;
@@ -1,4 +0,0 @@
1
- import { applyFunctionToColumnName } from '../../../utils/apply-function-to-column-name.js';
2
- export function getNodeAlias(node) {
3
- return applyFunctionToColumnName(node.fieldKey);
4
- }
@@ -1,5 +0,0 @@
1
- import type { Filter, SchemaOverview } from '@directus/types';
2
- import type { Knex } from 'knex';
3
- import type { FieldNode, FunctionFieldNode, M2ONode, O2MNode } from '../../../types/index.js';
4
- import type { AliasMap } from '../../../utils/get-column-path.js';
5
- export declare function getInnerQueryColumnPreProcessor(knex: Knex, schema: SchemaOverview, table: string, cases: Filter[], aliasMap: AliasMap, aliasPrefix: string): (fieldNode: FieldNode | FunctionFieldNode | M2ONode | O2MNode) => Knex.Raw<string> | null;
@@ -1,23 +0,0 @@
1
- import { applyCaseWhen } from './apply-case-when.js';
2
- import { getNodeAlias } from './get-field-alias.js';
3
- export function getInnerQueryColumnPreProcessor(knex, schema, table, cases, aliasMap, aliasPrefix) {
4
- return function (fieldNode) {
5
- const alias = getNodeAlias(fieldNode);
6
- if (fieldNode.whenCase && fieldNode.whenCase.length > 0) {
7
- const columnCases = [];
8
- for (const index of fieldNode.whenCase) {
9
- columnCases.push(cases[index]);
10
- }
11
- // Don't pass in the alias as we need to wrap the whole case/when in a count() an alias that
12
- const caseWhen = applyCaseWhen({
13
- column: knex.raw(1),
14
- columnCases,
15
- aliasMap,
16
- cases,
17
- table,
18
- }, { knex, schema });
19
- return knex.raw('COUNT(??) AS ??', [caseWhen, `${aliasPrefix}_${alias}`]);
20
- }
21
- return null;
22
- };
23
- }
@@ -1,3 +0,0 @@
1
- import type { Item, SchemaOverview } from '@directus/types';
2
- import type { NestedCollectionNode } from '../../../types/ast.js';
3
- export declare function mergeWithParentItems(schema: SchemaOverview, nestedItem: Item | Item[], parentItem: Item | Item[], nestedNode: NestedCollectionNode, fieldAllowed: boolean | boolean[]): Item | Item[] | undefined;
@@ -1,87 +0,0 @@
1
- import { useEnv } from '@directus/env';
2
- import { toArray } from '@directus/utils';
3
- import { clone, isArray } from 'lodash-es';
4
- export function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode, fieldAllowed) {
5
- const env = useEnv();
6
- const nestedItems = toArray(nestedItem);
7
- const parentItems = clone(toArray(parentItem));
8
- if (nestedNode.type === 'm2o') {
9
- for (const parentItem of parentItems) {
10
- const itemChild = nestedItems.find((nestedItem) => {
11
- return (nestedItem[schema.collections[nestedNode.relation.related_collection].primary] ==
12
- parentItem[nestedNode.relation.field]);
13
- });
14
- parentItem[nestedNode.fieldKey] = itemChild || null;
15
- }
16
- }
17
- else if (nestedNode.type === 'o2m') {
18
- for (const [index, parentItem] of parentItems.entries()) {
19
- if (fieldAllowed === false || (isArray(fieldAllowed) && !fieldAllowed[index])) {
20
- parentItem[nestedNode.fieldKey] = null;
21
- continue;
22
- }
23
- if (!parentItem[nestedNode.fieldKey])
24
- parentItem[nestedNode.fieldKey] = [];
25
- const itemChildren = nestedItems.filter((nestedItem) => {
26
- if (nestedItem === null)
27
- return false;
28
- if (Array.isArray(nestedItem[nestedNode.relation.field]))
29
- return true;
30
- return (nestedItem[nestedNode.relation.field] ==
31
- parentItem[schema.collections[nestedNode.relation.related_collection].primary] ||
32
- nestedItem[nestedNode.relation.field]?.[schema.collections[nestedNode.relation.related_collection].primary] == parentItem[schema.collections[nestedNode.relation.related_collection].primary]);
33
- });
34
- parentItem[nestedNode.fieldKey].push(...itemChildren);
35
- const limit = nestedNode.query.limit ?? Number(env['QUERY_LIMIT_DEFAULT']);
36
- if (nestedNode.query.page && nestedNode.query.page > 1) {
37
- parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(limit * (nestedNode.query.page - 1));
38
- }
39
- if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
40
- parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
41
- }
42
- if (limit !== -1) {
43
- parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, limit);
44
- }
45
- parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
46
- // This is pre-filled in get-ast-from-query
47
- const sortField = nestedNode.query.sort[0];
48
- let column = sortField;
49
- let order = 'asc';
50
- if (sortField.startsWith('-')) {
51
- column = sortField.substring(1);
52
- order = 'desc';
53
- }
54
- if (a[column] === b[column])
55
- return 0;
56
- if (a[column] === null)
57
- return 1;
58
- if (b[column] === null)
59
- return -1;
60
- if (order === 'asc') {
61
- return a[column] < b[column] ? -1 : 1;
62
- }
63
- else {
64
- return a[column] < b[column] ? 1 : -1;
65
- }
66
- });
67
- }
68
- }
69
- else if (nestedNode.type === 'a2o') {
70
- for (const parentItem of parentItems) {
71
- if (!nestedNode.relation.meta?.one_collection_field) {
72
- parentItem[nestedNode.fieldKey] = null;
73
- continue;
74
- }
75
- const relatedCollection = parentItem[nestedNode.relation.meta.one_collection_field];
76
- if (!nestedItem[relatedCollection]) {
77
- parentItem[nestedNode.fieldKey] = null;
78
- continue;
79
- }
80
- const itemChild = nestedItem[relatedCollection].find((nestedItem) => {
81
- return nestedItem[nestedNode.relatedKey[relatedCollection]] == parentItem[nestedNode.fieldKey];
82
- });
83
- parentItem[nestedNode.fieldKey] = itemChild || null;
84
- }
85
- }
86
- return Array.isArray(parentItem) ? parentItems : parentItems[0];
87
- }
@@ -1,3 +0,0 @@
1
- import type { Item, SchemaOverview } from '@directus/types';
2
- import type { AST, NestedCollectionNode } from '../../../types/ast.js';
3
- export declare function removeTemporaryFields(schema: SchemaOverview, rawItem: Item | Item[], ast: AST | NestedCollectionNode, primaryKeyField: string, parentItem?: Item): null | Item | Item[];
@@ -1,73 +0,0 @@
1
- import { toArray } from '@directus/utils';
2
- import { cloneDeep, pick } from 'lodash-es';
3
- import { applyFunctionToColumnName } from '../../../utils/apply-function-to-column-name.js';
4
- export function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem) {
5
- const rawItems = cloneDeep(toArray(rawItem));
6
- const items = [];
7
- if (ast.type === 'a2o') {
8
- const fields = {};
9
- const nestedCollectionNodes = {};
10
- for (const relatedCollection of ast.names) {
11
- if (!fields[relatedCollection])
12
- fields[relatedCollection] = [];
13
- if (!nestedCollectionNodes[relatedCollection])
14
- nestedCollectionNodes[relatedCollection] = [];
15
- for (const child of ast.children[relatedCollection]) {
16
- if (child.type === 'field' || child.type === 'functionField') {
17
- fields[relatedCollection].push(child.name);
18
- }
19
- else {
20
- fields[relatedCollection].push(child.fieldKey);
21
- nestedCollectionNodes[relatedCollection].push(child);
22
- }
23
- }
24
- }
25
- for (const rawItem of rawItems) {
26
- const relatedCollection = parentItem?.[ast.relation.meta.one_collection_field];
27
- if (rawItem === null || rawItem === undefined)
28
- return rawItem;
29
- let item = rawItem;
30
- for (const nestedNode of nestedCollectionNodes[relatedCollection]) {
31
- item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, schema.collections[nestedNode.relation.collection].primary, item);
32
- }
33
- const fieldsWithFunctionsApplied = fields[relatedCollection].map((field) => applyFunctionToColumnName(field));
34
- item =
35
- fields[relatedCollection].length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
36
- items.push(item);
37
- }
38
- }
39
- else {
40
- const fields = [];
41
- const nestedCollectionNodes = [];
42
- for (const child of ast.children) {
43
- fields.push(child.fieldKey);
44
- if (child.type !== 'field' && child.type !== 'functionField') {
45
- nestedCollectionNodes.push(child);
46
- }
47
- }
48
- // Make sure any requested aggregate fields are included
49
- if (ast.query?.aggregate) {
50
- for (const [operation, aggregateFields] of Object.entries(ast.query.aggregate)) {
51
- if (!fields)
52
- continue;
53
- if (operation === 'count' && aggregateFields.includes('*'))
54
- fields.push('count');
55
- fields.push(...aggregateFields.map((field) => `${operation}.${field}`));
56
- }
57
- }
58
- for (const rawItem of rawItems) {
59
- if (rawItem === null || rawItem === undefined)
60
- return rawItem;
61
- let item = rawItem;
62
- for (const nestedNode of nestedCollectionNodes) {
63
- item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, nestedNode.type === 'm2o'
64
- ? schema.collections[nestedNode.relation.related_collection].primary
65
- : schema.collections[nestedNode.relation.collection].primary, item);
66
- }
67
- const fieldsWithFunctionsApplied = fields.map((field) => applyFunctionToColumnName(field));
68
- item = fields.length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
69
- items.push(item);
70
- }
71
- }
72
- return Array.isArray(rawItem) ? items : items[0];
73
- }
@@ -1,2 +0,0 @@
1
- export declare const useCache: () => import("@directus/memory").Cache;
2
- export declare function clearCache(): Promise<void>;
@@ -1,23 +0,0 @@
1
- import { defineCache } from '@directus/memory';
2
- import { redisConfigAvailable, useRedis } from '../redis/index.js';
3
- const localOnly = redisConfigAvailable() === false;
4
- const config = localOnly
5
- ? {
6
- type: 'local',
7
- maxKeys: 500,
8
- }
9
- : {
10
- type: 'multi',
11
- redis: {
12
- namespace: 'permissions',
13
- redis: useRedis(),
14
- },
15
- local: {
16
- maxKeys: 100,
17
- },
18
- };
19
- export const useCache = defineCache(config);
20
- export function clearCache() {
21
- const cache = useCache();
22
- return cache.clear();
23
- }
@@ -1,10 +0,0 @@
1
- import type { Accountability, Permission, PermissionsAction } from '@directus/types';
2
- import type { Context } from '../types.js';
3
- export declare const fetchPermissions: typeof _fetchPermissions;
4
- export interface FetchPermissionsOptions {
5
- action?: PermissionsAction;
6
- policies: string[];
7
- collections?: string[];
8
- accountability?: Pick<Accountability, 'user' | 'role' | 'roles' | 'app'>;
9
- }
10
- export declare function _fetchPermissions(options: FetchPermissionsOptions, context: Context): Promise<Permission[]>;
@@ -1,55 +0,0 @@
1
- import { pick, sortBy } from 'lodash-es';
2
- import { fetchDynamicVariableContext } from '../utils/fetch-dynamic-variable-context.js';
3
- import { processPermissions } from '../utils/process-permissions.js';
4
- import { withCache } from '../utils/with-cache.js';
5
- import { withAppMinimalPermissions } from './with-app-minimal-permissions.js';
6
- export const fetchPermissions = withCache('permissions', _fetchPermissions, ({ action, policies, collections, accountability }) => ({
7
- policies, // we assume that policies always come from the same source, so they should be in the same order
8
- ...(action && { action }),
9
- ...(collections && { collections: sortBy(collections) }),
10
- ...(accountability && { accountability: pick(accountability, ['user', 'role', 'roles', 'app']) }),
11
- }));
12
- export async function _fetchPermissions(options, context) {
13
- const { PermissionsService } = await import('../../services/permissions.js');
14
- const permissionsService = new PermissionsService(context);
15
- const filter = {
16
- _and: [{ policy: { _in: options.policies } }],
17
- };
18
- if (options.action) {
19
- filter._and.push({ action: { _eq: options.action } });
20
- }
21
- if (options.collections) {
22
- filter._and.push({ collection: { _in: options.collections } });
23
- }
24
- let permissions = (await permissionsService.readByQuery({
25
- filter,
26
- limit: -1,
27
- }));
28
- // Sort permissions by their order in the policies array
29
- // This ensures that if a sorted array of policies is passed in the permissions are returned in the same order
30
- // which is necessary for correctly applying the presets in order
31
- permissions = sortBy(permissions, (permission) => options.policies.indexOf(permission.policy));
32
- if (options.accountability) {
33
- // Add app minimal permissions for the request accountability, if applicable.
34
- // Normally this is done in the permissions service readByQuery, but it also needs to do it here
35
- // since the permissions service is created without accountability.
36
- // We call it without the policies filter, since the static minimal app permissions don't have a policy attached.
37
- const permissionsWithAppPermissions = withAppMinimalPermissions(options.accountability ?? null, permissions, {
38
- _and: filter._and.slice(1),
39
- });
40
- const permissionsContext = await fetchDynamicVariableContext({
41
- accountability: options.accountability,
42
- policies: options.policies,
43
- permissions: permissionsWithAppPermissions,
44
- }, context);
45
- // Replace dynamic variables with their actual values
46
- const processedPermissions = processPermissions({
47
- permissions: permissionsWithAppPermissions,
48
- accountability: options.accountability,
49
- permissionsContext,
50
- });
51
- // TODO merge in permissions coming from the share scope
52
- return processedPermissions;
53
- }
54
- return permissions;
55
- }