@directus/api 19.3.0 → 20.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +4 -4
- package/dist/auth/drivers/ldap.js +4 -4
- package/dist/auth/drivers/local.js +4 -4
- package/dist/auth/drivers/oauth2.js +4 -4
- package/dist/auth/drivers/openid.js +2 -4
- package/dist/cache.js +3 -0
- package/dist/cli/commands/bootstrap/index.js +8 -2
- package/dist/cli/commands/init/index.js +9 -10
- package/dist/cli/utils/defaults.d.ts +4 -11
- package/dist/cli/utils/defaults.js +7 -1
- package/dist/constants.d.ts +1 -1
- package/dist/controllers/access.d.ts +2 -0
- package/dist/controllers/access.js +148 -0
- package/dist/controllers/auth.js +5 -16
- package/dist/controllers/permissions.js +14 -2
- package/dist/controllers/policies.d.ts +2 -0
- package/dist/controllers/policies.js +169 -0
- package/dist/controllers/roles.js +22 -1
- package/dist/controllers/users.js +0 -55
- package/dist/database/errors/dialects/mysql.js +23 -23
- package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +16 -0
- package/dist/database/get-ast-from-query/get-ast-from-query.js +82 -0
- package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +13 -0
- package/dist/database/get-ast-from-query/lib/convert-wildcards.js +69 -0
- package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +15 -0
- package/dist/database/get-ast-from-query/lib/parse-fields.js +190 -0
- package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +14 -0
- package/dist/database/get-ast-from-query/utils/get-deep-query.js +17 -0
- package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +2 -0
- package/dist/database/get-ast-from-query/utils/get-related-collection.js +13 -0
- package/dist/database/get-ast-from-query/utils/get-relation.d.ts +2 -0
- package/dist/database/get-ast-from-query/utils/get-relation.js +7 -0
- package/dist/database/helpers/fn/types.d.ts +2 -1
- package/dist/database/helpers/fn/types.js +1 -1
- package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
- package/dist/database/helpers/geometry/dialects/mssql.js +4 -2
- package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
- package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
- package/dist/database/helpers/geometry/dialects/oracle.js +5 -3
- package/dist/database/helpers/geometry/types.d.ts +1 -1
- package/dist/database/helpers/geometry/types.js +4 -2
- package/dist/database/index.js +2 -1
- package/dist/database/migrations/20240619A-permissions-policies.d.ts +3 -0
- package/dist/database/migrations/20240619A-permissions-policies.js +163 -0
- package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
- package/dist/database/run-ast/lib/get-db-query.js +194 -0
- package/dist/database/run-ast/lib/parse-current-level.d.ts +7 -0
- package/dist/database/run-ast/lib/parse-current-level.js +41 -0
- package/dist/database/run-ast/run-ast.d.ts +7 -0
- package/dist/database/run-ast/run-ast.js +107 -0
- package/dist/database/{run-ast.d.ts → run-ast/types.d.ts} +3 -9
- package/dist/database/run-ast/types.js +1 -0
- package/dist/database/run-ast/utils/apply-case-when.d.ts +16 -0
- package/dist/database/run-ast/utils/apply-case-when.js +26 -0
- package/dist/database/run-ast/utils/apply-parent-filters.d.ts +3 -0
- package/dist/database/run-ast/utils/apply-parent-filters.js +55 -0
- package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +10 -0
- package/dist/database/run-ast/utils/get-column-pre-processor.js +57 -0
- package/dist/database/run-ast/utils/get-field-alias.d.ts +2 -0
- package/dist/database/run-ast/utils/get-field-alias.js +4 -0
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +5 -0
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +23 -0
- package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +3 -0
- package/dist/database/run-ast/utils/merge-with-parent-items.js +87 -0
- package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +3 -0
- package/dist/database/run-ast/utils/remove-temporary-fields.js +73 -0
- package/dist/extensions/lib/sandbox/generate-api-extensions-sandbox-entrypoint.d.ts +1 -1
- package/dist/flows.js +3 -4
- package/dist/middleware/authenticate.js +2 -7
- package/dist/middleware/cache.js +1 -1
- package/dist/middleware/cors.js +4 -4
- package/dist/middleware/respond.js +1 -1
- package/dist/permissions/cache.d.ts +2 -0
- package/dist/permissions/cache.js +23 -0
- package/dist/permissions/lib/fetch-permissions.d.ts +10 -0
- package/dist/permissions/lib/fetch-permissions.js +55 -0
- package/dist/permissions/lib/fetch-policies.d.ts +7 -0
- package/dist/permissions/lib/fetch-policies.js +28 -0
- package/dist/permissions/lib/fetch-roles-tree.d.ts +3 -0
- package/dist/permissions/lib/fetch-roles-tree.js +28 -0
- package/dist/{services/permissions → permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
- package/dist/permissions/lib/with-app-minimal-permissions.js +10 -0
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +7 -0
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +56 -0
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +3 -0
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +16 -0
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +8 -0
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +24 -0
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +9 -0
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +31 -0
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +16 -0
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +27 -0
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +10 -0
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +23 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +5 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +7 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +5 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +10 -0
- package/dist/permissions/modules/fetch-global-access/types.d.ts +4 -0
- package/dist/permissions/modules/fetch-global-access/types.js +1 -0
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +4 -0
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +27 -0
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +12 -0
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +32 -0
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +4 -0
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +29 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +4 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +49 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +3 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +56 -0
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +4 -0
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +8 -0
- package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +9 -0
- package/dist/permissions/modules/process-ast/lib/inject-cases.js +93 -0
- package/dist/permissions/modules/process-ast/process-ast.d.ts +9 -0
- package/dist/permissions/modules/process-ast/process-ast.js +39 -0
- package/dist/permissions/modules/process-ast/types.d.ts +24 -0
- package/dist/permissions/modules/process-ast/types.js +1 -0
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +7 -0
- package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +12 -0
- package/dist/permissions/modules/process-ast/utils/dedupe-access.js +30 -0
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +15 -0
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +50 -0
- package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/find-related-collection.js +9 -0
- package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/flatten-filter.js +24 -0
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +1 -0
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +3 -0
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +5 -0
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +7 -0
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +3 -0
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +3 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +16 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +12 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +28 -0
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +5 -0
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +12 -0
- package/dist/permissions/modules/process-payload/process-payload.d.ts +13 -0
- package/dist/permissions/modules/process-payload/process-payload.js +77 -0
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +12 -0
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +11 -0
- package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +9 -0
- package/dist/permissions/modules/validate-access/lib/validate-item-access.js +33 -0
- package/dist/permissions/modules/validate-access/validate-access.d.ts +14 -0
- package/dist/permissions/modules/validate-access/validate-access.js +28 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +1 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +8 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +5 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +10 -0
- package/dist/permissions/types.d.ts +6 -0
- package/dist/permissions/types.js +1 -0
- package/dist/permissions/utils/create-default-accountability.d.ts +2 -0
- package/dist/permissions/utils/create-default-accountability.js +11 -0
- package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +8 -0
- package/dist/permissions/utils/extract-required-dynamic-variable-context.js +27 -0
- package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +9 -0
- package/dist/permissions/utils/fetch-dynamic-variable-context.js +43 -0
- package/dist/permissions/utils/filter-policies-by-ip.d.ts +2 -0
- package/dist/permissions/utils/filter-policies-by-ip.js +15 -0
- package/dist/permissions/utils/get-unaliased-field-key.d.ts +5 -0
- package/dist/permissions/utils/get-unaliased-field-key.js +17 -0
- package/dist/permissions/utils/process-permissions.d.ts +7 -0
- package/dist/permissions/utils/process-permissions.js +9 -0
- package/dist/permissions/utils/with-cache.d.ts +10 -0
- package/dist/permissions/utils/with-cache.js +25 -0
- package/dist/services/access.d.ts +10 -0
- package/dist/services/access.js +43 -0
- package/dist/services/activity.js +22 -10
- package/dist/services/assets.d.ts +2 -3
- package/dist/services/assets.js +10 -5
- package/dist/services/authentication.js +18 -18
- package/dist/services/collections.js +18 -17
- package/dist/services/fields.d.ts +0 -1
- package/dist/services/fields.js +53 -24
- package/dist/services/files.d.ts +0 -4
- package/dist/services/files.js +10 -10
- package/dist/services/flows.d.ts +0 -2
- package/dist/services/flows.js +2 -14
- package/dist/services/graphql/index.d.ts +3 -3
- package/dist/services/graphql/index.js +126 -22
- package/dist/services/graphql/subscription.js +2 -4
- package/dist/services/import-export.js +23 -9
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +3 -2
- package/dist/services/items.d.ts +40 -14
- package/dist/services/items.js +182 -79
- package/dist/services/meta.js +60 -23
- package/dist/services/notifications.d.ts +0 -1
- package/dist/services/notifications.js +0 -7
- package/dist/services/operations.d.ts +0 -2
- package/dist/services/operations.js +2 -14
- package/dist/services/payload.d.ts +9 -10
- package/dist/services/payload.js +35 -19
- package/dist/services/{permissions/index.d.ts → permissions.d.ts} +5 -7
- package/dist/services/{permissions/index.js → permissions.js} +30 -54
- package/dist/services/policies.d.ts +12 -0
- package/dist/services/policies.js +87 -0
- package/dist/services/relations.d.ts +0 -6
- package/dist/services/relations.js +26 -29
- package/dist/services/roles.d.ts +4 -14
- package/dist/services/roles.js +56 -420
- package/dist/services/shares.d.ts +0 -2
- package/dist/services/shares.js +12 -8
- package/dist/services/specifications.d.ts +2 -2
- package/dist/services/specifications.js +39 -27
- package/dist/services/users.d.ts +2 -20
- package/dist/services/users.js +87 -190
- package/dist/services/utils.js +11 -7
- package/dist/services/versions.d.ts +0 -2
- package/dist/services/versions.js +34 -10
- package/dist/telemetry/lib/get-report.js +6 -3
- package/dist/telemetry/types/report.d.ts +4 -0
- package/dist/telemetry/utils/check-user-limits.d.ts +5 -0
- package/dist/telemetry/utils/check-user-limits.js +19 -0
- package/dist/telemetry/utils/get-filesize-sum.d.ts +5 -0
- package/dist/telemetry/utils/get-filesize-sum.js +7 -0
- package/dist/telemetry/utils/should-check-user-limits.d.ts +4 -0
- package/dist/telemetry/utils/should-check-user-limits.js +13 -0
- package/dist/types/ast.d.ts +43 -1
- package/dist/types/items.d.ts +11 -0
- package/dist/utils/apply-query.d.ts +4 -3
- package/dist/utils/apply-query.js +37 -8
- package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +17 -0
- package/dist/utils/fetch-user-count/fetch-access-lookup.js +22 -0
- package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +16 -0
- package/dist/utils/fetch-user-count/fetch-access-roles.js +37 -0
- package/dist/utils/fetch-user-count/fetch-active-users.d.ts +6 -0
- package/dist/utils/fetch-user-count/fetch-active-users.js +3 -0
- package/dist/utils/fetch-user-count/fetch-user-count.d.ts +12 -0
- package/dist/utils/fetch-user-count/fetch-user-count.js +57 -0
- package/dist/utils/fetch-user-count/get-user-count-query.d.ts +20 -0
- package/dist/utils/fetch-user-count/get-user-count-query.js +17 -0
- package/dist/utils/get-accountability-for-role.js +16 -25
- package/dist/utils/get-accountability-for-token.js +17 -16
- package/dist/utils/get-cache-key.d.ts +1 -1
- package/dist/utils/get-cache-key.js +12 -1
- package/dist/utils/get-column.d.ts +2 -1
- package/dist/utils/get-column.js +1 -0
- package/dist/utils/get-graphql-type.js +1 -0
- package/dist/utils/get-service.d.ts +1 -1
- package/dist/utils/get-service.js +14 -10
- package/dist/utils/reduce-schema.d.ts +4 -6
- package/dist/utils/reduce-schema.js +14 -34
- package/dist/utils/validate-user-count-integrity.d.ts +13 -0
- package/dist/utils/validate-user-count-integrity.js +29 -0
- package/dist/websocket/authenticate.d.ts +0 -2
- package/dist/websocket/authenticate.js +0 -12
- package/dist/websocket/controllers/graphql.js +1 -4
- package/dist/websocket/controllers/hooks.js +4 -0
- package/dist/websocket/controllers/rest.js +0 -2
- package/dist/websocket/handlers/subscribe.js +0 -2
- package/dist/websocket/utils/items.d.ts +1 -1
- package/dist/websocket/utils/items.js +4 -1
- package/package.json +36 -35
- package/dist/database/run-ast.js +0 -450
- package/dist/middleware/check-ip.d.ts +0 -2
- package/dist/middleware/check-ip.js +0 -37
- package/dist/middleware/get-permissions.d.ts +0 -3
- package/dist/middleware/get-permissions.js +0 -10
- package/dist/services/authorization.d.ts +0 -17
- package/dist/services/authorization.js +0 -456
- package/dist/services/permissions/lib/with-app-minimal-permissions.js +0 -13
- package/dist/telemetry/utils/check-increased-user-limits.d.ts +0 -7
- package/dist/telemetry/utils/check-increased-user-limits.js +0 -22
- package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +0 -6
- package/dist/telemetry/utils/get-role-counts-by-roles.js +0 -27
- package/dist/telemetry/utils/get-role-counts-by-users.d.ts +0 -11
- package/dist/telemetry/utils/get-role-counts-by-users.js +0 -34
- package/dist/telemetry/utils/get-user-count.d.ts +0 -8
- package/dist/telemetry/utils/get-user-count.js +0 -33
- package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +0 -7
- package/dist/telemetry/utils/get-user-counts-by-roles.js +0 -35
- package/dist/utils/get-ast-from-query.d.ts +0 -13
- package/dist/utils/get-ast-from-query.js +0 -297
- package/dist/utils/get-permissions.d.ts +0 -2
- package/dist/utils/get-permissions.js +0 -150
- package/dist/utils/merge-permissions-for-share.d.ts +0 -4
- package/dist/utils/merge-permissions-for-share.js +0 -109
- package/dist/utils/merge-permissions.d.ts +0 -3
- package/dist/utils/merge-permissions.js +0 -95
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "20.0.0-rc.0",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"directus",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@rollup/plugin-node-resolve": "15.2.3",
|
|
66
66
|
"@rollup/plugin-virtual": "3.0.2",
|
|
67
67
|
"@types/cookie": "0.6.0",
|
|
68
|
-
"argon2": "0.40.
|
|
68
|
+
"argon2": "0.40.3",
|
|
69
69
|
"async": "3.2.5",
|
|
70
70
|
"axios": "1.7.2",
|
|
71
71
|
"busboy": "1.6.0",
|
|
@@ -91,12 +91,12 @@
|
|
|
91
91
|
"flat": "6.0.1",
|
|
92
92
|
"fs-extra": "11.2.0",
|
|
93
93
|
"glob-to-regexp": "0.4.1",
|
|
94
|
-
"graphql": "16.8.
|
|
94
|
+
"graphql": "16.8.2",
|
|
95
95
|
"graphql-compose": "9.0.11",
|
|
96
96
|
"graphql-ws": "5.16.0",
|
|
97
97
|
"helmet": "7.1.0",
|
|
98
98
|
"icc": "3.0.0",
|
|
99
|
-
"inquirer": "9.2.
|
|
99
|
+
"inquirer": "9.2.23",
|
|
100
100
|
"ioredis": "5.4.1",
|
|
101
101
|
"ip-matching": "2.1.2",
|
|
102
102
|
"isolated-vm": "4.7.2",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"nanoid": "5.0.7",
|
|
120
120
|
"node-machine-id": "1.1.12",
|
|
121
121
|
"node-schedule": "2.1.1",
|
|
122
|
-
"nodemailer": "6.9.
|
|
122
|
+
"nodemailer": "6.9.14",
|
|
123
123
|
"object-hash": "3.0.0",
|
|
124
124
|
"openapi3-ts": "4.3.2",
|
|
125
125
|
"openid-client": "5.6.5",
|
|
@@ -128,47 +128,47 @@
|
|
|
128
128
|
"p-limit": "5.0.0",
|
|
129
129
|
"p-queue": "8.0.1",
|
|
130
130
|
"papaparse": "5.4.1",
|
|
131
|
-
"pino": "9.
|
|
131
|
+
"pino": "9.2.0",
|
|
132
132
|
"pino-http": "9.0.0",
|
|
133
133
|
"pino-http-print": "3.1.0",
|
|
134
|
-
"pino-pretty": "11.
|
|
134
|
+
"pino-pretty": "11.2.1",
|
|
135
135
|
"qs": "6.12.1",
|
|
136
136
|
"rate-limiter-flexible": "5.0.3",
|
|
137
137
|
"rollup": "4.17.2",
|
|
138
138
|
"samlify": "2.8.10",
|
|
139
139
|
"sanitize-html": "2.13.0",
|
|
140
|
-
"sharp": "0.33.
|
|
140
|
+
"sharp": "0.33.4",
|
|
141
141
|
"snappy": "7.2.2",
|
|
142
142
|
"stream-json": "1.8.0",
|
|
143
|
-
"tar": "7.
|
|
144
|
-
"tsx": "4.
|
|
143
|
+
"tar": "7.2.0",
|
|
144
|
+
"tsx": "4.12.0",
|
|
145
145
|
"wellknown": "0.5.0",
|
|
146
146
|
"ws": "8.17.0",
|
|
147
147
|
"zod": "3.23.8",
|
|
148
|
-
"zod-validation-error": "3.
|
|
149
|
-
"@directus/app": "
|
|
150
|
-
"@directus/
|
|
151
|
-
"@directus/
|
|
152
|
-
"@directus/errors": "0.
|
|
153
|
-
"@directus/extensions": "1.0.
|
|
154
|
-
"@directus/extensions-
|
|
148
|
+
"zod-validation-error": "3.3.0",
|
|
149
|
+
"@directus/app": "13.0.0-rc.0",
|
|
150
|
+
"@directus/constants": "11.1.0-rc.0",
|
|
151
|
+
"@directus/env": "1.1.7-rc.0",
|
|
152
|
+
"@directus/errors": "0.4.0-rc.0",
|
|
153
|
+
"@directus/extensions-registry": "1.0.9-rc.0",
|
|
154
|
+
"@directus/extensions-sdk": "11.0.9-rc.0",
|
|
155
155
|
"@directus/format-title": "10.1.2",
|
|
156
|
-
"@directus/extensions
|
|
157
|
-
"@directus/
|
|
158
|
-
"@directus/
|
|
159
|
-
"@directus/schema": "11.0.2",
|
|
156
|
+
"@directus/extensions": "2.0.0-rc.0",
|
|
157
|
+
"@directus/memory": "1.1.0-rc.0",
|
|
158
|
+
"@directus/pressure": "1.0.21-rc.0",
|
|
160
159
|
"@directus/specs": "10.2.10",
|
|
160
|
+
"@directus/schema": "11.0.3",
|
|
161
161
|
"@directus/storage": "10.0.13",
|
|
162
|
-
"@directus/storage-driver-azure": "10.0.
|
|
163
|
-
"@directus/storage-driver-cloudinary": "10.0.
|
|
164
|
-
"@directus/storage-driver-gcs": "10.0.
|
|
162
|
+
"@directus/storage-driver-azure": "10.0.23-rc.0",
|
|
163
|
+
"@directus/storage-driver-cloudinary": "10.0.23-rc.0",
|
|
164
|
+
"@directus/storage-driver-gcs": "10.0.24-rc.0",
|
|
165
165
|
"@directus/storage-driver-local": "10.0.20",
|
|
166
|
-
"@directus/storage-driver-supabase": "1.0.
|
|
167
|
-
"@directus/storage-driver-s3": "10.0.
|
|
168
|
-
"@directus/
|
|
169
|
-
"@directus/
|
|
170
|
-
"directus": "
|
|
171
|
-
"
|
|
166
|
+
"@directus/storage-driver-supabase": "1.0.15-rc.0",
|
|
167
|
+
"@directus/storage-driver-s3": "10.0.24-rc.0",
|
|
168
|
+
"@directus/utils": "12.0.0-rc.0",
|
|
169
|
+
"@directus/system-data": "2.0.0-rc.0",
|
|
170
|
+
"@directus/validation": "0.0.18-rc.0",
|
|
171
|
+
"directus": "11.0.0-rc.1"
|
|
172
172
|
},
|
|
173
173
|
"devDependencies": {
|
|
174
174
|
"@ngneat/falso": "7.2.0",
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
"@types/destroy": "1.0.3",
|
|
183
183
|
"@types/encodeurl": "1.0.2",
|
|
184
184
|
"@types/express": "4.17.21",
|
|
185
|
-
"@types/express-serve-static-core": "4.19.
|
|
185
|
+
"@types/express-serve-static-core": "4.19.3",
|
|
186
186
|
"@types/fs-extra": "11.0.4",
|
|
187
187
|
"@types/glob-to-regexp": "0.4.4",
|
|
188
188
|
"@types/inquirer": "9.0.7",
|
|
@@ -211,14 +211,14 @@
|
|
|
211
211
|
"vitest": "1.5.3",
|
|
212
212
|
"@directus/random": "0.2.8",
|
|
213
213
|
"@directus/tsconfig": "1.0.1",
|
|
214
|
-
"@directus/types": "
|
|
214
|
+
"@directus/types": "12.0.0-rc.0"
|
|
215
215
|
},
|
|
216
216
|
"optionalDependencies": {
|
|
217
217
|
"@keyv/redis": "2.8.4",
|
|
218
|
-
"
|
|
218
|
+
"mysql2": "3.10.0",
|
|
219
219
|
"nodemailer-mailgun-transport": "2.1.5",
|
|
220
220
|
"nodemailer-sendgrid": "1.0.3",
|
|
221
|
-
"oracledb": "6.5.
|
|
221
|
+
"oracledb": "6.5.1",
|
|
222
222
|
"pg": "8.11.5",
|
|
223
223
|
"sqlite3": "5.1.7",
|
|
224
224
|
"tedious": "18.2.0"
|
|
@@ -230,6 +230,7 @@
|
|
|
230
230
|
"build": "tsc --project tsconfig.prod.json && copyfiles \"src/**/*.{yaml,liquid}\" -u 1 dist",
|
|
231
231
|
"cli": "NODE_ENV=development SERVE_APP=false tsx src/cli/run.ts",
|
|
232
232
|
"dev": "NODE_ENV=development SERVE_APP=true tsx watch --ignore extensions --clear-screen=false src/start.ts",
|
|
233
|
-
"test": "vitest
|
|
233
|
+
"test": "vitest run",
|
|
234
|
+
"test:watch": "vitest"
|
|
234
235
|
}
|
|
235
236
|
}
|
package/dist/database/run-ast.js
DELETED
|
@@ -1,450 +0,0 @@
|
|
|
1
|
-
import { useEnv } from '@directus/env';
|
|
2
|
-
import { toArray } from '@directus/utils';
|
|
3
|
-
import { clone, cloneDeep, isNil, merge, pick, uniq } from 'lodash-es';
|
|
4
|
-
import { PayloadService } from '../services/payload.js';
|
|
5
|
-
import { applyFunctionToColumnName } from '../utils/apply-function-to-column-name.js';
|
|
6
|
-
import applyQuery, { applyLimit, applySort, generateAlias } from '../utils/apply-query.js';
|
|
7
|
-
import { getCollectionFromAlias } from '../utils/get-collection-from-alias.js';
|
|
8
|
-
import { getColumn } from '../utils/get-column.js';
|
|
9
|
-
import { parseFilterKey } from '../utils/parse-filter-key.js';
|
|
10
|
-
import { getHelpers } from './helpers/index.js';
|
|
11
|
-
import getDatabase from './index.js';
|
|
12
|
-
/**
|
|
13
|
-
* Execute a given AST using Knex. Returns array of items based on requested AST.
|
|
14
|
-
*/
|
|
15
|
-
export default async function runAST(originalAST, schema, options) {
|
|
16
|
-
const ast = cloneDeep(originalAST);
|
|
17
|
-
const knex = options?.knex || getDatabase();
|
|
18
|
-
if (ast.type === 'a2o') {
|
|
19
|
-
const results = {};
|
|
20
|
-
for (const collection of ast.names) {
|
|
21
|
-
results[collection] = await run(collection, ast.children[collection], ast.query[collection]);
|
|
22
|
-
}
|
|
23
|
-
return results;
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
return await run(ast.name, ast.children, options?.query || ast.query);
|
|
27
|
-
}
|
|
28
|
-
async function run(collection, children, query) {
|
|
29
|
-
const env = useEnv();
|
|
30
|
-
// Retrieve the database columns to select in the current AST
|
|
31
|
-
const { fieldNodes, primaryKeyField, nestedCollectionNodes } = await parseCurrentLevel(schema, collection, children, query);
|
|
32
|
-
// The actual knex query builder instance. This is a promise that resolves with the raw items from the db
|
|
33
|
-
const dbQuery = await getDBQuery(schema, knex, collection, fieldNodes, query);
|
|
34
|
-
const rawItems = await dbQuery;
|
|
35
|
-
if (!rawItems)
|
|
36
|
-
return null;
|
|
37
|
-
// Run the items through the special transforms
|
|
38
|
-
const payloadService = new PayloadService(collection, { knex, schema });
|
|
39
|
-
let items = await payloadService.processValues('read', rawItems, query.alias ?? {});
|
|
40
|
-
if (!items || (Array.isArray(items) && items.length === 0))
|
|
41
|
-
return items;
|
|
42
|
-
// Apply the `_in` filters to the nested collection batches
|
|
43
|
-
const nestedNodes = applyParentFilters(schema, nestedCollectionNodes, items);
|
|
44
|
-
for (const nestedNode of nestedNodes) {
|
|
45
|
-
let nestedItems = [];
|
|
46
|
-
if (nestedNode.type === 'o2m') {
|
|
47
|
-
let hasMore = true;
|
|
48
|
-
let batchCount = 0;
|
|
49
|
-
while (hasMore) {
|
|
50
|
-
const node = merge({}, nestedNode, {
|
|
51
|
-
query: {
|
|
52
|
-
limit: env['RELATIONAL_BATCH_SIZE'],
|
|
53
|
-
offset: batchCount * env['RELATIONAL_BATCH_SIZE'],
|
|
54
|
-
page: null,
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
nestedItems = (await runAST(node, schema, { knex, nested: true }));
|
|
58
|
-
if (nestedItems) {
|
|
59
|
-
items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
|
|
60
|
-
}
|
|
61
|
-
if (!nestedItems || nestedItems.length < env['RELATIONAL_BATCH_SIZE']) {
|
|
62
|
-
hasMore = false;
|
|
63
|
-
}
|
|
64
|
-
batchCount++;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
const node = merge({}, nestedNode, {
|
|
69
|
-
query: { limit: -1 },
|
|
70
|
-
});
|
|
71
|
-
nestedItems = (await runAST(node, schema, { knex, nested: true }));
|
|
72
|
-
if (nestedItems) {
|
|
73
|
-
// Merge all fetched nested records with the parent items
|
|
74
|
-
items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// During the fetching of data, we have to inject a couple of required fields for the child nesting
|
|
79
|
-
// to work (primary / foreign keys) even if they're not explicitly requested. After all fetching
|
|
80
|
-
// and nesting is done, we parse through the output structure, and filter out all non-requested
|
|
81
|
-
// fields
|
|
82
|
-
if (options?.nested !== true && options?.stripNonRequested !== false) {
|
|
83
|
-
items = removeTemporaryFields(schema, items, originalAST, primaryKeyField);
|
|
84
|
-
}
|
|
85
|
-
return items;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
async function parseCurrentLevel(schema, collection, children, query) {
|
|
89
|
-
const primaryKeyField = schema.collections[collection].primary;
|
|
90
|
-
const columnsInCollection = Object.keys(schema.collections[collection].fields);
|
|
91
|
-
const columnsToSelectInternal = [];
|
|
92
|
-
const nestedCollectionNodes = [];
|
|
93
|
-
for (const child of children) {
|
|
94
|
-
if (child.type === 'field' || child.type === 'functionField') {
|
|
95
|
-
const { fieldName } = parseFilterKey(child.name);
|
|
96
|
-
if (columnsInCollection.includes(fieldName)) {
|
|
97
|
-
columnsToSelectInternal.push(child.fieldKey);
|
|
98
|
-
}
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
if (!child.relation)
|
|
102
|
-
continue;
|
|
103
|
-
if (child.type === 'm2o') {
|
|
104
|
-
columnsToSelectInternal.push(child.relation.field);
|
|
105
|
-
}
|
|
106
|
-
if (child.type === 'a2o') {
|
|
107
|
-
columnsToSelectInternal.push(child.relation.field);
|
|
108
|
-
columnsToSelectInternal.push(child.relation.meta.one_collection_field);
|
|
109
|
-
}
|
|
110
|
-
nestedCollectionNodes.push(child);
|
|
111
|
-
}
|
|
112
|
-
const isAggregate = (query.group || (query.aggregate && Object.keys(query.aggregate).length > 0)) ?? false;
|
|
113
|
-
/** Always fetch primary key in case there's a nested relation that needs it. Aggregate payloads
|
|
114
|
-
* can't have nested relational fields
|
|
115
|
-
*/
|
|
116
|
-
if (isAggregate === false && columnsToSelectInternal.includes(primaryKeyField) === false) {
|
|
117
|
-
columnsToSelectInternal.push(primaryKeyField);
|
|
118
|
-
}
|
|
119
|
-
/** Make sure select list has unique values */
|
|
120
|
-
const columnsToSelect = [...new Set(columnsToSelectInternal)];
|
|
121
|
-
const fieldNodes = columnsToSelect.map((column) => children.find((childNode) => (childNode.type === 'field' || childNode.type === 'functionField') && childNode.fieldKey === column) ?? {
|
|
122
|
-
type: 'field',
|
|
123
|
-
name: column,
|
|
124
|
-
fieldKey: column,
|
|
125
|
-
});
|
|
126
|
-
return { fieldNodes, nestedCollectionNodes, primaryKeyField };
|
|
127
|
-
}
|
|
128
|
-
function getColumnPreprocessor(knex, schema, table) {
|
|
129
|
-
const helpers = getHelpers(knex);
|
|
130
|
-
return function (fieldNode) {
|
|
131
|
-
let alias = undefined;
|
|
132
|
-
if (fieldNode.name !== fieldNode.fieldKey) {
|
|
133
|
-
alias = fieldNode.fieldKey;
|
|
134
|
-
}
|
|
135
|
-
let field;
|
|
136
|
-
if (fieldNode.type === 'field' || fieldNode.type === 'functionField') {
|
|
137
|
-
const { fieldName } = parseFilterKey(fieldNode.name);
|
|
138
|
-
field = schema.collections[table].fields[fieldName];
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
field = schema.collections[fieldNode.relation.collection].fields[fieldNode.relation.field];
|
|
142
|
-
}
|
|
143
|
-
if (field?.type?.startsWith('geometry')) {
|
|
144
|
-
return helpers.st.asText(table, field.field);
|
|
145
|
-
}
|
|
146
|
-
if (fieldNode.type === 'functionField') {
|
|
147
|
-
return getColumn(knex, table, fieldNode.name, alias, schema, { query: fieldNode.query });
|
|
148
|
-
}
|
|
149
|
-
return getColumn(knex, table, fieldNode.name, alias, schema);
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
async function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
153
|
-
const env = useEnv();
|
|
154
|
-
const preProcess = getColumnPreprocessor(knex, schema, table);
|
|
155
|
-
const queryCopy = clone(query);
|
|
156
|
-
const helpers = getHelpers(knex);
|
|
157
|
-
queryCopy.limit = typeof queryCopy.limit === 'number' ? queryCopy.limit : Number(env['QUERY_LIMIT_DEFAULT']);
|
|
158
|
-
// Queries with aggregates and groupBy will not have duplicate result
|
|
159
|
-
if (queryCopy.aggregate || queryCopy.group) {
|
|
160
|
-
const flatQuery = knex.select(fieldNodes.map(preProcess)).from(table);
|
|
161
|
-
return await applyQuery(knex, table, flatQuery, queryCopy, schema).query;
|
|
162
|
-
}
|
|
163
|
-
const primaryKey = schema.collections[table].primary;
|
|
164
|
-
const aliasMap = Object.create(null);
|
|
165
|
-
let dbQuery = knex.from(table);
|
|
166
|
-
let sortRecords;
|
|
167
|
-
const innerQuerySortRecords = [];
|
|
168
|
-
let hasMultiRelationalSort;
|
|
169
|
-
if (queryCopy.sort) {
|
|
170
|
-
const sortResult = applySort(knex, schema, dbQuery, queryCopy, table, aliasMap, true);
|
|
171
|
-
if (sortResult) {
|
|
172
|
-
sortRecords = sortResult.sortRecords;
|
|
173
|
-
hasMultiRelationalSort = sortResult.hasMultiRelationalSort;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
const { hasMultiRelationalFilter } = applyQuery(knex, table, dbQuery, queryCopy, schema, {
|
|
177
|
-
aliasMap,
|
|
178
|
-
isInnerQuery: true,
|
|
179
|
-
hasMultiRelationalSort,
|
|
180
|
-
});
|
|
181
|
-
const needsInnerQuery = hasMultiRelationalSort || hasMultiRelationalFilter;
|
|
182
|
-
if (needsInnerQuery) {
|
|
183
|
-
dbQuery.select(`${table}.${primaryKey}`).distinct();
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
dbQuery.select(fieldNodes.map(preProcess));
|
|
187
|
-
}
|
|
188
|
-
if (sortRecords) {
|
|
189
|
-
// Clears the order if any, eg: from MSSQL offset
|
|
190
|
-
dbQuery.clear('order');
|
|
191
|
-
if (needsInnerQuery) {
|
|
192
|
-
let orderByString = '';
|
|
193
|
-
const orderByFields = [];
|
|
194
|
-
sortRecords.map((sortRecord) => {
|
|
195
|
-
if (orderByString.length !== 0) {
|
|
196
|
-
orderByString += ', ';
|
|
197
|
-
}
|
|
198
|
-
const sortAlias = `sort_${generateAlias()}`;
|
|
199
|
-
if (sortRecord.column.includes('.')) {
|
|
200
|
-
const [alias, field] = sortRecord.column.split('.');
|
|
201
|
-
const originalCollectionName = getCollectionFromAlias(alias, aliasMap);
|
|
202
|
-
dbQuery.select(getColumn(knex, alias, field, sortAlias, schema, { originalCollectionName }));
|
|
203
|
-
orderByString += `?? ${sortRecord.order}`;
|
|
204
|
-
orderByFields.push(getColumn(knex, alias, field, false, schema, { originalCollectionName }));
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
dbQuery.select(getColumn(knex, table, sortRecord.column, sortAlias, schema));
|
|
208
|
-
orderByString += `?? ${sortRecord.order}`;
|
|
209
|
-
orderByFields.push(getColumn(knex, table, sortRecord.column, false, schema));
|
|
210
|
-
}
|
|
211
|
-
innerQuerySortRecords.push({ alias: sortAlias, order: sortRecord.order });
|
|
212
|
-
});
|
|
213
|
-
dbQuery.orderByRaw(orderByString, orderByFields);
|
|
214
|
-
if (hasMultiRelationalSort) {
|
|
215
|
-
dbQuery = helpers.schema.applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
sortRecords.map((sortRecord) => {
|
|
220
|
-
if (sortRecord.column.includes('.')) {
|
|
221
|
-
const [alias, field] = sortRecord.column.split('.');
|
|
222
|
-
sortRecord.column = getColumn(knex, alias, field, false, schema, {
|
|
223
|
-
originalCollectionName: getCollectionFromAlias(alias, aliasMap),
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
sortRecord.column = getColumn(knex, table, sortRecord.column, false, schema);
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
dbQuery.orderBy(sortRecords);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (!needsInnerQuery)
|
|
234
|
-
return dbQuery;
|
|
235
|
-
const wrapperQuery = knex
|
|
236
|
-
.select(fieldNodes.map(preProcess))
|
|
237
|
-
.from(table)
|
|
238
|
-
.innerJoin(knex.raw('??', dbQuery.as('inner')), `${table}.${primaryKey}`, `inner.${primaryKey}`);
|
|
239
|
-
if (sortRecords && needsInnerQuery) {
|
|
240
|
-
innerQuerySortRecords.map((innerQuerySortRecord) => {
|
|
241
|
-
wrapperQuery.orderBy(`inner.${innerQuerySortRecord.alias}`, innerQuerySortRecord.order);
|
|
242
|
-
});
|
|
243
|
-
if (hasMultiRelationalSort) {
|
|
244
|
-
wrapperQuery.where('inner.directus_row_number', '=', 1);
|
|
245
|
-
applyLimit(knex, wrapperQuery, queryCopy.limit);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return wrapperQuery;
|
|
249
|
-
}
|
|
250
|
-
function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
|
|
251
|
-
const parentItems = toArray(parentItem);
|
|
252
|
-
for (const nestedNode of nestedCollectionNodes) {
|
|
253
|
-
if (!nestedNode.relation)
|
|
254
|
-
continue;
|
|
255
|
-
if (nestedNode.type === 'm2o') {
|
|
256
|
-
const foreignField = schema.collections[nestedNode.relation.related_collection].primary;
|
|
257
|
-
const foreignIds = uniq(parentItems.map((res) => res[nestedNode.relation.field])).filter((id) => !isNil(id));
|
|
258
|
-
merge(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
|
|
259
|
-
}
|
|
260
|
-
else if (nestedNode.type === 'o2m') {
|
|
261
|
-
const relatedM2OisFetched = !!nestedNode.children.find((child) => {
|
|
262
|
-
return child.type === 'field' && child.name === nestedNode.relation.field;
|
|
263
|
-
});
|
|
264
|
-
if (relatedM2OisFetched === false) {
|
|
265
|
-
nestedNode.children.push({
|
|
266
|
-
type: 'field',
|
|
267
|
-
name: nestedNode.relation.field,
|
|
268
|
-
fieldKey: nestedNode.relation.field,
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
if (nestedNode.relation.meta?.sort_field) {
|
|
272
|
-
nestedNode.children.push({
|
|
273
|
-
type: 'field',
|
|
274
|
-
name: nestedNode.relation.meta.sort_field,
|
|
275
|
-
fieldKey: nestedNode.relation.meta.sort_field,
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
const foreignField = nestedNode.relation.field;
|
|
279
|
-
const foreignIds = uniq(parentItems.map((res) => res[nestedNode.parentKey])).filter((id) => !isNil(id));
|
|
280
|
-
merge(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
|
|
281
|
-
}
|
|
282
|
-
else if (nestedNode.type === 'a2o') {
|
|
283
|
-
const keysPerCollection = {};
|
|
284
|
-
for (const parentItem of parentItems) {
|
|
285
|
-
const collection = parentItem[nestedNode.relation.meta.one_collection_field];
|
|
286
|
-
if (!keysPerCollection[collection])
|
|
287
|
-
keysPerCollection[collection] = [];
|
|
288
|
-
keysPerCollection[collection].push(parentItem[nestedNode.relation.field]);
|
|
289
|
-
}
|
|
290
|
-
for (const relatedCollection of nestedNode.names) {
|
|
291
|
-
const foreignField = nestedNode.relatedKey[relatedCollection];
|
|
292
|
-
const foreignIds = uniq(keysPerCollection[relatedCollection]);
|
|
293
|
-
merge(nestedNode, {
|
|
294
|
-
query: { [relatedCollection]: { filter: { [foreignField]: { _in: foreignIds } }, limit: foreignIds.length } },
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return nestedCollectionNodes;
|
|
300
|
-
}
|
|
301
|
-
function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
|
|
302
|
-
const env = useEnv();
|
|
303
|
-
const nestedItems = toArray(nestedItem);
|
|
304
|
-
const parentItems = clone(toArray(parentItem));
|
|
305
|
-
if (nestedNode.type === 'm2o') {
|
|
306
|
-
for (const parentItem of parentItems) {
|
|
307
|
-
const itemChild = nestedItems.find((nestedItem) => {
|
|
308
|
-
return (nestedItem[schema.collections[nestedNode.relation.related_collection].primary] ==
|
|
309
|
-
parentItem[nestedNode.relation.field]);
|
|
310
|
-
});
|
|
311
|
-
parentItem[nestedNode.fieldKey] = itemChild || null;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
else if (nestedNode.type === 'o2m') {
|
|
315
|
-
for (const parentItem of parentItems) {
|
|
316
|
-
if (!parentItem[nestedNode.fieldKey])
|
|
317
|
-
parentItem[nestedNode.fieldKey] = [];
|
|
318
|
-
const itemChildren = nestedItems.filter((nestedItem) => {
|
|
319
|
-
if (nestedItem === null)
|
|
320
|
-
return false;
|
|
321
|
-
if (Array.isArray(nestedItem[nestedNode.relation.field]))
|
|
322
|
-
return true;
|
|
323
|
-
return (nestedItem[nestedNode.relation.field] ==
|
|
324
|
-
parentItem[schema.collections[nestedNode.relation.related_collection].primary] ||
|
|
325
|
-
nestedItem[nestedNode.relation.field]?.[schema.collections[nestedNode.relation.related_collection].primary] == parentItem[schema.collections[nestedNode.relation.related_collection].primary]);
|
|
326
|
-
});
|
|
327
|
-
parentItem[nestedNode.fieldKey].push(...itemChildren);
|
|
328
|
-
const limit = nestedNode.query.limit ?? Number(env['QUERY_LIMIT_DEFAULT']);
|
|
329
|
-
if (nestedNode.query.page && nestedNode.query.page > 1) {
|
|
330
|
-
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(limit * (nestedNode.query.page - 1));
|
|
331
|
-
}
|
|
332
|
-
if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
|
|
333
|
-
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
|
|
334
|
-
}
|
|
335
|
-
if (limit !== -1) {
|
|
336
|
-
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, limit);
|
|
337
|
-
}
|
|
338
|
-
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
|
|
339
|
-
// This is pre-filled in get-ast-from-query
|
|
340
|
-
const sortField = nestedNode.query.sort[0];
|
|
341
|
-
let column = sortField;
|
|
342
|
-
let order = 'asc';
|
|
343
|
-
if (sortField.startsWith('-')) {
|
|
344
|
-
column = sortField.substring(1);
|
|
345
|
-
order = 'desc';
|
|
346
|
-
}
|
|
347
|
-
if (a[column] === b[column])
|
|
348
|
-
return 0;
|
|
349
|
-
if (a[column] === null)
|
|
350
|
-
return 1;
|
|
351
|
-
if (b[column] === null)
|
|
352
|
-
return -1;
|
|
353
|
-
if (order === 'asc') {
|
|
354
|
-
return a[column] < b[column] ? -1 : 1;
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
return a[column] < b[column] ? 1 : -1;
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
else if (nestedNode.type === 'a2o') {
|
|
363
|
-
for (const parentItem of parentItems) {
|
|
364
|
-
if (!nestedNode.relation.meta?.one_collection_field) {
|
|
365
|
-
parentItem[nestedNode.fieldKey] = null;
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
const relatedCollection = parentItem[nestedNode.relation.meta.one_collection_field];
|
|
369
|
-
if (!nestedItem[relatedCollection]) {
|
|
370
|
-
parentItem[nestedNode.fieldKey] = null;
|
|
371
|
-
continue;
|
|
372
|
-
}
|
|
373
|
-
const itemChild = nestedItem[relatedCollection].find((nestedItem) => {
|
|
374
|
-
return nestedItem[nestedNode.relatedKey[relatedCollection]] == parentItem[nestedNode.fieldKey];
|
|
375
|
-
});
|
|
376
|
-
parentItem[nestedNode.fieldKey] = itemChild || null;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
return Array.isArray(parentItem) ? parentItems : parentItems[0];
|
|
380
|
-
}
|
|
381
|
-
function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem) {
|
|
382
|
-
const rawItems = cloneDeep(toArray(rawItem));
|
|
383
|
-
const items = [];
|
|
384
|
-
if (ast.type === 'a2o') {
|
|
385
|
-
const fields = {};
|
|
386
|
-
const nestedCollectionNodes = {};
|
|
387
|
-
for (const relatedCollection of ast.names) {
|
|
388
|
-
if (!fields[relatedCollection])
|
|
389
|
-
fields[relatedCollection] = [];
|
|
390
|
-
if (!nestedCollectionNodes[relatedCollection])
|
|
391
|
-
nestedCollectionNodes[relatedCollection] = [];
|
|
392
|
-
for (const child of ast.children[relatedCollection]) {
|
|
393
|
-
if (child.type === 'field' || child.type === 'functionField') {
|
|
394
|
-
fields[relatedCollection].push(child.name);
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
fields[relatedCollection].push(child.fieldKey);
|
|
398
|
-
nestedCollectionNodes[relatedCollection].push(child);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
for (const rawItem of rawItems) {
|
|
403
|
-
const relatedCollection = parentItem?.[ast.relation.meta.one_collection_field];
|
|
404
|
-
if (rawItem === null || rawItem === undefined)
|
|
405
|
-
return rawItem;
|
|
406
|
-
let item = rawItem;
|
|
407
|
-
for (const nestedNode of nestedCollectionNodes[relatedCollection]) {
|
|
408
|
-
item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, schema.collections[nestedNode.relation.collection].primary, item);
|
|
409
|
-
}
|
|
410
|
-
const fieldsWithFunctionsApplied = fields[relatedCollection].map((field) => applyFunctionToColumnName(field));
|
|
411
|
-
item =
|
|
412
|
-
fields[relatedCollection].length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
|
|
413
|
-
items.push(item);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
else {
|
|
417
|
-
const fields = [];
|
|
418
|
-
const nestedCollectionNodes = [];
|
|
419
|
-
for (const child of ast.children) {
|
|
420
|
-
fields.push(child.fieldKey);
|
|
421
|
-
if (child.type !== 'field' && child.type !== 'functionField') {
|
|
422
|
-
nestedCollectionNodes.push(child);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
// Make sure any requested aggregate fields are included
|
|
426
|
-
if (ast.query?.aggregate) {
|
|
427
|
-
for (const [operation, aggregateFields] of Object.entries(ast.query.aggregate)) {
|
|
428
|
-
if (!fields)
|
|
429
|
-
continue;
|
|
430
|
-
if (operation === 'count' && aggregateFields.includes('*'))
|
|
431
|
-
fields.push('count');
|
|
432
|
-
fields.push(...aggregateFields.map((field) => `${operation}.${field}`));
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
for (const rawItem of rawItems) {
|
|
436
|
-
if (rawItem === null || rawItem === undefined)
|
|
437
|
-
return rawItem;
|
|
438
|
-
let item = rawItem;
|
|
439
|
-
for (const nestedNode of nestedCollectionNodes) {
|
|
440
|
-
item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, nestedNode.type === 'm2o'
|
|
441
|
-
? schema.collections[nestedNode.relation.related_collection].primary
|
|
442
|
-
: schema.collections[nestedNode.relation.collection].primary, item);
|
|
443
|
-
}
|
|
444
|
-
const fieldsWithFunctionsApplied = fields.map((field) => applyFunctionToColumnName(field));
|
|
445
|
-
item = fields.length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
|
|
446
|
-
items.push(item);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
return Array.isArray(rawItem) ? items : items[0];
|
|
450
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { InvalidIpError } from '@directus/errors';
|
|
2
|
-
import getDatabase from '../database/index.js';
|
|
3
|
-
import { useLogger } from '../logger.js';
|
|
4
|
-
import asyncHandler from '../utils/async-handler.js';
|
|
5
|
-
import { ipInNetworks } from '../utils/ip-in-networks.js';
|
|
6
|
-
export const checkIP = asyncHandler(async (req, _res, next) => {
|
|
7
|
-
const database = getDatabase();
|
|
8
|
-
const logger = useLogger();
|
|
9
|
-
const { role: roleId, ip } = req.accountability;
|
|
10
|
-
const query = database.select('ip_access').from('directus_roles');
|
|
11
|
-
if (roleId) {
|
|
12
|
-
query.where({ id: roleId });
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
query.whereNull('id');
|
|
16
|
-
}
|
|
17
|
-
const role = await query.first();
|
|
18
|
-
if (!role?.ip_access)
|
|
19
|
-
return next();
|
|
20
|
-
const ipAllowList = role.ip_access.split(',').filter((ip) => ip);
|
|
21
|
-
if (ipAllowList.length > 0) {
|
|
22
|
-
if (!ip)
|
|
23
|
-
throw new InvalidIpError();
|
|
24
|
-
let allowed;
|
|
25
|
-
try {
|
|
26
|
-
allowed = ipInNetworks(ip, ipAllowList);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
logger.warn(`Invalid IP access configuration for role "${roleId}"`);
|
|
30
|
-
logger.warn(error);
|
|
31
|
-
throw new InvalidIpError();
|
|
32
|
-
}
|
|
33
|
-
if (!allowed)
|
|
34
|
-
throw new InvalidIpError();
|
|
35
|
-
}
|
|
36
|
-
return next();
|
|
37
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import asyncHandler from '../utils/async-handler.js';
|
|
2
|
-
import { getPermissions as getPermissionsUtil } from '../utils/get-permissions.js';
|
|
3
|
-
const getPermissions = asyncHandler(async (req, _res, next) => {
|
|
4
|
-
if (!req.accountability) {
|
|
5
|
-
throw new Error('getPermissions middleware needs to be called after authenticate');
|
|
6
|
-
}
|
|
7
|
-
req.accountability.permissions = await getPermissionsUtil(req.accountability, req.schema);
|
|
8
|
-
return next();
|
|
9
|
-
});
|
|
10
|
-
export default getPermissions;
|