@directus/api 20.0.0-rc.0 → 20.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/dist/app.js +9 -4
  2. package/dist/auth/drivers/ldap.js +4 -4
  3. package/dist/auth/drivers/local.js +4 -4
  4. package/dist/auth/drivers/oauth2.js +4 -4
  5. package/dist/auth/drivers/openid.js +4 -2
  6. package/dist/cache.js +0 -3
  7. package/dist/cli/commands/bootstrap/index.js +2 -8
  8. package/dist/cli/commands/init/index.js +10 -9
  9. package/dist/cli/utils/defaults.d.ts +11 -4
  10. package/dist/cli/utils/defaults.js +1 -7
  11. package/dist/constants.d.ts +9 -1
  12. package/dist/constants.js +10 -0
  13. package/dist/controllers/auth.js +16 -5
  14. package/dist/controllers/permissions.js +2 -14
  15. package/dist/controllers/roles.js +1 -22
  16. package/dist/controllers/{access.d.ts → tus.d.ts} +1 -0
  17. package/dist/controllers/tus.js +72 -0
  18. package/dist/controllers/users.js +55 -0
  19. package/dist/database/helpers/fn/types.d.ts +1 -2
  20. package/dist/database/helpers/fn/types.js +1 -1
  21. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  22. package/dist/database/helpers/geometry/dialects/mssql.js +2 -4
  23. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  24. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  25. package/dist/database/helpers/geometry/dialects/oracle.js +3 -5
  26. package/dist/database/helpers/geometry/types.d.ts +1 -1
  27. package/dist/database/helpers/geometry/types.js +2 -4
  28. package/dist/database/index.js +1 -2
  29. package/dist/database/migrations/20240701A-add-tus-data.js +12 -0
  30. package/dist/database/{run-ast/types.d.ts → run-ast.d.ts} +9 -3
  31. package/dist/database/run-ast.js +450 -0
  32. package/dist/flows.js +4 -3
  33. package/dist/middleware/authenticate.js +7 -2
  34. package/dist/middleware/cache.js +1 -1
  35. package/dist/middleware/check-ip.d.ts +2 -0
  36. package/dist/middleware/check-ip.js +37 -0
  37. package/dist/middleware/get-permissions.d.ts +3 -0
  38. package/dist/middleware/get-permissions.js +10 -0
  39. package/dist/middleware/respond.js +1 -1
  40. package/dist/services/activity.js +10 -22
  41. package/dist/services/assets.d.ts +3 -2
  42. package/dist/services/assets.js +5 -10
  43. package/dist/services/authentication.js +26 -32
  44. package/dist/services/authorization.d.ts +17 -0
  45. package/dist/services/authorization.js +456 -0
  46. package/dist/services/collections.js +17 -18
  47. package/dist/services/fields.d.ts +1 -0
  48. package/dist/services/fields.js +24 -53
  49. package/dist/services/files/lib/extract-metadata.d.ts +3 -0
  50. package/dist/services/files/lib/extract-metadata.js +32 -0
  51. package/dist/services/files/utils/get-metadata.d.ts +5 -0
  52. package/dist/services/files/utils/get-metadata.js +107 -0
  53. package/dist/services/files.d.ts +4 -6
  54. package/dist/services/files.js +24 -140
  55. package/dist/services/graphql/index.d.ts +3 -3
  56. package/dist/services/graphql/index.js +22 -126
  57. package/dist/services/graphql/subscription.js +4 -2
  58. package/dist/services/import-export.js +4 -18
  59. package/dist/services/index.d.ts +2 -3
  60. package/dist/services/index.js +2 -3
  61. package/dist/services/items.js +44 -115
  62. package/dist/services/meta.js +23 -60
  63. package/dist/services/payload.d.ts +10 -9
  64. package/dist/services/payload.js +3 -18
  65. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +7 -5
  66. package/dist/services/{permissions.js → permissions/index.js} +54 -30
  67. package/dist/{permissions → services/permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  68. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  69. package/dist/services/relations.d.ts +6 -0
  70. package/dist/services/relations.js +29 -26
  71. package/dist/services/roles.d.ts +12 -4
  72. package/dist/services/roles.js +424 -57
  73. package/dist/services/server.js +6 -0
  74. package/dist/services/shares.d.ts +2 -0
  75. package/dist/services/shares.js +8 -12
  76. package/dist/services/specifications.d.ts +2 -2
  77. package/dist/services/specifications.js +27 -39
  78. package/dist/services/tus/data-store.d.ts +36 -0
  79. package/dist/services/tus/data-store.js +214 -0
  80. package/dist/services/tus/index.d.ts +2 -0
  81. package/dist/services/tus/index.js +2 -0
  82. package/dist/services/tus/lockers.d.ts +36 -0
  83. package/dist/services/tus/lockers.js +83 -0
  84. package/dist/services/tus/server.d.ts +8 -0
  85. package/dist/services/tus/server.js +80 -0
  86. package/dist/services/tus/utils/wait-timeout.d.ts +1 -0
  87. package/dist/services/tus/utils/wait-timeout.js +13 -0
  88. package/dist/services/users.d.ts +5 -1
  89. package/dist/services/users.js +161 -78
  90. package/dist/services/utils.js +7 -11
  91. package/dist/services/versions.d.ts +2 -0
  92. package/dist/services/versions.js +10 -34
  93. package/dist/storage/register-locations.js +5 -1
  94. package/dist/telemetry/lib/get-report.js +2 -2
  95. package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
  96. package/dist/telemetry/utils/check-increased-user-limits.js +25 -0
  97. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
  98. package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
  99. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
  100. package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
  101. package/dist/telemetry/utils/get-user-count.d.ts +8 -0
  102. package/dist/telemetry/utils/get-user-count.js +33 -0
  103. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
  104. package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
  105. package/dist/types/ast.d.ts +1 -43
  106. package/dist/types/items.d.ts +0 -11
  107. package/dist/utils/apply-query.d.ts +3 -4
  108. package/dist/utils/apply-query.js +8 -37
  109. package/dist/utils/get-accountability-for-role.js +25 -16
  110. package/dist/utils/get-accountability-for-token.js +16 -17
  111. package/dist/utils/get-ast-from-query.d.ts +13 -0
  112. package/dist/utils/get-ast-from-query.js +297 -0
  113. package/dist/utils/get-cache-key.d.ts +1 -1
  114. package/dist/utils/get-cache-key.js +1 -12
  115. package/dist/utils/get-column.d.ts +1 -2
  116. package/dist/utils/get-column.js +0 -1
  117. package/dist/utils/get-permissions.d.ts +2 -0
  118. package/dist/utils/get-permissions.js +150 -0
  119. package/dist/utils/get-service.js +1 -5
  120. package/dist/utils/merge-permissions-for-share.d.ts +4 -0
  121. package/dist/utils/merge-permissions-for-share.js +109 -0
  122. package/dist/utils/merge-permissions.d.ts +3 -0
  123. package/dist/utils/merge-permissions.js +95 -0
  124. package/dist/utils/reduce-schema.d.ts +6 -4
  125. package/dist/utils/reduce-schema.js +34 -14
  126. package/dist/utils/verify-session-jwt.js +2 -1
  127. package/dist/websocket/authenticate.d.ts +2 -0
  128. package/dist/websocket/authenticate.js +12 -0
  129. package/dist/websocket/controllers/graphql.js +4 -1
  130. package/dist/websocket/controllers/hooks.js +0 -4
  131. package/dist/websocket/controllers/rest.js +2 -0
  132. package/dist/websocket/handlers/subscribe.js +2 -0
  133. package/dist/websocket/utils/items.d.ts +1 -1
  134. package/package.json +35 -33
  135. package/dist/controllers/access.js +0 -148
  136. package/dist/controllers/policies.d.ts +0 -2
  137. package/dist/controllers/policies.js +0 -169
  138. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +0 -16
  139. package/dist/database/get-ast-from-query/get-ast-from-query.js +0 -82
  140. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +0 -13
  141. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +0 -69
  142. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +0 -15
  143. package/dist/database/get-ast-from-query/lib/parse-fields.js +0 -190
  144. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +0 -14
  145. package/dist/database/get-ast-from-query/utils/get-deep-query.js +0 -17
  146. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +0 -2
  147. package/dist/database/get-ast-from-query/utils/get-related-collection.js +0 -13
  148. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +0 -2
  149. package/dist/database/get-ast-from-query/utils/get-relation.js +0 -7
  150. package/dist/database/migrations/20240619A-permissions-policies.js +0 -163
  151. package/dist/database/run-ast/lib/get-db-query.d.ts +0 -4
  152. package/dist/database/run-ast/lib/get-db-query.js +0 -194
  153. package/dist/database/run-ast/lib/parse-current-level.d.ts +0 -7
  154. package/dist/database/run-ast/lib/parse-current-level.js +0 -41
  155. package/dist/database/run-ast/run-ast.d.ts +0 -7
  156. package/dist/database/run-ast/run-ast.js +0 -107
  157. package/dist/database/run-ast/types.js +0 -1
  158. package/dist/database/run-ast/utils/apply-case-when.d.ts +0 -16
  159. package/dist/database/run-ast/utils/apply-case-when.js +0 -26
  160. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +0 -3
  161. package/dist/database/run-ast/utils/apply-parent-filters.js +0 -55
  162. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +0 -10
  163. package/dist/database/run-ast/utils/get-column-pre-processor.js +0 -57
  164. package/dist/database/run-ast/utils/get-field-alias.d.ts +0 -2
  165. package/dist/database/run-ast/utils/get-field-alias.js +0 -4
  166. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +0 -5
  167. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +0 -23
  168. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +0 -3
  169. package/dist/database/run-ast/utils/merge-with-parent-items.js +0 -87
  170. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +0 -3
  171. package/dist/database/run-ast/utils/remove-temporary-fields.js +0 -73
  172. package/dist/permissions/cache.d.ts +0 -2
  173. package/dist/permissions/cache.js +0 -23
  174. package/dist/permissions/lib/fetch-permissions.d.ts +0 -10
  175. package/dist/permissions/lib/fetch-permissions.js +0 -55
  176. package/dist/permissions/lib/fetch-policies.d.ts +0 -7
  177. package/dist/permissions/lib/fetch-policies.js +0 -28
  178. package/dist/permissions/lib/fetch-roles-tree.d.ts +0 -3
  179. package/dist/permissions/lib/fetch-roles-tree.js +0 -28
  180. package/dist/permissions/lib/with-app-minimal-permissions.js +0 -10
  181. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +0 -7
  182. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +0 -56
  183. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +0 -3
  184. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +0 -16
  185. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +0 -8
  186. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +0 -24
  187. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +0 -9
  188. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +0 -31
  189. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +0 -16
  190. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +0 -27
  191. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +0 -10
  192. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +0 -23
  193. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
  194. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
  195. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
  196. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
  197. package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
  198. package/dist/permissions/modules/fetch-global-access/types.js +0 -1
  199. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
  200. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
  201. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +0 -12
  202. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +0 -32
  203. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +0 -4
  204. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +0 -29
  205. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +0 -4
  206. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +0 -49
  207. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +0 -3
  208. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +0 -56
  209. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +0 -4
  210. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +0 -8
  211. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +0 -9
  212. package/dist/permissions/modules/process-ast/lib/inject-cases.js +0 -93
  213. package/dist/permissions/modules/process-ast/process-ast.d.ts +0 -9
  214. package/dist/permissions/modules/process-ast/process-ast.js +0 -39
  215. package/dist/permissions/modules/process-ast/types.d.ts +0 -24
  216. package/dist/permissions/modules/process-ast/types.js +0 -1
  217. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +0 -2
  218. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +0 -7
  219. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +0 -12
  220. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +0 -30
  221. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +0 -15
  222. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +0 -50
  223. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +0 -3
  224. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +0 -9
  225. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +0 -3
  226. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +0 -24
  227. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +0 -1
  228. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +0 -3
  229. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +0 -5
  230. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +0 -7
  231. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +0 -2
  232. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +0 -3
  233. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +0 -2
  234. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +0 -3
  235. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +0 -3
  236. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +0 -16
  237. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +0 -2
  238. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +0 -12
  239. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +0 -2
  240. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +0 -28
  241. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +0 -5
  242. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +0 -12
  243. package/dist/permissions/modules/process-payload/process-payload.d.ts +0 -13
  244. package/dist/permissions/modules/process-payload/process-payload.js +0 -77
  245. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +0 -12
  246. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +0 -11
  247. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +0 -9
  248. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +0 -33
  249. package/dist/permissions/modules/validate-access/validate-access.d.ts +0 -14
  250. package/dist/permissions/modules/validate-access/validate-access.js +0 -28
  251. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +0 -1
  252. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +0 -8
  253. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +0 -5
  254. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +0 -10
  255. package/dist/permissions/types.d.ts +0 -6
  256. package/dist/permissions/types.js +0 -1
  257. package/dist/permissions/utils/create-default-accountability.d.ts +0 -2
  258. package/dist/permissions/utils/create-default-accountability.js +0 -11
  259. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +0 -8
  260. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +0 -27
  261. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +0 -9
  262. package/dist/permissions/utils/fetch-dynamic-variable-context.js +0 -43
  263. package/dist/permissions/utils/filter-policies-by-ip.d.ts +0 -2
  264. package/dist/permissions/utils/filter-policies-by-ip.js +0 -15
  265. package/dist/permissions/utils/get-unaliased-field-key.d.ts +0 -5
  266. package/dist/permissions/utils/get-unaliased-field-key.js +0 -17
  267. package/dist/permissions/utils/process-permissions.d.ts +0 -7
  268. package/dist/permissions/utils/process-permissions.js +0 -9
  269. package/dist/permissions/utils/with-cache.d.ts +0 -10
  270. package/dist/permissions/utils/with-cache.js +0 -25
  271. package/dist/services/access.d.ts +0 -10
  272. package/dist/services/access.js +0 -43
  273. package/dist/services/policies.d.ts +0 -12
  274. package/dist/services/policies.js +0 -87
  275. package/dist/telemetry/utils/check-user-limits.d.ts +0 -5
  276. package/dist/telemetry/utils/check-user-limits.js +0 -19
  277. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +0 -17
  278. package/dist/utils/fetch-user-count/fetch-access-lookup.js +0 -22
  279. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +0 -16
  280. package/dist/utils/fetch-user-count/fetch-access-roles.js +0 -37
  281. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +0 -6
  282. package/dist/utils/fetch-user-count/fetch-active-users.js +0 -3
  283. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +0 -12
  284. package/dist/utils/fetch-user-count/fetch-user-count.js +0 -57
  285. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +0 -20
  286. package/dist/utils/fetch-user-count/get-user-count-query.js +0 -17
  287. package/dist/utils/validate-user-count-integrity.d.ts +0 -13
  288. package/dist/utils/validate-user-count-integrity.js +0 -29
  289. /package/dist/database/migrations/{20240619A-permissions-policies.d.ts → 20240701A-add-tus-data.d.ts} +0 -0
  290. /package/dist/{utils → services/files/utils}/parse-image-metadata.d.ts +0 -0
  291. /package/dist/{utils → services/files/utils}/parse-image-metadata.js +0 -0
@@ -0,0 +1,32 @@
1
+ import { SUPPORTED_IMAGE_METADATA_FORMATS } from '../../../constants.js';
2
+ import { getStorage } from '../../../storage/index.js';
3
+ import { getMetadata } from '../utils/get-metadata.js';
4
+ export async function extractMetadata(storageLocation, data) {
5
+ const storage = await getStorage();
6
+ const fileMeta = {};
7
+ if (data.type && SUPPORTED_IMAGE_METADATA_FORMATS.includes(data.type)) {
8
+ const stream = await storage.location(storageLocation).read(data.filename_disk);
9
+ const { height, width, description, title, tags, metadata } = await getMetadata(stream);
10
+ // Note that if this is a replace file upload, the below properties are fetched and included in the data above
11
+ // in the `existingFile` variable... so this will ONLY set the values if they're not already set
12
+ if (!data.height && height) {
13
+ fileMeta.height = height;
14
+ }
15
+ if (!data.width && width) {
16
+ fileMeta.width = width;
17
+ }
18
+ if (!data.metadata && metadata) {
19
+ fileMeta.metadata = metadata;
20
+ }
21
+ if (!data.description && description) {
22
+ fileMeta.description = description;
23
+ }
24
+ if (!data.title && title) {
25
+ fileMeta.title = title;
26
+ }
27
+ if (!data.tags && tags) {
28
+ fileMeta.tags = tags;
29
+ }
30
+ }
31
+ return fileMeta;
32
+ }
@@ -0,0 +1,5 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import type { File } from '@directus/types';
3
+ import type { Readable } from 'node:stream';
4
+ export type Metadata = Partial<Pick<File, 'height' | 'width' | 'description' | 'title' | 'tags' | 'metadata'>>;
5
+ export declare function getMetadata(stream: Readable, allowList?: string | string[]): Promise<Metadata>;
@@ -0,0 +1,107 @@
1
+ import exif, {} from 'exif-reader';
2
+ import { parse as parseIcc } from 'icc';
3
+ import { pick } from 'lodash-es';
4
+ import { pipeline } from 'node:stream/promises';
5
+ import sharp from 'sharp';
6
+ import { useEnv } from '@directus/env';
7
+ import { useLogger } from '../../../logger.js';
8
+ import { parseIptc, parseXmp } from './parse-image-metadata.js';
9
+ const env = useEnv();
10
+ const logger = useLogger();
11
+ export async function getMetadata(stream, allowList = env['FILE_METADATA_ALLOW_LIST']) {
12
+ return new Promise((resolve, reject) => {
13
+ pipeline(stream, sharp().metadata(async (err, sharpMetadata) => {
14
+ if (err) {
15
+ reject(err);
16
+ return;
17
+ }
18
+ const metadata = {};
19
+ if (sharpMetadata.orientation && sharpMetadata.orientation >= 5) {
20
+ metadata.height = sharpMetadata.width ?? null;
21
+ metadata.width = sharpMetadata.height ?? null;
22
+ }
23
+ else {
24
+ metadata.width = sharpMetadata.width ?? null;
25
+ metadata.height = sharpMetadata.height ?? null;
26
+ }
27
+ // Backward-compatible layout as it used to be with 'exifr'
28
+ const fullMetadata = {};
29
+ if (sharpMetadata.exif) {
30
+ try {
31
+ const { Image, ThumbnailTags, Iop, GPSInfo, Photo } = exif(sharpMetadata.exif);
32
+ if (Image) {
33
+ fullMetadata.ifd0 = Image;
34
+ }
35
+ if (ThumbnailTags) {
36
+ fullMetadata.ifd1 = ThumbnailTags;
37
+ }
38
+ if (Iop) {
39
+ fullMetadata.interop = Iop;
40
+ }
41
+ if (GPSInfo) {
42
+ fullMetadata.gps = GPSInfo;
43
+ }
44
+ if (Photo) {
45
+ fullMetadata.exif = Photo;
46
+ }
47
+ }
48
+ catch (err) {
49
+ logger.warn(`Couldn't extract Exif metadata from file`);
50
+ logger.warn(err);
51
+ }
52
+ }
53
+ if (sharpMetadata.icc) {
54
+ try {
55
+ fullMetadata.icc = parseIcc(sharpMetadata.icc);
56
+ }
57
+ catch (err) {
58
+ logger.warn(`Couldn't extract ICC profile data from file`);
59
+ logger.warn(err);
60
+ }
61
+ }
62
+ if (sharpMetadata.iptc) {
63
+ try {
64
+ fullMetadata.iptc = parseIptc(sharpMetadata.iptc);
65
+ }
66
+ catch (err) {
67
+ logger.warn(`Couldn't extract IPTC Photo Metadata from file`);
68
+ logger.warn(err);
69
+ }
70
+ }
71
+ if (sharpMetadata.xmp) {
72
+ try {
73
+ fullMetadata.xmp = parseXmp(sharpMetadata.xmp);
74
+ }
75
+ catch (err) {
76
+ logger.warn(`Couldn't extract XMP data from file`);
77
+ logger.warn(err);
78
+ }
79
+ }
80
+ if (fullMetadata?.iptc?.['Caption'] && typeof fullMetadata.iptc['Caption'] === 'string') {
81
+ metadata.description = fullMetadata.iptc?.['Caption'];
82
+ }
83
+ if (fullMetadata?.iptc?.['Headline'] && typeof fullMetadata.iptc['Headline'] === 'string') {
84
+ metadata.title = fullMetadata.iptc['Headline'];
85
+ }
86
+ if (fullMetadata?.iptc?.['Keywords']) {
87
+ metadata.tags = fullMetadata.iptc['Keywords'];
88
+ }
89
+ if (allowList === '*' || allowList?.[0] === '*') {
90
+ metadata.metadata = fullMetadata;
91
+ }
92
+ else {
93
+ metadata.metadata = pick(fullMetadata, allowList);
94
+ }
95
+ // Fix (incorrectly parsed?) values starting / ending with spaces,
96
+ // limited to one level and string values only
97
+ for (const section of Object.keys(metadata.metadata)) {
98
+ for (const [key, value] of Object.entries(metadata.metadata[section])) {
99
+ if (typeof value === 'string') {
100
+ metadata.metadata[section][key] = value.trim();
101
+ }
102
+ }
103
+ }
104
+ resolve(metadata);
105
+ }));
106
+ });
107
+ }
@@ -1,10 +1,9 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
- import type { BusboyFileStream, File, PrimaryKey } from '@directus/types';
2
+ import type { BusboyFileStream, File, PrimaryKey, Query } from '@directus/types';
3
3
  import type { Readable } from 'node:stream';
4
4
  import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
5
- import { ItemsService } from './items.js';
6
- type Metadata = Partial<Pick<File, 'height' | 'width' | 'description' | 'title' | 'tags' | 'metadata'>>;
7
- export declare class FilesService extends ItemsService {
5
+ import { ItemsService, type QueryOptions } from './items.js';
6
+ export declare class FilesService extends ItemsService<File> {
8
7
  constructor(options: AbstractServiceOptions);
9
8
  /**
10
9
  * Upload a single new file to the configured storage adapter
@@ -15,7 +14,6 @@ export declare class FilesService extends ItemsService {
15
14
  /**
16
15
  * Extract metadata from a buffer's content
17
16
  */
18
- getMetadata(stream: Readable, allowList?: string | string[]): Promise<Metadata>;
19
17
  /**
20
18
  * Import a single file from an external URL
21
19
  */
@@ -29,5 +27,5 @@ export declare class FilesService extends ItemsService {
29
27
  * Delete multiple files
30
28
  */
31
29
  deleteMany(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
30
+ readByQuery(query: Query, opts?: QueryOptions | undefined): Promise<File[]>;
32
31
  }
33
- export {};
@@ -3,23 +3,17 @@ import { ContentTooLargeError, ForbiddenError, InvalidPayloadError, ServiceUnava
3
3
  import formatTitle from '@directus/format-title';
4
4
  import { toArray } from '@directus/utils';
5
5
  import encodeURL from 'encodeurl';
6
- import exif, {} from 'exif-reader';
7
- import { parse as parseIcc } from 'icc';
8
- import { clone, pick } from 'lodash-es';
6
+ import { clone, cloneDeep } from 'lodash-es';
9
7
  import { extension } from 'mime-types';
10
8
  import { PassThrough as PassThroughStream, Transform as TransformStream } from 'node:stream';
11
- import { pipeline } from 'node:stream/promises';
12
9
  import zlib from 'node:zlib';
13
10
  import path from 'path';
14
- import sharp from 'sharp';
15
11
  import url from 'url';
16
- import { SUPPORTED_IMAGE_METADATA_FORMATS } from '../constants.js';
17
12
  import emitter from '../emitter.js';
18
13
  import { useLogger } from '../logger.js';
19
- import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
20
14
  import { getAxios } from '../request/index.js';
21
15
  import { getStorage } from '../storage/index.js';
22
- import { parseIptc, parseXmp } from '../utils/parse-image-metadata.js';
16
+ import { extractMetadata } from './files/lib/extract-metadata.js';
23
17
  import { ItemsService } from './items.js';
24
18
  const env = useEnv();
25
19
  const logger = useLogger();
@@ -61,7 +55,7 @@ export class FilesService extends ItemsService {
61
55
  }
62
56
  const fileExtension = path.extname(payload.filename_download) || (payload.type && '.' + extension(payload.type)) || '';
63
57
  // The filename_disk is the FINAL filename on disk
64
- payload.filename_disk = primaryKey + (fileExtension || '');
58
+ payload.filename_disk ||= primaryKey + (fileExtension || '');
65
59
  // Temp filename is used for replacements
66
60
  const tempFilenameDisk = 'temp_' + payload.filename_disk;
67
61
  if (!payload.type) {
@@ -129,37 +123,14 @@ export class FilesService extends ItemsService {
129
123
  }
130
124
  const { size } = await storage.location(data.storage).stat(payload.filename_disk);
131
125
  payload.filesize = size;
132
- if (SUPPORTED_IMAGE_METADATA_FORMATS.includes(payload.type)) {
133
- const stream = await storage.location(data.storage).read(payload.filename_disk);
134
- const { height, width, description, title, tags, metadata } = await this.getMetadata(stream);
135
- if (!payload.height && height) {
136
- payload.height = height;
137
- }
138
- if (!payload.width && width) {
139
- payload.width = width;
140
- }
141
- if (!payload.metadata && metadata) {
142
- payload.metadata = metadata;
143
- }
144
- // Note that if this is a replace file upload, the below properties are fetched and included in the payload above
145
- // in the `existingFile` variable... so this will ONLY set the values if they're not already set
146
- if (!payload.description && description) {
147
- payload.description = description;
148
- }
149
- if (!payload.title && title) {
150
- payload.title = title;
151
- }
152
- if (!payload.tags && tags) {
153
- payload.tags = tags;
154
- }
155
- }
126
+ const metadata = await extractMetadata(data.storage, payload);
156
127
  // We do this in a service without accountability. Even if you don't have update permissions to the file,
157
128
  // we still want to be able to set the extracted values from the file on create
158
129
  const sudoService = new ItemsService('directus_files', {
159
130
  knex: this.knex,
160
131
  schema: this.schema,
161
132
  });
162
- await sudoService.updateOne(primaryKey, payload, { emitEvents: false });
133
+ await sudoService.updateOne(primaryKey, { ...payload, ...metadata }, { emitEvents: false });
163
134
  if (opts?.emitEvents !== false) {
164
135
  emitter.emitAction('files.upload', {
165
136
  payload,
@@ -176,116 +147,13 @@ export class FilesService extends ItemsService {
176
147
  /**
177
148
  * Extract metadata from a buffer's content
178
149
  */
179
- async getMetadata(stream, allowList = env['FILE_METADATA_ALLOW_LIST']) {
180
- return new Promise((resolve, reject) => {
181
- pipeline(stream, sharp().metadata(async (err, sharpMetadata) => {
182
- if (err) {
183
- reject(err);
184
- return;
185
- }
186
- const metadata = {};
187
- if (sharpMetadata.orientation && sharpMetadata.orientation >= 5) {
188
- metadata.height = sharpMetadata.width ?? null;
189
- metadata.width = sharpMetadata.height ?? null;
190
- }
191
- else {
192
- metadata.width = sharpMetadata.width ?? null;
193
- metadata.height = sharpMetadata.height ?? null;
194
- }
195
- // Backward-compatible layout as it used to be with 'exifr'
196
- const fullMetadata = {};
197
- if (sharpMetadata.exif) {
198
- try {
199
- const { Image, ThumbnailTags, Iop, GPSInfo, Photo } = exif(sharpMetadata.exif);
200
- if (Image) {
201
- fullMetadata.ifd0 = Image;
202
- }
203
- if (ThumbnailTags) {
204
- fullMetadata.ifd1 = ThumbnailTags;
205
- }
206
- if (Iop) {
207
- fullMetadata.interop = Iop;
208
- }
209
- if (GPSInfo) {
210
- fullMetadata.gps = GPSInfo;
211
- }
212
- if (Photo) {
213
- fullMetadata.exif = Photo;
214
- }
215
- }
216
- catch (err) {
217
- logger.warn(`Couldn't extract Exif metadata from file`);
218
- logger.warn(err);
219
- }
220
- }
221
- if (sharpMetadata.icc) {
222
- try {
223
- fullMetadata.icc = parseIcc(sharpMetadata.icc);
224
- }
225
- catch (err) {
226
- logger.warn(`Couldn't extract ICC profile data from file`);
227
- logger.warn(err);
228
- }
229
- }
230
- if (sharpMetadata.iptc) {
231
- try {
232
- fullMetadata.iptc = parseIptc(sharpMetadata.iptc);
233
- }
234
- catch (err) {
235
- logger.warn(`Couldn't extract IPTC Photo Metadata from file`);
236
- logger.warn(err);
237
- }
238
- }
239
- if (sharpMetadata.xmp) {
240
- try {
241
- fullMetadata.xmp = parseXmp(sharpMetadata.xmp);
242
- }
243
- catch (err) {
244
- logger.warn(`Couldn't extract XMP data from file`);
245
- logger.warn(err);
246
- }
247
- }
248
- if (fullMetadata?.iptc?.['Caption'] && typeof fullMetadata.iptc['Caption'] === 'string') {
249
- metadata.description = fullMetadata.iptc?.['Caption'];
250
- }
251
- if (fullMetadata?.iptc?.['Headline'] && typeof fullMetadata.iptc['Headline'] === 'string') {
252
- metadata.title = fullMetadata.iptc['Headline'];
253
- }
254
- if (fullMetadata?.iptc?.['Keywords']) {
255
- metadata.tags = fullMetadata.iptc['Keywords'];
256
- }
257
- if (allowList === '*' || allowList?.[0] === '*') {
258
- metadata.metadata = fullMetadata;
259
- }
260
- else {
261
- metadata.metadata = pick(fullMetadata, allowList);
262
- }
263
- // Fix (incorrectly parsed?) values starting / ending with spaces,
264
- // limited to one level and string values only
265
- for (const section of Object.keys(metadata.metadata)) {
266
- for (const [key, value] of Object.entries(metadata.metadata[section])) {
267
- if (typeof value === 'string') {
268
- metadata.metadata[section][key] = value.trim();
269
- }
270
- }
271
- }
272
- resolve(metadata);
273
- }));
274
- });
275
- }
276
150
  /**
277
151
  * Import a single file from an external URL
278
152
  */
279
153
  async importOne(importURL, body) {
280
- if (this.accountability) {
281
- await validateAccess({
282
- accountability: this.accountability,
283
- action: 'create',
284
- collection: 'directus_files',
285
- }, {
286
- knex: this.knex,
287
- schema: this.schema,
288
- });
154
+ const fileCreatePermissions = this.accountability?.permissions?.find((permission) => permission.collection === 'directus_files' && permission.action === 'create');
155
+ if (this.accountability && this.accountability?.admin !== true && !fileCreatePermissions) {
156
+ throw new ForbiddenError();
289
157
  }
290
158
  let fileResponse;
291
159
  try {
@@ -345,6 +213,22 @@ export class FilesService extends ItemsService {
345
213
  }
346
214
  return keys;
347
215
  }
216
+ async readByQuery(query, opts) {
217
+ const filteredQuery = cloneDeep(query);
218
+ const filterPartialUploads = { tus_id: { _null: true } };
219
+ if (!filteredQuery.filter) {
220
+ filteredQuery.filter = filterPartialUploads;
221
+ }
222
+ else if ('_and' in filteredQuery.filter && Array.isArray(filteredQuery.filter['_and'])) {
223
+ filteredQuery.filter['_and'].push(filterPartialUploads);
224
+ }
225
+ else {
226
+ filteredQuery.filter = {
227
+ _and: [filteredQuery.filter, filterPartialUploads],
228
+ };
229
+ }
230
+ return super.readByQuery(filteredQuery, opts);
231
+ }
348
232
  }
349
233
  function decompressResponse(stream, headers) {
350
234
  const contentEncoding = (headers['content-encoding'] || '').toLowerCase();
@@ -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(): Promise<GraphQLSchema>;
24
- getSchema(type: 'schema'): Promise<GraphQLSchema>;
25
- getSchema(type: 'sdl'): Promise<GraphQLSchema | string>;
23
+ getSchema(): GraphQLSchema;
24
+ getSchema(type: 'schema'): GraphQLSchema;
25
+ getSchema(type: 'sdl'): 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,9 +11,6 @@ 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';
17
14
  import { generateHash } from '../../utils/generate-hash.js';
18
15
  import { getGraphQLType } from '../../utils/get-graphql-type.js';
19
16
  import { getIPFromReq } from '../../utils/get-ip-from-req.js';
@@ -51,9 +48,6 @@ import { GraphQLVoid } from './types/void.js';
51
48
  import { addPathToValidationError } from './utils/add-path-to-validation-error.js';
52
49
  import processError from './utils/process-error.js';
53
50
  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';
57
51
  const env = useEnv();
58
52
  const validationRules = Array.from(specifiedRules);
59
53
  if (env['GRAPHQL_INTROSPECTION'] === false) {
@@ -86,7 +80,7 @@ export class GraphQLService {
86
80
  * Execute a GraphQL structure
87
81
  */
88
82
  async execute({ document, variables, operationName, contextValue, }) {
89
- const schema = await this.getSchema();
83
+ const schema = this.getSchema();
90
84
  const validationErrors = validate(schema, document, validationRules).map((validationError) => addPathToValidationError(validationError));
91
85
  if (validationErrors.length > 0) {
92
86
  throw new GraphQLValidationError({ errors: validationErrors });
@@ -114,7 +108,7 @@ export class GraphQLService {
114
108
  formattedResult.extensions = result['extensions'];
115
109
  return formattedResult;
116
110
  }
117
- async getSchema(type = 'schema') {
111
+ getSchema(type = 'schema') {
118
112
  const key = `${this.scope}_${type}_${this.accountability?.role}_${this.accountability?.user}`;
119
113
  const cachedSchema = cache.get(key);
120
114
  if (cachedSchema)
@@ -122,53 +116,20 @@ export class GraphQLService {
122
116
  // eslint-disable-next-line @typescript-eslint/no-this-alias
123
117
  const self = this;
124
118
  const schemaComposer = new SchemaComposer();
125
- let schema;
126
119
  const sanitizedSchema = sanitizeGraphqlSchema(this.schema);
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 }),
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']),
172
133
  };
173
134
  const subscriptionEventType = schemaComposer.createEnumTC({
174
135
  name: 'EventEnum',
@@ -339,18 +300,16 @@ export class GraphQLService {
339
300
  name: action === 'read' ? collection.collection : `${action}_${collection.collection}`,
340
301
  fields: Object.values(collection.fields).reduce((acc, field) => {
341
302
  let type = getGraphQLType(field.type, field.special);
342
- const fieldIsInconsistent = inconsistentFields[action][collection.collection]?.includes(field.field);
343
303
  // GraphQL doesn't differentiate between not-null and has-to-be-submitted. We
344
304
  // can't non-null in update, as that would require every not-nullable field to be
345
305
  // submitted on updates
346
306
  if (field.nullable === false &&
347
307
  !field.defaultValue &&
348
308
  !GENERATE_SPECIAL.some((flag) => field.special.includes(flag)) &&
349
- fieldIsInconsistent === false &&
350
309
  action !== 'update') {
351
310
  type = new GraphQLNonNull(type);
352
311
  }
353
- if (collection.primary === field.field && fieldIsInconsistent === false) {
312
+ if (collection.primary === field.field) {
354
313
  // permissions IDs need to be nullable https://github.com/directus/directus/issues/20509
355
314
  if (collection.collection === 'directus_permissions') {
356
315
  type = GraphQLID;
@@ -1803,7 +1762,7 @@ export class GraphQLService {
1803
1762
  accountability: this.accountability,
1804
1763
  scope: args['scope'] ?? 'items',
1805
1764
  });
1806
- return await service.getSchema('sdl');
1765
+ return service.getSchema('sdl');
1807
1766
  },
1808
1767
  },
1809
1768
  server_ping: {
@@ -1856,7 +1815,7 @@ export class GraphQLService {
1856
1815
  otp: GraphQLString,
1857
1816
  },
1858
1817
  resolve: async (_, args, { req, res }) => {
1859
- const accountability = createDefaultAccountability();
1818
+ const accountability = { role: null };
1860
1819
  if (req?.ip)
1861
1820
  accountability.ip = req.ip;
1862
1821
  const userAgent = req?.get('user-agent');
@@ -1896,7 +1855,7 @@ export class GraphQLService {
1896
1855
  mode: AuthMode,
1897
1856
  },
1898
1857
  resolve: async (_, args, { req, res }) => {
1899
- const accountability = createDefaultAccountability();
1858
+ const accountability = { role: null };
1900
1859
  if (req?.ip)
1901
1860
  accountability.ip = req.ip;
1902
1861
  const userAgent = req?.get('user-agent');
@@ -1954,7 +1913,7 @@ export class GraphQLService {
1954
1913
  mode: AuthMode,
1955
1914
  },
1956
1915
  resolve: async (_, args, { req, res }) => {
1957
- const accountability = createDefaultAccountability();
1916
+ const accountability = { role: null };
1958
1917
  if (req?.ip)
1959
1918
  accountability.ip = req.ip;
1960
1919
  const userAgent = req?.get('user-agent');
@@ -2004,7 +1963,7 @@ export class GraphQLService {
2004
1963
  reset_url: GraphQLString,
2005
1964
  },
2006
1965
  resolve: async (_, args, { req }) => {
2007
- const accountability = createDefaultAccountability();
1966
+ const accountability = { role: null };
2008
1967
  if (req?.ip)
2009
1968
  accountability.ip = req.ip;
2010
1969
  const userAgent = req?.get('user-agent');
@@ -2032,7 +1991,7 @@ export class GraphQLService {
2032
1991
  password: new GraphQLNonNull(GraphQLString),
2033
1992
  },
2034
1993
  resolve: async (_, args, { req }) => {
2035
- const accountability = createDefaultAccountability();
1994
+ const accountability = { role: null };
2036
1995
  if (req?.ip)
2037
1996
  accountability.ip = req.ip;
2038
1997
  const userAgent = req?.get('user-agent');
@@ -2673,69 +2632,6 @@ export class GraphQLService {
2673
2632
  },
2674
2633
  });
2675
2634
  }
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
- }
2739
2635
  if ('directus_users' in schema.update.collections && this.accountability?.user) {
2740
2636
  schemaComposer.Mutation.addFields({
2741
2637
  update_users_me: {