@directus/api 21.0.0 → 22.1.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/commands/init/questions.d.ts +7 -6
- package/dist/cli/commands/init/questions.js +2 -2
- package/dist/cli/utils/create-env/index.d.ts +2 -2
- package/dist/cli/utils/create-env/index.js +3 -1
- package/dist/cli/utils/defaults.d.ts +4 -11
- package/dist/cli/utils/defaults.js +7 -1
- package/dist/cli/utils/drivers.js +1 -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/tus.js +14 -26
- 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 +200 -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/helpers/index.d.ts +3 -3
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/cockroachdb.js +4 -0
- package/dist/database/helpers/schema/dialects/mssql.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/mssql.js +4 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/oracle.js +4 -0
- package/dist/database/helpers/schema/dialects/postgres.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/postgres.js +4 -0
- package/dist/database/helpers/schema/types.d.ts +5 -0
- package/dist/database/helpers/schema/types.js +3 -0
- package/dist/database/helpers/schema/utils/preprocess-bindings.d.ts +8 -0
- package/dist/database/helpers/schema/utils/preprocess-bindings.js +30 -0
- package/dist/database/index.js +6 -1
- package/dist/database/migrations/20210519A-add-system-fk-triggers.js +3 -2
- package/dist/database/migrations/20230721A-require-shares-fields.js +3 -5
- package/dist/database/migrations/20240716A-update-files-date-fields.js +3 -7
- package/dist/{utils/merge-permissions.d.ts → database/migrations/20240806A-permissions-policies.d.ts} +4 -1
- package/dist/database/migrations/20240806A-permissions-policies.js +352 -0
- package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
- package/dist/database/run-ast/lib/get-db-query.js +218 -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 +27 -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/database/run-ast/utils/with-preprocess-bindings.d.ts +2 -0
- package/dist/database/run-ast/utils/with-preprocess-bindings.js +14 -0
- package/dist/flows.js +3 -4
- package/dist/middleware/authenticate.js +2 -7
- package/dist/middleware/cache.js +1 -1
- 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 +11 -0
- package/dist/permissions/lib/fetch-permissions.js +56 -0
- package/dist/permissions/lib/fetch-policies.d.ts +14 -0
- package/dist/permissions/lib/fetch-policies.js +43 -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 +18 -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 +60 -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/server.js +17 -4
- 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 +54 -25
- package/dist/services/files.js +10 -3
- 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.d.ts +3 -1
- package/dist/services/import-export.js +67 -9
- 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/meta.js +60 -23
- package/dist/services/notifications.js +14 -6
- 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 +27 -30
- package/dist/services/roles.d.ts +4 -12
- package/dist/services/roles.js +57 -424
- 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 +1 -5
- package/dist/services/users.js +78 -161
- 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 +2 -2
- 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/database.d.ts +1 -1
- package/dist/types/items.d.ts +11 -0
- package/dist/utils/apply-query.d.ts +11 -7
- package/dist/utils/apply-query.js +69 -11
- package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +19 -0
- package/dist/utils/fetch-user-count/fetch-access-lookup.js +23 -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 +64 -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-address.d.ts +5 -0
- package/dist/utils/get-address.js +13 -0
- 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-service.js +5 -1
- package/dist/utils/reduce-schema.d.ts +4 -6
- package/dist/utils/reduce-schema.js +16 -32
- package/dist/utils/sanitize-schema.d.ts +1 -1
- package/dist/utils/transaction.js +28 -11
- 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 +3 -7
- package/dist/websocket/controllers/hooks.js +4 -0
- package/dist/websocket/controllers/rest.js +2 -5
- package/dist/websocket/handlers/subscribe.js +0 -2
- package/dist/websocket/utils/items.d.ts +1 -1
- package/package.json +31 -30
- 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.js +0 -95
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
2
|
import formatTitle from '@directus/format-title';
|
|
3
3
|
import { spec } from '@directus/specs';
|
|
4
|
+
import { isSystemCollection } from '@directus/system-data';
|
|
4
5
|
import { version } from 'directus/version';
|
|
5
6
|
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
6
7
|
import { OAS_REQUIRED_SCHEMAS } from '../constants.js';
|
|
7
8
|
import getDatabase from '../database/index.js';
|
|
9
|
+
import { fetchPermissions } from '../permissions/lib/fetch-permissions.js';
|
|
10
|
+
import { fetchPolicies } from '../permissions/lib/fetch-policies.js';
|
|
11
|
+
import { fetchAllowedFieldMap } from '../permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js';
|
|
8
12
|
import { getRelationType } from '../utils/get-relation-type.js';
|
|
9
13
|
import { reduceSchema } from '../utils/reduce-schema.js';
|
|
10
14
|
import { GraphQLService } from './graphql/index.js';
|
|
11
|
-
import { isSystemCollection } from '@directus/system-data';
|
|
12
15
|
const env = useEnv();
|
|
13
16
|
export class SpecificationService {
|
|
14
17
|
accountability;
|
|
@@ -16,29 +19,38 @@ export class SpecificationService {
|
|
|
16
19
|
schema;
|
|
17
20
|
oas;
|
|
18
21
|
graphql;
|
|
19
|
-
constructor(
|
|
20
|
-
this.accountability = accountability || null;
|
|
21
|
-
this.knex = knex || getDatabase();
|
|
22
|
-
this.schema = schema;
|
|
23
|
-
this.oas = new OASSpecsService(
|
|
24
|
-
this.graphql = new GraphQLSpecsService(
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.accountability = options.accountability || null;
|
|
24
|
+
this.knex = options.knex || getDatabase();
|
|
25
|
+
this.schema = options.schema;
|
|
26
|
+
this.oas = new OASSpecsService(options);
|
|
27
|
+
this.graphql = new GraphQLSpecsService(options);
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
class OASSpecsService {
|
|
28
31
|
accountability;
|
|
29
32
|
knex;
|
|
30
33
|
schema;
|
|
31
|
-
constructor(
|
|
32
|
-
this.accountability = accountability || null;
|
|
33
|
-
this.knex = knex || getDatabase();
|
|
34
|
-
this.schema =
|
|
35
|
-
this.accountability?.admin === true ? schema : reduceSchema(schema, accountability?.permissions || null);
|
|
34
|
+
constructor(options) {
|
|
35
|
+
this.accountability = options.accountability || null;
|
|
36
|
+
this.knex = options.knex || getDatabase();
|
|
37
|
+
this.schema = options.schema;
|
|
36
38
|
}
|
|
37
39
|
async generate(host) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
let schema = this.schema;
|
|
41
|
+
let permissions = [];
|
|
42
|
+
if (this.accountability && this.accountability.admin !== true) {
|
|
43
|
+
const allowedFields = await fetchAllowedFieldMap({
|
|
44
|
+
accountability: this.accountability,
|
|
45
|
+
action: 'read',
|
|
46
|
+
}, { schema, knex: this.knex });
|
|
47
|
+
schema = reduceSchema(schema, allowedFields);
|
|
48
|
+
const policies = await fetchPolicies(this.accountability, { schema, knex: this.knex });
|
|
49
|
+
permissions = await fetchPermissions({ action: 'read', policies, accountability: this.accountability }, { schema, knex: this.knex });
|
|
50
|
+
}
|
|
51
|
+
const tags = await this.generateTags(schema);
|
|
40
52
|
const paths = await this.generatePaths(permissions, tags);
|
|
41
|
-
const components = await this.generateComponents(tags);
|
|
53
|
+
const components = await this.generateComponents(schema, tags);
|
|
42
54
|
const isDefaultPublicUrl = env['PUBLIC_URL'] === '/';
|
|
43
55
|
const url = isDefaultPublicUrl && host ? host : env['PUBLIC_URL'];
|
|
44
56
|
const spec = {
|
|
@@ -62,9 +74,9 @@ class OASSpecsService {
|
|
|
62
74
|
spec.components = components;
|
|
63
75
|
return spec;
|
|
64
76
|
}
|
|
65
|
-
async generateTags() {
|
|
77
|
+
async generateTags(schema) {
|
|
66
78
|
const systemTags = cloneDeep(spec.tags);
|
|
67
|
-
const collections = Object.values(
|
|
79
|
+
const collections = Object.values(schema.collections);
|
|
68
80
|
const tags = [];
|
|
69
81
|
for (const systemTag of systemTags) {
|
|
70
82
|
// Check if necessary authentication level is given
|
|
@@ -246,7 +258,7 @@ class OASSpecsService {
|
|
|
246
258
|
}
|
|
247
259
|
return paths;
|
|
248
260
|
}
|
|
249
|
-
async generateComponents(tags) {
|
|
261
|
+
async generateComponents(schema, tags) {
|
|
250
262
|
if (!tags)
|
|
251
263
|
return;
|
|
252
264
|
let components = cloneDeep(spec.components);
|
|
@@ -264,7 +276,7 @@ class OASSpecsService {
|
|
|
264
276
|
};
|
|
265
277
|
}
|
|
266
278
|
}
|
|
267
|
-
const collections = Object.values(
|
|
279
|
+
const collections = Object.values(schema.collections);
|
|
268
280
|
for (const collection of collections) {
|
|
269
281
|
const tag = tags.find((tag) => tag['x-collection'] === collection.collection);
|
|
270
282
|
if (!tag)
|
|
@@ -277,7 +289,7 @@ class OASSpecsService {
|
|
|
277
289
|
schemaComponent['x-collection'] = collection.collection;
|
|
278
290
|
for (const field of fieldsInCollection) {
|
|
279
291
|
schemaComponent.properties[field.field] =
|
|
280
|
-
cloneDeep(spec.components.schemas[tag.name].properties[field.field]) || this.generateField(collection.collection, field, tags);
|
|
292
|
+
cloneDeep(spec.components.schemas[tag.name].properties[field.field]) || this.generateField(schema, collection.collection, field, tags);
|
|
281
293
|
}
|
|
282
294
|
components.schemas[tag.name] = schemaComponent;
|
|
283
295
|
}
|
|
@@ -288,7 +300,7 @@ class OASSpecsService {
|
|
|
288
300
|
'x-collection': collection.collection,
|
|
289
301
|
};
|
|
290
302
|
for (const field of fieldsInCollection) {
|
|
291
|
-
schemaComponent.properties[field.field] = this.generateField(collection.collection, field, tags);
|
|
303
|
+
schemaComponent.properties[field.field] = this.generateField(schema, collection.collection, field, tags);
|
|
292
304
|
}
|
|
293
305
|
components.schemas[tag.name] = schemaComponent;
|
|
294
306
|
}
|
|
@@ -311,13 +323,13 @@ class OASSpecsService {
|
|
|
311
323
|
return 'read';
|
|
312
324
|
}
|
|
313
325
|
}
|
|
314
|
-
generateField(collection, field, tags) {
|
|
326
|
+
generateField(schema, collection, field, tags) {
|
|
315
327
|
let propertyObject = {};
|
|
316
328
|
propertyObject.nullable = field.nullable;
|
|
317
329
|
if (field.note) {
|
|
318
330
|
propertyObject.description = field.note;
|
|
319
331
|
}
|
|
320
|
-
const relation =
|
|
332
|
+
const relation = schema.relations.find((relation) => (relation.collection === collection && relation.field === field.field) ||
|
|
321
333
|
(relation.related_collection === collection && relation.meta?.one_field === field.field));
|
|
322
334
|
if (!relation) {
|
|
323
335
|
propertyObject = {
|
|
@@ -335,10 +347,10 @@ class OASSpecsService {
|
|
|
335
347
|
const relatedTag = tags.find((tag) => tag['x-collection'] === relation.related_collection);
|
|
336
348
|
if (!relatedTag ||
|
|
337
349
|
!relation.related_collection ||
|
|
338
|
-
relation.related_collection in
|
|
350
|
+
relation.related_collection in schema.collections === false) {
|
|
339
351
|
return propertyObject;
|
|
340
352
|
}
|
|
341
|
-
const relatedCollection =
|
|
353
|
+
const relatedCollection = schema.collections[relation.related_collection];
|
|
342
354
|
const relatedPrimaryKeyField = relatedCollection.fields[relatedCollection.primary];
|
|
343
355
|
propertyObject.oneOf = [
|
|
344
356
|
{
|
|
@@ -351,10 +363,10 @@ class OASSpecsService {
|
|
|
351
363
|
}
|
|
352
364
|
else if (relationType === 'o2m') {
|
|
353
365
|
const relatedTag = tags.find((tag) => tag['x-collection'] === relation.collection);
|
|
354
|
-
if (!relatedTag || !relation.related_collection || relation.collection in
|
|
366
|
+
if (!relatedTag || !relation.related_collection || relation.collection in schema.collections === false) {
|
|
355
367
|
return propertyObject;
|
|
356
368
|
}
|
|
357
|
-
const relatedCollection =
|
|
369
|
+
const relatedCollection = schema.collections[relation.collection];
|
|
358
370
|
const relatedPrimaryKeyField = relatedCollection.fields[relatedCollection.primary];
|
|
359
371
|
if (!relatedTag || !relatedPrimaryKeyField)
|
|
360
372
|
return propertyObject;
|
package/dist/services/users.d.ts
CHANGED
|
@@ -13,11 +13,6 @@ export declare class UsersService extends ItemsService {
|
|
|
13
13
|
* directus_settings.auth_password_policy
|
|
14
14
|
*/
|
|
15
15
|
private checkPasswordPolicy;
|
|
16
|
-
private checkRemainingAdminExistence;
|
|
17
|
-
/**
|
|
18
|
-
* Make sure there's at least one active admin user when updating user status
|
|
19
|
-
*/
|
|
20
|
-
private checkRemainingActiveAdmin;
|
|
21
16
|
/**
|
|
22
17
|
* Get basic information of user identified by email
|
|
23
18
|
*/
|
|
@@ -52,4 +47,5 @@ export declare class UsersService extends ItemsService {
|
|
|
52
47
|
verifyRegistration(token: string): Promise<string>;
|
|
53
48
|
requestPasswordReset(email: string, url: string | null, subject?: string | null): Promise<void>;
|
|
54
49
|
resetPassword(token: string, password: string): Promise<void>;
|
|
50
|
+
private clearCaches;
|
|
55
51
|
}
|
package/dist/services/users.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
|
-
import { ForbiddenError, InvalidPayloadError, RecordNotUniqueError
|
|
3
|
-
import { getSimpleHash, toArray,
|
|
2
|
+
import { ForbiddenError, InvalidPayloadError, RecordNotUniqueError } from '@directus/errors';
|
|
3
|
+
import { getSimpleHash, toArray, validatePayload } from '@directus/utils';
|
|
4
4
|
import { FailedValidationError, joiValidationErrorItemToErrorExtensions } from '@directus/validation';
|
|
5
5
|
import Joi from 'joi';
|
|
6
6
|
import jwt from 'jsonwebtoken';
|
|
7
|
-
import { isEmpty
|
|
7
|
+
import { isEmpty } from 'lodash-es';
|
|
8
8
|
import { performance } from 'perf_hooks';
|
|
9
|
+
import { clearSystemCache } from '../cache.js';
|
|
9
10
|
import getDatabase from '../database/index.js';
|
|
10
11
|
import { useLogger } from '../logger/index.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { getRoleCountsByUsers } from '../telemetry/utils/get-role-counts-by-users.js';
|
|
14
|
-
import {} from '../telemetry/utils/get-user-count.js';
|
|
15
|
-
import { shouldCheckUserLimits } from '../telemetry/utils/should-check-user-limits.js';
|
|
12
|
+
import { validateRemainingAdminUsers } from '../permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js';
|
|
13
|
+
import { createDefaultAccountability } from '../permissions/utils/create-default-accountability.js';
|
|
16
14
|
import { getSecret } from '../utils/get-secret.js';
|
|
17
15
|
import isUrlAllowed from '../utils/is-url-allowed.js';
|
|
18
16
|
import { verifyJWT } from '../utils/jwt.js';
|
|
19
17
|
import { stall } from '../utils/stall.js';
|
|
20
18
|
import { Url } from '../utils/url.js';
|
|
19
|
+
import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
|
|
21
20
|
import { ItemsService } from './items.js';
|
|
22
21
|
import { MailService } from './mail/index.js';
|
|
23
22
|
import { SettingsService } from './settings.js';
|
|
@@ -88,42 +87,11 @@ export class UsersService extends ItemsService {
|
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
|
-
async checkRemainingAdminExistence(excludeKeys) {
|
|
92
|
-
// Make sure there's at least one admin user left after this deletion is done
|
|
93
|
-
const otherAdminUsers = await this.knex
|
|
94
|
-
.count('*', { as: 'count' })
|
|
95
|
-
.from('directus_users')
|
|
96
|
-
.whereNotIn('directus_users.id', excludeKeys)
|
|
97
|
-
.andWhere({ 'directus_roles.admin_access': true })
|
|
98
|
-
.leftJoin('directus_roles', 'directus_users.role', 'directus_roles.id')
|
|
99
|
-
.first();
|
|
100
|
-
const otherAdminUsersCount = +(otherAdminUsers?.count || 0);
|
|
101
|
-
if (otherAdminUsersCount === 0) {
|
|
102
|
-
throw new UnprocessableContentError({ reason: `You can't remove the last admin user from the role` });
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Make sure there's at least one active admin user when updating user status
|
|
107
|
-
*/
|
|
108
|
-
async checkRemainingActiveAdmin(excludeKeys) {
|
|
109
|
-
const otherAdminUsers = await this.knex
|
|
110
|
-
.count('*', { as: 'count' })
|
|
111
|
-
.from('directus_users')
|
|
112
|
-
.whereNotIn('directus_users.id', excludeKeys)
|
|
113
|
-
.andWhere({ 'directus_roles.admin_access': true })
|
|
114
|
-
.andWhere({ 'directus_users.status': 'active' })
|
|
115
|
-
.leftJoin('directus_roles', 'directus_users.role', 'directus_roles.id')
|
|
116
|
-
.first();
|
|
117
|
-
const otherAdminUsersCount = +(otherAdminUsers?.count || 0);
|
|
118
|
-
if (otherAdminUsersCount === 0) {
|
|
119
|
-
throw new UnprocessableContentError({ reason: `You can't change the active status of the last admin user` });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
90
|
/**
|
|
123
91
|
* Get basic information of user identified by email
|
|
124
92
|
*/
|
|
125
93
|
async getUserByEmail(email) {
|
|
126
|
-
return
|
|
94
|
+
return this.knex
|
|
127
95
|
.select('id', 'role', 'status', 'password', 'email')
|
|
128
96
|
.from('directus_users')
|
|
129
97
|
.whereRaw(`LOWER(??) = ?`, ['email', email.toLowerCase()])
|
|
@@ -158,51 +126,34 @@ export class UsersService extends ItemsService {
|
|
|
158
126
|
/**
|
|
159
127
|
* Create a new user
|
|
160
128
|
*/
|
|
161
|
-
async createOne(data, opts) {
|
|
129
|
+
async createOne(data, opts = {}) {
|
|
162
130
|
try {
|
|
163
|
-
if (
|
|
131
|
+
if ('email' in data) {
|
|
164
132
|
this.validateEmail(data['email']);
|
|
165
133
|
await this.checkUniqueEmails([data['email']]);
|
|
166
134
|
}
|
|
167
|
-
if (
|
|
135
|
+
if ('password' in data) {
|
|
168
136
|
await this.checkPasswordPolicy([data['password']]);
|
|
169
137
|
}
|
|
170
|
-
if (shouldCheckUserLimits() && data['role']) {
|
|
171
|
-
const increasedCounts = {
|
|
172
|
-
admin: 0,
|
|
173
|
-
app: 0,
|
|
174
|
-
api: 0,
|
|
175
|
-
};
|
|
176
|
-
if (typeof data['role'] === 'object') {
|
|
177
|
-
if ('admin_access' in data['role'] && data['role']['admin_access'] === true) {
|
|
178
|
-
increasedCounts.admin++;
|
|
179
|
-
}
|
|
180
|
-
else if ('app_access' in data['role'] && data['role']['app_access'] === true) {
|
|
181
|
-
increasedCounts.app++;
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
increasedCounts.api++;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
const existingRoleCounts = await getRoleCountsByRoles(this.knex, [data['role']]);
|
|
189
|
-
mergeWith(increasedCounts, existingRoleCounts, (x, y) => x + y);
|
|
190
|
-
}
|
|
191
|
-
await checkIncreasedUserLimits(this.knex, increasedCounts);
|
|
192
|
-
}
|
|
193
138
|
}
|
|
194
139
|
catch (err) {
|
|
195
|
-
|
|
140
|
+
opts.preMutationError = err;
|
|
141
|
+
}
|
|
142
|
+
if (!('status' in data) || data['status'] === 'active') {
|
|
143
|
+
// Creating a user only requires checking user limits if the user is active, no need to care about the role
|
|
144
|
+
opts.userIntegrityCheckFlags =
|
|
145
|
+
(opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;
|
|
146
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
196
147
|
}
|
|
197
148
|
return await super.createOne(data, opts);
|
|
198
149
|
}
|
|
199
150
|
/**
|
|
200
151
|
* Create multiple new users
|
|
201
152
|
*/
|
|
202
|
-
async createMany(data, opts) {
|
|
203
|
-
const emails = data
|
|
204
|
-
const passwords = data
|
|
205
|
-
const
|
|
153
|
+
async createMany(data, opts = {}) {
|
|
154
|
+
const emails = data.map((payload) => payload['email']).filter((email) => email);
|
|
155
|
+
const passwords = data.map((payload) => payload['password']).filter((password) => password);
|
|
156
|
+
const someActive = data.some((payload) => !('status' in payload) || payload['status'] === 'active');
|
|
206
157
|
try {
|
|
207
158
|
if (emails.length) {
|
|
208
159
|
this.validateEmail(emails);
|
|
@@ -211,96 +162,30 @@ export class UsersService extends ItemsService {
|
|
|
211
162
|
if (passwords.length) {
|
|
212
163
|
await this.checkPasswordPolicy(passwords);
|
|
213
164
|
}
|
|
214
|
-
if (shouldCheckUserLimits() && roles.length) {
|
|
215
|
-
const increasedCounts = {
|
|
216
|
-
admin: 0,
|
|
217
|
-
app: 0,
|
|
218
|
-
api: 0,
|
|
219
|
-
};
|
|
220
|
-
const existingRoles = [];
|
|
221
|
-
for (const role of roles) {
|
|
222
|
-
if (typeof role === 'object') {
|
|
223
|
-
if ('admin_access' in role && role['admin_access'] === true) {
|
|
224
|
-
increasedCounts.admin++;
|
|
225
|
-
}
|
|
226
|
-
else if ('app_access' in role && role['app_access'] === true) {
|
|
227
|
-
increasedCounts.app++;
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
increasedCounts.api++;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
234
|
-
existingRoles.push(role);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
const existingRoleCounts = await getRoleCountsByRoles(this.knex, existingRoles);
|
|
238
|
-
mergeWith(increasedCounts, existingRoleCounts, (x, y) => x + y);
|
|
239
|
-
await checkIncreasedUserLimits(this.knex, increasedCounts);
|
|
240
|
-
}
|
|
241
165
|
}
|
|
242
166
|
catch (err) {
|
|
243
|
-
|
|
167
|
+
opts.preMutationError = err;
|
|
168
|
+
}
|
|
169
|
+
if (someActive) {
|
|
170
|
+
// Creating users only requires checking user limits if the users are active, no need to care about the role
|
|
171
|
+
opts.userIntegrityCheckFlags =
|
|
172
|
+
(opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;
|
|
173
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
244
174
|
}
|
|
245
|
-
|
|
175
|
+
// Use generic ItemsService to avoid calling `UserService.createOne` to avoid additional work of validating emails,
|
|
176
|
+
// as this requires one query per email if done in `createOne`
|
|
177
|
+
const itemsService = new ItemsService(this.collection, {
|
|
178
|
+
schema: this.schema,
|
|
179
|
+
accountability: this.accountability,
|
|
180
|
+
knex: this.knex,
|
|
181
|
+
});
|
|
182
|
+
return await itemsService.createMany(data, opts);
|
|
246
183
|
}
|
|
247
184
|
/**
|
|
248
185
|
* Update many users by primary key
|
|
249
186
|
*/
|
|
250
|
-
async updateMany(keys, data, opts) {
|
|
187
|
+
async updateMany(keys, data, opts = {}) {
|
|
251
188
|
try {
|
|
252
|
-
const needsUserLimitCheck = shouldCheckUserLimits();
|
|
253
|
-
if (data['role']) {
|
|
254
|
-
/*
|
|
255
|
-
* data['role'] has the following cases:
|
|
256
|
-
* - a string with existing role id
|
|
257
|
-
* - an object with existing role id for GraphQL mutations
|
|
258
|
-
* - an object with data for new role
|
|
259
|
-
*/
|
|
260
|
-
const role = data['role']?.id ?? data['role'];
|
|
261
|
-
let newRole;
|
|
262
|
-
if (typeof role === 'string') {
|
|
263
|
-
newRole = await this.knex
|
|
264
|
-
.select('admin_access', 'app_access')
|
|
265
|
-
.from('directus_roles')
|
|
266
|
-
.where('id', role)
|
|
267
|
-
.first();
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
newRole = role;
|
|
271
|
-
}
|
|
272
|
-
if (!newRole?.admin_access) {
|
|
273
|
-
await this.checkRemainingAdminExistence(keys);
|
|
274
|
-
}
|
|
275
|
-
if (needsUserLimitCheck && newRole) {
|
|
276
|
-
const existingCounts = await getRoleCountsByUsers(this.knex, keys);
|
|
277
|
-
const increasedCounts = {
|
|
278
|
-
admin: 0,
|
|
279
|
-
app: 0,
|
|
280
|
-
api: 0,
|
|
281
|
-
};
|
|
282
|
-
if (toBoolean(newRole.admin_access)) {
|
|
283
|
-
increasedCounts.admin = keys.length - existingCounts.admin;
|
|
284
|
-
}
|
|
285
|
-
else if (toBoolean(newRole.app_access)) {
|
|
286
|
-
increasedCounts.app = keys.length - existingCounts.app;
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
increasedCounts.api = keys.length - existingCounts.api;
|
|
290
|
-
}
|
|
291
|
-
await checkIncreasedUserLimits(this.knex, increasedCounts);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
if (needsUserLimitCheck && data['role'] === null) {
|
|
295
|
-
await checkIncreasedUserLimits(this.knex, { admin: 0, app: 0, api: 1 });
|
|
296
|
-
}
|
|
297
|
-
if (data['status'] !== undefined && data['status'] !== 'active') {
|
|
298
|
-
await this.checkRemainingActiveAdmin(keys);
|
|
299
|
-
}
|
|
300
|
-
if (needsUserLimitCheck && data['status'] === 'active') {
|
|
301
|
-
const increasedCounts = await getRoleCountsByUsers(this.knex, keys, { inactiveUsers: true });
|
|
302
|
-
await checkIncreasedUserLimits(this.knex, increasedCounts);
|
|
303
|
-
}
|
|
304
189
|
if (data['email']) {
|
|
305
190
|
if (keys.length > 1) {
|
|
306
191
|
throw new RecordNotUniqueError({
|
|
@@ -331,19 +216,45 @@ export class UsersService extends ItemsService {
|
|
|
331
216
|
}
|
|
332
217
|
}
|
|
333
218
|
catch (err) {
|
|
334
|
-
|
|
219
|
+
opts.preMutationError = err;
|
|
220
|
+
}
|
|
221
|
+
if ('role' in data) {
|
|
222
|
+
opts.userIntegrityCheckFlags = UserIntegrityCheckFlag.All;
|
|
335
223
|
}
|
|
336
|
-
|
|
224
|
+
if ('status' in data) {
|
|
225
|
+
if (data['status'] === 'active') {
|
|
226
|
+
// User are being activated, no need to check if there are enough admins
|
|
227
|
+
opts.userIntegrityCheckFlags =
|
|
228
|
+
(opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
opts.userIntegrityCheckFlags = UserIntegrityCheckFlag.All;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (opts.userIntegrityCheckFlags) {
|
|
235
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
236
|
+
}
|
|
237
|
+
const result = await super.updateMany(keys, data, opts);
|
|
238
|
+
// Only clear the caches if the role has been updated
|
|
239
|
+
if ('role' in data) {
|
|
240
|
+
await this.clearCaches(opts);
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
337
243
|
}
|
|
338
244
|
/**
|
|
339
245
|
* Delete multiple users by primary key
|
|
340
246
|
*/
|
|
341
|
-
async deleteMany(keys, opts) {
|
|
342
|
-
|
|
343
|
-
|
|
247
|
+
async deleteMany(keys, opts = {}) {
|
|
248
|
+
if (opts?.onRequireUserIntegrityCheck) {
|
|
249
|
+
opts.onRequireUserIntegrityCheck(opts?.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None);
|
|
344
250
|
}
|
|
345
|
-
|
|
346
|
-
|
|
251
|
+
else {
|
|
252
|
+
try {
|
|
253
|
+
await validateRemainingAdminUsers({ excludeUsers: keys }, { knex: this.knex, schema: this.schema });
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
opts.preMutationError = err;
|
|
257
|
+
}
|
|
347
258
|
}
|
|
348
259
|
// Manual constraint, see https://github.com/directus/directus/pull/19912
|
|
349
260
|
await this.knex('directus_notifications').update({ sender: null }).whereIn('sender', keys);
|
|
@@ -566,10 +477,16 @@ export class UsersService extends ItemsService {
|
|
|
566
477
|
knex: this.knex,
|
|
567
478
|
schema: this.schema,
|
|
568
479
|
accountability: {
|
|
569
|
-
...(this.accountability ??
|
|
480
|
+
...(this.accountability ?? createDefaultAccountability()),
|
|
570
481
|
admin: true, // We need to skip permissions checks for the update call below
|
|
571
482
|
},
|
|
572
483
|
});
|
|
573
484
|
await service.updateOne(user.id, { password, status: 'active' }, opts);
|
|
574
485
|
}
|
|
486
|
+
async clearCaches(opts) {
|
|
487
|
+
await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
|
|
488
|
+
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
489
|
+
await this.cache.clear();
|
|
490
|
+
}
|
|
491
|
+
}
|
|
575
492
|
}
|
package/dist/services/utils.js
CHANGED
|
@@ -3,6 +3,8 @@ import { systemCollectionRows } from '@directus/system-data';
|
|
|
3
3
|
import { clearSystemCache, getCache } from '../cache.js';
|
|
4
4
|
import getDatabase from '../database/index.js';
|
|
5
5
|
import emitter from '../emitter.js';
|
|
6
|
+
import { fetchAllowedFields } from '../permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js';
|
|
7
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
6
8
|
import { shouldClearCache } from '../utils/should-clear-cache.js';
|
|
7
9
|
export class UtilsService {
|
|
8
10
|
knex;
|
|
@@ -20,14 +22,16 @@ export class UtilsService {
|
|
|
20
22
|
if (!sortField) {
|
|
21
23
|
throw new InvalidPayloadError({ reason: `Collection "${collection}" doesn't have a sort field` });
|
|
22
24
|
}
|
|
23
|
-
if (this.accountability
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
if (this.accountability && this.accountability.admin !== true) {
|
|
26
|
+
await validateAccess({
|
|
27
|
+
accountability: this.accountability,
|
|
28
|
+
action: 'update',
|
|
29
|
+
collection,
|
|
30
|
+
}, {
|
|
31
|
+
schema: this.schema,
|
|
32
|
+
knex: this.knex,
|
|
26
33
|
});
|
|
27
|
-
|
|
28
|
-
throw new ForbiddenError();
|
|
29
|
-
}
|
|
30
|
-
const allowedFields = permissions.fields ?? [];
|
|
34
|
+
const allowedFields = await fetchAllowedFields({ collection, action: 'update', accountability: this.accountability }, { schema: this.schema, knex: this.knex });
|
|
31
35
|
if (allowedFields[0] !== '*' && allowedFields.includes(sortField) === false) {
|
|
32
36
|
throw new ForbiddenError();
|
|
33
37
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { Item, PrimaryKey, Query } from '@directus/types';
|
|
2
2
|
import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
|
|
3
|
-
import { AuthorizationService } from './authorization.js';
|
|
4
3
|
import { ItemsService } from './items.js';
|
|
5
4
|
export declare class VersionsService extends ItemsService {
|
|
6
|
-
authorizationService: AuthorizationService;
|
|
7
5
|
constructor(options: AbstractServiceOptions);
|
|
8
6
|
private validateCreateData;
|
|
9
7
|
getMainItem(collection: string, item: PrimaryKey, query?: Query): Promise<Item>;
|
|
@@ -6,21 +6,15 @@ import objectHash from 'object-hash';
|
|
|
6
6
|
import { getCache } from '../cache.js';
|
|
7
7
|
import getDatabase from '../database/index.js';
|
|
8
8
|
import emitter from '../emitter.js';
|
|
9
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
9
10
|
import { shouldClearCache } from '../utils/should-clear-cache.js';
|
|
10
11
|
import { ActivityService } from './activity.js';
|
|
11
|
-
import { AuthorizationService } from './authorization.js';
|
|
12
12
|
import { ItemsService } from './items.js';
|
|
13
13
|
import { PayloadService } from './payload.js';
|
|
14
14
|
import { RevisionsService } from './revisions.js';
|
|
15
15
|
export class VersionsService extends ItemsService {
|
|
16
|
-
authorizationService;
|
|
17
16
|
constructor(options) {
|
|
18
17
|
super('directus_versions', options);
|
|
19
|
-
this.authorizationService = new AuthorizationService({
|
|
20
|
-
accountability: this.accountability,
|
|
21
|
-
knex: this.knex,
|
|
22
|
-
schema: this.schema,
|
|
23
|
-
});
|
|
24
18
|
}
|
|
25
19
|
async validateCreateData(data) {
|
|
26
20
|
if (!data['key'])
|
|
@@ -55,11 +49,31 @@ export class VersionsService extends ItemsService {
|
|
|
55
49
|
});
|
|
56
50
|
}
|
|
57
51
|
// will throw an error if the accountability does not have permission to read the item
|
|
58
|
-
|
|
52
|
+
if (this.accountability) {
|
|
53
|
+
await validateAccess({
|
|
54
|
+
accountability: this.accountability,
|
|
55
|
+
action: 'read',
|
|
56
|
+
collection: data['collection'],
|
|
57
|
+
primaryKeys: [data['item']],
|
|
58
|
+
}, {
|
|
59
|
+
schema: this.schema,
|
|
60
|
+
knex: this.knex,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
59
63
|
}
|
|
60
64
|
async getMainItem(collection, item, query) {
|
|
61
65
|
// will throw an error if the accountability does not have permission to read the item
|
|
62
|
-
|
|
66
|
+
if (this.accountability) {
|
|
67
|
+
await validateAccess({
|
|
68
|
+
accountability: this.accountability,
|
|
69
|
+
action: 'read',
|
|
70
|
+
collection,
|
|
71
|
+
primaryKeys: [item],
|
|
72
|
+
}, {
|
|
73
|
+
schema: this.schema,
|
|
74
|
+
knex: this.knex,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
63
77
|
const itemsService = new ItemsService(collection, {
|
|
64
78
|
knex: this.knex,
|
|
65
79
|
accountability: this.accountability,
|
|
@@ -200,7 +214,17 @@ export class VersionsService extends ItemsService {
|
|
|
200
214
|
async promote(version, mainHash, fields) {
|
|
201
215
|
const { id, collection, item } = (await this.readOne(version));
|
|
202
216
|
// will throw an error if the accountability does not have permission to update the item
|
|
203
|
-
|
|
217
|
+
if (this.accountability) {
|
|
218
|
+
await validateAccess({
|
|
219
|
+
accountability: this.accountability,
|
|
220
|
+
action: 'update',
|
|
221
|
+
collection,
|
|
222
|
+
primaryKeys: [item],
|
|
223
|
+
}, {
|
|
224
|
+
schema: this.schema,
|
|
225
|
+
knex: this.knex,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
204
228
|
const { outdated } = await this.verifyHash(collection, item, mainHash);
|
|
205
229
|
if (outdated) {
|
|
206
230
|
throw new UnprocessableContentError({
|
|
@@ -2,11 +2,11 @@ import { useEnv } from '@directus/env';
|
|
|
2
2
|
import { version } from 'directus/version';
|
|
3
3
|
import { getHelpers } from '../../database/helpers/index.js';
|
|
4
4
|
import { getDatabase, getDatabaseClient } from '../../database/index.js';
|
|
5
|
+
import { fetchUserCount } from '../../utils/fetch-user-count/fetch-user-count.js';
|
|
5
6
|
import { getExtensionCount } from '../utils/get-extension-count.js';
|
|
6
7
|
import { getFieldCount } from '../utils/get-field-count.js';
|
|
7
8
|
import { getFilesizeSum } from '../utils/get-filesize-sum.js';
|
|
8
9
|
import { getItemCount } from '../utils/get-item-count.js';
|
|
9
|
-
import { getUserCount } from '../utils/get-user-count.js';
|
|
10
10
|
import { getUserItemCount } from '../utils/get-user-item-count.js';
|
|
11
11
|
const basicCountTasks = [
|
|
12
12
|
{ collection: 'directus_dashboards' },
|
|
@@ -27,7 +27,7 @@ export const getReport = async () => {
|
|
|
27
27
|
const helpers = getHelpers(db);
|
|
28
28
|
const [basicCounts, userCounts, userItemCount, fieldsCounts, extensionsCounts, databaseSize, filesizes] = await Promise.all([
|
|
29
29
|
getItemCount(db, basicCountTasks),
|
|
30
|
-
|
|
30
|
+
fetchUserCount({ knex: db }),
|
|
31
31
|
getUserItemCount(db),
|
|
32
32
|
getFieldCount(db),
|
|
33
33
|
getExtensionCount(db),
|