@directus/api 20.1.0 → 21.0.0-rc.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 (328) hide show
  1. package/dist/app.js +5 -5
  2. package/dist/auth/drivers/ldap.js +5 -5
  3. package/dist/auth/drivers/local.js +4 -4
  4. package/dist/auth/drivers/oauth2.js +5 -5
  5. package/dist/auth/drivers/openid.js +3 -5
  6. package/dist/auth/drivers/saml.js +1 -1
  7. package/dist/auth.js +1 -1
  8. package/dist/cache.js +4 -1
  9. package/dist/cli/commands/bootstrap/index.js +9 -3
  10. package/dist/cli/commands/count/index.js +1 -1
  11. package/dist/cli/commands/database/install.js +1 -1
  12. package/dist/cli/commands/database/migrate.js +1 -1
  13. package/dist/cli/commands/init/index.js +9 -10
  14. package/dist/cli/commands/roles/create.js +1 -1
  15. package/dist/cli/commands/schema/apply.js +1 -1
  16. package/dist/cli/commands/schema/snapshot.js +1 -1
  17. package/dist/cli/commands/users/create.js +1 -1
  18. package/dist/cli/commands/users/passwd.js +1 -1
  19. package/dist/cli/load-extensions.js +1 -1
  20. package/dist/cli/utils/defaults.d.ts +4 -11
  21. package/dist/cli/utils/defaults.js +7 -1
  22. package/dist/constants.d.ts +1 -1
  23. package/dist/constants.js +2 -2
  24. package/dist/controllers/access.d.ts +2 -0
  25. package/dist/controllers/access.js +148 -0
  26. package/dist/controllers/assets.js +1 -1
  27. package/dist/controllers/auth.js +6 -17
  28. package/dist/controllers/files.js +1 -1
  29. package/dist/controllers/permissions.js +14 -2
  30. package/dist/controllers/policies.d.ts +2 -0
  31. package/dist/controllers/policies.js +169 -0
  32. package/dist/controllers/roles.js +22 -1
  33. package/dist/controllers/schema.js +1 -1
  34. package/dist/controllers/tus.js +11 -23
  35. package/dist/controllers/users.js +0 -55
  36. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +16 -0
  37. package/dist/database/get-ast-from-query/get-ast-from-query.js +82 -0
  38. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +13 -0
  39. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +69 -0
  40. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +15 -0
  41. package/dist/database/get-ast-from-query/lib/parse-fields.js +190 -0
  42. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +14 -0
  43. package/dist/database/get-ast-from-query/utils/get-deep-query.js +17 -0
  44. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +2 -0
  45. package/dist/database/get-ast-from-query/utils/get-related-collection.js +13 -0
  46. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +2 -0
  47. package/dist/database/get-ast-from-query/utils/get-relation.js +7 -0
  48. package/dist/database/helpers/fn/types.d.ts +2 -1
  49. package/dist/database/helpers/fn/types.js +1 -1
  50. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  51. package/dist/database/helpers/geometry/dialects/mssql.js +4 -2
  52. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  53. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  54. package/dist/database/helpers/geometry/dialects/oracle.js +5 -3
  55. package/dist/database/helpers/geometry/types.d.ts +1 -1
  56. package/dist/database/helpers/geometry/types.js +4 -2
  57. package/dist/database/index.js +3 -2
  58. package/dist/database/migrations/20210518A-add-foreign-key-constraints.js +1 -1
  59. package/dist/database/migrations/20210519A-add-system-fk-triggers.js +1 -1
  60. package/dist/database/migrations/20210802A-replace-groups.js +1 -1
  61. package/dist/database/migrations/20230721A-require-shares-fields.js +1 -1
  62. package/dist/database/migrations/20240710A-permissions-policies.d.ts +3 -0
  63. package/dist/database/migrations/20240710A-permissions-policies.js +169 -0
  64. package/dist/database/migrations/run.js +1 -1
  65. package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
  66. package/dist/database/run-ast/lib/get-db-query.js +208 -0
  67. package/dist/database/run-ast/lib/parse-current-level.d.ts +7 -0
  68. package/dist/database/run-ast/lib/parse-current-level.js +41 -0
  69. package/dist/database/run-ast/run-ast.d.ts +7 -0
  70. package/dist/database/run-ast/run-ast.js +107 -0
  71. package/dist/database/{run-ast.d.ts → run-ast/types.d.ts} +3 -9
  72. package/dist/database/run-ast/types.js +1 -0
  73. package/dist/database/run-ast/utils/apply-case-when.d.ts +16 -0
  74. package/dist/database/run-ast/utils/apply-case-when.js +26 -0
  75. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +3 -0
  76. package/dist/database/run-ast/utils/apply-parent-filters.js +55 -0
  77. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +10 -0
  78. package/dist/database/run-ast/utils/get-column-pre-processor.js +57 -0
  79. package/dist/database/run-ast/utils/get-field-alias.d.ts +2 -0
  80. package/dist/database/run-ast/utils/get-field-alias.js +4 -0
  81. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +5 -0
  82. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +23 -0
  83. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +3 -0
  84. package/dist/database/run-ast/utils/merge-with-parent-items.js +87 -0
  85. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +3 -0
  86. package/dist/database/run-ast/utils/remove-temporary-fields.js +73 -0
  87. package/dist/emitter.js +1 -1
  88. package/dist/extensions/lib/get-shared-deps-mapping.js +1 -1
  89. package/dist/extensions/lib/installation/manager.js +1 -1
  90. package/dist/extensions/lib/sandbox/register/call-reference.js +1 -1
  91. package/dist/extensions/lib/sandbox/sdk/generators/log.js +1 -1
  92. package/dist/extensions/lib/sync-extensions.js +1 -1
  93. package/dist/extensions/manager.js +1 -1
  94. package/dist/flows.js +4 -5
  95. package/dist/{logger.js → logger/index.js} +2 -8
  96. package/dist/logger/redact-query.d.ts +1 -0
  97. package/dist/logger/redact-query.js +13 -0
  98. package/dist/mailer.js +1 -1
  99. package/dist/middleware/authenticate.js +2 -7
  100. package/dist/middleware/cache.js +2 -2
  101. package/dist/middleware/error-handler.js +1 -1
  102. package/dist/middleware/rate-limiter-global.js +1 -1
  103. package/dist/middleware/respond.js +2 -2
  104. package/dist/operations/log/index.js +1 -1
  105. package/dist/operations/mail/index.js +1 -1
  106. package/dist/permissions/cache.d.ts +2 -0
  107. package/dist/permissions/cache.js +23 -0
  108. package/dist/permissions/lib/fetch-permissions.d.ts +10 -0
  109. package/dist/permissions/lib/fetch-permissions.js +55 -0
  110. package/dist/permissions/lib/fetch-policies.d.ts +7 -0
  111. package/dist/permissions/lib/fetch-policies.js +28 -0
  112. package/dist/permissions/lib/fetch-roles-tree.d.ts +3 -0
  113. package/dist/permissions/lib/fetch-roles-tree.js +28 -0
  114. package/dist/{services/permissions → permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  115. package/dist/permissions/lib/with-app-minimal-permissions.js +10 -0
  116. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +7 -0
  117. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +56 -0
  118. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +3 -0
  119. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +16 -0
  120. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +8 -0
  121. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +24 -0
  122. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +9 -0
  123. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +31 -0
  124. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +16 -0
  125. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +27 -0
  126. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +10 -0
  127. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +23 -0
  128. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +5 -0
  129. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +7 -0
  130. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +5 -0
  131. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +10 -0
  132. package/dist/permissions/modules/fetch-global-access/types.d.ts +4 -0
  133. package/dist/permissions/modules/fetch-global-access/types.js +1 -0
  134. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +4 -0
  135. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +27 -0
  136. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +12 -0
  137. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +32 -0
  138. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +4 -0
  139. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +29 -0
  140. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +4 -0
  141. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +49 -0
  142. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +3 -0
  143. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +56 -0
  144. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +4 -0
  145. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +8 -0
  146. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +9 -0
  147. package/dist/permissions/modules/process-ast/lib/inject-cases.js +93 -0
  148. package/dist/permissions/modules/process-ast/process-ast.d.ts +9 -0
  149. package/dist/permissions/modules/process-ast/process-ast.js +39 -0
  150. package/dist/permissions/modules/process-ast/types.d.ts +24 -0
  151. package/dist/permissions/modules/process-ast/types.js +1 -0
  152. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +2 -0
  153. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +7 -0
  154. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +12 -0
  155. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +30 -0
  156. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +15 -0
  157. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +50 -0
  158. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +3 -0
  159. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +9 -0
  160. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +3 -0
  161. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +34 -0
  162. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +1 -0
  163. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +3 -0
  164. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +5 -0
  165. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +7 -0
  166. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +2 -0
  167. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +3 -0
  168. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +2 -0
  169. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +3 -0
  170. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +3 -0
  171. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +16 -0
  172. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +2 -0
  173. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +12 -0
  174. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +2 -0
  175. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +28 -0
  176. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +5 -0
  177. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +12 -0
  178. package/dist/permissions/modules/process-payload/process-payload.d.ts +13 -0
  179. package/dist/permissions/modules/process-payload/process-payload.js +77 -0
  180. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +12 -0
  181. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +11 -0
  182. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +9 -0
  183. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +33 -0
  184. package/dist/permissions/modules/validate-access/validate-access.d.ts +14 -0
  185. package/dist/permissions/modules/validate-access/validate-access.js +28 -0
  186. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +1 -0
  187. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +8 -0
  188. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +5 -0
  189. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +10 -0
  190. package/dist/permissions/types.d.ts +6 -0
  191. package/dist/permissions/types.js +1 -0
  192. package/dist/permissions/utils/create-default-accountability.d.ts +2 -0
  193. package/dist/permissions/utils/create-default-accountability.js +11 -0
  194. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +8 -0
  195. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +27 -0
  196. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +9 -0
  197. package/dist/permissions/utils/fetch-dynamic-variable-context.js +43 -0
  198. package/dist/permissions/utils/filter-policies-by-ip.d.ts +2 -0
  199. package/dist/permissions/utils/filter-policies-by-ip.js +15 -0
  200. package/dist/permissions/utils/get-unaliased-field-key.d.ts +5 -0
  201. package/dist/permissions/utils/get-unaliased-field-key.js +17 -0
  202. package/dist/permissions/utils/process-permissions.d.ts +7 -0
  203. package/dist/permissions/utils/process-permissions.js +9 -0
  204. package/dist/permissions/utils/with-cache.d.ts +10 -0
  205. package/dist/permissions/utils/with-cache.js +25 -0
  206. package/dist/request/is-denied-ip.js +1 -1
  207. package/dist/server.js +1 -1
  208. package/dist/services/access.d.ts +10 -0
  209. package/dist/services/access.js +43 -0
  210. package/dist/services/activity.js +23 -11
  211. package/dist/services/assets.d.ts +2 -3
  212. package/dist/services/assets.js +11 -6
  213. package/dist/services/authentication.js +18 -18
  214. package/dist/services/collections.js +18 -17
  215. package/dist/services/fields.d.ts +0 -1
  216. package/dist/services/fields.js +53 -24
  217. package/dist/services/files/utils/get-metadata.js +1 -1
  218. package/dist/services/files.js +11 -4
  219. package/dist/services/graphql/index.d.ts +3 -3
  220. package/dist/services/graphql/index.js +126 -22
  221. package/dist/services/graphql/subscription.js +2 -4
  222. package/dist/services/graphql/utils/process-error.js +1 -1
  223. package/dist/services/graphql/utils/sanitize-gql-schema.js +1 -1
  224. package/dist/services/import-export.js +19 -5
  225. package/dist/services/index.d.ts +3 -2
  226. package/dist/services/index.js +3 -2
  227. package/dist/services/items.js +115 -44
  228. package/dist/services/mail/index.js +1 -1
  229. package/dist/services/meta.js +60 -23
  230. package/dist/services/notifications.js +15 -7
  231. package/dist/services/payload.d.ts +9 -10
  232. package/dist/services/payload.js +18 -3
  233. package/dist/services/{permissions/index.d.ts → permissions.d.ts} +5 -7
  234. package/dist/services/{permissions/index.js → permissions.js} +30 -54
  235. package/dist/services/policies.d.ts +12 -0
  236. package/dist/services/policies.js +87 -0
  237. package/dist/services/relations.d.ts +0 -6
  238. package/dist/services/relations.js +26 -29
  239. package/dist/services/roles.d.ts +4 -12
  240. package/dist/services/roles.js +57 -424
  241. package/dist/services/server.js +1 -1
  242. package/dist/services/shares.d.ts +0 -2
  243. package/dist/services/shares.js +13 -9
  244. package/dist/services/specifications.d.ts +2 -2
  245. package/dist/services/specifications.js +39 -27
  246. package/dist/services/tus/data-store.js +1 -1
  247. package/dist/services/users.d.ts +1 -5
  248. package/dist/services/users.js +79 -162
  249. package/dist/services/utils.js +11 -7
  250. package/dist/services/versions.d.ts +0 -2
  251. package/dist/services/versions.js +34 -10
  252. package/dist/services/webhooks.js +1 -1
  253. package/dist/telemetry/lib/get-report.js +2 -2
  254. package/dist/telemetry/lib/track.js +1 -1
  255. package/dist/telemetry/utils/check-user-limits.d.ts +5 -0
  256. package/dist/telemetry/utils/check-user-limits.js +19 -0
  257. package/dist/types/ast.d.ts +43 -1
  258. package/dist/types/items.d.ts +11 -0
  259. package/dist/utils/apply-diff.js +1 -1
  260. package/dist/utils/apply-query.d.ts +4 -3
  261. package/dist/utils/apply-query.js +37 -8
  262. package/dist/utils/delete-from-require-cache.js +1 -1
  263. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +17 -0
  264. package/dist/utils/fetch-user-count/fetch-access-lookup.js +22 -0
  265. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +16 -0
  266. package/dist/utils/fetch-user-count/fetch-access-roles.js +37 -0
  267. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +6 -0
  268. package/dist/utils/fetch-user-count/fetch-active-users.js +3 -0
  269. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +12 -0
  270. package/dist/utils/fetch-user-count/fetch-user-count.js +57 -0
  271. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +20 -0
  272. package/dist/utils/fetch-user-count/get-user-count-query.js +17 -0
  273. package/dist/utils/get-accountability-for-role.js +16 -25
  274. package/dist/utils/get-accountability-for-token.js +17 -16
  275. package/dist/utils/get-cache-key.d.ts +1 -1
  276. package/dist/utils/get-cache-key.js +12 -1
  277. package/dist/utils/get-column.d.ts +2 -1
  278. package/dist/utils/get-column.js +1 -0
  279. package/dist/utils/get-default-value.js +1 -1
  280. package/dist/utils/get-ip-from-req.js +1 -1
  281. package/dist/utils/get-schema.js +1 -1
  282. package/dist/utils/get-service.js +5 -1
  283. package/dist/utils/is-url-allowed.js +1 -1
  284. package/dist/utils/reduce-schema.d.ts +4 -6
  285. package/dist/utils/reduce-schema.js +16 -32
  286. package/dist/utils/sanitize-query.js +1 -1
  287. package/dist/utils/transaction.js +1 -1
  288. package/dist/utils/validate-env.js +1 -1
  289. package/dist/utils/validate-storage.js +1 -1
  290. package/dist/utils/validate-user-count-integrity.d.ts +13 -0
  291. package/dist/utils/validate-user-count-integrity.js +29 -0
  292. package/dist/websocket/authenticate.d.ts +0 -2
  293. package/dist/websocket/authenticate.js +0 -12
  294. package/dist/websocket/controllers/base.js +1 -1
  295. package/dist/websocket/controllers/graphql.js +2 -5
  296. package/dist/websocket/controllers/hooks.js +4 -0
  297. package/dist/websocket/controllers/rest.js +1 -3
  298. package/dist/websocket/errors.js +1 -1
  299. package/dist/websocket/handlers/subscribe.js +0 -2
  300. package/dist/websocket/utils/items.d.ts +1 -1
  301. package/package.json +24 -23
  302. package/dist/database/run-ast.js +0 -458
  303. package/dist/middleware/check-ip.d.ts +0 -2
  304. package/dist/middleware/check-ip.js +0 -37
  305. package/dist/middleware/get-permissions.d.ts +0 -3
  306. package/dist/middleware/get-permissions.js +0 -10
  307. package/dist/services/authorization.d.ts +0 -17
  308. package/dist/services/authorization.js +0 -456
  309. package/dist/services/permissions/lib/with-app-minimal-permissions.js +0 -13
  310. package/dist/telemetry/utils/check-increased-user-limits.d.ts +0 -7
  311. package/dist/telemetry/utils/check-increased-user-limits.js +0 -25
  312. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +0 -6
  313. package/dist/telemetry/utils/get-role-counts-by-roles.js +0 -27
  314. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +0 -11
  315. package/dist/telemetry/utils/get-role-counts-by-users.js +0 -34
  316. package/dist/telemetry/utils/get-user-count.d.ts +0 -8
  317. package/dist/telemetry/utils/get-user-count.js +0 -33
  318. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +0 -7
  319. package/dist/telemetry/utils/get-user-counts-by-roles.js +0 -35
  320. package/dist/utils/get-ast-from-query.d.ts +0 -13
  321. package/dist/utils/get-ast-from-query.js +0 -297
  322. package/dist/utils/get-permissions.d.ts +0 -2
  323. package/dist/utils/get-permissions.js +0 -150
  324. package/dist/utils/merge-permissions-for-share.d.ts +0 -4
  325. package/dist/utils/merge-permissions-for-share.js +0 -109
  326. package/dist/utils/merge-permissions.d.ts +0 -3
  327. package/dist/utils/merge-permissions.js +0 -95
  328. /package/dist/{logger.d.ts → logger/index.d.ts} +0 -0
@@ -0,0 +1,190 @@
1
+ import { REGEX_BETWEEN_PARENS } from '@directus/constants';
2
+ import { isEmpty } from 'lodash-es';
3
+ import { fetchPermissions } from '../../../permissions/lib/fetch-permissions.js';
4
+ import { fetchPolicies } from '../../../permissions/lib/fetch-policies.js';
5
+ import { getRelationType } from '../../../utils/get-relation-type.js';
6
+ import { getDeepQuery } from '../utils/get-deep-query.js';
7
+ import { getRelatedCollection } from '../utils/get-related-collection.js';
8
+ import { getRelation } from '../utils/get-relation.js';
9
+ import { convertWildcards } from './convert-wildcards.js';
10
+ export async function parseFields(options, context) {
11
+ let { fields } = options;
12
+ if (!fields)
13
+ return [];
14
+ fields = await convertWildcards({
15
+ fields,
16
+ parentCollection: options.parentCollection,
17
+ query: options.query,
18
+ accountability: options.accountability,
19
+ }, context);
20
+ if (!fields || !Array.isArray(fields))
21
+ return [];
22
+ const children = [];
23
+ const policies = options.accountability && options.accountability.admin === false
24
+ ? await fetchPolicies(options.accountability, context)
25
+ : null;
26
+ const relationalStructure = Object.create(null);
27
+ for (const fieldKey of fields) {
28
+ let name = fieldKey;
29
+ if (options.query.alias) {
30
+ // check for field alias (is one of the key)
31
+ if (name in options.query.alias) {
32
+ name = options.query.alias[fieldKey];
33
+ }
34
+ }
35
+ const isRelational = name.includes('.') ||
36
+ // We'll always treat top level o2m fields as a related item. This is an alias field, otherwise it won't return
37
+ // anything
38
+ !!context.schema.relations.find((relation) => relation.related_collection === options.parentCollection && relation.meta?.one_field === name);
39
+ if (isRelational) {
40
+ // field is relational
41
+ const parts = fieldKey.split('.');
42
+ let rootField = parts[0];
43
+ let collectionScope = null;
44
+ // a2o related collection scoped field selector `fields=sections.section_id:headings.title`
45
+ if (rootField.includes(':')) {
46
+ const [key, scope] = rootField.split(':');
47
+ rootField = key;
48
+ collectionScope = scope;
49
+ }
50
+ if (rootField in relationalStructure === false) {
51
+ if (collectionScope) {
52
+ relationalStructure[rootField] = { [collectionScope]: [] };
53
+ }
54
+ else {
55
+ relationalStructure[rootField] = [];
56
+ }
57
+ }
58
+ if (parts.length > 1) {
59
+ const childKey = parts.slice(1).join('.');
60
+ if (collectionScope) {
61
+ if (collectionScope in relationalStructure[rootField] === false) {
62
+ relationalStructure[rootField][collectionScope] = [];
63
+ }
64
+ relationalStructure[rootField][collectionScope].push(childKey);
65
+ }
66
+ else {
67
+ relationalStructure[rootField].push(childKey);
68
+ }
69
+ }
70
+ }
71
+ else {
72
+ if (name.includes('(') && name.includes(')')) {
73
+ const columnName = name.match(REGEX_BETWEEN_PARENS)[1];
74
+ const foundField = context.schema.collections[options.parentCollection].fields[columnName];
75
+ if (foundField && foundField.type === 'alias') {
76
+ const foundRelation = context.schema.relations.find((relation) => relation.related_collection === options.parentCollection && relation.meta?.one_field === columnName);
77
+ if (foundRelation) {
78
+ children.push({
79
+ type: 'functionField',
80
+ name,
81
+ fieldKey,
82
+ query: {},
83
+ relatedCollection: foundRelation.collection,
84
+ whenCase: [],
85
+ cases: [],
86
+ });
87
+ continue;
88
+ }
89
+ }
90
+ }
91
+ children.push({ type: 'field', name, fieldKey, whenCase: [] });
92
+ }
93
+ }
94
+ for (const [fieldKey, nestedFields] of Object.entries(relationalStructure)) {
95
+ let fieldName = fieldKey;
96
+ if (options.query.alias && fieldKey in options.query.alias) {
97
+ fieldName = options.query.alias[fieldKey];
98
+ }
99
+ const relatedCollection = getRelatedCollection(context.schema, options.parentCollection, fieldName);
100
+ const relation = getRelation(context.schema, options.parentCollection, fieldName);
101
+ if (!relation)
102
+ continue;
103
+ const relationType = getRelationType({
104
+ relation,
105
+ collection: options.parentCollection,
106
+ field: fieldName,
107
+ });
108
+ if (!relationType)
109
+ continue;
110
+ let child = null;
111
+ if (relationType === 'a2o') {
112
+ const allowedCollections = relation.meta.one_allowed_collections;
113
+ child = {
114
+ type: 'a2o',
115
+ names: allowedCollections,
116
+ children: {},
117
+ query: {},
118
+ relatedKey: {},
119
+ parentKey: context.schema.collections[options.parentCollection].primary,
120
+ fieldKey: fieldKey,
121
+ relation: relation,
122
+ cases: {},
123
+ whenCase: [],
124
+ };
125
+ for (const relatedCollection of allowedCollections) {
126
+ child.children[relatedCollection] = await parseFields({
127
+ parentCollection: relatedCollection,
128
+ fields: Array.isArray(nestedFields)
129
+ ? nestedFields
130
+ : nestedFields[relatedCollection] || [],
131
+ query: options.query,
132
+ deep: options.deep?.[`${fieldKey}:${relatedCollection}`],
133
+ accountability: options.accountability,
134
+ }, context);
135
+ child.query[relatedCollection] = getDeepQuery(options.deep?.[`${fieldKey}:${relatedCollection}`] || {});
136
+ child.relatedKey[relatedCollection] = context.schema.collections[relatedCollection].primary;
137
+ }
138
+ }
139
+ else if (relatedCollection) {
140
+ if (options.accountability && options.accountability.admin === false && policies) {
141
+ const permissions = await fetchPermissions({
142
+ action: 'read',
143
+ collections: [relatedCollection],
144
+ policies: policies,
145
+ accountability: options.accountability,
146
+ }, context);
147
+ // Skip related collection if no permissions
148
+ if (permissions.length === 0) {
149
+ continue;
150
+ }
151
+ }
152
+ // update query alias for children parseFields
153
+ const deepAlias = getDeepQuery(options.deep?.[fieldKey] || {})?.['alias'];
154
+ if (!isEmpty(deepAlias))
155
+ options.query.alias = deepAlias;
156
+ child = {
157
+ type: relationType,
158
+ name: relatedCollection,
159
+ fieldKey: fieldKey,
160
+ parentKey: context.schema.collections[options.parentCollection].primary,
161
+ relatedKey: context.schema.collections[relatedCollection].primary,
162
+ relation: relation,
163
+ query: getDeepQuery(options.deep?.[fieldKey] || {}),
164
+ children: await parseFields({
165
+ parentCollection: relatedCollection,
166
+ fields: nestedFields,
167
+ query: options.query,
168
+ deep: options.deep?.[fieldKey] || {},
169
+ accountability: options.accountability,
170
+ }, context),
171
+ cases: [],
172
+ whenCase: [],
173
+ };
174
+ if (relationType === 'o2m' && !child.query.sort) {
175
+ child.query.sort = [relation.meta?.sort_field || context.schema.collections[relation.collection].primary];
176
+ }
177
+ }
178
+ if (child) {
179
+ children.push(child);
180
+ }
181
+ }
182
+ // Deduplicate any children fields that are included both as a regular field, and as a nested m2o field
183
+ const nestedCollectionNodes = children.filter((childNode) => childNode.type !== 'field');
184
+ return children.filter((childNode) => {
185
+ const existsAsNestedRelational = !!nestedCollectionNodes.find((nestedCollectionNode) => childNode.fieldKey === nestedCollectionNode.fieldKey);
186
+ if (childNode.type === 'field' && existsAsNestedRelational)
187
+ return false;
188
+ return true;
189
+ });
190
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Convert Deep query object to regular query object by ignoring all nested fields and returning the
3
+ * `_` prefixed fields as top level query fields
4
+ *
5
+ * @example
6
+ *
7
+ * ```js
8
+ * getDeepQuery({
9
+ * _sort: ['a']
10
+ * });
11
+ * // => { sort: ['a'] }
12
+ * ```
13
+ */
14
+ export declare function getDeepQuery(query: Record<string, any>): Record<string, any>;
@@ -0,0 +1,17 @@
1
+ import { mapKeys, omitBy } from 'lodash-es';
2
+ /**
3
+ * Convert Deep query object to regular query object by ignoring all nested fields and returning the
4
+ * `_` prefixed fields as top level query fields
5
+ *
6
+ * @example
7
+ *
8
+ * ```js
9
+ * getDeepQuery({
10
+ * _sort: ['a']
11
+ * });
12
+ * // => { sort: ['a'] }
13
+ * ```
14
+ */
15
+ export function getDeepQuery(query) {
16
+ return mapKeys(omitBy(query, (_value, key) => key.startsWith('_') === false), (_value, key) => key.substring(1));
17
+ }
@@ -0,0 +1,2 @@
1
+ import type { SchemaOverview } from '@directus/types';
2
+ export declare function getRelatedCollection(schema: SchemaOverview, collection: string, field: string): string | null;
@@ -0,0 +1,13 @@
1
+ import { getRelation } from './get-relation.js';
2
+ export function getRelatedCollection(schema, collection, field) {
3
+ const relation = getRelation(schema, collection, field);
4
+ if (!relation)
5
+ return null;
6
+ if (relation.collection === collection && relation.field === field) {
7
+ return relation.related_collection || null;
8
+ }
9
+ if (relation.related_collection === collection && relation.meta?.one_field === field) {
10
+ return relation.collection || null;
11
+ }
12
+ return null;
13
+ }
@@ -0,0 +1,2 @@
1
+ import type { SchemaOverview } from '@directus/types';
2
+ export declare function getRelation(schema: SchemaOverview, collection: string, field: string): import("@directus/types").Relation | undefined;
@@ -0,0 +1,7 @@
1
+ export function getRelation(schema, collection, field) {
2
+ const relation = schema.relations.find((relation) => {
3
+ return ((relation.collection === collection && relation.field === field) ||
4
+ (relation.related_collection === collection && relation.meta?.one_field === field));
5
+ });
6
+ return relation;
7
+ }
@@ -1,9 +1,10 @@
1
- import type { Query, SchemaOverview } from '@directus/types';
1
+ import type { Filter, Query, SchemaOverview } from '@directus/types';
2
2
  import type { Knex } from 'knex';
3
3
  import { DatabaseHelper } from '../types.js';
4
4
  export type FnHelperOptions = {
5
5
  type: string | undefined;
6
6
  query: Query | undefined;
7
+ cases: Filter[] | undefined;
7
8
  originalCollectionName: string | undefined;
8
9
  };
9
10
  export declare abstract class FnHelper extends DatabaseHelper {
@@ -28,7 +28,7 @@ export class FnHelper extends DatabaseHelper {
28
28
  collection: relation.collection,
29
29
  },
30
30
  };
31
- countQuery = applyFilter(this.knex, this.schema, countQuery, options.query.filter, relation.collection, aliasMap).query;
31
+ countQuery = applyFilter(this.knex, this.schema, countQuery, options.query.filter, relation.collection, aliasMap, options.cases ?? []).query;
32
32
  }
33
33
  return this.knex.raw('(' + countQuery.toQuery() + ')');
34
34
  }
@@ -6,7 +6,7 @@ export declare class GeometryHelperMSSQL extends GeometryHelper {
6
6
  isTrue(expression: Knex.Raw): Knex.Raw<any>;
7
7
  isFalse(expression: Knex.Raw): Knex.Raw<any>;
8
8
  createColumn(table: Knex.CreateTableBuilder, field: RawField | Field): Knex.ColumnBuilder;
9
- asText(table: string, column: string): Knex.Raw;
9
+ asText(table: string, column: string, alias: string | false): Knex.Raw;
10
10
  fromText(text: string): Knex.Raw;
11
11
  _intersects(key: string, geojson: GeoJSONGeometry): Knex.Raw;
12
12
  _intersects_bbox(key: string, geojson: GeoJSONGeometry): Knex.Raw;
@@ -12,8 +12,10 @@ export class GeometryHelperMSSQL extends GeometryHelper {
12
12
  }
13
13
  return table.specificType(field.field, 'geometry');
14
14
  }
15
- asText(table, column) {
16
- return this.knex.raw('??.??.STAsText() as ??', [table, column, column]);
15
+ asText(table, column, alias) {
16
+ if (alias)
17
+ return this.knex.raw('??.??.STAsText() as ??', [table, column, alias]);
18
+ return this.knex.raw('??.??.STAsText()', [table, column]);
17
19
  }
18
20
  fromText(text) {
19
21
  return this.knex.raw('geometry::STGeomFromText(?, 4326)', text);
@@ -1,7 +1,7 @@
1
1
  import { GeometryHelper } from '../types.js';
2
2
  export class GeometryHelperMySQL extends GeometryHelper {
3
3
  collect(table, column) {
4
- return this.knex.raw(`concat('geometrycollection(', group_concat(? separator ', '), ')'`, this.asText(table, column));
4
+ return this.knex.raw(`concat('geometrycollection(', group_concat(? separator ', '), ')'`, this.asText(table, column, column));
5
5
  }
6
6
  fromText(text) {
7
7
  return this.knex.raw('st_geomfromtext(?)', text);
@@ -6,7 +6,7 @@ export declare class GeometryHelperOracle extends GeometryHelper {
6
6
  isTrue(expression: Knex.Raw): Knex.Raw<any>;
7
7
  isFalse(expression: Knex.Raw): Knex.Raw<any>;
8
8
  createColumn(table: Knex.CreateTableBuilder, field: RawField | Field): Knex.ColumnBuilder;
9
- asText(table: string, column: string): Knex.Raw;
9
+ asText(table: string, column: string, alias: string | false): Knex.Raw;
10
10
  asGeoJSON(table: string, column: string): Knex.Raw;
11
11
  fromText(text: string): Knex.Raw;
12
12
  _intersects(key: string, geojson: GeoJSONGeometry): Knex.Raw;
@@ -12,8 +12,10 @@ export class GeometryHelperOracle extends GeometryHelper {
12
12
  }
13
13
  return table.specificType(field.field, 'sdo_geometry');
14
14
  }
15
- asText(table, column) {
16
- return this.knex.raw('sdo_util.to_wktgeometry(??.??) as ??', [table, column, column]);
15
+ asText(table, column, alias) {
16
+ if (alias)
17
+ return this.knex.raw('sdo_util.to_wktgeometry(??.??) as ??', [table, column, alias]);
18
+ return this.knex.raw('sdo_util.to_wktgeometry(??.??)', [table, column]);
17
19
  }
18
20
  asGeoJSON(table, column) {
19
21
  return this.knex.raw('sdo_util.to_geojson(??.??) as ??', [table, column, column]);
@@ -30,6 +32,6 @@ export class GeometryHelperOracle extends GeometryHelper {
30
32
  return this.knex.raw(`sdo_overlapbdyintersect(sdo_geom.sdo_mbr(??), sdo_geom.sdo_mbr(?))`, [key, geometry]);
31
33
  }
32
34
  collect(table, column) {
33
- return this.knex.raw(`concat('geometrycollection(', listagg(?, ', '), ')'`, this.asText(table, column));
35
+ return this.knex.raw(`concat('geometrycollection(', listagg(?, ', '), ')'`, this.asText(table, column, column));
34
36
  }
35
37
  }
@@ -7,7 +7,7 @@ export declare abstract class GeometryHelper extends DatabaseHelper {
7
7
  isTrue(expression: Knex.Raw): Knex.Raw<any>;
8
8
  isFalse(expression: Knex.Raw): Knex.Raw<any>;
9
9
  createColumn(table: Knex.CreateTableBuilder, field: RawField | Field): Knex.ColumnBuilder;
10
- asText(table: string, column: string): Knex.Raw;
10
+ asText(table: string, column: string, alias: string | false): Knex.Raw;
11
11
  fromText(text: string): Knex.Raw;
12
12
  fromGeoJSON(geojson: GeoJSONGeometry): Knex.Raw;
13
13
  _intersects(key: string, geojson: GeoJSONGeometry): Knex.Raw;
@@ -14,8 +14,10 @@ export class GeometryHelper extends DatabaseHelper {
14
14
  const type = field.type.split('.')[1] ?? 'geometry';
15
15
  return table.specificType(field.field, type);
16
16
  }
17
- asText(table, column) {
18
- return this.knex.raw('st_astext(??.??) as ??', [table, column, column]);
17
+ asText(table, column, alias) {
18
+ if (alias)
19
+ return this.knex.raw('st_astext(??.??) as ??', [table, column, alias]);
20
+ return this.knex.raw('st_astext(??.??)', [table, column]);
19
21
  }
20
22
  fromText(text) {
21
23
  return this.knex.raw('st_geomfromtext(?, 4326)', text);
@@ -9,7 +9,7 @@ import path from 'path';
9
9
  import { performance } from 'perf_hooks';
10
10
  import { promisify } from 'util';
11
11
  import { getExtensionsPath } from '../extensions/lib/get-extensions-path.js';
12
- import { useLogger } from '../logger.js';
12
+ import { useLogger } from '../logger/index.js';
13
13
  import { getConfigFromEnv } from '../utils/get-config-from-env.js';
14
14
  import { validateEnv } from '../utils/validate-env.js';
15
15
  import { getHelpers } from './helpers/index.js';
@@ -106,6 +106,7 @@ export function getDatabase() {
106
106
  };
107
107
  }
108
108
  if (client === 'mysql') {
109
+ Object.assign(knexConfig, { client: 'mysql2' });
109
110
  poolConfig.afterCreate = async (conn, callback) => {
110
111
  logger.trace('Retrieving database version');
111
112
  const run = promisify(conn.query.bind(conn));
@@ -185,7 +186,7 @@ export async function validateDatabaseConnection(database) {
185
186
  export function getDatabaseClient(database) {
186
187
  database = database ?? getDatabase();
187
188
  switch (database.client.constructor.name) {
188
- case 'Client_MySQL':
189
+ case 'Client_MySQL2':
189
190
  return 'mysql';
190
191
  case 'Client_PG':
191
192
  return 'postgres';
@@ -1,5 +1,5 @@
1
1
  import { createInspector } from '@directus/schema';
2
- import { useLogger } from '../../logger.js';
2
+ import { useLogger } from '../../logger/index.js';
3
3
  import { getDefaultIndexName } from '../../utils/get-default-index-name.js';
4
4
  export async function up(knex) {
5
5
  const logger = useLogger();
@@ -1,5 +1,5 @@
1
1
  import { createInspector } from '@directus/schema';
2
- import { useLogger } from '../../logger.js';
2
+ import { useLogger } from '../../logger/index.js';
3
3
  /**
4
4
  * Things to keep in mind:
5
5
  *
@@ -1,5 +1,5 @@
1
1
  import { parseJSON } from '@directus/utils';
2
- import { useLogger } from '../../logger.js';
2
+ import { useLogger } from '../../logger/index.js';
3
3
  export async function up(knex) {
4
4
  const logger = useLogger();
5
5
  const dividerGroups = await knex.select('*').from('directus_fields').where('interface', '=', 'group-divider');
@@ -1,5 +1,5 @@
1
1
  import { createInspector } from '@directus/schema';
2
- import { useLogger } from '../../logger.js';
2
+ import { useLogger } from '../../logger/index.js';
3
3
  import { getHelpers } from '../helpers/index.js';
4
4
  export async function up(knex) {
5
5
  const helper = getHelpers(knex).schema;
@@ -0,0 +1,3 @@
1
+ import type { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
@@ -0,0 +1,169 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { processChunk } from '@directus/utils';
3
+ /**
4
+ * The public role used to be `null`, we gotta create a single new policy for the permissions
5
+ * previously attached to the public role (marked through `role = null`).
6
+ */
7
+ const PUBLIC_POLICY_ID = 'abf8a154-5b1c-4a46-ac9c-7300570f4f17';
8
+ export async function up(knex) {
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////
10
+ // If the policies table already exists the migration has already run
11
+ if (await knex.schema.hasTable('directus_policies')) {
12
+ return;
13
+ }
14
+ /////////////////////////////////////////////////////////////////////////////////////////////////
15
+ // Create new policies table that mirrors previous Roles
16
+ await knex.schema.createTable('directus_policies', (table) => {
17
+ table.uuid('id').primary();
18
+ table.string('name', 100).notNullable();
19
+ table.string('icon', 64).notNullable().defaultTo('badge');
20
+ table.text('description');
21
+ table.text('ip_access');
22
+ table.boolean('enforce_tfa').defaultTo(false).notNullable();
23
+ table.boolean('admin_access').defaultTo(false).notNullable();
24
+ table.boolean('app_access').defaultTo(false).notNullable();
25
+ });
26
+ /////////////////////////////////////////////////////////////////////////////////////////////////
27
+ // Copy over all existing roles into new policies
28
+ const roles = await knex
29
+ .select('id', 'name', 'icon', 'description', 'ip_access', 'enforce_tfa', 'admin_access', 'app_access')
30
+ .from('directus_roles');
31
+ if (roles.length > 0) {
32
+ await processChunk(roles, 100, async (chunk) => {
33
+ await knex('directus_policies').insert(chunk);
34
+ });
35
+ }
36
+ await knex
37
+ .insert({
38
+ id: PUBLIC_POLICY_ID,
39
+ name: '$t:public_label',
40
+ icon: 'public',
41
+ description: '$t:public_description',
42
+ app_access: false,
43
+ })
44
+ .into('directus_policies');
45
+ // Change the admin policy description to $t:admin_policy_description
46
+ await knex('directus_policies')
47
+ .update({
48
+ description: '$t:admin_policy_description',
49
+ })
50
+ .where('description', 'LIKE', '$t:admin_description');
51
+ /////////////////////////////////////////////////////////////////////////////////////////////////
52
+ // Remove access control + add nesting to roles
53
+ await knex.schema.alterTable('directus_roles', (table) => {
54
+ table.dropColumn('ip_access');
55
+ table.dropColumn('enforce_tfa');
56
+ table.dropColumn('admin_access');
57
+ table.dropColumn('app_access');
58
+ table.uuid('parent').references('directus_roles.id');
59
+ });
60
+ /////////////////////////////////////////////////////////////////////////////////////////////////
61
+ // Link permissions to policies instead of roles
62
+ await knex.schema.alterTable('directus_permissions', (table) => {
63
+ table.uuid('policy').references('directus_policies.id').onDelete('CASCADE');
64
+ // Drop the foreign key constraint here in order to update `null` role to public policy ID
65
+ table.dropForeign('role');
66
+ });
67
+ await knex('directus_permissions')
68
+ .update({
69
+ role: PUBLIC_POLICY_ID,
70
+ })
71
+ .whereNull('role');
72
+ await knex('directus_permissions').update({
73
+ policy: knex.ref('role'),
74
+ });
75
+ await knex.schema.alterTable('directus_permissions', (table) => {
76
+ table.dropColumns('role');
77
+ table.dropNullable('policy');
78
+ });
79
+ /////////////////////////////////////////////////////////////////////////////////////////////////
80
+ // Setup junction table between roles/users and policies
81
+ // This could be a A2O style setup with a collection/item field rather than individual foreign
82
+ // keys, but we want to be able to show the reverse-relationship on the individual policies as
83
+ // well, which would require the O2A type to exist in Directus which currently doesn't.
84
+ // Shouldn't be the end of the world here, as we know we're only attaching policies to two other
85
+ // collections.
86
+ await knex.schema.createTable('directus_access', (table) => {
87
+ table.uuid('id').primary();
88
+ table.uuid('role').references('directus_roles.id').nullable().onDelete('CASCADE');
89
+ table.uuid('user').references('directus_users.id').nullable().onDelete('CASCADE');
90
+ table.uuid('policy').references('directus_policies.id').notNullable().onDelete('CASCADE');
91
+ table.integer('sort');
92
+ });
93
+ /////////////////////////////////////////////////////////////////////////////////////////////////
94
+ // Attach policies to existing roles for backwards compatibility
95
+ const policyAttachments = roles.map((role) => ({
96
+ id: randomUUID(),
97
+ role: role.id,
98
+ user: null,
99
+ policy: role.id,
100
+ sort: 1,
101
+ }));
102
+ await processChunk(policyAttachments, 100, async (chunk) => {
103
+ await knex('directus_access').insert(chunk);
104
+ });
105
+ await knex('directus_access').insert({
106
+ id: randomUUID(),
107
+ role: null,
108
+ user: null,
109
+ policy: PUBLIC_POLICY_ID,
110
+ sort: 1,
111
+ });
112
+ }
113
+ export async function down(knex) {
114
+ /////////////////////////////////////////////////////////////////////////////////////////////////
115
+ // Reinstate access control fields on directus roles + remove nesting
116
+ await knex.schema.alterTable('directus_roles', (table) => {
117
+ table.text('ip_access');
118
+ table.boolean('enforce_tfa').defaultTo(false).notNullable();
119
+ table.boolean('admin_access').defaultTo(false).notNullable();
120
+ table.boolean('app_access').defaultTo(true).notNullable();
121
+ table.dropForeign('parent');
122
+ table.dropColumn('parent');
123
+ });
124
+ /////////////////////////////////////////////////////////////////////////////////////////////////
125
+ // Copy policy access control rules back to roles
126
+ const policies = await knex
127
+ .select('id', 'ip_access', 'enforce_tfa', 'admin_access', 'app_access')
128
+ .from('directus_policies')
129
+ .whereNot({ id: PUBLIC_POLICY_ID });
130
+ for (const policy of policies) {
131
+ await knex('directus_roles')
132
+ .update({
133
+ ip_access: policy.ip_access,
134
+ enforce_tfa: policy.enforce_tfa,
135
+ admin_access: policy.admin_access,
136
+ app_access: policy.app_access,
137
+ })
138
+ .where({ id: policy.id });
139
+ }
140
+ /////////////////////////////////////////////////////////////////////////////////////////////////
141
+ // Drop all permissions that are only attached to a user
142
+ // TODO query all policies that are attached to a user and delete their permissions,
143
+ // since we don't know were to put them now and it'll cause a foreign key problem
144
+ // as soon as we reference directus_roles in directus_permissions again
145
+ /////////////////////////////////////////////////////////////////////////////////////////////////
146
+ // Drop policy attachments
147
+ await knex.schema.dropTable('directus_access');
148
+ /////////////////////////////////////////////////////////////////////////////////////////////////
149
+ // Reattach permissions to roles instead of policies
150
+ await knex.schema.alterTable('directus_permissions', (table) => {
151
+ table.uuid('role').nullable();
152
+ });
153
+ await knex('directus_permissions').update({
154
+ role: knex.ref('policy'),
155
+ });
156
+ await knex('directus_permissions')
157
+ .update({
158
+ role: null,
159
+ })
160
+ .where({ role: PUBLIC_POLICY_ID });
161
+ await knex.schema.alterTable('directus_permissions', (table) => {
162
+ table.uuid('role').references('directus_roles.id').alter();
163
+ table.dropForeign('policy');
164
+ table.dropColumn('policy');
165
+ });
166
+ /////////////////////////////////////////////////////////////////////////////////////////////////
167
+ // Drop policies table
168
+ await knex.schema.dropTable('directus_policies');
169
+ }
@@ -6,7 +6,7 @@ import { dirname } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import path from 'path';
8
8
  import { flushCaches } from '../../cache.js';
9
- import { useLogger } from '../../logger.js';
9
+ import { useLogger } from '../../logger/index.js';
10
10
  import getModuleDefault from '../../utils/get-module-default.js';
11
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
12
  export default async function run(database, direction, log = true) {
@@ -0,0 +1,4 @@
1
+ import type { Filter, Query, SchemaOverview } from '@directus/types';
2
+ import type { Knex } from 'knex';
3
+ import type { FieldNode, FunctionFieldNode, O2MNode } from '../../../types/ast.js';
4
+ export declare function getDBQuery(schema: SchemaOverview, knex: Knex, table: string, fieldNodes: (FieldNode | FunctionFieldNode)[], o2mNodes: O2MNode[], query: Query, cases: Filter[]): Knex.QueryBuilder;