@directus/api 20.1.0 → 21.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +5 -5
- package/dist/auth/drivers/ldap.js +5 -5
- package/dist/auth/drivers/local.js +4 -4
- package/dist/auth/drivers/oauth2.js +5 -5
- package/dist/auth/drivers/openid.js +3 -5
- package/dist/auth/drivers/saml.js +1 -1
- package/dist/auth.js +1 -1
- package/dist/cache.js +4 -1
- package/dist/cli/commands/bootstrap/index.js +9 -3
- package/dist/cli/commands/count/index.js +1 -1
- package/dist/cli/commands/database/install.js +1 -1
- package/dist/cli/commands/database/migrate.js +1 -1
- package/dist/cli/commands/init/index.js +9 -10
- package/dist/cli/commands/roles/create.js +1 -1
- package/dist/cli/commands/schema/apply.js +1 -1
- package/dist/cli/commands/schema/snapshot.js +1 -1
- package/dist/cli/commands/users/create.js +1 -1
- package/dist/cli/commands/users/passwd.js +1 -1
- package/dist/cli/load-extensions.js +1 -1
- 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/constants.js +2 -2
- package/dist/controllers/access.d.ts +2 -0
- package/dist/controllers/access.js +148 -0
- package/dist/controllers/assets.js +1 -1
- package/dist/controllers/auth.js +6 -17
- package/dist/controllers/files.js +1 -1
- 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/schema.js +1 -1
- package/dist/controllers/tus.js +11 -23
- package/dist/controllers/users.js +0 -55
- 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 +3 -2
- package/dist/database/migrations/20210518A-add-foreign-key-constraints.js +1 -1
- package/dist/database/migrations/20210519A-add-system-fk-triggers.js +1 -1
- package/dist/database/migrations/20210802A-replace-groups.js +1 -1
- package/dist/database/migrations/20230721A-require-shares-fields.js +1 -1
- package/dist/database/migrations/20240710A-permissions-policies.d.ts +3 -0
- package/dist/database/migrations/20240710A-permissions-policies.js +169 -0
- package/dist/database/migrations/run.js +1 -1
- package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
- package/dist/database/run-ast/lib/get-db-query.js +208 -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/emitter.js +1 -1
- package/dist/extensions/lib/get-shared-deps-mapping.js +1 -1
- package/dist/extensions/lib/installation/manager.js +1 -1
- package/dist/extensions/lib/sandbox/register/call-reference.js +1 -1
- package/dist/extensions/lib/sandbox/sdk/generators/log.js +1 -1
- package/dist/extensions/lib/sync-extensions.js +1 -1
- package/dist/extensions/manager.js +1 -1
- package/dist/flows.js +4 -5
- package/dist/{logger.js → logger/index.js} +2 -8
- package/dist/logger/redact-query.d.ts +1 -0
- package/dist/logger/redact-query.js +13 -0
- package/dist/mailer.js +1 -1
- package/dist/middleware/authenticate.js +2 -7
- package/dist/middleware/cache.js +2 -2
- package/dist/middleware/error-handler.js +1 -1
- package/dist/middleware/rate-limiter-global.js +1 -1
- package/dist/middleware/respond.js +2 -2
- package/dist/operations/log/index.js +1 -1
- package/dist/operations/mail/index.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 +34 -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/request/is-denied-ip.js +1 -1
- package/dist/server.js +1 -1
- package/dist/services/access.d.ts +10 -0
- package/dist/services/access.js +43 -0
- package/dist/services/activity.js +23 -11
- package/dist/services/assets.d.ts +2 -3
- package/dist/services/assets.js +11 -6
- 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/utils/get-metadata.js +1 -1
- package/dist/services/files.js +11 -4
- 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/graphql/utils/process-error.js +1 -1
- package/dist/services/graphql/utils/sanitize-gql-schema.js +1 -1
- package/dist/services/import-export.js +19 -5
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +3 -2
- package/dist/services/items.js +115 -44
- package/dist/services/mail/index.js +1 -1
- package/dist/services/meta.js +60 -23
- package/dist/services/notifications.js +15 -7
- package/dist/services/payload.d.ts +9 -10
- package/dist/services/payload.js +18 -3
- 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 -12
- package/dist/services/roles.js +57 -424
- package/dist/services/server.js +1 -1
- package/dist/services/shares.d.ts +0 -2
- package/dist/services/shares.js +13 -9
- package/dist/services/specifications.d.ts +2 -2
- package/dist/services/specifications.js +39 -27
- package/dist/services/tus/data-store.js +1 -1
- package/dist/services/users.d.ts +1 -5
- package/dist/services/users.js +79 -162
- package/dist/services/utils.js +11 -7
- package/dist/services/versions.d.ts +0 -2
- package/dist/services/versions.js +34 -10
- package/dist/services/webhooks.js +1 -1
- package/dist/telemetry/lib/get-report.js +2 -2
- package/dist/telemetry/lib/track.js +1 -1
- package/dist/telemetry/utils/check-user-limits.d.ts +5 -0
- package/dist/telemetry/utils/check-user-limits.js +19 -0
- package/dist/types/ast.d.ts +43 -1
- package/dist/types/items.d.ts +11 -0
- package/dist/utils/apply-diff.js +1 -1
- package/dist/utils/apply-query.d.ts +4 -3
- package/dist/utils/apply-query.js +37 -8
- package/dist/utils/delete-from-require-cache.js +1 -1
- 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-default-value.js +1 -1
- package/dist/utils/get-ip-from-req.js +1 -1
- package/dist/utils/get-schema.js +1 -1
- package/dist/utils/get-service.js +5 -1
- package/dist/utils/is-url-allowed.js +1 -1
- package/dist/utils/reduce-schema.d.ts +4 -6
- package/dist/utils/reduce-schema.js +16 -32
- package/dist/utils/sanitize-query.js +1 -1
- package/dist/utils/transaction.js +1 -1
- package/dist/utils/validate-env.js +1 -1
- package/dist/utils/validate-storage.js +1 -1
- 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/base.js +1 -1
- package/dist/websocket/controllers/graphql.js +2 -5
- package/dist/websocket/controllers/hooks.js +4 -0
- package/dist/websocket/controllers/rest.js +1 -3
- package/dist/websocket/errors.js +1 -1
- package/dist/websocket/handlers/subscribe.js +0 -2
- package/dist/websocket/utils/items.d.ts +1 -1
- package/package.json +24 -23
- package/dist/database/run-ast.js +0 -458
- 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 -25
- 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/dist/{logger.d.ts → logger/index.d.ts} +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { toArray } from '@directus/utils';
|
|
3
|
+
import { clone, isArray } from 'lodash-es';
|
|
4
|
+
export function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode, fieldAllowed) {
|
|
5
|
+
const env = useEnv();
|
|
6
|
+
const nestedItems = toArray(nestedItem);
|
|
7
|
+
const parentItems = clone(toArray(parentItem));
|
|
8
|
+
if (nestedNode.type === 'm2o') {
|
|
9
|
+
for (const parentItem of parentItems) {
|
|
10
|
+
const itemChild = nestedItems.find((nestedItem) => {
|
|
11
|
+
return (nestedItem[schema.collections[nestedNode.relation.related_collection].primary] ==
|
|
12
|
+
parentItem[nestedNode.relation.field]);
|
|
13
|
+
});
|
|
14
|
+
parentItem[nestedNode.fieldKey] = itemChild || null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
else if (nestedNode.type === 'o2m') {
|
|
18
|
+
for (const [index, parentItem] of parentItems.entries()) {
|
|
19
|
+
if (fieldAllowed === false || (isArray(fieldAllowed) && !fieldAllowed[index])) {
|
|
20
|
+
parentItem[nestedNode.fieldKey] = null;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (!parentItem[nestedNode.fieldKey])
|
|
24
|
+
parentItem[nestedNode.fieldKey] = [];
|
|
25
|
+
const itemChildren = nestedItems.filter((nestedItem) => {
|
|
26
|
+
if (nestedItem === null)
|
|
27
|
+
return false;
|
|
28
|
+
if (Array.isArray(nestedItem[nestedNode.relation.field]))
|
|
29
|
+
return true;
|
|
30
|
+
return (nestedItem[nestedNode.relation.field] ==
|
|
31
|
+
parentItem[schema.collections[nestedNode.relation.related_collection].primary] ||
|
|
32
|
+
nestedItem[nestedNode.relation.field]?.[schema.collections[nestedNode.relation.related_collection].primary] == parentItem[schema.collections[nestedNode.relation.related_collection].primary]);
|
|
33
|
+
});
|
|
34
|
+
parentItem[nestedNode.fieldKey].push(...itemChildren);
|
|
35
|
+
const limit = nestedNode.query.limit ?? Number(env['QUERY_LIMIT_DEFAULT']);
|
|
36
|
+
if (nestedNode.query.page && nestedNode.query.page > 1) {
|
|
37
|
+
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(limit * (nestedNode.query.page - 1));
|
|
38
|
+
}
|
|
39
|
+
if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
|
|
40
|
+
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
|
|
41
|
+
}
|
|
42
|
+
if (limit !== -1) {
|
|
43
|
+
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, limit);
|
|
44
|
+
}
|
|
45
|
+
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
|
|
46
|
+
// This is pre-filled in get-ast-from-query
|
|
47
|
+
const sortField = nestedNode.query.sort[0];
|
|
48
|
+
let column = sortField;
|
|
49
|
+
let order = 'asc';
|
|
50
|
+
if (sortField.startsWith('-')) {
|
|
51
|
+
column = sortField.substring(1);
|
|
52
|
+
order = 'desc';
|
|
53
|
+
}
|
|
54
|
+
if (a[column] === b[column])
|
|
55
|
+
return 0;
|
|
56
|
+
if (a[column] === null)
|
|
57
|
+
return 1;
|
|
58
|
+
if (b[column] === null)
|
|
59
|
+
return -1;
|
|
60
|
+
if (order === 'asc') {
|
|
61
|
+
return a[column] < b[column] ? -1 : 1;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return a[column] < b[column] ? 1 : -1;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else if (nestedNode.type === 'a2o') {
|
|
70
|
+
for (const parentItem of parentItems) {
|
|
71
|
+
if (!nestedNode.relation.meta?.one_collection_field) {
|
|
72
|
+
parentItem[nestedNode.fieldKey] = null;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const relatedCollection = parentItem[nestedNode.relation.meta.one_collection_field];
|
|
76
|
+
if (!nestedItem[relatedCollection]) {
|
|
77
|
+
parentItem[nestedNode.fieldKey] = null;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const itemChild = nestedItem[relatedCollection].find((nestedItem) => {
|
|
81
|
+
return nestedItem[nestedNode.relatedKey[relatedCollection]] == parentItem[nestedNode.fieldKey];
|
|
82
|
+
});
|
|
83
|
+
parentItem[nestedNode.fieldKey] = itemChild || null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return Array.isArray(parentItem) ? parentItems : parentItems[0];
|
|
87
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { Item, SchemaOverview } from '@directus/types';
|
|
2
|
+
import type { AST, NestedCollectionNode } from '../../../types/ast.js';
|
|
3
|
+
export declare function removeTemporaryFields(schema: SchemaOverview, rawItem: Item | Item[], ast: AST | NestedCollectionNode, primaryKeyField: string, parentItem?: Item): null | Item | Item[];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { toArray } from '@directus/utils';
|
|
2
|
+
import { cloneDeep, pick } from 'lodash-es';
|
|
3
|
+
import { applyFunctionToColumnName } from '../../../utils/apply-function-to-column-name.js';
|
|
4
|
+
export function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem) {
|
|
5
|
+
const rawItems = cloneDeep(toArray(rawItem));
|
|
6
|
+
const items = [];
|
|
7
|
+
if (ast.type === 'a2o') {
|
|
8
|
+
const fields = {};
|
|
9
|
+
const nestedCollectionNodes = {};
|
|
10
|
+
for (const relatedCollection of ast.names) {
|
|
11
|
+
if (!fields[relatedCollection])
|
|
12
|
+
fields[relatedCollection] = [];
|
|
13
|
+
if (!nestedCollectionNodes[relatedCollection])
|
|
14
|
+
nestedCollectionNodes[relatedCollection] = [];
|
|
15
|
+
for (const child of ast.children[relatedCollection]) {
|
|
16
|
+
if (child.type === 'field' || child.type === 'functionField') {
|
|
17
|
+
fields[relatedCollection].push(child.name);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
fields[relatedCollection].push(child.fieldKey);
|
|
21
|
+
nestedCollectionNodes[relatedCollection].push(child);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
for (const rawItem of rawItems) {
|
|
26
|
+
const relatedCollection = parentItem?.[ast.relation.meta.one_collection_field];
|
|
27
|
+
if (rawItem === null || rawItem === undefined)
|
|
28
|
+
return rawItem;
|
|
29
|
+
let item = rawItem;
|
|
30
|
+
for (const nestedNode of nestedCollectionNodes[relatedCollection]) {
|
|
31
|
+
item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, schema.collections[nestedNode.relation.collection].primary, item);
|
|
32
|
+
}
|
|
33
|
+
const fieldsWithFunctionsApplied = fields[relatedCollection].map((field) => applyFunctionToColumnName(field));
|
|
34
|
+
item =
|
|
35
|
+
fields[relatedCollection].length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
|
|
36
|
+
items.push(item);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const fields = [];
|
|
41
|
+
const nestedCollectionNodes = [];
|
|
42
|
+
for (const child of ast.children) {
|
|
43
|
+
fields.push(child.fieldKey);
|
|
44
|
+
if (child.type !== 'field' && child.type !== 'functionField') {
|
|
45
|
+
nestedCollectionNodes.push(child);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Make sure any requested aggregate fields are included
|
|
49
|
+
if (ast.query?.aggregate) {
|
|
50
|
+
for (const [operation, aggregateFields] of Object.entries(ast.query.aggregate)) {
|
|
51
|
+
if (!fields)
|
|
52
|
+
continue;
|
|
53
|
+
if (operation === 'count' && aggregateFields.includes('*'))
|
|
54
|
+
fields.push('count');
|
|
55
|
+
fields.push(...aggregateFields.map((field) => `${operation}.${field}`));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const rawItem of rawItems) {
|
|
59
|
+
if (rawItem === null || rawItem === undefined)
|
|
60
|
+
return rawItem;
|
|
61
|
+
let item = rawItem;
|
|
62
|
+
for (const nestedNode of nestedCollectionNodes) {
|
|
63
|
+
item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, nestedNode.type === 'm2o'
|
|
64
|
+
? schema.collections[nestedNode.relation.related_collection].primary
|
|
65
|
+
: schema.collections[nestedNode.relation.collection].primary, item);
|
|
66
|
+
}
|
|
67
|
+
const fieldsWithFunctionsApplied = fields.map((field) => applyFunctionToColumnName(field));
|
|
68
|
+
item = fields.length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
|
|
69
|
+
items.push(item);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return Array.isArray(rawItem) ? items : items[0];
|
|
73
|
+
}
|
package/dist/emitter.js
CHANGED
|
@@ -5,7 +5,7 @@ import { readdir } from 'node:fs/promises';
|
|
|
5
5
|
import { dirname } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import path from 'path';
|
|
8
|
-
import { useLogger } from '../../logger.js';
|
|
8
|
+
import { useLogger } from '../../logger/index.js';
|
|
9
9
|
import { Url } from '../../utils/url.js';
|
|
10
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
export const getSharedDepsMapping = async (deps) => {
|
|
@@ -9,7 +9,7 @@ import { Readable } from 'node:stream';
|
|
|
9
9
|
import Queue from 'p-queue';
|
|
10
10
|
import { join } from 'path';
|
|
11
11
|
import { extract } from 'tar';
|
|
12
|
-
import { useLogger } from '../../../logger.js';
|
|
12
|
+
import { useLogger } from '../../../logger/index.js';
|
|
13
13
|
import { getStorage } from '../../../storage/index.js';
|
|
14
14
|
import { getExtensionsPath } from '../get-extensions-path.js';
|
|
15
15
|
const env = useEnv();
|
|
@@ -8,7 +8,7 @@ import { pipeline } from 'node:stream/promises';
|
|
|
8
8
|
import Queue from 'p-queue';
|
|
9
9
|
import { useBus } from '../../bus/index.js';
|
|
10
10
|
import { useLock } from '../../lock/index.js';
|
|
11
|
-
import { useLogger } from '../../logger.js';
|
|
11
|
+
import { useLogger } from '../../logger/index.js';
|
|
12
12
|
import { getStorage } from '../../storage/index.js';
|
|
13
13
|
import { getExtensionsPath } from './get-extensions-path.js';
|
|
14
14
|
import { SyncStatus, getSyncStatus, setSyncStatus } from './sync-status.js';
|
|
@@ -20,7 +20,7 @@ import { useBus } from '../bus/index.js';
|
|
|
20
20
|
import getDatabase from '../database/index.js';
|
|
21
21
|
import emitter, { Emitter } from '../emitter.js';
|
|
22
22
|
import { getFlowManager } from '../flows.js';
|
|
23
|
-
import { useLogger } from '../logger.js';
|
|
23
|
+
import { useLogger } from '../logger/index.js';
|
|
24
24
|
import * as services from '../services/index.js';
|
|
25
25
|
import { deleteFromRequireCache } from '../utils/delete-from-require-cache.js';
|
|
26
26
|
import getModuleDefault from '../utils/get-module-default.js';
|
package/dist/flows.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Action } from '@directus/constants';
|
|
2
2
|
import { useEnv } from '@directus/env';
|
|
3
3
|
import { ForbiddenError } from '@directus/errors';
|
|
4
|
+
import { isSystemCollection } from '@directus/system-data';
|
|
4
5
|
import { applyOptionsData, getRedactedString, isValidJSON, parseJSON, toArray } from '@directus/utils';
|
|
5
|
-
import {
|
|
6
|
+
import { pick } from 'lodash-es';
|
|
6
7
|
import { get } from 'micromustache';
|
|
7
8
|
import { useBus } from './bus/index.js';
|
|
8
9
|
import getDatabase from './database/index.js';
|
|
9
10
|
import emitter from './emitter.js';
|
|
10
|
-
import { useLogger } from './logger.js';
|
|
11
|
+
import { useLogger } from './logger/index.js';
|
|
11
12
|
import { ActivityService } from './services/activity.js';
|
|
12
13
|
import { FlowsService } from './services/flows.js';
|
|
13
14
|
import * as services from './services/index.js';
|
|
@@ -18,7 +19,6 @@ import { JobQueue } from './utils/job-queue.js';
|
|
|
18
19
|
import { mapValuesDeep } from './utils/map-values-deep.js';
|
|
19
20
|
import { redactObject } from './utils/redact-object.js';
|
|
20
21
|
import { scheduleSynchronizedJob, validateCron } from './utils/schedule.js';
|
|
21
|
-
import { isSystemCollection } from '@directus/system-data';
|
|
22
22
|
let flowManager;
|
|
23
23
|
export function getFlowManager() {
|
|
24
24
|
if (flowManager) {
|
|
@@ -284,8 +284,7 @@ class FlowManager {
|
|
|
284
284
|
item: flow.id,
|
|
285
285
|
data: {
|
|
286
286
|
steps: steps.map((step) => redactObject(step, { values: this.envs }, getRedactedString)),
|
|
287
|
-
data: redactObject(
|
|
288
|
-
{
|
|
287
|
+
data: redactObject(keyedData, {
|
|
289
288
|
keys: [
|
|
290
289
|
['**', 'headers', 'authorization'],
|
|
291
290
|
['**', 'headers', 'cookie'],
|
|
@@ -4,7 +4,8 @@ import { merge } from 'lodash-es';
|
|
|
4
4
|
import { URL } from 'node:url';
|
|
5
5
|
import { pino } from 'pino';
|
|
6
6
|
import { pinoHttp, stdSerializers } from 'pino-http';
|
|
7
|
-
import { getConfigFromEnv } from '
|
|
7
|
+
import { getConfigFromEnv } from '../utils/get-config-from-env.js';
|
|
8
|
+
import { redactQuery } from './redact-query.js';
|
|
8
9
|
export const _cache = { logger: undefined };
|
|
9
10
|
export const useLogger = () => {
|
|
10
11
|
if (_cache.logger) {
|
|
@@ -131,10 +132,3 @@ export const createExpressLogger = () => {
|
|
|
131
132
|
},
|
|
132
133
|
});
|
|
133
134
|
};
|
|
134
|
-
function redactQuery(originalPath) {
|
|
135
|
-
const url = new URL(originalPath, 'http://example.com/');
|
|
136
|
-
if (url.searchParams.has('access_token')) {
|
|
137
|
-
url.searchParams.set('access_token', REDACTED_TEXT);
|
|
138
|
-
}
|
|
139
|
-
return url.pathname + url.search;
|
|
140
|
-
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function redactQuery(originalPath: string): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { REDACTED_TEXT } from '@directus/utils';
|
|
2
|
+
export function redactQuery(originalPath) {
|
|
3
|
+
try {
|
|
4
|
+
const url = new URL(originalPath, 'http://example.com/');
|
|
5
|
+
if (url.searchParams.has('access_token')) {
|
|
6
|
+
url.searchParams.set('access_token', REDACTED_TEXT);
|
|
7
|
+
}
|
|
8
|
+
return url.pathname + url.search;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return originalPath;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/mailer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
2
|
import nodemailer from 'nodemailer';
|
|
3
|
-
import { useLogger } from './logger.js';
|
|
3
|
+
import { useLogger } from './logger/index.js';
|
|
4
4
|
import { getConfigFromEnv } from './utils/get-config-from-env.js';
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isEqual } from 'lodash-es';
|
|
2
2
|
import getDatabase from '../database/index.js';
|
|
3
3
|
import emitter from '../emitter.js';
|
|
4
|
+
import { createDefaultAccountability } from '../permissions/utils/create-default-accountability.js';
|
|
4
5
|
import asyncHandler from '../utils/async-handler.js';
|
|
5
6
|
import { getAccountabilityForToken } from '../utils/get-accountability-for-token.js';
|
|
6
7
|
import { getIPFromReq } from '../utils/get-ip-from-req.js';
|
|
@@ -12,13 +13,7 @@ import { SESSION_COOKIE_OPTIONS } from '../constants.js';
|
|
|
12
13
|
*/
|
|
13
14
|
export const handler = async (req, res, next) => {
|
|
14
15
|
const env = useEnv();
|
|
15
|
-
const defaultAccountability = {
|
|
16
|
-
user: null,
|
|
17
|
-
role: null,
|
|
18
|
-
admin: false,
|
|
19
|
-
app: false,
|
|
20
|
-
ip: getIPFromReq(req),
|
|
21
|
-
};
|
|
16
|
+
const defaultAccountability = createDefaultAccountability({ ip: getIPFromReq(req) });
|
|
22
17
|
const userAgent = req.get('user-agent')?.substring(0, 1024);
|
|
23
18
|
if (userAgent)
|
|
24
19
|
defaultAccountability.userAgent = userAgent;
|
package/dist/middleware/cache.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
2
|
import { getCache, getCacheValue } from '../cache.js';
|
|
3
|
-
import { useLogger } from '../logger.js';
|
|
3
|
+
import { useLogger } from '../logger/index.js';
|
|
4
4
|
import asyncHandler from '../utils/async-handler.js';
|
|
5
5
|
import { getCacheControlHeader } from '../utils/get-cache-headers.js';
|
|
6
6
|
import { getCacheKey } from '../utils/get-cache-key.js';
|
|
@@ -20,7 +20,7 @@ const checkCacheMiddleware = asyncHandler(async (req, res, next) => {
|
|
|
20
20
|
res.setHeader(`${env['CACHE_STATUS_HEADER']}`, 'MISS');
|
|
21
21
|
return next();
|
|
22
22
|
}
|
|
23
|
-
const key = getCacheKey(req);
|
|
23
|
+
const key = await getCacheKey(req);
|
|
24
24
|
let cachedData;
|
|
25
25
|
try {
|
|
26
26
|
cachedData = await getCacheValue(cache, key);
|
|
@@ -3,7 +3,7 @@ import { isObject, toArray } from '@directus/utils';
|
|
|
3
3
|
import { getNodeEnv } from '@directus/utils/node';
|
|
4
4
|
import getDatabase from '../database/index.js';
|
|
5
5
|
import emitter from '../emitter.js';
|
|
6
|
-
import { useLogger } from '../logger.js';
|
|
6
|
+
import { useLogger } from '../logger/index.js';
|
|
7
7
|
// Note: keep all 4 parameters here. That's how Express recognizes it's the error handler, even if
|
|
8
8
|
// we don't use next
|
|
9
9
|
const errorHandler = (err, req, res, _next) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
2
|
import { HitRateLimitError } from '@directus/errors';
|
|
3
|
-
import { useLogger } from '../logger.js';
|
|
3
|
+
import { useLogger } from '../logger/index.js';
|
|
4
4
|
import { createRateLimiter } from '../rate-limiter.js';
|
|
5
5
|
import asyncHandler from '../utils/async-handler.js';
|
|
6
6
|
import { validateEnv } from '../utils/validate-env.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
2
|
import { parse as parseBytesConfiguration } from 'bytes';
|
|
3
3
|
import { getCache, setCacheValue } from '../cache.js';
|
|
4
|
-
import { useLogger } from '../logger.js';
|
|
4
|
+
import { useLogger } from '../logger/index.js';
|
|
5
5
|
import { ExportService } from '../services/import-export.js';
|
|
6
6
|
import asyncHandler from '../utils/async-handler.js';
|
|
7
7
|
import { getCacheControlHeader } from '../utils/get-cache-headers.js';
|
|
@@ -25,7 +25,7 @@ export const respond = asyncHandler(async (req, res) => {
|
|
|
25
25
|
!req.sanitizedQuery.export &&
|
|
26
26
|
res.locals['cache'] !== false &&
|
|
27
27
|
exceedsMaxSize === false) {
|
|
28
|
-
const key = getCacheKey(req);
|
|
28
|
+
const key = await getCacheKey(req);
|
|
29
29
|
try {
|
|
30
30
|
await setCacheValue(cache, key, res.locals['payload'], getMilliseconds(env['CACHE_TTL']));
|
|
31
31
|
await setCacheValue(cache, `${key}__expires_at`, { exp: Date.now() + getMilliseconds(env['CACHE_TTL'], 0) });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineOperationApi } from '@directus/extensions';
|
|
2
2
|
import { optionToString } from '@directus/utils';
|
|
3
|
-
import { useLogger } from '../../logger.js';
|
|
3
|
+
import { useLogger } from '../../logger/index.js';
|
|
4
4
|
export default defineOperationApi({
|
|
5
5
|
id: 'log',
|
|
6
6
|
handler: ({ message }) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineOperationApi } from '@directus/extensions';
|
|
2
2
|
import { MailService } from '../../services/mail/index.js';
|
|
3
3
|
import { md } from '../../utils/md.js';
|
|
4
|
-
import { useLogger } from '../../logger.js';
|
|
4
|
+
import { useLogger } from '../../logger/index.js';
|
|
5
5
|
const logger = useLogger();
|
|
6
6
|
export default defineOperationApi({
|
|
7
7
|
id: 'mail',
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineCache } from '@directus/memory';
|
|
2
|
+
import { redisConfigAvailable, useRedis } from '../redis/index.js';
|
|
3
|
+
const localOnly = redisConfigAvailable() === false;
|
|
4
|
+
const config = localOnly
|
|
5
|
+
? {
|
|
6
|
+
type: 'local',
|
|
7
|
+
maxKeys: 500,
|
|
8
|
+
}
|
|
9
|
+
: {
|
|
10
|
+
type: 'multi',
|
|
11
|
+
redis: {
|
|
12
|
+
namespace: 'permissions',
|
|
13
|
+
redis: useRedis(),
|
|
14
|
+
},
|
|
15
|
+
local: {
|
|
16
|
+
maxKeys: 100,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
export const useCache = defineCache(config);
|
|
20
|
+
export function clearCache() {
|
|
21
|
+
const cache = useCache();
|
|
22
|
+
return cache.clear();
|
|
23
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Accountability, Permission, PermissionsAction } from '@directus/types';
|
|
2
|
+
import type { Context } from '../types.js';
|
|
3
|
+
export declare const fetchPermissions: typeof _fetchPermissions;
|
|
4
|
+
export interface FetchPermissionsOptions {
|
|
5
|
+
action?: PermissionsAction;
|
|
6
|
+
policies: string[];
|
|
7
|
+
collections?: string[];
|
|
8
|
+
accountability?: Pick<Accountability, 'user' | 'role' | 'roles' | 'app'>;
|
|
9
|
+
}
|
|
10
|
+
export declare function _fetchPermissions(options: FetchPermissionsOptions, context: Context): Promise<Permission[]>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { pick, sortBy } from 'lodash-es';
|
|
2
|
+
import { fetchDynamicVariableContext } from '../utils/fetch-dynamic-variable-context.js';
|
|
3
|
+
import { processPermissions } from '../utils/process-permissions.js';
|
|
4
|
+
import { withCache } from '../utils/with-cache.js';
|
|
5
|
+
import { withAppMinimalPermissions } from './with-app-minimal-permissions.js';
|
|
6
|
+
export const fetchPermissions = withCache('permissions', _fetchPermissions, ({ action, policies, collections, accountability }) => ({
|
|
7
|
+
policies, // we assume that policies always come from the same source, so they should be in the same order
|
|
8
|
+
...(action && { action }),
|
|
9
|
+
...(collections && { collections: sortBy(collections) }),
|
|
10
|
+
...(accountability && { accountability: pick(accountability, ['user', 'role', 'roles', 'app']) }),
|
|
11
|
+
}));
|
|
12
|
+
export async function _fetchPermissions(options, context) {
|
|
13
|
+
const { PermissionsService } = await import('../../services/permissions.js');
|
|
14
|
+
const permissionsService = new PermissionsService(context);
|
|
15
|
+
const filter = {
|
|
16
|
+
_and: [{ policy: { _in: options.policies } }],
|
|
17
|
+
};
|
|
18
|
+
if (options.action) {
|
|
19
|
+
filter._and.push({ action: { _eq: options.action } });
|
|
20
|
+
}
|
|
21
|
+
if (options.collections) {
|
|
22
|
+
filter._and.push({ collection: { _in: options.collections } });
|
|
23
|
+
}
|
|
24
|
+
let permissions = (await permissionsService.readByQuery({
|
|
25
|
+
filter,
|
|
26
|
+
limit: -1,
|
|
27
|
+
}));
|
|
28
|
+
// Sort permissions by their order in the policies array
|
|
29
|
+
// This ensures that if a sorted array of policies is passed in the permissions are returned in the same order
|
|
30
|
+
// which is necessary for correctly applying the presets in order
|
|
31
|
+
permissions = sortBy(permissions, (permission) => options.policies.indexOf(permission.policy));
|
|
32
|
+
if (options.accountability) {
|
|
33
|
+
// Add app minimal permissions for the request accountability, if applicable.
|
|
34
|
+
// Normally this is done in the permissions service readByQuery, but it also needs to do it here
|
|
35
|
+
// since the permissions service is created without accountability.
|
|
36
|
+
// We call it without the policies filter, since the static minimal app permissions don't have a policy attached.
|
|
37
|
+
const permissionsWithAppPermissions = withAppMinimalPermissions(options.accountability ?? null, permissions, {
|
|
38
|
+
_and: filter._and.slice(1),
|
|
39
|
+
});
|
|
40
|
+
const permissionsContext = await fetchDynamicVariableContext({
|
|
41
|
+
accountability: options.accountability,
|
|
42
|
+
policies: options.policies,
|
|
43
|
+
permissions: permissionsWithAppPermissions,
|
|
44
|
+
}, context);
|
|
45
|
+
// Replace dynamic variables with their actual values
|
|
46
|
+
const processedPermissions = processPermissions({
|
|
47
|
+
permissions: permissionsWithAppPermissions,
|
|
48
|
+
accountability: options.accountability,
|
|
49
|
+
permissionsContext,
|
|
50
|
+
});
|
|
51
|
+
// TODO merge in permissions coming from the share scope
|
|
52
|
+
return processedPermissions;
|
|
53
|
+
}
|
|
54
|
+
return permissions;
|
|
55
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Accountability } from '@directus/types';
|
|
2
|
+
import type { Context } from '../types.js';
|
|
3
|
+
export declare const fetchPolicies: typeof _fetchPolicies;
|
|
4
|
+
/**
|
|
5
|
+
* Fetch the policies associated with the current user accountability
|
|
6
|
+
*/
|
|
7
|
+
export declare function _fetchPolicies({ roles, user, ip }: Pick<Accountability, 'user' | 'roles' | 'ip'>, context: Context): Promise<string[]>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { filterPoliciesByIp } from '../utils/filter-policies-by-ip.js';
|
|
2
|
+
import { withCache } from '../utils/with-cache.js';
|
|
3
|
+
export const fetchPolicies = withCache('policies', _fetchPolicies, ({ roles, user, ip }) => ({ roles, user, ip }));
|
|
4
|
+
/**
|
|
5
|
+
* Fetch the policies associated with the current user accountability
|
|
6
|
+
*/
|
|
7
|
+
export async function _fetchPolicies({ roles, user, ip }, context) {
|
|
8
|
+
const { AccessService } = await import('../../services/access.js');
|
|
9
|
+
const accessService = new AccessService(context);
|
|
10
|
+
let roleFilter;
|
|
11
|
+
if (roles.length === 0) {
|
|
12
|
+
// Users without role assumes the Public role permissions along with their attached policies
|
|
13
|
+
roleFilter = { _and: [{ role: { _null: true } }, { user: { _null: true } }] };
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
roleFilter = { role: { _in: roles } };
|
|
17
|
+
}
|
|
18
|
+
// If the user is not null, we also want to include the policies attached to the user
|
|
19
|
+
const filter = user ? { _or: [{ user: { _eq: user } }, roleFilter] } : roleFilter;
|
|
20
|
+
const accessRows = (await accessService.readByQuery({
|
|
21
|
+
filter,
|
|
22
|
+
fields: ['policy.id', 'policy.ip_access'],
|
|
23
|
+
limit: -1,
|
|
24
|
+
}));
|
|
25
|
+
const filteredAccessRows = filterPoliciesByIp(accessRows, ip);
|
|
26
|
+
const ids = filteredAccessRows.map(({ policy }) => policy.id);
|
|
27
|
+
return ids;
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { withCache } from '../utils/with-cache.js';
|
|
2
|
+
export const fetchRolesTree = withCache('roles-tree', _fetchRolesTree);
|
|
3
|
+
export async function _fetchRolesTree(start, knex) {
|
|
4
|
+
if (!start)
|
|
5
|
+
return [];
|
|
6
|
+
let parent = start;
|
|
7
|
+
const roles = [];
|
|
8
|
+
while (parent) {
|
|
9
|
+
const role = await knex
|
|
10
|
+
.select('id', 'parent')
|
|
11
|
+
.from('directus_roles')
|
|
12
|
+
.where({ id: parent })
|
|
13
|
+
.first();
|
|
14
|
+
if (!role) {
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
roles.push(role.id);
|
|
18
|
+
// Prevent infinite recursion loops
|
|
19
|
+
if (role.parent && roles.includes(role.parent) === true) {
|
|
20
|
+
roles.reverse();
|
|
21
|
+
const rolesStr = roles.map((role) => `"${role}"`).join('->');
|
|
22
|
+
throw new Error(`Recursion encountered: role "${role.id}" already exists in tree path ${rolesStr}`);
|
|
23
|
+
}
|
|
24
|
+
parent = role.parent;
|
|
25
|
+
}
|
|
26
|
+
roles.reverse();
|
|
27
|
+
return roles;
|
|
28
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Accountability, Permission, Query } from '@directus/types';
|
|
2
|
-
export declare function withAppMinimalPermissions(accountability: Accountability | null, permissions: Permission[], filter: Query['filter']): Permission[];
|
|
2
|
+
export declare function withAppMinimalPermissions(accountability: Pick<Accountability, 'app'> | null, permissions: Permission[], filter: Query['filter']): Permission[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { appAccessMinimalPermissions } from '@directus/system-data';
|
|
2
|
+
import { cloneDeep } from 'lodash-es';
|
|
3
|
+
import { filterItems } from '../../utils/filter-items.js';
|
|
4
|
+
export function withAppMinimalPermissions(accountability, permissions, filter) {
|
|
5
|
+
if (accountability?.app === true) {
|
|
6
|
+
const filteredAppMinimalPermissions = cloneDeep(filterItems(appAccessMinimalPermissions, filter));
|
|
7
|
+
return [...permissions, ...filteredAppMinimalPermissions];
|
|
8
|
+
}
|
|
9
|
+
return permissions;
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Accountability, CollectionAccess } from '@directus/types';
|
|
2
|
+
import type { Context } from '../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Get all permissions + minimal app permissions (if applicable) for the user + role in the current accountability.
|
|
5
|
+
* The permissions will be filtered by IP access.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fetchAccountabilityCollectionAccess(accountability: Pick<Accountability, 'user' | 'roles' | 'role' | 'ip' | 'admin' | 'app'>, context: Context): Promise<CollectionAccess>;
|