@directus/api 21.0.0 → 22.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 +4 -4
  2. package/dist/auth/drivers/ldap.js +4 -4
  3. package/dist/auth/drivers/local.js +4 -4
  4. package/dist/auth/drivers/oauth2.js +4 -4
  5. package/dist/auth/drivers/openid.js +2 -4
  6. package/dist/cache.js +3 -0
  7. package/dist/cli/commands/bootstrap/index.js +8 -2
  8. package/dist/cli/commands/init/index.js +9 -10
  9. package/dist/cli/utils/defaults.d.ts +4 -11
  10. package/dist/cli/utils/defaults.js +7 -1
  11. package/dist/constants.d.ts +1 -1
  12. package/dist/controllers/access.d.ts +2 -0
  13. package/dist/controllers/access.js +148 -0
  14. package/dist/controllers/auth.js +5 -16
  15. package/dist/controllers/permissions.js +14 -2
  16. package/dist/controllers/policies.d.ts +2 -0
  17. package/dist/controllers/policies.js +169 -0
  18. package/dist/controllers/roles.js +22 -1
  19. package/dist/controllers/tus.js +14 -26
  20. package/dist/controllers/users.js +0 -55
  21. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +16 -0
  22. package/dist/database/get-ast-from-query/get-ast-from-query.js +82 -0
  23. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +13 -0
  24. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +69 -0
  25. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +15 -0
  26. package/dist/database/get-ast-from-query/lib/parse-fields.js +200 -0
  27. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +14 -0
  28. package/dist/database/get-ast-from-query/utils/get-deep-query.js +17 -0
  29. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +2 -0
  30. package/dist/database/get-ast-from-query/utils/get-related-collection.js +13 -0
  31. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +2 -0
  32. package/dist/database/get-ast-from-query/utils/get-relation.js +7 -0
  33. package/dist/database/helpers/fn/types.d.ts +2 -1
  34. package/dist/database/helpers/fn/types.js +1 -1
  35. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  36. package/dist/database/helpers/geometry/dialects/mssql.js +4 -2
  37. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  38. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  39. package/dist/database/helpers/geometry/dialects/oracle.js +5 -3
  40. package/dist/database/helpers/geometry/types.d.ts +1 -1
  41. package/dist/database/helpers/geometry/types.js +4 -2
  42. package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +2 -1
  43. package/dist/database/helpers/schema/dialects/cockroachdb.js +4 -0
  44. package/dist/database/helpers/schema/dialects/mssql.d.ts +2 -1
  45. package/dist/database/helpers/schema/dialects/mssql.js +4 -0
  46. package/dist/database/helpers/schema/dialects/oracle.d.ts +2 -1
  47. package/dist/database/helpers/schema/dialects/oracle.js +4 -0
  48. package/dist/database/helpers/schema/dialects/postgres.d.ts +2 -1
  49. package/dist/database/helpers/schema/dialects/postgres.js +4 -0
  50. package/dist/database/helpers/schema/types.d.ts +5 -0
  51. package/dist/database/helpers/schema/types.js +3 -0
  52. package/dist/database/helpers/schema/utils/preprocess-bindings.d.ts +8 -0
  53. package/dist/database/helpers/schema/utils/preprocess-bindings.js +30 -0
  54. package/dist/database/index.js +6 -1
  55. package/dist/{utils/merge-permissions.d.ts → database/migrations/20240806A-permissions-policies.d.ts} +4 -1
  56. package/dist/database/migrations/20240806A-permissions-policies.js +338 -0
  57. package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
  58. package/dist/database/run-ast/lib/get-db-query.js +218 -0
  59. package/dist/database/run-ast/lib/parse-current-level.d.ts +7 -0
  60. package/dist/database/run-ast/lib/parse-current-level.js +41 -0
  61. package/dist/database/run-ast/run-ast.d.ts +7 -0
  62. package/dist/database/run-ast/run-ast.js +107 -0
  63. package/dist/database/{run-ast.d.ts → run-ast/types.d.ts} +3 -9
  64. package/dist/database/run-ast/types.js +1 -0
  65. package/dist/database/run-ast/utils/apply-case-when.d.ts +16 -0
  66. package/dist/database/run-ast/utils/apply-case-when.js +27 -0
  67. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +3 -0
  68. package/dist/database/run-ast/utils/apply-parent-filters.js +55 -0
  69. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +10 -0
  70. package/dist/database/run-ast/utils/get-column-pre-processor.js +57 -0
  71. package/dist/database/run-ast/utils/get-field-alias.d.ts +2 -0
  72. package/dist/database/run-ast/utils/get-field-alias.js +4 -0
  73. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +5 -0
  74. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +23 -0
  75. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +3 -0
  76. package/dist/database/run-ast/utils/merge-with-parent-items.js +87 -0
  77. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +3 -0
  78. package/dist/database/run-ast/utils/remove-temporary-fields.js +73 -0
  79. package/dist/database/run-ast/utils/with-preprocess-bindings.d.ts +2 -0
  80. package/dist/database/run-ast/utils/with-preprocess-bindings.js +14 -0
  81. package/dist/flows.js +3 -4
  82. package/dist/middleware/authenticate.js +2 -7
  83. package/dist/middleware/cache.js +1 -1
  84. package/dist/middleware/respond.js +1 -1
  85. package/dist/permissions/cache.d.ts +2 -0
  86. package/dist/permissions/cache.js +23 -0
  87. package/dist/permissions/lib/fetch-permissions.d.ts +11 -0
  88. package/dist/permissions/lib/fetch-permissions.js +56 -0
  89. package/dist/permissions/lib/fetch-policies.d.ts +14 -0
  90. package/dist/permissions/lib/fetch-policies.js +43 -0
  91. package/dist/permissions/lib/fetch-roles-tree.d.ts +3 -0
  92. package/dist/permissions/lib/fetch-roles-tree.js +28 -0
  93. package/dist/{services/permissions → permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  94. package/dist/permissions/lib/with-app-minimal-permissions.js +10 -0
  95. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +7 -0
  96. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +56 -0
  97. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +3 -0
  98. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +16 -0
  99. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +8 -0
  100. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +24 -0
  101. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +9 -0
  102. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +31 -0
  103. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +16 -0
  104. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +27 -0
  105. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +10 -0
  106. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +23 -0
  107. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +5 -0
  108. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +7 -0
  109. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +5 -0
  110. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +10 -0
  111. package/dist/permissions/modules/fetch-global-access/types.d.ts +4 -0
  112. package/dist/permissions/modules/fetch-global-access/types.js +1 -0
  113. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +4 -0
  114. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +27 -0
  115. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +12 -0
  116. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +32 -0
  117. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +4 -0
  118. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +29 -0
  119. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +4 -0
  120. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +49 -0
  121. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +3 -0
  122. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +56 -0
  123. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +4 -0
  124. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +8 -0
  125. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +9 -0
  126. package/dist/permissions/modules/process-ast/lib/inject-cases.js +93 -0
  127. package/dist/permissions/modules/process-ast/process-ast.d.ts +9 -0
  128. package/dist/permissions/modules/process-ast/process-ast.js +39 -0
  129. package/dist/permissions/modules/process-ast/types.d.ts +18 -0
  130. package/dist/permissions/modules/process-ast/types.js +1 -0
  131. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +2 -0
  132. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +7 -0
  133. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +12 -0
  134. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +30 -0
  135. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +15 -0
  136. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +60 -0
  137. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +3 -0
  138. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +9 -0
  139. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +3 -0
  140. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +34 -0
  141. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +1 -0
  142. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +3 -0
  143. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +5 -0
  144. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +7 -0
  145. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +2 -0
  146. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +3 -0
  147. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +2 -0
  148. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +3 -0
  149. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +3 -0
  150. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +16 -0
  151. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +2 -0
  152. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +12 -0
  153. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +2 -0
  154. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +28 -0
  155. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +5 -0
  156. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +12 -0
  157. package/dist/permissions/modules/process-payload/process-payload.d.ts +13 -0
  158. package/dist/permissions/modules/process-payload/process-payload.js +77 -0
  159. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +12 -0
  160. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +11 -0
  161. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +9 -0
  162. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +33 -0
  163. package/dist/permissions/modules/validate-access/validate-access.d.ts +14 -0
  164. package/dist/permissions/modules/validate-access/validate-access.js +28 -0
  165. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +1 -0
  166. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +8 -0
  167. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +5 -0
  168. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +10 -0
  169. package/dist/permissions/types.d.ts +6 -0
  170. package/dist/permissions/types.js +1 -0
  171. package/dist/permissions/utils/create-default-accountability.d.ts +2 -0
  172. package/dist/permissions/utils/create-default-accountability.js +11 -0
  173. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +8 -0
  174. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +27 -0
  175. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +9 -0
  176. package/dist/permissions/utils/fetch-dynamic-variable-context.js +43 -0
  177. package/dist/permissions/utils/filter-policies-by-ip.d.ts +2 -0
  178. package/dist/permissions/utils/filter-policies-by-ip.js +15 -0
  179. package/dist/permissions/utils/get-unaliased-field-key.d.ts +5 -0
  180. package/dist/permissions/utils/get-unaliased-field-key.js +17 -0
  181. package/dist/permissions/utils/process-permissions.d.ts +7 -0
  182. package/dist/permissions/utils/process-permissions.js +9 -0
  183. package/dist/permissions/utils/with-cache.d.ts +10 -0
  184. package/dist/permissions/utils/with-cache.js +25 -0
  185. package/dist/services/access.d.ts +10 -0
  186. package/dist/services/access.js +43 -0
  187. package/dist/services/activity.js +22 -10
  188. package/dist/services/assets.d.ts +2 -3
  189. package/dist/services/assets.js +10 -5
  190. package/dist/services/authentication.js +18 -18
  191. package/dist/services/collections.js +18 -17
  192. package/dist/services/fields.d.ts +0 -1
  193. package/dist/services/fields.js +54 -25
  194. package/dist/services/files.js +10 -3
  195. package/dist/services/graphql/index.d.ts +3 -3
  196. package/dist/services/graphql/index.js +126 -22
  197. package/dist/services/graphql/subscription.js +2 -4
  198. package/dist/services/import-export.d.ts +3 -1
  199. package/dist/services/import-export.js +67 -9
  200. package/dist/services/index.d.ts +3 -2
  201. package/dist/services/index.js +3 -2
  202. package/dist/services/items.js +115 -44
  203. package/dist/services/meta.js +60 -23
  204. package/dist/services/notifications.js +14 -6
  205. package/dist/services/payload.d.ts +9 -10
  206. package/dist/services/payload.js +18 -3
  207. package/dist/services/{permissions/index.d.ts → permissions.d.ts} +5 -7
  208. package/dist/services/{permissions/index.js → permissions.js} +30 -54
  209. package/dist/services/policies.d.ts +12 -0
  210. package/dist/services/policies.js +87 -0
  211. package/dist/services/relations.d.ts +0 -6
  212. package/dist/services/relations.js +27 -30
  213. package/dist/services/roles.d.ts +4 -12
  214. package/dist/services/roles.js +57 -424
  215. package/dist/services/shares.d.ts +0 -2
  216. package/dist/services/shares.js +12 -8
  217. package/dist/services/specifications.d.ts +2 -2
  218. package/dist/services/specifications.js +39 -27
  219. package/dist/services/users.d.ts +1 -5
  220. package/dist/services/users.js +78 -161
  221. package/dist/services/utils.js +11 -7
  222. package/dist/services/versions.d.ts +0 -2
  223. package/dist/services/versions.js +34 -10
  224. package/dist/telemetry/lib/get-report.js +2 -2
  225. package/dist/telemetry/utils/check-user-limits.d.ts +5 -0
  226. package/dist/telemetry/utils/check-user-limits.js +19 -0
  227. package/dist/types/ast.d.ts +43 -1
  228. package/dist/types/items.d.ts +11 -0
  229. package/dist/utils/apply-query.d.ts +11 -7
  230. package/dist/utils/apply-query.js +69 -11
  231. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +19 -0
  232. package/dist/utils/fetch-user-count/fetch-access-lookup.js +23 -0
  233. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +16 -0
  234. package/dist/utils/fetch-user-count/fetch-access-roles.js +37 -0
  235. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +6 -0
  236. package/dist/utils/fetch-user-count/fetch-active-users.js +3 -0
  237. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +12 -0
  238. package/dist/utils/fetch-user-count/fetch-user-count.js +64 -0
  239. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +20 -0
  240. package/dist/utils/fetch-user-count/get-user-count-query.js +17 -0
  241. package/dist/utils/get-accountability-for-role.js +16 -25
  242. package/dist/utils/get-accountability-for-token.js +17 -16
  243. package/dist/utils/get-cache-key.d.ts +1 -1
  244. package/dist/utils/get-cache-key.js +12 -1
  245. package/dist/utils/get-column.d.ts +2 -1
  246. package/dist/utils/get-column.js +1 -0
  247. package/dist/utils/get-service.js +5 -1
  248. package/dist/utils/reduce-schema.d.ts +4 -6
  249. package/dist/utils/reduce-schema.js +16 -32
  250. package/dist/utils/sanitize-schema.d.ts +1 -1
  251. package/dist/utils/validate-user-count-integrity.d.ts +13 -0
  252. package/dist/utils/validate-user-count-integrity.js +29 -0
  253. package/dist/websocket/authenticate.d.ts +0 -2
  254. package/dist/websocket/authenticate.js +0 -12
  255. package/dist/websocket/controllers/graphql.js +1 -4
  256. package/dist/websocket/controllers/hooks.js +4 -0
  257. package/dist/websocket/controllers/rest.js +0 -2
  258. package/dist/websocket/handlers/subscribe.js +0 -2
  259. package/dist/websocket/utils/items.d.ts +1 -1
  260. package/package.json +30 -29
  261. package/dist/database/run-ast.js +0 -458
  262. package/dist/middleware/check-ip.d.ts +0 -2
  263. package/dist/middleware/check-ip.js +0 -37
  264. package/dist/middleware/get-permissions.d.ts +0 -3
  265. package/dist/middleware/get-permissions.js +0 -10
  266. package/dist/services/authorization.d.ts +0 -17
  267. package/dist/services/authorization.js +0 -456
  268. package/dist/services/permissions/lib/with-app-minimal-permissions.js +0 -13
  269. package/dist/telemetry/utils/check-increased-user-limits.d.ts +0 -7
  270. package/dist/telemetry/utils/check-increased-user-limits.js +0 -25
  271. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +0 -6
  272. package/dist/telemetry/utils/get-role-counts-by-roles.js +0 -27
  273. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +0 -11
  274. package/dist/telemetry/utils/get-role-counts-by-users.js +0 -34
  275. package/dist/telemetry/utils/get-user-count.d.ts +0 -8
  276. package/dist/telemetry/utils/get-user-count.js +0 -33
  277. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +0 -7
  278. package/dist/telemetry/utils/get-user-counts-by-roles.js +0 -35
  279. package/dist/utils/get-ast-from-query.d.ts +0 -13
  280. package/dist/utils/get-ast-from-query.js +0 -297
  281. package/dist/utils/get-permissions.d.ts +0 -2
  282. package/dist/utils/get-permissions.js +0 -150
  283. package/dist/utils/merge-permissions-for-share.d.ts +0 -4
  284. package/dist/utils/merge-permissions-for-share.js +0 -109
  285. package/dist/utils/merge-permissions.js +0 -95
@@ -1,3 +1,5 @@
1
+ import { fetchRolesTree } from '../permissions/lib/fetch-roles-tree.js';
2
+ import { fetchGlobalAccess } from '../permissions/modules/fetch-global-access/fetch-global-access.js';
1
3
  import { Action } from '@directus/constants';
2
4
  import { useEnv } from '@directus/env';
3
5
  import { InvalidCredentialsError, InvalidOtpError, ServiceUnavailableError, UserSuspendedError, } from '@directus/errors';
@@ -48,10 +50,9 @@ export class AuthenticationService {
48
50
  throw err;
49
51
  }
50
52
  const user = await this.knex
51
- .select('u.id', 'u.first_name', 'u.last_name', 'u.email', 'u.password', 'u.status', 'u.role', 'r.admin_access', 'r.app_access', 'u.tfa_secret', 'u.provider', 'u.external_identifier', 'u.auth_data')
52
- .from('directus_users as u')
53
- .leftJoin('directus_roles as r', 'u.role', 'r.id')
54
- .where('u.id', userId)
53
+ .select('id', 'first_name', 'last_name', 'email', 'password', 'status', 'role', 'tfa_secret', 'provider', 'external_identifier', 'auth_data')
54
+ .from('directus_users')
55
+ .where('id', userId)
55
56
  .first();
56
57
  const updatedPayload = await emitter.emitFilter('auth.login', payload, {
57
58
  status: 'pending',
@@ -128,11 +129,13 @@ export class AuthenticationService {
128
129
  throw new InvalidOtpError();
129
130
  }
130
131
  }
132
+ const roles = await fetchRolesTree(user.role, this.knex);
133
+ const globalAccess = await fetchGlobalAccess({ roles, user: user.id, ip: this.accountability?.ip ?? null }, this.knex);
131
134
  const tokenPayload = {
132
135
  id: user.id,
133
136
  role: user.role,
134
- app_access: user.app_access,
135
- admin_access: user.admin_access,
137
+ app_access: globalAccess.app,
138
+ admin_access: globalAccess.admin,
136
139
  };
137
140
  const refreshToken = nanoid(64);
138
141
  const refreshTokenExpiration = new Date(Date.now() + getMilliseconds(env['REFRESH_TOKEN_TTL'], 0));
@@ -207,9 +210,7 @@ export class AuthenticationService {
207
210
  user_provider: 'u.provider',
208
211
  user_external_identifier: 'u.external_identifier',
209
212
  user_auth_data: 'u.auth_data',
210
- role_id: 'r.id',
211
- role_admin_access: 'r.admin_access',
212
- role_app_access: 'r.app_access',
213
+ user_role: 'u.role',
213
214
  share_id: 'd.id',
214
215
  share_item: 'd.item',
215
216
  share_role: 'd.role',
@@ -222,9 +223,6 @@ export class AuthenticationService {
222
223
  .from('directus_sessions AS s')
223
224
  .leftJoin('directus_users AS u', 's.user', 'u.id')
224
225
  .leftJoin('directus_shares AS d', 's.share', 'd.id')
225
- .leftJoin('directus_roles AS r', (join) => {
226
- join.onIn('r.id', [this.knex.ref('u.role'), this.knex.ref('d.role')]);
227
- })
228
226
  .where('s.token', refreshToken)
229
227
  .andWhere('s.expires', '>=', new Date())
230
228
  .andWhere((subQuery) => {
@@ -248,6 +246,8 @@ export class AuthenticationService {
248
246
  throw new InvalidCredentialsError();
249
247
  }
250
248
  }
249
+ const roles = await fetchRolesTree(record.user_role, this.knex);
250
+ const globalAccess = await fetchGlobalAccess({ user: record.user_id, roles, ip: this.accountability?.ip ?? null }, this.knex);
251
251
  if (record.user_id) {
252
252
  const provider = getAuthProvider(record.user_provider);
253
253
  await provider.refresh({
@@ -260,9 +260,9 @@ export class AuthenticationService {
260
260
  provider: record.user_provider,
261
261
  external_identifier: record.user_external_identifier,
262
262
  auth_data: record.user_auth_data,
263
- role: record.role_id,
264
- app_access: record.role_app_access,
265
- admin_access: record.role_admin_access,
263
+ role: record.user_role,
264
+ app_access: globalAccess.app,
265
+ admin_access: globalAccess.admin,
266
266
  });
267
267
  }
268
268
  let newRefreshToken = record.session_next_token ?? nanoid(64);
@@ -270,9 +270,9 @@ export class AuthenticationService {
270
270
  const refreshTokenExpiration = new Date(Date.now() + getMilliseconds(sessionDuration, 0));
271
271
  const tokenPayload = {
272
272
  id: record.user_id,
273
- role: record.role_id,
274
- app_access: record.role_app_access,
275
- admin_access: record.role_admin_access,
273
+ role: record.user_role,
274
+ app_access: globalAccess.app,
275
+ admin_access: globalAccess.admin,
276
276
  };
277
277
  if (options?.session) {
278
278
  newRefreshToken = await this.updateStatefulSession(record, refreshToken, newRefreshToken, refreshTokenExpiration);
@@ -9,6 +9,8 @@ import { ALIAS_TYPES } from '../constants.js';
9
9
  import { getHelpers } from '../database/helpers/index.js';
10
10
  import getDatabase, { getSchemaInspector } from '../database/index.js';
11
11
  import emitter from '../emitter.js';
12
+ import { fetchAllowedCollections } from '../permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js';
13
+ import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
12
14
  import { getSchema } from '../utils/get-schema.js';
13
15
  import { shouldClearCache } from '../utils/should-clear-cache.js';
14
16
  import { transaction } from '../utils/transaction.js';
@@ -223,11 +225,13 @@ export class CollectionsService {
223
225
  ...meta,
224
226
  [item.collection]: item.group,
225
227
  }), {});
226
- let collectionsYouHavePermissionToRead = this.accountability
227
- .permissions.filter((permission) => {
228
- return permission.action === 'read';
229
- })
230
- .map(({ collection }) => collection);
228
+ let collectionsYouHavePermissionToRead = await fetchAllowedCollections({
229
+ accountability: this.accountability,
230
+ action: 'read',
231
+ }, {
232
+ knex: this.knex,
233
+ schema: this.schema,
234
+ });
231
235
  for (const collection of collectionsYouHavePermissionToRead) {
232
236
  const group = collectionsGroups[collection];
233
237
  if (group)
@@ -279,18 +283,15 @@ export class CollectionsService {
279
283
  * Read many collections by name
280
284
  */
281
285
  async readMany(collectionKeys) {
282
- if (this.accountability && this.accountability.admin !== true) {
283
- const permissions = this.accountability.permissions.filter((permission) => {
284
- return permission.action === 'read' && collectionKeys.includes(permission.collection);
285
- });
286
- if (collectionKeys.length !== permissions.length) {
287
- const collectionsYouHavePermissionToRead = permissions.map(({ collection }) => collection);
288
- for (const collectionKey of collectionKeys) {
289
- if (collectionsYouHavePermissionToRead.includes(collectionKey) === false) {
290
- throw new ForbiddenError();
291
- }
292
- }
293
- }
286
+ if (this.accountability) {
287
+ await Promise.all(collectionKeys.map((collection) => validateAccess({
288
+ accountability: this.accountability,
289
+ action: 'read',
290
+ collection,
291
+ }, {
292
+ schema: this.schema,
293
+ knex: this.knex,
294
+ })));
294
295
  }
295
296
  const collections = await this.readByQuery();
296
297
  return collections.filter(({ collection }) => collectionKeys.includes(collection));
@@ -18,7 +18,6 @@ export declare class FieldsService {
18
18
  systemCache: Keyv<any>;
19
19
  schemaCache: Keyv<any>;
20
20
  constructor(options: AbstractServiceOptions);
21
- private get hasReadAccess();
22
21
  columnInfo(collection?: string): Promise<Column[]>;
23
22
  columnInfo(collection: string, field: string): Promise<Column>;
24
23
  readAll(collection?: string): Promise<Field[]>;
@@ -1,4 +1,5 @@
1
- import { KNEX_TYPES, REGEX_BETWEEN_PARENS, DEFAULT_NUMERIC_PRECISION, DEFAULT_NUMERIC_SCALE, } from '@directus/constants';
1
+ import { DEFAULT_NUMERIC_PRECISION, DEFAULT_NUMERIC_SCALE, KNEX_TYPES, REGEX_BETWEEN_PARENS, } from '@directus/constants';
2
+ import { useEnv } from '@directus/env';
2
3
  import { ForbiddenError, InvalidPayloadError } from '@directus/errors';
3
4
  import { createInspector } from '@directus/schema';
4
5
  import { addFieldFlag, toArray } from '@directus/utils';
@@ -9,6 +10,9 @@ import { translateDatabaseError } from '../database/errors/translate.js';
9
10
  import { getHelpers } from '../database/helpers/index.js';
10
11
  import getDatabase, { getSchemaInspector } from '../database/index.js';
11
12
  import emitter from '../emitter.js';
13
+ import { fetchPermissions } from '../permissions/lib/fetch-permissions.js';
14
+ import { fetchPolicies } from '../permissions/lib/fetch-policies.js';
15
+ import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
12
16
  import getDefaultValue from '../utils/get-default-value.js';
13
17
  import { getSystemFieldRowsWithAuthProviders } from '../utils/get-field-system-rows.js';
14
18
  import getLocalType from '../utils/get-local-type.js';
@@ -19,7 +23,6 @@ import { transaction } from '../utils/transaction.js';
19
23
  import { ItemsService } from './items.js';
20
24
  import { PayloadService } from './payload.js';
21
25
  import { RelationsService } from './relations.js';
22
- import { useEnv } from '@directus/env';
23
26
  const systemFieldRows = getSystemFieldRowsWithAuthProviders();
24
27
  const env = useEnv();
25
28
  export class FieldsService {
@@ -46,11 +49,6 @@ export class FieldsService {
46
49
  this.systemCache = systemCache;
47
50
  this.schemaCache = localSchemaCache;
48
51
  }
49
- get hasReadAccess() {
50
- return !!this.accountability?.permissions?.find((permission) => {
51
- return permission.collection === 'directus_fields' && permission.action === 'read';
52
- });
53
- }
54
52
  async columnInfo(collection, field) {
55
53
  const schemaCacheIsEnabled = Boolean(env['CACHE_SCHEMA']);
56
54
  let columnInfo = null;
@@ -73,8 +71,15 @@ export class FieldsService {
73
71
  }
74
72
  async readAll(collection) {
75
73
  let fields;
76
- if (this.accountability && this.accountability.admin !== true && this.hasReadAccess === false) {
77
- throw new ForbiddenError();
74
+ if (this.accountability) {
75
+ await validateAccess({
76
+ accountability: this.accountability,
77
+ action: 'read',
78
+ collection: 'directus_fields',
79
+ }, {
80
+ schema: this.schema,
81
+ knex: this.knex,
82
+ });
78
83
  }
79
84
  const nonAuthorizedItemsService = new ItemsService('directus_fields', {
80
85
  knex: this.knex,
@@ -143,12 +148,27 @@ export class FieldsService {
143
148
  const result = [...columnsWithSystem, ...aliasFieldsAsField].filter((field) => knownCollections.includes(field.collection));
144
149
  // Filter the result so we only return the fields you have read access to
145
150
  if (this.accountability && this.accountability.admin !== true) {
146
- const permissions = this.accountability.permissions.filter((permission) => {
147
- return permission.action === 'read';
148
- });
151
+ const policies = await fetchPolicies(this.accountability, { knex: this.knex, schema: this.schema });
152
+ const permissions = await fetchPermissions(collection
153
+ ? {
154
+ action: 'read',
155
+ policies,
156
+ collections: [collection],
157
+ accountability: this.accountability,
158
+ }
159
+ : {
160
+ action: 'read',
161
+ policies,
162
+ accountability: this.accountability,
163
+ }, { knex: this.knex, schema: this.schema });
149
164
  const allowedFieldsInCollection = {};
150
165
  permissions.forEach((permission) => {
151
- allowedFieldsInCollection[permission.collection] = permission.fields ?? [];
166
+ if (!allowedFieldsInCollection[permission.collection]) {
167
+ allowedFieldsInCollection[permission.collection] = new Set();
168
+ }
169
+ for (const field of permission.fields ?? []) {
170
+ allowedFieldsInCollection[permission.collection].add(field);
171
+ }
152
172
  });
153
173
  if (collection && collection in allowedFieldsInCollection === false) {
154
174
  throw new ForbiddenError();
@@ -157,9 +177,9 @@ export class FieldsService {
157
177
  if (field.collection in allowedFieldsInCollection === false)
158
178
  return false;
159
179
  const allowedFields = allowedFieldsInCollection[field.collection];
160
- if (allowedFields[0] === '*')
180
+ if (allowedFields.has('*'))
161
181
  return true;
162
- return allowedFields.includes(field.field);
182
+ return allowedFields.has(field.field);
163
183
  });
164
184
  }
165
185
  // Update specific database type overrides
@@ -176,18 +196,27 @@ export class FieldsService {
176
196
  }
177
197
  async readOne(collection, field) {
178
198
  if (this.accountability && this.accountability.admin !== true) {
179
- if (this.hasReadAccess === false) {
180
- throw new ForbiddenError();
181
- }
182
- const permissions = this.accountability.permissions.find((permission) => {
183
- return permission.action === 'read' && permission.collection === collection;
199
+ await validateAccess({
200
+ accountability: this.accountability,
201
+ action: 'read',
202
+ collection,
203
+ }, {
204
+ schema: this.schema,
205
+ knex: this.knex,
184
206
  });
185
- if (!permissions || !permissions.fields)
207
+ const policies = await fetchPolicies(this.accountability, { knex: this.knex, schema: this.schema });
208
+ const permissions = await fetchPermissions({ action: 'read', policies, collections: [collection], accountability: this.accountability }, { knex: this.knex, schema: this.schema });
209
+ let hasAccess = false;
210
+ for (const permission of permissions) {
211
+ if (permission.fields) {
212
+ if (permission.fields.includes('*') || permission.fields.includes(field)) {
213
+ hasAccess = true;
214
+ break;
215
+ }
216
+ }
217
+ }
218
+ if (!hasAccess) {
186
219
  throw new ForbiddenError();
187
- if (permissions.fields.includes('*') === false) {
188
- const allowedFields = permissions.fields;
189
- if (allowedFields.includes(field) === false)
190
- throw new ForbiddenError();
191
220
  }
192
221
  }
193
222
  let column = undefined;
@@ -12,6 +12,7 @@ import url from 'url';
12
12
  import { RESUMABLE_UPLOADS } from '../constants.js';
13
13
  import emitter from '../emitter.js';
14
14
  import { useLogger } from '../logger/index.js';
15
+ import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
15
16
  import { getAxios } from '../request/index.js';
16
17
  import { getStorage } from '../storage/index.js';
17
18
  import { extractMetadata } from './files/lib/extract-metadata.js';
@@ -157,9 +158,15 @@ export class FilesService extends ItemsService {
157
158
  * Import a single file from an external URL
158
159
  */
159
160
  async importOne(importURL, body) {
160
- const fileCreatePermissions = this.accountability?.permissions?.find((permission) => permission.collection === 'directus_files' && permission.action === 'create');
161
- if (this.accountability && this.accountability?.admin !== true && !fileCreatePermissions) {
162
- throw new ForbiddenError();
161
+ if (this.accountability) {
162
+ await validateAccess({
163
+ accountability: this.accountability,
164
+ action: 'create',
165
+ collection: 'directus_files',
166
+ }, {
167
+ knex: this.knex,
168
+ schema: this.schema,
169
+ });
163
170
  }
164
171
  let fileResponse;
165
172
  try {
@@ -20,9 +20,9 @@ export declare class GraphQLService {
20
20
  /**
21
21
  * Generate the GraphQL schema. Pulls from the schema information generated by the get-schema util.
22
22
  */
23
- getSchema(): GraphQLSchema;
24
- getSchema(type: 'schema'): GraphQLSchema;
25
- getSchema(type: 'sdl'): GraphQLSchema | string;
23
+ getSchema(): Promise<GraphQLSchema>;
24
+ getSchema(type: 'schema'): Promise<GraphQLSchema>;
25
+ getSchema(type: 'sdl'): Promise<GraphQLSchema | string>;
26
26
  /**
27
27
  * Generic resolver that's used for every "regular" items/system query. Converts the incoming GraphQL AST / fragments into
28
28
  * Directus' query structure which is then executed by the services.
@@ -11,6 +11,9 @@ import { clearSystemCache, getCache } from '../../cache.js';
11
11
  import { DEFAULT_AUTH_PROVIDER, GENERATE_SPECIAL, REFRESH_COOKIE_OPTIONS, SESSION_COOKIE_OPTIONS, } from '../../constants.js';
12
12
  import getDatabase from '../../database/index.js';
13
13
  import { rateLimiter } from '../../middleware/rate-limiter-registration.js';
14
+ import { fetchAllowedFieldMap } from '../../permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js';
15
+ import { fetchInconsistentFieldMap } from '../../permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js';
16
+ import { createDefaultAccountability } from '../../permissions/utils/create-default-accountability.js';
14
17
  import { generateHash } from '../../utils/generate-hash.js';
15
18
  import { getGraphQLType } from '../../utils/get-graphql-type.js';
16
19
  import { getIPFromReq } from '../../utils/get-ip-from-req.js';
@@ -48,6 +51,9 @@ import { GraphQLVoid } from './types/void.js';
48
51
  import { addPathToValidationError } from './utils/add-path-to-validation-error.js';
49
52
  import processError from './utils/process-error.js';
50
53
  import { sanitizeGraphqlSchema } from './utils/sanitize-gql-schema.js';
54
+ import { fetchAccountabilityCollectionAccess } from '../../permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js';
55
+ import { fetchAccountabilityPolicyGlobals } from '../../permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js';
56
+ import { RolesService } from '../roles.js';
51
57
  const env = useEnv();
52
58
  const validationRules = Array.from(specifiedRules);
53
59
  if (env['GRAPHQL_INTROSPECTION'] === false) {
@@ -80,7 +86,7 @@ export class GraphQLService {
80
86
  * Execute a GraphQL structure
81
87
  */
82
88
  async execute({ document, variables, operationName, contextValue, }) {
83
- const schema = this.getSchema();
89
+ const schema = await this.getSchema();
84
90
  const validationErrors = validate(schema, document, validationRules).map((validationError) => addPathToValidationError(validationError));
85
91
  if (validationErrors.length > 0) {
86
92
  throw new GraphQLValidationError({ errors: validationErrors });
@@ -108,7 +114,7 @@ export class GraphQLService {
108
114
  formattedResult.extensions = result['extensions'];
109
115
  return formattedResult;
110
116
  }
111
- getSchema(type = 'schema') {
117
+ async getSchema(type = 'schema') {
112
118
  const key = `${this.scope}_${type}_${this.accountability?.role}_${this.accountability?.user}`;
113
119
  const cachedSchema = cache.get(key);
114
120
  if (cachedSchema)
@@ -116,20 +122,53 @@ export class GraphQLService {
116
122
  // eslint-disable-next-line @typescript-eslint/no-this-alias
117
123
  const self = this;
118
124
  const schemaComposer = new SchemaComposer();
125
+ let schema;
119
126
  const sanitizedSchema = sanitizeGraphqlSchema(this.schema);
120
- const schema = {
121
- read: this.accountability?.admin === true
122
- ? sanitizedSchema
123
- : reduceSchema(sanitizedSchema, this.accountability?.permissions || null, ['read']),
124
- create: this.accountability?.admin === true
125
- ? sanitizedSchema
126
- : reduceSchema(sanitizedSchema, this.accountability?.permissions || null, ['create']),
127
- update: this.accountability?.admin === true
128
- ? sanitizedSchema
129
- : reduceSchema(sanitizedSchema, this.accountability?.permissions || null, ['update']),
130
- delete: this.accountability?.admin === true
131
- ? sanitizedSchema
132
- : reduceSchema(sanitizedSchema, this.accountability?.permissions || null, ['delete']),
127
+ if (!this.accountability || this.accountability.admin) {
128
+ schema = {
129
+ read: sanitizedSchema,
130
+ create: sanitizedSchema,
131
+ update: sanitizedSchema,
132
+ delete: sanitizedSchema,
133
+ };
134
+ }
135
+ else {
136
+ schema = {
137
+ read: reduceSchema(sanitizedSchema, await fetchAllowedFieldMap({
138
+ accountability: this.accountability,
139
+ action: 'read',
140
+ }, { schema: this.schema, knex: this.knex })),
141
+ create: reduceSchema(sanitizedSchema, await fetchAllowedFieldMap({
142
+ accountability: this.accountability,
143
+ action: 'create',
144
+ }, { schema: this.schema, knex: this.knex })),
145
+ update: reduceSchema(sanitizedSchema, await fetchAllowedFieldMap({
146
+ accountability: this.accountability,
147
+ action: 'update',
148
+ }, { schema: this.schema, knex: this.knex })),
149
+ delete: reduceSchema(sanitizedSchema, await fetchAllowedFieldMap({
150
+ accountability: this.accountability,
151
+ action: 'delete',
152
+ }, { schema: this.schema, knex: this.knex })),
153
+ };
154
+ }
155
+ const inconsistentFields = {
156
+ read: await fetchInconsistentFieldMap({
157
+ accountability: this.accountability,
158
+ action: 'read',
159
+ }, { schema: this.schema, knex: this.knex }),
160
+ create: await fetchInconsistentFieldMap({
161
+ accountability: this.accountability,
162
+ action: 'create',
163
+ }, { schema: this.schema, knex: this.knex }),
164
+ update: await fetchInconsistentFieldMap({
165
+ accountability: this.accountability,
166
+ action: 'update',
167
+ }, { schema: this.schema, knex: this.knex }),
168
+ delete: await fetchInconsistentFieldMap({
169
+ accountability: this.accountability,
170
+ action: 'delete',
171
+ }, { schema: this.schema, knex: this.knex }),
133
172
  };
134
173
  const subscriptionEventType = schemaComposer.createEnumTC({
135
174
  name: 'EventEnum',
@@ -300,16 +339,18 @@ export class GraphQLService {
300
339
  name: action === 'read' ? collection.collection : `${action}_${collection.collection}`,
301
340
  fields: Object.values(collection.fields).reduce((acc, field) => {
302
341
  let type = getGraphQLType(field.type, field.special);
342
+ const fieldIsInconsistent = inconsistentFields[action][collection.collection]?.includes(field.field);
303
343
  // GraphQL doesn't differentiate between not-null and has-to-be-submitted. We
304
344
  // can't non-null in update, as that would require every not-nullable field to be
305
345
  // submitted on updates
306
346
  if (field.nullable === false &&
307
347
  !field.defaultValue &&
308
348
  !GENERATE_SPECIAL.some((flag) => field.special.includes(flag)) &&
349
+ fieldIsInconsistent === false &&
309
350
  action !== 'update') {
310
351
  type = new GraphQLNonNull(type);
311
352
  }
312
- if (collection.primary === field.field) {
353
+ if (collection.primary === field.field && fieldIsInconsistent === false) {
313
354
  // permissions IDs need to be nullable https://github.com/directus/directus/issues/20509
314
355
  if (collection.collection === 'directus_permissions') {
315
356
  type = GraphQLID;
@@ -1762,7 +1803,7 @@ export class GraphQLService {
1762
1803
  accountability: this.accountability,
1763
1804
  scope: args['scope'] ?? 'items',
1764
1805
  });
1765
- return service.getSchema('sdl');
1806
+ return await service.getSchema('sdl');
1766
1807
  },
1767
1808
  },
1768
1809
  server_ping: {
@@ -1815,7 +1856,7 @@ export class GraphQLService {
1815
1856
  otp: GraphQLString,
1816
1857
  },
1817
1858
  resolve: async (_, args, { req, res }) => {
1818
- const accountability = { role: null };
1859
+ const accountability = createDefaultAccountability();
1819
1860
  if (req?.ip)
1820
1861
  accountability.ip = req.ip;
1821
1862
  const userAgent = req?.get('user-agent');
@@ -1855,7 +1896,7 @@ export class GraphQLService {
1855
1896
  mode: AuthMode,
1856
1897
  },
1857
1898
  resolve: async (_, args, { req, res }) => {
1858
- const accountability = { role: null };
1899
+ const accountability = createDefaultAccountability();
1859
1900
  if (req?.ip)
1860
1901
  accountability.ip = req.ip;
1861
1902
  const userAgent = req?.get('user-agent');
@@ -1913,7 +1954,7 @@ export class GraphQLService {
1913
1954
  mode: AuthMode,
1914
1955
  },
1915
1956
  resolve: async (_, args, { req, res }) => {
1916
- const accountability = { role: null };
1957
+ const accountability = createDefaultAccountability();
1917
1958
  if (req?.ip)
1918
1959
  accountability.ip = req.ip;
1919
1960
  const userAgent = req?.get('user-agent');
@@ -1963,7 +2004,7 @@ export class GraphQLService {
1963
2004
  reset_url: GraphQLString,
1964
2005
  },
1965
2006
  resolve: async (_, args, { req }) => {
1966
- const accountability = { role: null };
2007
+ const accountability = createDefaultAccountability();
1967
2008
  if (req?.ip)
1968
2009
  accountability.ip = req.ip;
1969
2010
  const userAgent = req?.get('user-agent');
@@ -1991,7 +2032,7 @@ export class GraphQLService {
1991
2032
  password: new GraphQLNonNull(GraphQLString),
1992
2033
  },
1993
2034
  resolve: async (_, args, { req }) => {
1994
- const accountability = { role: null };
2035
+ const accountability = createDefaultAccountability();
1995
2036
  if (req?.ip)
1996
2037
  accountability.ip = req.ip;
1997
2038
  const userAgent = req?.get('user-agent');
@@ -2632,6 +2673,69 @@ export class GraphQLService {
2632
2673
  },
2633
2674
  });
2634
2675
  }
2676
+ if ('directus_permissions' in schema.read.collections) {
2677
+ schemaComposer.Query.addFields({
2678
+ permissions_me: {
2679
+ type: schemaComposer.createScalarTC({
2680
+ name: 'permissions_me_type',
2681
+ parseValue: (value) => value,
2682
+ serialize: (value) => value,
2683
+ }),
2684
+ resolve: async (_, _args, __, _info) => {
2685
+ if (!this.accountability?.user && !this.accountability?.role)
2686
+ return null;
2687
+ const result = await fetchAccountabilityCollectionAccess(this.accountability, {
2688
+ schema: this.schema,
2689
+ knex: getDatabase(),
2690
+ });
2691
+ return result;
2692
+ },
2693
+ },
2694
+ });
2695
+ }
2696
+ if ('directus_roles' in schema.read.collections) {
2697
+ schemaComposer.Query.addFields({
2698
+ roles_me: {
2699
+ type: ReadCollectionTypes['directus_roles'].List,
2700
+ resolve: async (_, args, __, info) => {
2701
+ if (!this.accountability?.user && !this.accountability?.role)
2702
+ return null;
2703
+ const service = new RolesService({
2704
+ accountability: this.accountability,
2705
+ schema: this.schema,
2706
+ });
2707
+ const selections = this.replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
2708
+ const query = this.getQuery(args, selections || [], info.variableValues);
2709
+ query.limit = -1;
2710
+ const roles = await service.readMany(this.accountability.roles, query);
2711
+ return roles;
2712
+ },
2713
+ },
2714
+ });
2715
+ }
2716
+ if ('directus_policies' in schema.read.collections) {
2717
+ schemaComposer.Query.addFields({
2718
+ policies_me_globals: {
2719
+ type: schemaComposer.createObjectTC({
2720
+ name: 'policy_me_globals_type',
2721
+ fields: {
2722
+ enforce_tfa: 'Boolean',
2723
+ app_access: 'Boolean',
2724
+ admin_access: 'Boolean',
2725
+ },
2726
+ }),
2727
+ resolve: async (_, _args, __, _info) => {
2728
+ if (!this.accountability?.user && !this.accountability?.role)
2729
+ return null;
2730
+ const result = await fetchAccountabilityPolicyGlobals(this.accountability, {
2731
+ schema: this.schema,
2732
+ knex: getDatabase(),
2733
+ });
2734
+ return result;
2735
+ },
2736
+ },
2737
+ });
2738
+ }
2635
2739
  if ('directus_users' in schema.update.collections && this.accountability?.user) {
2636
2740
  schemaComposer.Mutation.addFields({
2637
2741
  update_users_me: {
@@ -1,7 +1,6 @@
1
1
  import { EventEmitter, on } from 'events';
2
2
  import { useBus } from '../../bus/index.js';
3
3
  import { getSchema } from '../../utils/get-schema.js';
4
- import { refreshAccountability } from '../../websocket/authenticate.js';
5
4
  import { getPayload } from '../../websocket/utils/items.js';
6
5
  const messages = createPubSub(new EventEmitter());
7
6
  export function bindPubSub() {
@@ -19,7 +18,6 @@ export function createSubscriptionGenerator(self, event) {
19
18
  if ('event' in args && eventData['action'] !== args['event']) {
20
19
  continue; // skip filtered events
21
20
  }
22
- const accountability = await refreshAccountability(self.accountability);
23
21
  const schema = await getSchema();
24
22
  const subscription = {
25
23
  collection: eventData['collection'],
@@ -35,7 +33,7 @@ export function createSubscriptionGenerator(self, event) {
35
33
  if (eventData['action'] === 'create') {
36
34
  try {
37
35
  subscription.item = eventData['key'];
38
- const result = await getPayload(subscription, accountability, schema, eventData);
36
+ const result = await getPayload(subscription, self.accountability, schema, eventData);
39
37
  yield {
40
38
  [event]: {
41
39
  key: eventData['key'],
@@ -52,7 +50,7 @@ export function createSubscriptionGenerator(self, event) {
52
50
  for (const key of eventData['keys']) {
53
51
  try {
54
52
  subscription.item = key;
55
- const result = await getPayload(subscription, accountability, schema, eventData);
53
+ const result = await getPayload(subscription, self.accountability, schema, eventData);
56
54
  yield {
57
55
  [event]: {
58
56
  key,
@@ -2,7 +2,7 @@
2
2
  import type { Accountability, File, Query, SchemaOverview } from '@directus/types';
3
3
  import type { Knex } from 'knex';
4
4
  import type { Readable } from 'node:stream';
5
- import type { AbstractServiceOptions } from '../types/index.js';
5
+ import type { AbstractServiceOptions, FunctionFieldNode, FieldNode, NestedCollectionNode } from '../types/index.js';
6
6
  type ExportFormat = 'csv' | 'json' | 'xml' | 'yaml';
7
7
  export declare class ImportService {
8
8
  knex: Knex;
@@ -32,6 +32,8 @@ export declare class ExportService {
32
32
  transform(input: Record<string, any>[], format: ExportFormat, options?: {
33
33
  includeHeader?: boolean;
34
34
  includeFooter?: boolean;
35
+ fields?: string[] | null;
35
36
  }): string;
36
37
  }
38
+ export declare function getHeadingsForCsvExport(nodes: (NestedCollectionNode | FieldNode | FunctionFieldNode)[] | undefined, prefix?: string): string[];
37
39
  export {};