@directus/api 19.3.0 → 20.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +4 -4
- package/dist/auth/drivers/ldap.js +4 -4
- package/dist/auth/drivers/local.js +4 -4
- package/dist/auth/drivers/oauth2.js +4 -4
- package/dist/auth/drivers/openid.js +2 -4
- package/dist/cache.js +3 -0
- package/dist/cli/commands/bootstrap/index.js +8 -2
- package/dist/cli/commands/init/index.js +9 -10
- package/dist/cli/utils/defaults.d.ts +4 -11
- package/dist/cli/utils/defaults.js +7 -1
- package/dist/constants.d.ts +1 -1
- package/dist/controllers/access.d.ts +2 -0
- package/dist/controllers/access.js +148 -0
- package/dist/controllers/auth.js +5 -16
- package/dist/controllers/permissions.js +14 -2
- package/dist/controllers/policies.d.ts +2 -0
- package/dist/controllers/policies.js +169 -0
- package/dist/controllers/roles.js +22 -1
- package/dist/controllers/users.js +0 -55
- package/dist/database/errors/dialects/mysql.js +23 -23
- package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +16 -0
- package/dist/database/get-ast-from-query/get-ast-from-query.js +82 -0
- package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +13 -0
- package/dist/database/get-ast-from-query/lib/convert-wildcards.js +69 -0
- package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +15 -0
- package/dist/database/get-ast-from-query/lib/parse-fields.js +190 -0
- package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +14 -0
- package/dist/database/get-ast-from-query/utils/get-deep-query.js +17 -0
- package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +2 -0
- package/dist/database/get-ast-from-query/utils/get-related-collection.js +13 -0
- package/dist/database/get-ast-from-query/utils/get-relation.d.ts +2 -0
- package/dist/database/get-ast-from-query/utils/get-relation.js +7 -0
- package/dist/database/helpers/fn/types.d.ts +2 -1
- package/dist/database/helpers/fn/types.js +1 -1
- package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
- package/dist/database/helpers/geometry/dialects/mssql.js +4 -2
- package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
- package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
- package/dist/database/helpers/geometry/dialects/oracle.js +5 -3
- package/dist/database/helpers/geometry/types.d.ts +1 -1
- package/dist/database/helpers/geometry/types.js +4 -2
- package/dist/database/index.js +2 -1
- package/dist/database/migrations/20240619A-permissions-policies.d.ts +3 -0
- package/dist/database/migrations/20240619A-permissions-policies.js +163 -0
- package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
- package/dist/database/run-ast/lib/get-db-query.js +194 -0
- package/dist/database/run-ast/lib/parse-current-level.d.ts +7 -0
- package/dist/database/run-ast/lib/parse-current-level.js +41 -0
- package/dist/database/run-ast/run-ast.d.ts +7 -0
- package/dist/database/run-ast/run-ast.js +107 -0
- package/dist/database/{run-ast.d.ts → run-ast/types.d.ts} +3 -9
- package/dist/database/run-ast/types.js +1 -0
- package/dist/database/run-ast/utils/apply-case-when.d.ts +16 -0
- package/dist/database/run-ast/utils/apply-case-when.js +26 -0
- package/dist/database/run-ast/utils/apply-parent-filters.d.ts +3 -0
- package/dist/database/run-ast/utils/apply-parent-filters.js +55 -0
- package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +10 -0
- package/dist/database/run-ast/utils/get-column-pre-processor.js +57 -0
- package/dist/database/run-ast/utils/get-field-alias.d.ts +2 -0
- package/dist/database/run-ast/utils/get-field-alias.js +4 -0
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +5 -0
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +23 -0
- package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +3 -0
- package/dist/database/run-ast/utils/merge-with-parent-items.js +87 -0
- package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +3 -0
- package/dist/database/run-ast/utils/remove-temporary-fields.js +73 -0
- package/dist/extensions/lib/sandbox/generate-api-extensions-sandbox-entrypoint.d.ts +1 -1
- package/dist/flows.js +3 -4
- package/dist/middleware/authenticate.js +2 -7
- package/dist/middleware/cache.js +1 -1
- package/dist/middleware/cors.js +4 -4
- package/dist/middleware/respond.js +1 -1
- package/dist/permissions/cache.d.ts +2 -0
- package/dist/permissions/cache.js +23 -0
- package/dist/permissions/lib/fetch-permissions.d.ts +10 -0
- package/dist/permissions/lib/fetch-permissions.js +55 -0
- package/dist/permissions/lib/fetch-policies.d.ts +7 -0
- package/dist/permissions/lib/fetch-policies.js +28 -0
- package/dist/permissions/lib/fetch-roles-tree.d.ts +3 -0
- package/dist/permissions/lib/fetch-roles-tree.js +28 -0
- package/dist/{services/permissions → permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
- package/dist/permissions/lib/with-app-minimal-permissions.js +10 -0
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +7 -0
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +56 -0
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +3 -0
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +16 -0
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +8 -0
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +24 -0
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +9 -0
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +31 -0
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +16 -0
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +27 -0
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +10 -0
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +23 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +5 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +7 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +5 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +10 -0
- package/dist/permissions/modules/fetch-global-access/types.d.ts +4 -0
- package/dist/permissions/modules/fetch-global-access/types.js +1 -0
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +4 -0
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +27 -0
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +12 -0
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +32 -0
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +4 -0
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +29 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +4 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +49 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +3 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +56 -0
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +4 -0
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +8 -0
- package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +9 -0
- package/dist/permissions/modules/process-ast/lib/inject-cases.js +93 -0
- package/dist/permissions/modules/process-ast/process-ast.d.ts +9 -0
- package/dist/permissions/modules/process-ast/process-ast.js +39 -0
- package/dist/permissions/modules/process-ast/types.d.ts +24 -0
- package/dist/permissions/modules/process-ast/types.js +1 -0
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +7 -0
- package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +12 -0
- package/dist/permissions/modules/process-ast/utils/dedupe-access.js +30 -0
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +15 -0
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +50 -0
- package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/find-related-collection.js +9 -0
- package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/flatten-filter.js +24 -0
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +1 -0
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +3 -0
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +5 -0
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +7 -0
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +3 -0
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +3 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +16 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +12 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +28 -0
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +5 -0
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +12 -0
- package/dist/permissions/modules/process-payload/process-payload.d.ts +13 -0
- package/dist/permissions/modules/process-payload/process-payload.js +77 -0
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +12 -0
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +11 -0
- package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +9 -0
- package/dist/permissions/modules/validate-access/lib/validate-item-access.js +33 -0
- package/dist/permissions/modules/validate-access/validate-access.d.ts +14 -0
- package/dist/permissions/modules/validate-access/validate-access.js +28 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +1 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +8 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +5 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +10 -0
- package/dist/permissions/types.d.ts +6 -0
- package/dist/permissions/types.js +1 -0
- package/dist/permissions/utils/create-default-accountability.d.ts +2 -0
- package/dist/permissions/utils/create-default-accountability.js +11 -0
- package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +8 -0
- package/dist/permissions/utils/extract-required-dynamic-variable-context.js +27 -0
- package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +9 -0
- package/dist/permissions/utils/fetch-dynamic-variable-context.js +43 -0
- package/dist/permissions/utils/filter-policies-by-ip.d.ts +2 -0
- package/dist/permissions/utils/filter-policies-by-ip.js +15 -0
- package/dist/permissions/utils/get-unaliased-field-key.d.ts +5 -0
- package/dist/permissions/utils/get-unaliased-field-key.js +17 -0
- package/dist/permissions/utils/process-permissions.d.ts +7 -0
- package/dist/permissions/utils/process-permissions.js +9 -0
- package/dist/permissions/utils/with-cache.d.ts +10 -0
- package/dist/permissions/utils/with-cache.js +25 -0
- package/dist/services/access.d.ts +10 -0
- package/dist/services/access.js +43 -0
- package/dist/services/activity.js +22 -10
- package/dist/services/assets.d.ts +2 -3
- package/dist/services/assets.js +10 -5
- package/dist/services/authentication.js +18 -18
- package/dist/services/collections.js +18 -17
- package/dist/services/fields.d.ts +0 -1
- package/dist/services/fields.js +53 -24
- package/dist/services/files.d.ts +0 -4
- package/dist/services/files.js +10 -10
- package/dist/services/flows.d.ts +0 -2
- package/dist/services/flows.js +2 -14
- package/dist/services/graphql/index.d.ts +3 -3
- package/dist/services/graphql/index.js +126 -22
- package/dist/services/graphql/subscription.js +2 -4
- package/dist/services/import-export.js +23 -9
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +3 -2
- package/dist/services/items.d.ts +40 -14
- package/dist/services/items.js +182 -79
- package/dist/services/meta.js +60 -23
- package/dist/services/notifications.d.ts +0 -1
- package/dist/services/notifications.js +0 -7
- package/dist/services/operations.d.ts +0 -2
- package/dist/services/operations.js +2 -14
- package/dist/services/payload.d.ts +9 -10
- package/dist/services/payload.js +35 -19
- package/dist/services/{permissions/index.d.ts → permissions.d.ts} +5 -7
- package/dist/services/{permissions/index.js → permissions.js} +30 -54
- package/dist/services/policies.d.ts +12 -0
- package/dist/services/policies.js +87 -0
- package/dist/services/relations.d.ts +0 -6
- package/dist/services/relations.js +26 -29
- package/dist/services/roles.d.ts +4 -14
- package/dist/services/roles.js +56 -420
- package/dist/services/shares.d.ts +0 -2
- package/dist/services/shares.js +12 -8
- package/dist/services/specifications.d.ts +2 -2
- package/dist/services/specifications.js +39 -27
- package/dist/services/users.d.ts +2 -20
- package/dist/services/users.js +87 -190
- package/dist/services/utils.js +11 -7
- package/dist/services/versions.d.ts +0 -2
- package/dist/services/versions.js +34 -10
- package/dist/telemetry/lib/get-report.js +6 -3
- package/dist/telemetry/types/report.d.ts +4 -0
- package/dist/telemetry/utils/check-user-limits.d.ts +5 -0
- package/dist/telemetry/utils/check-user-limits.js +19 -0
- package/dist/telemetry/utils/get-filesize-sum.d.ts +5 -0
- package/dist/telemetry/utils/get-filesize-sum.js +7 -0
- package/dist/telemetry/utils/should-check-user-limits.d.ts +4 -0
- package/dist/telemetry/utils/should-check-user-limits.js +13 -0
- package/dist/types/ast.d.ts +43 -1
- package/dist/types/items.d.ts +11 -0
- package/dist/utils/apply-query.d.ts +4 -3
- package/dist/utils/apply-query.js +37 -8
- package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +17 -0
- package/dist/utils/fetch-user-count/fetch-access-lookup.js +22 -0
- package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +16 -0
- package/dist/utils/fetch-user-count/fetch-access-roles.js +37 -0
- package/dist/utils/fetch-user-count/fetch-active-users.d.ts +6 -0
- package/dist/utils/fetch-user-count/fetch-active-users.js +3 -0
- package/dist/utils/fetch-user-count/fetch-user-count.d.ts +12 -0
- package/dist/utils/fetch-user-count/fetch-user-count.js +57 -0
- package/dist/utils/fetch-user-count/get-user-count-query.d.ts +20 -0
- package/dist/utils/fetch-user-count/get-user-count-query.js +17 -0
- package/dist/utils/get-accountability-for-role.js +16 -25
- package/dist/utils/get-accountability-for-token.js +17 -16
- package/dist/utils/get-cache-key.d.ts +1 -1
- package/dist/utils/get-cache-key.js +12 -1
- package/dist/utils/get-column.d.ts +2 -1
- package/dist/utils/get-column.js +1 -0
- package/dist/utils/get-graphql-type.js +1 -0
- package/dist/utils/get-service.d.ts +1 -1
- package/dist/utils/get-service.js +14 -10
- package/dist/utils/reduce-schema.d.ts +4 -6
- package/dist/utils/reduce-schema.js +14 -34
- package/dist/utils/validate-user-count-integrity.d.ts +13 -0
- package/dist/utils/validate-user-count-integrity.js +29 -0
- package/dist/websocket/authenticate.d.ts +0 -2
- package/dist/websocket/authenticate.js +0 -12
- package/dist/websocket/controllers/graphql.js +1 -4
- package/dist/websocket/controllers/hooks.js +4 -0
- package/dist/websocket/controllers/rest.js +0 -2
- package/dist/websocket/handlers/subscribe.js +0 -2
- package/dist/websocket/utils/items.d.ts +1 -1
- package/dist/websocket/utils/items.js +4 -1
- package/package.json +36 -35
- package/dist/database/run-ast.js +0 -450
- package/dist/middleware/check-ip.d.ts +0 -2
- package/dist/middleware/check-ip.js +0 -37
- package/dist/middleware/get-permissions.d.ts +0 -3
- package/dist/middleware/get-permissions.js +0 -10
- package/dist/services/authorization.d.ts +0 -17
- package/dist/services/authorization.js +0 -456
- package/dist/services/permissions/lib/with-app-minimal-permissions.js +0 -13
- package/dist/telemetry/utils/check-increased-user-limits.d.ts +0 -7
- package/dist/telemetry/utils/check-increased-user-limits.js +0 -22
- package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +0 -6
- package/dist/telemetry/utils/get-role-counts-by-roles.js +0 -27
- package/dist/telemetry/utils/get-role-counts-by-users.d.ts +0 -11
- package/dist/telemetry/utils/get-role-counts-by-users.js +0 -34
- package/dist/telemetry/utils/get-user-count.d.ts +0 -8
- package/dist/telemetry/utils/get-user-count.js +0 -33
- package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +0 -7
- package/dist/telemetry/utils/get-user-counts-by-roles.js +0 -35
- package/dist/utils/get-ast-from-query.d.ts +0 -13
- package/dist/utils/get-ast-from-query.js +0 -297
- package/dist/utils/get-permissions.d.ts +0 -2
- package/dist/utils/get-permissions.js +0 -150
- package/dist/utils/merge-permissions-for-share.d.ts +0 -4
- package/dist/utils/merge-permissions-for-share.js +0 -109
- package/dist/utils/merge-permissions.d.ts +0 -3
- package/dist/utils/merge-permissions.js +0 -95
|
@@ -5,32 +5,20 @@ export class OperationsService extends ItemsService {
|
|
|
5
5
|
super('directus_operations', options);
|
|
6
6
|
}
|
|
7
7
|
async createOne(data, opts) {
|
|
8
|
-
const flowManager = getFlowManager();
|
|
9
8
|
const result = await super.createOne(data, opts);
|
|
10
|
-
await flowManager.reload();
|
|
11
|
-
return result;
|
|
12
|
-
}
|
|
13
|
-
async createMany(data, opts) {
|
|
14
|
-
const flowManager = getFlowManager();
|
|
15
|
-
const result = await super.createMany(data, opts);
|
|
16
|
-
await flowManager.reload();
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
async updateBatch(data, opts) {
|
|
20
9
|
const flowManager = getFlowManager();
|
|
21
|
-
const result = await super.updateBatch(data, opts);
|
|
22
10
|
await flowManager.reload();
|
|
23
11
|
return result;
|
|
24
12
|
}
|
|
25
13
|
async updateMany(keys, data, opts) {
|
|
26
|
-
const flowManager = getFlowManager();
|
|
27
14
|
const result = await super.updateMany(keys, data, opts);
|
|
15
|
+
const flowManager = getFlowManager();
|
|
28
16
|
await flowManager.reload();
|
|
29
17
|
return result;
|
|
30
18
|
}
|
|
31
19
|
async deleteMany(keys, opts) {
|
|
32
|
-
const flowManager = getFlowManager();
|
|
33
20
|
const result = await super.deleteMany(keys, opts);
|
|
21
|
+
const flowManager = getFlowManager();
|
|
34
22
|
await flowManager.reload();
|
|
35
23
|
return result;
|
|
36
24
|
}
|
|
@@ -2,6 +2,7 @@ import type { Accountability, Item, PrimaryKey, SchemaOverview } from '@directus
|
|
|
2
2
|
import type { Knex } from 'knex';
|
|
3
3
|
import type { Helpers } from '../database/helpers/index.js';
|
|
4
4
|
import type { AbstractServiceOptions, ActionEventParams, MutationOptions } from '../types/index.js';
|
|
5
|
+
import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
|
|
5
6
|
type Action = 'create' | 'read' | 'update';
|
|
6
7
|
type Transformers = {
|
|
7
8
|
[type: string]: (context: {
|
|
@@ -13,6 +14,11 @@ type Transformers = {
|
|
|
13
14
|
helpers: Helpers;
|
|
14
15
|
}) => Promise<any>;
|
|
15
16
|
};
|
|
17
|
+
type PayloadServiceProcessRelationResult = {
|
|
18
|
+
revisions: PrimaryKey[];
|
|
19
|
+
nestedActionEvents: ActionEventParams[];
|
|
20
|
+
userIntegrityCheckFlags: UserIntegrityCheckFlag;
|
|
21
|
+
};
|
|
16
22
|
/**
|
|
17
23
|
* Process a given payload for a collection to ensure the special fields (hash, uuid, date etc) are
|
|
18
24
|
* handled correctly.
|
|
@@ -46,26 +52,19 @@ export declare class PayloadService {
|
|
|
46
52
|
/**
|
|
47
53
|
* Recursively save/update all nested related Any-to-One items
|
|
48
54
|
*/
|
|
49
|
-
processA2O(data: Partial<Item>, opts?: MutationOptions): Promise<{
|
|
55
|
+
processA2O(data: Partial<Item>, opts?: MutationOptions): Promise<PayloadServiceProcessRelationResult & {
|
|
50
56
|
payload: Partial<Item>;
|
|
51
|
-
revisions: PrimaryKey[];
|
|
52
|
-
nestedActionEvents: ActionEventParams[];
|
|
53
57
|
}>;
|
|
54
58
|
/**
|
|
55
59
|
* Save/update all nested related m2o items inside the payload
|
|
56
60
|
*/
|
|
57
|
-
processM2O(data: Partial<Item>, opts?: MutationOptions): Promise<{
|
|
61
|
+
processM2O(data: Partial<Item>, opts?: MutationOptions): Promise<PayloadServiceProcessRelationResult & {
|
|
58
62
|
payload: Partial<Item>;
|
|
59
|
-
revisions: PrimaryKey[];
|
|
60
|
-
nestedActionEvents: ActionEventParams[];
|
|
61
63
|
}>;
|
|
62
64
|
/**
|
|
63
65
|
* Recursively save/update all nested related o2m items
|
|
64
66
|
*/
|
|
65
|
-
processO2M(data: Partial<Item>, parent: PrimaryKey, opts?: MutationOptions): Promise<
|
|
66
|
-
revisions: PrimaryKey[];
|
|
67
|
-
nestedActionEvents: ActionEventParams[];
|
|
68
|
-
}>;
|
|
67
|
+
processO2M(data: Partial<Item>, parent: PrimaryKey, opts?: MutationOptions): Promise<PayloadServiceProcessRelationResult>;
|
|
69
68
|
/**
|
|
70
69
|
* Transforms the input partial payload to match the output structure, to have consistency
|
|
71
70
|
* between delta and data
|
package/dist/services/payload.js
CHANGED
|
@@ -9,7 +9,7 @@ import { parse as wktToGeoJSON } from 'wellknown';
|
|
|
9
9
|
import { getHelpers } from '../database/helpers/index.js';
|
|
10
10
|
import getDatabase from '../database/index.js';
|
|
11
11
|
import { generateHash } from '../utils/generate-hash.js';
|
|
12
|
-
import {
|
|
12
|
+
import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
|
|
13
13
|
/**
|
|
14
14
|
* Process a given payload for a collection to ensure the special fields (hash, uuid, date etc) are
|
|
15
15
|
* handled correctly.
|
|
@@ -318,6 +318,7 @@ export class PayloadService {
|
|
|
318
318
|
return relation.collection === this.collection;
|
|
319
319
|
});
|
|
320
320
|
const revisions = [];
|
|
321
|
+
let userIntegrityCheckFlags = UserIntegrityCheckFlag.None;
|
|
321
322
|
const nestedActionEvents = [];
|
|
322
323
|
const payload = cloneDeep(data);
|
|
323
324
|
// Only process related records that are actually in the payload
|
|
@@ -340,7 +341,8 @@ export class PayloadService {
|
|
|
340
341
|
reason: `"${relation.collection}.${relation.field}" can't be linked to collection "${relatedCollection}"`,
|
|
341
342
|
});
|
|
342
343
|
}
|
|
343
|
-
const
|
|
344
|
+
const { getService } = await import('../utils/get-service.js');
|
|
345
|
+
const service = getService(relatedCollection, {
|
|
344
346
|
accountability: this.accountability,
|
|
345
347
|
knex: this.knex,
|
|
346
348
|
schema: this.schema,
|
|
@@ -360,8 +362,9 @@ export class PayloadService {
|
|
|
360
362
|
if (exists) {
|
|
361
363
|
const fieldsToUpdate = omit(relatedRecord, relatedPrimary);
|
|
362
364
|
if (Object.keys(fieldsToUpdate).length > 0) {
|
|
363
|
-
await
|
|
365
|
+
await service.updateOne(relatedPrimaryKey, relatedRecord, {
|
|
364
366
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
367
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
365
368
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
366
369
|
emitEvents: opts?.emitEvents,
|
|
367
370
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -369,8 +372,9 @@ export class PayloadService {
|
|
|
369
372
|
}
|
|
370
373
|
}
|
|
371
374
|
else {
|
|
372
|
-
relatedPrimaryKey = await
|
|
375
|
+
relatedPrimaryKey = await service.createOne(relatedRecord, {
|
|
373
376
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
377
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
374
378
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
375
379
|
emitEvents: opts?.emitEvents,
|
|
376
380
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -379,7 +383,7 @@ export class PayloadService {
|
|
|
379
383
|
// Overwrite the nested object with just the primary key, so the parent level can be saved correctly
|
|
380
384
|
payload[relation.field] = relatedPrimaryKey;
|
|
381
385
|
}
|
|
382
|
-
return { payload, revisions, nestedActionEvents };
|
|
386
|
+
return { payload, revisions, nestedActionEvents, userIntegrityCheckFlags };
|
|
383
387
|
}
|
|
384
388
|
/**
|
|
385
389
|
* Save/update all nested related m2o items inside the payload
|
|
@@ -388,6 +392,7 @@ export class PayloadService {
|
|
|
388
392
|
const payload = cloneDeep(data);
|
|
389
393
|
// All the revisions saved on this level
|
|
390
394
|
const revisions = [];
|
|
395
|
+
let userIntegrityCheckFlags = UserIntegrityCheckFlag.None;
|
|
391
396
|
const nestedActionEvents = [];
|
|
392
397
|
// Many to one relations that exist on the current collection
|
|
393
398
|
const relations = this.schema.relations.filter((relation) => {
|
|
@@ -402,8 +407,8 @@ export class PayloadService {
|
|
|
402
407
|
if (!relation.related_collection)
|
|
403
408
|
continue;
|
|
404
409
|
const relatedPrimaryKeyField = this.schema.collections[relation.related_collection].primary;
|
|
405
|
-
|
|
406
|
-
const
|
|
410
|
+
const { getService } = await import('../utils/get-service.js');
|
|
411
|
+
const service = getService(relation.related_collection, {
|
|
407
412
|
accountability: this.accountability,
|
|
408
413
|
knex: this.knex,
|
|
409
414
|
schema: this.schema,
|
|
@@ -422,8 +427,9 @@ export class PayloadService {
|
|
|
422
427
|
if (exists) {
|
|
423
428
|
const fieldsToUpdate = omit(relatedRecord, relatedPrimaryKeyField);
|
|
424
429
|
if (Object.keys(fieldsToUpdate).length > 0) {
|
|
425
|
-
await
|
|
430
|
+
await service.updateOne(relatedPrimaryKey, relatedRecord, {
|
|
426
431
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
432
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
427
433
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
428
434
|
emitEvents: opts?.emitEvents,
|
|
429
435
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -431,8 +437,9 @@ export class PayloadService {
|
|
|
431
437
|
}
|
|
432
438
|
}
|
|
433
439
|
else {
|
|
434
|
-
relatedPrimaryKey = await
|
|
440
|
+
relatedPrimaryKey = await service.createOne(relatedRecord, {
|
|
435
441
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
442
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
436
443
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
437
444
|
emitEvents: opts?.emitEvents,
|
|
438
445
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -441,13 +448,14 @@ export class PayloadService {
|
|
|
441
448
|
// Overwrite the nested object with just the primary key, so the parent level can be saved correctly
|
|
442
449
|
payload[relation.field] = relatedPrimaryKey;
|
|
443
450
|
}
|
|
444
|
-
return { payload, revisions, nestedActionEvents };
|
|
451
|
+
return { payload, revisions, nestedActionEvents, userIntegrityCheckFlags };
|
|
445
452
|
}
|
|
446
453
|
/**
|
|
447
454
|
* Recursively save/update all nested related o2m items
|
|
448
455
|
*/
|
|
449
456
|
async processO2M(data, parent, opts) {
|
|
450
457
|
const revisions = [];
|
|
458
|
+
let userIntegrityCheckFlags = UserIntegrityCheckFlag.None;
|
|
451
459
|
const nestedActionEvents = [];
|
|
452
460
|
const relations = this.schema.relations.filter((relation) => {
|
|
453
461
|
return relation.related_collection === this.collection;
|
|
@@ -469,7 +477,8 @@ export class PayloadService {
|
|
|
469
477
|
continue;
|
|
470
478
|
const currentPrimaryKeyField = this.schema.collections[relation.related_collection].primary;
|
|
471
479
|
const relatedPrimaryKeyField = this.schema.collections[relation.collection].primary;
|
|
472
|
-
const
|
|
480
|
+
const { getService } = await import('../utils/get-service.js');
|
|
481
|
+
const service = getService(relation.collection, {
|
|
473
482
|
accountability: this.accountability,
|
|
474
483
|
knex: this.knex,
|
|
475
484
|
schema: this.schema,
|
|
@@ -513,8 +522,9 @@ export class PayloadService {
|
|
|
513
522
|
[relation.field]: parent || payload[currentPrimaryKeyField],
|
|
514
523
|
});
|
|
515
524
|
}
|
|
516
|
-
savedPrimaryKeys.push(...(await
|
|
525
|
+
savedPrimaryKeys.push(...(await service.upsertMany(recordsToUpsert, {
|
|
517
526
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
527
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
518
528
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
519
529
|
emitEvents: opts?.emitEvents,
|
|
520
530
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -538,15 +548,17 @@ export class PayloadService {
|
|
|
538
548
|
// Nullify all related items that aren't included in the current payload
|
|
539
549
|
if (relation.meta.one_deselect_action === 'delete') {
|
|
540
550
|
// There's no revision for a deletion
|
|
541
|
-
await
|
|
551
|
+
await service.deleteByQuery(query, {
|
|
552
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
542
553
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
543
554
|
emitEvents: opts?.emitEvents,
|
|
544
555
|
mutationTracker: opts?.mutationTracker,
|
|
545
556
|
});
|
|
546
557
|
}
|
|
547
558
|
else {
|
|
548
|
-
await
|
|
559
|
+
await service.updateByQuery(query, { [relation.field]: null }, {
|
|
549
560
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
561
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
550
562
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
551
563
|
emitEvents: opts?.emitEvents,
|
|
552
564
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -587,8 +599,9 @@ export class PayloadService {
|
|
|
587
599
|
[relation.field]: parent || payload[currentPrimaryKeyField],
|
|
588
600
|
}));
|
|
589
601
|
}
|
|
590
|
-
await
|
|
602
|
+
await service.createMany(createPayload, {
|
|
591
603
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
604
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
592
605
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
593
606
|
emitEvents: opts?.emitEvents,
|
|
594
607
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -597,11 +610,12 @@ export class PayloadService {
|
|
|
597
610
|
if (alterations.update) {
|
|
598
611
|
const primaryKeyField = this.schema.collections[relation.collection].primary;
|
|
599
612
|
for (const item of alterations.update) {
|
|
600
|
-
await
|
|
613
|
+
await service.updateOne(item[primaryKeyField], {
|
|
601
614
|
...item,
|
|
602
615
|
[relation.field]: parent || payload[currentPrimaryKeyField],
|
|
603
616
|
}, {
|
|
604
617
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
618
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
605
619
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
606
620
|
emitEvents: opts?.emitEvents,
|
|
607
621
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -626,15 +640,17 @@ export class PayloadService {
|
|
|
626
640
|
},
|
|
627
641
|
};
|
|
628
642
|
if (relation.meta.one_deselect_action === 'delete') {
|
|
629
|
-
await
|
|
643
|
+
await service.deleteByQuery(query, {
|
|
644
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
630
645
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
631
646
|
emitEvents: opts?.emitEvents,
|
|
632
647
|
mutationTracker: opts?.mutationTracker,
|
|
633
648
|
});
|
|
634
649
|
}
|
|
635
650
|
else {
|
|
636
|
-
await
|
|
651
|
+
await service.updateByQuery(query, { [relation.field]: null }, {
|
|
637
652
|
onRevisionCreate: (pk) => revisions.push(pk),
|
|
653
|
+
onRequireUserIntegrityCheck: (flags) => (userIntegrityCheckFlags |= flags),
|
|
638
654
|
bypassEmitAction: (params) => opts?.bypassEmitAction ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
639
655
|
emitEvents: opts?.emitEvents,
|
|
640
656
|
mutationTracker: opts?.mutationTracker,
|
|
@@ -643,7 +659,7 @@ export class PayloadService {
|
|
|
643
659
|
}
|
|
644
660
|
}
|
|
645
661
|
}
|
|
646
|
-
return { revisions, nestedActionEvents };
|
|
662
|
+
return { revisions, nestedActionEvents, userIntegrityCheckFlags };
|
|
647
663
|
}
|
|
648
664
|
/**
|
|
649
665
|
* Transforms the input partial payload to match the output structure, to have consistency
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import type { Item, ItemPermissions,
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
4
|
-
import
|
|
5
|
-
import { ItemsService } from '../items.js';
|
|
1
|
+
import type { Item, ItemPermissions, PrimaryKey, Query } from '@directus/types';
|
|
2
|
+
import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
|
|
3
|
+
import type { QueryOptions } from './items.js';
|
|
4
|
+
import { ItemsService } from './items.js';
|
|
6
5
|
export declare class PermissionsService extends ItemsService {
|
|
7
|
-
systemCache: Keyv<any>;
|
|
8
6
|
constructor(options: AbstractServiceOptions);
|
|
9
|
-
|
|
7
|
+
private clearCaches;
|
|
10
8
|
readByQuery(query: Query, opts?: QueryOptions): Promise<Partial<Item>[]>;
|
|
11
9
|
createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
12
10
|
createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
import { ForbiddenError } from '@directus/errors';
|
|
2
|
-
import { clearSystemCache
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { clearSystemCache } from '../cache.js';
|
|
3
|
+
import { withAppMinimalPermissions } from '../permissions/lib/with-app-minimal-permissions.js';
|
|
4
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
5
|
+
import { ItemsService } from './items.js';
|
|
6
6
|
export class PermissionsService extends ItemsService {
|
|
7
|
-
systemCache;
|
|
8
7
|
constructor(options) {
|
|
9
8
|
super('directus_permissions', options);
|
|
10
|
-
const { systemCache } = getCache();
|
|
11
|
-
this.systemCache = systemCache;
|
|
12
9
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
matchesCollection = permission.collection === collection;
|
|
18
|
-
}
|
|
19
|
-
const matchesAction = permission.action === action;
|
|
20
|
-
return collection ? matchesCollection && matchesAction : matchesAction;
|
|
21
|
-
}) ?? [];
|
|
22
|
-
const fieldsPerCollection = {};
|
|
23
|
-
for (const result of results) {
|
|
24
|
-
const { collection, fields } = result;
|
|
25
|
-
if (!fieldsPerCollection[collection])
|
|
26
|
-
fieldsPerCollection[collection] = [];
|
|
27
|
-
fieldsPerCollection[collection].push(...(fields ?? []));
|
|
10
|
+
async clearCaches(opts) {
|
|
11
|
+
await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
|
|
12
|
+
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
13
|
+
await this.cache.clear();
|
|
28
14
|
}
|
|
29
|
-
return fieldsPerCollection;
|
|
30
15
|
}
|
|
31
16
|
async readByQuery(query, opts) {
|
|
32
17
|
const result = (await super.readByQuery(query, opts));
|
|
@@ -34,50 +19,32 @@ export class PermissionsService extends ItemsService {
|
|
|
34
19
|
}
|
|
35
20
|
async createOne(data, opts) {
|
|
36
21
|
const res = await super.createOne(data, opts);
|
|
37
|
-
await
|
|
38
|
-
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
39
|
-
await this.cache.clear();
|
|
40
|
-
}
|
|
22
|
+
await this.clearCaches(opts);
|
|
41
23
|
return res;
|
|
42
24
|
}
|
|
43
25
|
async createMany(data, opts) {
|
|
44
26
|
const res = await super.createMany(data, opts);
|
|
45
|
-
await
|
|
46
|
-
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
47
|
-
await this.cache.clear();
|
|
48
|
-
}
|
|
27
|
+
await this.clearCaches(opts);
|
|
49
28
|
return res;
|
|
50
29
|
}
|
|
51
30
|
async updateBatch(data, opts) {
|
|
52
31
|
const res = await super.updateBatch(data, opts);
|
|
53
|
-
await
|
|
54
|
-
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
55
|
-
await this.cache.clear();
|
|
56
|
-
}
|
|
32
|
+
await this.clearCaches(opts);
|
|
57
33
|
return res;
|
|
58
34
|
}
|
|
59
35
|
async updateMany(keys, data, opts) {
|
|
60
36
|
const res = await super.updateMany(keys, data, opts);
|
|
61
|
-
await
|
|
62
|
-
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
63
|
-
await this.cache.clear();
|
|
64
|
-
}
|
|
37
|
+
await this.clearCaches(opts);
|
|
65
38
|
return res;
|
|
66
39
|
}
|
|
67
40
|
async upsertMany(payloads, opts) {
|
|
68
41
|
const res = await super.upsertMany(payloads, opts);
|
|
69
|
-
await
|
|
70
|
-
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
71
|
-
await this.cache.clear();
|
|
72
|
-
}
|
|
42
|
+
await this.clearCaches(opts);
|
|
73
43
|
return res;
|
|
74
44
|
}
|
|
75
45
|
async deleteMany(keys, opts) {
|
|
76
46
|
const res = await super.deleteMany(keys, opts);
|
|
77
|
-
await
|
|
78
|
-
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
79
|
-
await this.cache.clear();
|
|
80
|
-
}
|
|
47
|
+
await this.clearCaches(opts);
|
|
81
48
|
return res;
|
|
82
49
|
}
|
|
83
50
|
async getItemPermissions(collection, primaryKey) {
|
|
@@ -115,16 +82,25 @@ export class PermissionsService extends ItemsService {
|
|
|
115
82
|
updateAction = 'create';
|
|
116
83
|
}
|
|
117
84
|
}
|
|
118
|
-
const authorizationService = new AuthorizationService({
|
|
119
|
-
knex: this.knex,
|
|
120
|
-
accountability: this.accountability,
|
|
121
|
-
schema: this.schema,
|
|
122
|
-
});
|
|
123
85
|
await Promise.all(Object.keys(itemPermissions).map((key) => {
|
|
124
86
|
const action = key;
|
|
125
87
|
const checkAction = action === 'update' ? updateAction : action;
|
|
126
|
-
|
|
127
|
-
.
|
|
88
|
+
if (!this.accountability) {
|
|
89
|
+
itemPermissions[action].access = true;
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
}
|
|
92
|
+
const opts = {
|
|
93
|
+
accountability: this.accountability,
|
|
94
|
+
action: checkAction,
|
|
95
|
+
collection,
|
|
96
|
+
};
|
|
97
|
+
if (primaryKey) {
|
|
98
|
+
opts.primaryKeys = [primaryKey];
|
|
99
|
+
}
|
|
100
|
+
return validateAccess(opts, {
|
|
101
|
+
schema: this.schema,
|
|
102
|
+
knex: this.knex,
|
|
103
|
+
})
|
|
128
104
|
.then(() => (itemPermissions[action].access = true))
|
|
129
105
|
.catch(() => { });
|
|
130
106
|
}));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Policy, PrimaryKey } from '@directus/types';
|
|
2
|
+
import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
|
|
3
|
+
import { ItemsService } from './items.js';
|
|
4
|
+
export declare class PoliciesService extends ItemsService<Policy> {
|
|
5
|
+
constructor(options: AbstractServiceOptions);
|
|
6
|
+
private clearCaches;
|
|
7
|
+
private isIpAccessValid;
|
|
8
|
+
private assertValidIpAccess;
|
|
9
|
+
createOne(data: Partial<Policy>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
10
|
+
updateMany(keys: PrimaryKey[], data: Partial<Policy>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
11
|
+
deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { InvalidPayloadError } from '@directus/errors';
|
|
2
|
+
import { getMatch } from 'ip-matching';
|
|
3
|
+
import { clearSystemCache } from '../cache.js';
|
|
4
|
+
import { clearCache as clearPermissionsCache } from '../permissions/cache.js';
|
|
5
|
+
import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
|
|
6
|
+
import { ItemsService } from './items.js';
|
|
7
|
+
export class PoliciesService extends ItemsService {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super('directus_policies', options);
|
|
10
|
+
}
|
|
11
|
+
async clearCaches(opts) {
|
|
12
|
+
await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
|
|
13
|
+
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
14
|
+
await this.cache.clear();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
isIpAccessValid(value) {
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return false;
|
|
20
|
+
if (value === null)
|
|
21
|
+
return true;
|
|
22
|
+
if (Array.isArray(value) && value.length === 0)
|
|
23
|
+
return true;
|
|
24
|
+
for (const ip of value) {
|
|
25
|
+
if (typeof ip !== 'string' || ip.includes('*'))
|
|
26
|
+
return false;
|
|
27
|
+
try {
|
|
28
|
+
const match = getMatch(ip);
|
|
29
|
+
if (match.type == 'IPMask')
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
assertValidIpAccess(partialItem) {
|
|
39
|
+
if ('ip_access' in partialItem && !this.isIpAccessValid(partialItem['ip_access'])) {
|
|
40
|
+
throw new InvalidPayloadError({
|
|
41
|
+
reason: 'IP Access contains an incorrect value. Valid values are: IP addresses, IP ranges and CIDR blocks',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async createOne(data, opts = {}) {
|
|
46
|
+
this.assertValidIpAccess(data);
|
|
47
|
+
// A policy has been created, but the attachment to a user/role happens in the AccessService,
|
|
48
|
+
// so no need to check user integrity
|
|
49
|
+
const result = await super.createOne(data, opts);
|
|
50
|
+
// TODO is this necessary? Since the attachment should be handled in the AccessService
|
|
51
|
+
// A new policy has created, clear the permissions cache
|
|
52
|
+
await clearPermissionsCache();
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
async updateMany(keys, data, opts = {}) {
|
|
56
|
+
this.assertValidIpAccess(data);
|
|
57
|
+
if ('admin_access' in data) {
|
|
58
|
+
let flags = UserIntegrityCheckFlag.RemainingAdmins;
|
|
59
|
+
if (data['admin_access'] === true) {
|
|
60
|
+
// Only need to perform a full user count if the policy allows admin access
|
|
61
|
+
flags |= UserIntegrityCheckFlag.All;
|
|
62
|
+
}
|
|
63
|
+
opts.userIntegrityCheckFlags = (opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | flags;
|
|
64
|
+
}
|
|
65
|
+
if ('app_access' in data) {
|
|
66
|
+
opts.userIntegrityCheckFlags =
|
|
67
|
+
(opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;
|
|
68
|
+
}
|
|
69
|
+
if (opts.userIntegrityCheckFlags)
|
|
70
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
71
|
+
const result = await super.updateMany(keys, data, opts);
|
|
72
|
+
if ('admin_access' in data || 'app_access' in data || 'ip_access' in data || 'enforce_tfa' in data) {
|
|
73
|
+
// Some relevant properties on policies have been updated, clear the caches
|
|
74
|
+
await this.clearCaches(opts);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
async deleteMany(keys, opts = {}) {
|
|
79
|
+
opts.userIntegrityCheckFlags = UserIntegrityCheckFlag.All;
|
|
80
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
81
|
+
const result = await super.deleteMany(keys, opts);
|
|
82
|
+
// TODO is this necessary? Since the detachment should be handled in the AccessService
|
|
83
|
+
// Some policies have been deleted, clear the permissions cache
|
|
84
|
+
await this.clearCaches(opts);
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -5,10 +5,8 @@ import type { Knex } from 'knex';
|
|
|
5
5
|
import type { Helpers } from '../database/helpers/index.js';
|
|
6
6
|
import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
|
|
7
7
|
import { ItemsService, type QueryOptions } from './items.js';
|
|
8
|
-
import { PermissionsService } from './permissions/index.js';
|
|
9
8
|
export declare class RelationsService {
|
|
10
9
|
knex: Knex;
|
|
11
|
-
permissionsService: PermissionsService;
|
|
12
10
|
schemaInspector: SchemaInspector;
|
|
13
11
|
accountability: Accountability | null;
|
|
14
12
|
schema: SchemaOverview;
|
|
@@ -32,10 +30,6 @@ export declare class RelationsService {
|
|
|
32
30
|
* Delete an existing relationship
|
|
33
31
|
*/
|
|
34
32
|
deleteOne(collection: string, field: string, opts?: MutationOptions): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* Whether or not the current user has read access to relations
|
|
37
|
-
*/
|
|
38
|
-
private get hasReadAccess();
|
|
39
33
|
/**
|
|
40
34
|
* Combine raw schema foreign key information with Directus relations meta rows to form final
|
|
41
35
|
* Relation objects
|