@expo/entity 0.38.0 → 0.40.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/build/AuthorizationResultBasedEntityAssociationLoader.d.ts +99 -0
- package/build/AuthorizationResultBasedEntityAssociationLoader.js +124 -0
- package/build/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -0
- package/build/AuthorizationResultBasedEntityLoader.d.ts +1 -1
- package/build/AuthorizationResultBasedEntityLoader.js.map +1 -1
- package/build/{EntityMutator.d.ts → AuthorizationResultBasedEntityMutator.d.ts} +5 -17
- package/build/{EntityMutator.js → AuthorizationResultBasedEntityMutator.js} +22 -48
- package/build/AuthorizationResultBasedEntityMutator.js.map +1 -0
- package/build/EnforcingEntityAssociationLoader.d.ts +79 -0
- package/build/EnforcingEntityAssociationLoader.js +62 -0
- package/build/EnforcingEntityAssociationLoader.js.map +1 -0
- package/build/EnforcingEntityCreator.d.ts +24 -0
- package/build/EnforcingEntityCreator.js +32 -0
- package/build/EnforcingEntityCreator.js.map +1 -0
- package/build/EnforcingEntityDeleter.d.ts +17 -0
- package/build/EnforcingEntityDeleter.js +22 -0
- package/build/EnforcingEntityDeleter.js.map +1 -0
- package/build/EnforcingEntityUpdater.d.ts +24 -0
- package/build/EnforcingEntityUpdater.js +32 -0
- package/build/EnforcingEntityUpdater.js.map +1 -0
- package/build/Entity.d.ts +8 -12
- package/build/Entity.js +9 -34
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.d.ts +12 -91
- package/build/EntityAssociationLoader.js +20 -126
- package/build/EntityAssociationLoader.js.map +1 -1
- package/build/EntityCompanionProvider.d.ts +2 -2
- package/build/EntityCompanionProvider.js.map +1 -1
- package/build/EntityCreator.d.ts +27 -0
- package/build/EntityCreator.js +39 -0
- package/build/EntityCreator.js.map +1 -0
- package/build/EntityDatabaseAdapter.js +2 -2
- package/build/EntityDatabaseAdapter.js.map +1 -1
- package/build/EntityDeleter.d.ts +27 -0
- package/build/EntityDeleter.js +40 -0
- package/build/EntityDeleter.js.map +1 -0
- package/build/EntityLoader.d.ts +4 -14
- package/build/EntityLoader.js +7 -20
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityLoaderFactory.d.ts +2 -2
- package/build/EntityLoaderFactory.js +4 -2
- package/build/EntityLoaderFactory.js.map +1 -1
- package/build/EntityMutatorFactory.d.ts +4 -4
- package/build/EntityMutatorFactory.js +4 -4
- package/build/EntityMutatorFactory.js.map +1 -1
- package/build/EntitySecondaryCacheLoader.d.ts +3 -3
- package/build/EntitySecondaryCacheLoader.js +1 -3
- package/build/EntitySecondaryCacheLoader.js.map +1 -1
- package/build/EntityUpdater.d.ts +27 -0
- package/build/EntityUpdater.js +40 -0
- package/build/EntityUpdater.js.map +1 -0
- package/build/ReadonlyEntity.d.ts +2 -2
- package/build/ReadonlyEntity.js +4 -6
- package/build/ReadonlyEntity.js.map +1 -1
- package/build/ViewerScopedEntityLoaderFactory.d.ts +2 -2
- package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
- package/build/ViewerScopedEntityMutatorFactory.d.ts +4 -4
- package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
- package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.d.ts +1 -0
- package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js +273 -0
- package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js.map +1 -0
- package/build/__tests__/{EntityLoader-constructor-test.js → AuthorizationResultBasedEntityLoader-constructor-test.js} +11 -11
- package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js.map +1 -0
- package/build/__tests__/AuthorizationResultBasedEntityLoader-test.d.ts +1 -0
- package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js +401 -0
- package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js.map +1 -0
- package/build/__tests__/EnforcingEntityAssociationLoader-test.d.ts +1 -0
- package/build/__tests__/EnforcingEntityAssociationLoader-test.js +115 -0
- package/build/__tests__/EnforcingEntityAssociationLoader-test.js.map +1 -0
- package/build/__tests__/Entity-test.js +23 -5
- package/build/__tests__/Entity-test.js.map +1 -1
- package/build/__tests__/EntityAssociationLoader-test.js +14 -184
- package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js +34 -12
- package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
- package/build/__tests__/EntityCompanion-test.js +17 -7
- package/build/__tests__/EntityCompanion-test.js.map +1 -1
- package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
- package/build/__tests__/EntityEdges-test.js +41 -23
- package/build/__tests__/EntityEdges-test.js.map +1 -1
- package/build/__tests__/EntityLoader-test.js +22 -386
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +4 -3
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
- package/build/__tests__/EntityMutator-test.js +67 -70
- package/build/__tests__/EntityMutator-test.js.map +1 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js +17 -7
- package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
- package/build/__tests__/EntitySecondaryCacheLoader-test.js +7 -7
- package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
- package/build/__tests__/EntitySelfReferentialEdges-test.js +36 -24
- package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
- package/build/__tests__/ReadonlyEntity-test.js +1 -1
- package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +4 -2
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +7 -4
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
- package/build/__tests__/entityUtils-test.js +8 -0
- package/build/__tests__/entityUtils-test.js.map +1 -1
- package/build/entityUtils.d.ts +7 -0
- package/build/entityUtils.js +20 -10
- package/build/entityUtils.js.map +1 -1
- package/build/errors/EntityCacheAdapterError.js +17 -7
- package/build/errors/EntityCacheAdapterError.js.map +1 -1
- package/build/errors/EntityDatabaseAdapterError.js +17 -7
- package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
- package/build/errors/EntityInvalidFieldValueError.js +17 -7
- package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
- package/build/errors/EntityNotAuthorizedError.js +17 -7
- package/build/errors/EntityNotAuthorizedError.js.map +1 -1
- package/build/errors/EntityNotFoundError.js +17 -7
- package/build/errors/EntityNotFoundError.js.map +1 -1
- package/build/index.d.ts +19 -11
- package/build/index.js +24 -7
- package/build/index.js.map +1 -1
- package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/internal/__tests__/EntityDataManager-test.js +42 -32
- package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
- package/build/internal/__tests__/ReadThroughEntityCache-test.js +17 -7
- package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js +17 -7
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js +17 -7
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js +17 -7
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
- package/build/utils/EntityPrivacyUtils.d.ts +32 -4
- package/build/utils/EntityPrivacyUtils.js +68 -24
- package/build/utils/EntityPrivacyUtils.js.map +1 -1
- package/build/utils/__tests__/EntityPrivacyUtils-test.js +148 -23
- package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -1
- package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js +8 -5
- package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js.map +1 -1
- package/build/utils/collections/__tests__/maps-test.js +1 -1
- package/build/utils/collections/__tests__/maps-test.js.map +1 -1
- package/build/utils/collections/maps.js +2 -2
- package/build/utils/collections/maps.js.map +1 -1
- package/build/utils/mergeEntityMutationTriggerConfigurations.js +1 -2
- package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapter.js +17 -7
- package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
- package/build/utils/testing/StubQueryContextProvider.d.ts +1 -3
- package/build/utils/testing/StubQueryContextProvider.js +1 -3
- package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
- package/build/utils/testing/createUnitTestEntityCompanionProvider.js +2 -1
- package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +1 -1
- package/build/utils/testing/describeFieldTestCase.js +1 -1
- package/build/utils/testing/describeFieldTestCase.js.map +1 -1
- package/package.json +19 -3
- package/src/AuthorizationResultBasedEntityAssociationLoader.ts +492 -0
- package/src/AuthorizationResultBasedEntityLoader.ts +2 -2
- package/src/{EntityMutator.ts → AuthorizationResultBasedEntityMutator.ts} +62 -58
- package/src/EnforcingEntityAssociationLoader.ts +390 -0
- package/src/EnforcingEntityCreator.ts +55 -0
- package/src/EnforcingEntityDeleter.ts +44 -0
- package/src/EnforcingEntityUpdater.ts +55 -0
- package/src/Entity.ts +20 -65
- package/src/EntityAssociationLoader.ts +38 -495
- package/src/EntityCompanionProvider.ts +5 -2
- package/src/EntityCreator.ts +73 -0
- package/src/EntityDeleter.ts +73 -0
- package/src/EntityLoader.ts +10 -49
- package/src/EntityLoaderFactory.ts +20 -3
- package/src/EntityMutatorFactory.ts +32 -7
- package/src/EntitySecondaryCacheLoader.ts +5 -7
- package/src/EntityUpdater.ts +73 -0
- package/src/ReadonlyEntity.ts +14 -13
- package/src/ViewerScopedEntityLoaderFactory.ts +9 -2
- package/src/ViewerScopedEntityMutatorFactory.ts +29 -4
- package/src/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.ts +354 -0
- package/src/__tests__/{EntityLoader-constructor-test.ts → AuthorizationResultBasedEntityLoader-constructor-test.ts} +17 -10
- package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +730 -0
- package/src/__tests__/EnforcingEntityAssociationLoader-test.ts +253 -0
- package/src/__tests__/Entity-test.ts +24 -5
- package/src/__tests__/EntityAssociationLoader-test.ts +16 -259
- package/src/__tests__/EntityCommonUseCases-test.ts +20 -8
- package/src/__tests__/EntityCompanion-test.ts +1 -1
- package/src/__tests__/EntityDatabaseAdapter-test.ts +6 -6
- package/src/__tests__/EntityEdges-test.ts +24 -16
- package/src/__tests__/EntityLoader-test.ts +25 -675
- package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +4 -3
- package/src/__tests__/EntityMutator-test.ts +116 -103
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +36 -24
- package/src/__tests__/ReadonlyEntity-test.ts +1 -1
- package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +4 -2
- package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +7 -4
- package/src/__tests__/entityUtils-test.ts +12 -0
- package/src/entityUtils.ts +24 -9
- package/src/index.ts +19 -11
- package/src/internal/EntityFieldTransformationUtils.ts +2 -2
- package/src/internal/__tests__/EntityDataManager-test.ts +29 -29
- package/src/utils/EntityPrivacyUtils.ts +188 -107
- package/src/utils/__tests__/EntityPrivacyUtils-test.ts +169 -29
- package/src/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.ts +8 -5
- package/src/utils/collections/__tests__/maps-test.ts +1 -1
- package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +1 -1
- package/src/utils/testing/StubDatabaseAdapter.ts +1 -1
- package/src/utils/testing/StubQueryContextProvider.ts +1 -3
- package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +3 -1
- package/build/EntityMutator.js.map +0 -1
- package/build/__tests__/EntityLoader-constructor-test.js.map +0 -1
- /package/build/__tests__/{EntityLoader-constructor-test.d.ts → AuthorizationResultBasedEntityLoader-constructor-test.d.ts} +0 -0
|
@@ -9,9 +9,22 @@ import { EntityCascadingDeletionInfo } from '../EntityMutationInfo';
|
|
|
9
9
|
import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
|
|
10
10
|
import { EntityQueryContext } from '../EntityQueryContext';
|
|
11
11
|
import ViewerContext from '../ViewerContext';
|
|
12
|
-
import { failedResults } from '../entityUtils';
|
|
12
|
+
import { failedResults, partitionArray } from '../entityUtils';
|
|
13
13
|
import EntityNotAuthorizedError from '../errors/EntityNotAuthorizedError';
|
|
14
14
|
|
|
15
|
+
export type EntityPrivacyEvaluationResultSuccess = {
|
|
16
|
+
allowed: true;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type EntityPrivacyEvaluationResultFailure = {
|
|
20
|
+
allowed: false;
|
|
21
|
+
authorizationErrors: EntityNotAuthorizedError<any, any, any, any, any>[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type EntityPrivacyEvaluationResult =
|
|
25
|
+
| EntityPrivacyEvaluationResultSuccess
|
|
26
|
+
| EntityPrivacyEvaluationResultFailure;
|
|
27
|
+
|
|
15
28
|
/**
|
|
16
29
|
* Check whether an entity loaded by a viewer can be updated by that same viewer.
|
|
17
30
|
*
|
|
@@ -30,34 +43,67 @@ import EntityNotAuthorizedError from '../errors/EntityNotAuthorizedError';
|
|
|
30
43
|
* @param queryContext - query context in which to perform the check
|
|
31
44
|
*/
|
|
32
45
|
export async function canViewerUpdateAsync<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
TFields extends object,
|
|
47
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
48
|
+
TViewerContext extends ViewerContext,
|
|
49
|
+
TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
50
|
+
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
51
|
+
TFields,
|
|
52
|
+
TID,
|
|
53
|
+
TViewerContext,
|
|
54
|
+
TEntity,
|
|
55
|
+
TSelectedFields
|
|
43
56
|
>,
|
|
44
|
-
|
|
57
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
45
58
|
>(
|
|
46
|
-
entityClass: IEntityClass<
|
|
47
|
-
|
|
48
|
-
TMID,
|
|
49
|
-
TMViewerContext,
|
|
50
|
-
TMEntity,
|
|
51
|
-
TMPrivacyPolicy,
|
|
52
|
-
TMSelectedFields
|
|
53
|
-
>,
|
|
54
|
-
sourceEntity: TMEntity,
|
|
59
|
+
entityClass: IEntityClass<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields>,
|
|
60
|
+
sourceEntity: TEntity,
|
|
55
61
|
queryContext: EntityQueryContext = sourceEntity
|
|
56
62
|
.getViewerContext()
|
|
57
63
|
.getViewerScopedEntityCompanionForClass(entityClass)
|
|
58
64
|
.getQueryContextProvider()
|
|
59
65
|
.getQueryContext(),
|
|
60
66
|
): Promise<boolean> {
|
|
67
|
+
const result = await canViewerUpdateInternalAsync(
|
|
68
|
+
entityClass,
|
|
69
|
+
sourceEntity,
|
|
70
|
+
/* cascadingDeleteCause */ null,
|
|
71
|
+
queryContext,
|
|
72
|
+
);
|
|
73
|
+
return result.allowed;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check whether an entity loaded by a viewer can be updated by that same viewer and return the evaluation result.
|
|
78
|
+
*
|
|
79
|
+
* @see canViewerUpdateAsync
|
|
80
|
+
*
|
|
81
|
+
* @param entityClass - class of entity
|
|
82
|
+
* @param sourceEntity - entity loaded by viewer
|
|
83
|
+
* @param queryContext - query context in which to perform the check
|
|
84
|
+
*/
|
|
85
|
+
export async function getCanViewerUpdateResultAsync<
|
|
86
|
+
TFields extends object,
|
|
87
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
88
|
+
TViewerContext extends ViewerContext,
|
|
89
|
+
TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
90
|
+
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
91
|
+
TFields,
|
|
92
|
+
TID,
|
|
93
|
+
TViewerContext,
|
|
94
|
+
TEntity,
|
|
95
|
+
TSelectedFields
|
|
96
|
+
>,
|
|
97
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
98
|
+
>(
|
|
99
|
+
entityClass: IEntityClass<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields>,
|
|
100
|
+
sourceEntity: TEntity,
|
|
101
|
+
queryContext: EntityQueryContext = sourceEntity
|
|
102
|
+
.getViewerContext()
|
|
103
|
+
.getViewerScopedEntityCompanionForClass(entityClass)
|
|
104
|
+
.getQueryContextProvider()
|
|
105
|
+
.getQueryContext(),
|
|
106
|
+
): Promise<EntityPrivacyEvaluationResult> {
|
|
61
107
|
return await canViewerUpdateInternalAsync(
|
|
62
108
|
entityClass,
|
|
63
109
|
sourceEntity,
|
|
@@ -67,31 +113,24 @@ export async function canViewerUpdateAsync<
|
|
|
67
113
|
}
|
|
68
114
|
|
|
69
115
|
async function canViewerUpdateInternalAsync<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
116
|
+
TFields extends object,
|
|
117
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
118
|
+
TViewerContext extends ViewerContext,
|
|
119
|
+
TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
120
|
+
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
121
|
+
TFields,
|
|
122
|
+
TID,
|
|
123
|
+
TViewerContext,
|
|
124
|
+
TEntity,
|
|
125
|
+
TSelectedFields
|
|
80
126
|
>,
|
|
81
|
-
|
|
127
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
82
128
|
>(
|
|
83
|
-
entityClass: IEntityClass<
|
|
84
|
-
|
|
85
|
-
TMID,
|
|
86
|
-
TMViewerContext,
|
|
87
|
-
TMEntity,
|
|
88
|
-
TMPrivacyPolicy,
|
|
89
|
-
TMSelectedFields
|
|
90
|
-
>,
|
|
91
|
-
sourceEntity: TMEntity,
|
|
129
|
+
entityClass: IEntityClass<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields>,
|
|
130
|
+
sourceEntity: TEntity,
|
|
92
131
|
cascadingDeleteCause: EntityCascadingDeletionInfo | null,
|
|
93
132
|
queryContext: EntityQueryContext,
|
|
94
|
-
): Promise<
|
|
133
|
+
): Promise<EntityPrivacyEvaluationResult> {
|
|
95
134
|
const companion = sourceEntity
|
|
96
135
|
.getViewerContext()
|
|
97
136
|
.getViewerScopedEntityCompanionForClass(entityClass);
|
|
@@ -107,20 +146,19 @@ async function canViewerUpdateInternalAsync<
|
|
|
107
146
|
);
|
|
108
147
|
if (!evaluationResult.ok) {
|
|
109
148
|
if (evaluationResult.reason instanceof EntityNotAuthorizedError) {
|
|
110
|
-
return false;
|
|
149
|
+
return { allowed: false, authorizationErrors: [evaluationResult.reason] };
|
|
111
150
|
} else {
|
|
112
151
|
throw evaluationResult.reason;
|
|
113
152
|
}
|
|
114
153
|
}
|
|
115
|
-
return
|
|
154
|
+
return { allowed: true };
|
|
116
155
|
}
|
|
117
156
|
|
|
118
157
|
/**
|
|
119
158
|
* Check whether a single entity loaded by a viewer can be deleted by that same viewer.
|
|
120
159
|
* This recursively checks edge cascade permissions (EntityEdgeDeletionBehavior) as well.
|
|
121
160
|
*
|
|
122
|
-
* @
|
|
123
|
-
* See remarks for canViewerUpdate.
|
|
161
|
+
* @see canViewerUpdateAsync
|
|
124
162
|
*
|
|
125
163
|
* @param entityClass - class of entity
|
|
126
164
|
* @param sourceEntity - entity loaded by viewer
|
|
@@ -129,32 +167,65 @@ async function canViewerUpdateInternalAsync<
|
|
|
129
167
|
export async function canViewerDeleteAsync<
|
|
130
168
|
TFields extends object,
|
|
131
169
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
132
|
-
|
|
133
|
-
TEntity extends Entity<TFields, TID,
|
|
170
|
+
TViewerContext extends ViewerContext,
|
|
171
|
+
TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
134
172
|
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
135
173
|
TFields,
|
|
136
174
|
TID,
|
|
137
|
-
|
|
175
|
+
TViewerContext,
|
|
138
176
|
TEntity,
|
|
139
177
|
TSelectedFields
|
|
140
178
|
>,
|
|
141
179
|
TSelectedFields extends keyof TFields = keyof TFields,
|
|
142
180
|
>(
|
|
143
|
-
entityClass: IEntityClass<
|
|
181
|
+
entityClass: IEntityClass<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields>,
|
|
182
|
+
sourceEntity: TEntity,
|
|
183
|
+
queryContext: EntityQueryContext = sourceEntity
|
|
184
|
+
.getViewerContext()
|
|
185
|
+
.getViewerScopedEntityCompanionForClass(entityClass)
|
|
186
|
+
.getQueryContextProvider()
|
|
187
|
+
.getQueryContext(),
|
|
188
|
+
): Promise<boolean> {
|
|
189
|
+
const result = await canViewerDeleteInternalAsync(
|
|
190
|
+
entityClass,
|
|
191
|
+
sourceEntity,
|
|
192
|
+
/* cascadingDeleteCause */ null,
|
|
193
|
+
queryContext,
|
|
194
|
+
);
|
|
195
|
+
return result.allowed;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Check whether a single entity loaded by a viewer can be deleted by that same viewer and return the evaluation result.
|
|
200
|
+
*
|
|
201
|
+
* @see canViewerDeleteAsync
|
|
202
|
+
*
|
|
203
|
+
* @param entityClass - class of entity
|
|
204
|
+
* @param sourceEntity - entity loaded by viewer
|
|
205
|
+
* @param queryContext - query context in which to perform the check
|
|
206
|
+
*/
|
|
207
|
+
export async function getCanViewerDeleteResultAsync<
|
|
208
|
+
TFields extends object,
|
|
209
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
210
|
+
TViewerContext extends ViewerContext,
|
|
211
|
+
TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
212
|
+
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
144
213
|
TFields,
|
|
145
214
|
TID,
|
|
146
|
-
|
|
215
|
+
TViewerContext,
|
|
147
216
|
TEntity,
|
|
148
|
-
TPrivacyPolicy,
|
|
149
217
|
TSelectedFields
|
|
150
218
|
>,
|
|
219
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
220
|
+
>(
|
|
221
|
+
entityClass: IEntityClass<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields>,
|
|
151
222
|
sourceEntity: TEntity,
|
|
152
223
|
queryContext: EntityQueryContext = sourceEntity
|
|
153
224
|
.getViewerContext()
|
|
154
225
|
.getViewerScopedEntityCompanionForClass(entityClass)
|
|
155
226
|
.getQueryContextProvider()
|
|
156
227
|
.getQueryContext(),
|
|
157
|
-
): Promise<
|
|
228
|
+
): Promise<EntityPrivacyEvaluationResult> {
|
|
158
229
|
return await canViewerDeleteInternalAsync(
|
|
159
230
|
entityClass,
|
|
160
231
|
sourceEntity,
|
|
@@ -166,29 +237,22 @@ export async function canViewerDeleteAsync<
|
|
|
166
237
|
async function canViewerDeleteInternalAsync<
|
|
167
238
|
TFields extends object,
|
|
168
239
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
169
|
-
|
|
170
|
-
TEntity extends Entity<TFields, TID,
|
|
240
|
+
TViewerContext extends ViewerContext,
|
|
241
|
+
TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
171
242
|
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
172
243
|
TFields,
|
|
173
244
|
TID,
|
|
174
|
-
|
|
245
|
+
TViewerContext,
|
|
175
246
|
TEntity,
|
|
176
247
|
TSelectedFields
|
|
177
248
|
>,
|
|
178
249
|
TSelectedFields extends keyof TFields = keyof TFields,
|
|
179
250
|
>(
|
|
180
|
-
entityClass: IEntityClass<
|
|
181
|
-
TFields,
|
|
182
|
-
TID,
|
|
183
|
-
TMViewerContext,
|
|
184
|
-
TEntity,
|
|
185
|
-
TPrivacyPolicy,
|
|
186
|
-
TSelectedFields
|
|
187
|
-
>,
|
|
251
|
+
entityClass: IEntityClass<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields>,
|
|
188
252
|
sourceEntity: TEntity,
|
|
189
253
|
cascadingDeleteCause: EntityCascadingDeletionInfo | null,
|
|
190
254
|
queryContext: EntityQueryContext,
|
|
191
|
-
): Promise<
|
|
255
|
+
): Promise<EntityPrivacyEvaluationResult> {
|
|
192
256
|
const viewerContext = sourceEntity.getViewerContext();
|
|
193
257
|
const entityCompanionProvider = viewerContext.entityCompanionProvider;
|
|
194
258
|
const viewerScopedCompanion = sourceEntity
|
|
@@ -207,7 +271,7 @@ async function canViewerDeleteInternalAsync<
|
|
|
207
271
|
);
|
|
208
272
|
if (!evaluationResult.ok) {
|
|
209
273
|
if (evaluationResult.reason instanceof EntityNotAuthorizedError) {
|
|
210
|
-
return false;
|
|
274
|
+
return { allowed: false, authorizationErrors: [evaluationResult.reason] };
|
|
211
275
|
} else {
|
|
212
276
|
throw evaluationResult.reason;
|
|
213
277
|
}
|
|
@@ -266,9 +330,8 @@ async function canViewerDeleteInternalAsync<
|
|
|
266
330
|
edgeDeletionPermissionInferenceBehavior ===
|
|
267
331
|
EntityEdgeDeletionAuthorizationInferenceBehavior.ONE_IMPLIES_ALL
|
|
268
332
|
) {
|
|
269
|
-
const
|
|
270
|
-
.
|
|
271
|
-
.loadFirstByFieldEqualityConjunctionAsync(
|
|
333
|
+
const singleEntityResultToTestForInboundEdge =
|
|
334
|
+
await loader.loadFirstByFieldEqualityConjunctionAsync(
|
|
272
335
|
[
|
|
273
336
|
{
|
|
274
337
|
fieldName,
|
|
@@ -279,25 +342,23 @@ async function canViewerDeleteInternalAsync<
|
|
|
279
342
|
],
|
|
280
343
|
{ orderBy: [] },
|
|
281
344
|
);
|
|
282
|
-
entityResultsToCheckForInboundEdge =
|
|
283
|
-
? [
|
|
345
|
+
entityResultsToCheckForInboundEdge = singleEntityResultToTestForInboundEdge
|
|
346
|
+
? [singleEntityResultToTestForInboundEdge]
|
|
284
347
|
: [];
|
|
285
348
|
} else {
|
|
286
|
-
const entityResultsForInboundEdge = await loader
|
|
287
|
-
|
|
288
|
-
.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
: sourceEntity.getID(),
|
|
293
|
-
);
|
|
349
|
+
const entityResultsForInboundEdge = await loader.loadManyByFieldEqualingAsync(
|
|
350
|
+
fieldName,
|
|
351
|
+
association.associatedEntityLookupByField
|
|
352
|
+
? sourceEntity.getField(association.associatedEntityLookupByField as any)
|
|
353
|
+
: sourceEntity.getID(),
|
|
354
|
+
);
|
|
294
355
|
entityResultsToCheckForInboundEdge = entityResultsForInboundEdge;
|
|
295
356
|
}
|
|
296
357
|
|
|
297
358
|
const failedEntityLoadResults = failedResults(entityResultsToCheckForInboundEdge);
|
|
298
359
|
for (const failedResult of failedEntityLoadResults) {
|
|
299
360
|
if (failedResult.reason instanceof EntityNotAuthorizedError) {
|
|
300
|
-
return false;
|
|
361
|
+
return { allowed: false, authorizationErrors: [failedResult.reason] };
|
|
301
362
|
} else {
|
|
302
363
|
throw failedResult.reason;
|
|
303
364
|
}
|
|
@@ -311,48 +372,68 @@ async function canViewerDeleteInternalAsync<
|
|
|
311
372
|
switch (association.edgeDeletionBehavior) {
|
|
312
373
|
case EntityEdgeDeletionBehavior.CASCADE_DELETE:
|
|
313
374
|
case EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY: {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
queryContext,
|
|
322
|
-
),
|
|
375
|
+
const canDeleteEvaluationResults = await Promise.all(
|
|
376
|
+
entitiesForInboundEdge.map((entity) =>
|
|
377
|
+
canViewerDeleteInternalAsync(
|
|
378
|
+
inboundEdge,
|
|
379
|
+
entity,
|
|
380
|
+
newCascadingDeleteCause,
|
|
381
|
+
queryContext,
|
|
323
382
|
),
|
|
324
|
-
)
|
|
325
|
-
)
|
|
383
|
+
),
|
|
384
|
+
);
|
|
326
385
|
|
|
327
|
-
|
|
328
|
-
|
|
386
|
+
const reducedEvaluationResult = reduceEvaluationResults(canDeleteEvaluationResults);
|
|
387
|
+
if (!reducedEvaluationResult.allowed) {
|
|
388
|
+
return reducedEvaluationResult;
|
|
329
389
|
}
|
|
390
|
+
|
|
330
391
|
break;
|
|
331
392
|
}
|
|
332
393
|
|
|
333
394
|
case EntityEdgeDeletionBehavior.SET_NULL:
|
|
334
395
|
case EntityEdgeDeletionBehavior.SET_NULL_INVALIDATE_CACHE_ONLY: {
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
queryContext,
|
|
343
|
-
),
|
|
396
|
+
const canUpdateEvaluationResults = await Promise.all(
|
|
397
|
+
entitiesForInboundEdge.map((entity) =>
|
|
398
|
+
canViewerUpdateInternalAsync(
|
|
399
|
+
inboundEdge,
|
|
400
|
+
entity,
|
|
401
|
+
newCascadingDeleteCause,
|
|
402
|
+
queryContext,
|
|
344
403
|
),
|
|
345
|
-
)
|
|
346
|
-
)
|
|
404
|
+
),
|
|
405
|
+
);
|
|
347
406
|
|
|
348
|
-
|
|
349
|
-
|
|
407
|
+
const reducedEvaluationResult = reduceEvaluationResults(canUpdateEvaluationResults);
|
|
408
|
+
if (!reducedEvaluationResult.allowed) {
|
|
409
|
+
return reducedEvaluationResult;
|
|
350
410
|
}
|
|
411
|
+
|
|
351
412
|
break;
|
|
352
413
|
}
|
|
353
414
|
}
|
|
354
415
|
}
|
|
355
416
|
}
|
|
356
417
|
|
|
357
|
-
return true;
|
|
418
|
+
return { allowed: true };
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function reduceEvaluationResults(
|
|
422
|
+
evaluationResults: EntityPrivacyEvaluationResult[],
|
|
423
|
+
): EntityPrivacyEvaluationResult {
|
|
424
|
+
const [successResults, failureResults] = partitionArray<
|
|
425
|
+
EntityPrivacyEvaluationResultSuccess,
|
|
426
|
+
EntityPrivacyEvaluationResultFailure
|
|
427
|
+
>(evaluationResults, (evaluationResult) => evaluationResult.allowed);
|
|
428
|
+
|
|
429
|
+
if (successResults.length === evaluationResults.length) {
|
|
430
|
+
return { allowed: true };
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
allowed: false,
|
|
435
|
+
authorizationErrors: failureResults.flatMap(
|
|
436
|
+
(failureResult) => failureResult.authorizationErrors,
|
|
437
|
+
),
|
|
438
|
+
};
|
|
358
439
|
}
|