oak-domain 4.0.0 → 4.0.2

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.
Files changed (207) hide show
  1. package/lib/actions/action.d.ts +16 -16
  2. package/lib/actions/action.js +17 -17
  3. package/lib/actions/relation.d.ts +5 -5
  4. package/lib/actions/relation.js +25 -25
  5. package/lib/base-app-domain/ActionAuth/Schema.d.ts +186 -186
  6. package/lib/base-app-domain/ActionAuth/Storage.js +39 -39
  7. package/lib/base-app-domain/ActionDefDict.d.ts +8 -8
  8. package/lib/base-app-domain/ActionDefDict.js +9 -9
  9. package/lib/base-app-domain/EntityDict.d.ts +28 -28
  10. package/lib/base-app-domain/I18n/Schema.d.ts +129 -129
  11. package/lib/base-app-domain/I18n/Schema.js +2 -2
  12. package/lib/base-app-domain/I18n/Storage.d.ts +3 -3
  13. package/lib/base-app-domain/I18n/Storage.js +59 -59
  14. package/lib/base-app-domain/Modi/Action.d.ts +10 -10
  15. package/lib/base-app-domain/Modi/Action.js +14 -14
  16. package/lib/base-app-domain/Modi/Schema.d.ts +136 -136
  17. package/lib/base-app-domain/Modi/Storage.js +63 -63
  18. package/lib/base-app-domain/ModiEntity/Schema.d.ts +384 -384
  19. package/lib/base-app-domain/ModiEntity/Storage.js +30 -30
  20. package/lib/base-app-domain/Oper/Schema.d.ts +153 -153
  21. package/lib/base-app-domain/Oper/Storage.js +38 -38
  22. package/lib/base-app-domain/OperEntity/Schema.d.ts +373 -373
  23. package/lib/base-app-domain/OperEntity/Storage.js +30 -30
  24. package/lib/base-app-domain/Path/Schema.d.ts +149 -149
  25. package/lib/base-app-domain/Path/Schema.js +2 -2
  26. package/lib/base-app-domain/Path/Storage.d.ts +3 -3
  27. package/lib/base-app-domain/Path/Storage.js +54 -54
  28. package/lib/base-app-domain/Relation/Schema.d.ts +188 -188
  29. package/lib/base-app-domain/Relation/Storage.js +54 -54
  30. package/lib/base-app-domain/Relation.d.ts +2 -2
  31. package/lib/base-app-domain/Relation.js +4 -4
  32. package/lib/base-app-domain/RelationAuth/Schema.d.ts +214 -214
  33. package/lib/base-app-domain/RelationAuth/Storage.js +44 -44
  34. package/lib/base-app-domain/Storage.js +31 -31
  35. package/lib/base-app-domain/User/Action.d.ts +10 -10
  36. package/lib/base-app-domain/User/Action.js +12 -12
  37. package/lib/base-app-domain/User/Schema.d.ts +210 -210
  38. package/lib/base-app-domain/User/Storage.js +33 -33
  39. package/lib/base-app-domain/UserEntityClaim/Schema.d.ts +264 -264
  40. package/lib/base-app-domain/UserEntityClaim/Schema.js +2 -2
  41. package/lib/base-app-domain/UserEntityClaim/Storage.d.ts +3 -3
  42. package/lib/base-app-domain/UserEntityClaim/Storage.js +37 -37
  43. package/lib/base-app-domain/UserEntityGrant/Schema.d.ts +131 -131
  44. package/lib/base-app-domain/UserEntityGrant/Storage.js +25 -25
  45. package/lib/base-app-domain/UserRelation/Schema.d.ts +208 -208
  46. package/lib/base-app-domain/UserRelation/Storage.js +56 -56
  47. package/lib/base-app-domain/_SubQuery.d.ts +142 -142
  48. package/lib/base-app-domain/index.d.ts +4 -4
  49. package/lib/base-app-domain/index.js +7 -7
  50. package/lib/checkers/index.d.ts +5 -5
  51. package/lib/checkers/index.js +13 -13
  52. package/lib/compiler/entities.d.ts +2 -2
  53. package/lib/compiler/entities.js +7 -7
  54. package/lib/compiler/env.d.ts +13 -13
  55. package/lib/compiler/env.js +45 -45
  56. package/lib/compiler/localeBuilder.d.ts +27 -27
  57. package/lib/compiler/localeBuilder.js +37 -8
  58. package/lib/compiler/routerBuilder.d.ts +1 -0
  59. package/lib/compiler/routerBuilder.js +257 -0
  60. package/lib/compiler/schemalBuilder.d.ts +27 -27
  61. package/lib/compiler/schemalBuilder.js +3565 -3565
  62. package/lib/entities/ActionAuth.d.ts +10 -10
  63. package/lib/entities/ActionAuth.js +31 -31
  64. package/lib/entities/I18n.d.ts +9 -9
  65. package/lib/entities/I18n.js +36 -36
  66. package/lib/entities/Modi.js +49 -49
  67. package/lib/entities/ModiEntity.js +18 -18
  68. package/lib/entities/Oper.js +21 -21
  69. package/lib/entities/OperEntity.js +18 -18
  70. package/lib/entities/Path.d.ts +8 -8
  71. package/lib/entities/Path.js +35 -35
  72. package/lib/entities/Relation.d.ts +8 -8
  73. package/lib/entities/Relation.js +35 -35
  74. package/lib/entities/RelationAuth.d.ts +8 -8
  75. package/lib/entities/RelationAuth.js +34 -34
  76. package/lib/entities/User.js +31 -31
  77. package/lib/entities/UserEntityClaim.d.ts +13 -13
  78. package/lib/entities/UserEntityClaim.js +17 -17
  79. package/lib/entities/UserEntityGrant.d.ts +9 -9
  80. package/lib/entities/UserEntityGrant.js +15 -15
  81. package/lib/entities/UserRelation.d.ts +10 -10
  82. package/lib/entities/UserRelation.js +38 -38
  83. package/lib/index.d.ts +23 -23
  84. package/lib/index.js +37 -37
  85. package/lib/store/AsyncRowStore.d.ts +65 -60
  86. package/lib/store/AsyncRowStore.js +176 -118
  87. package/lib/store/CascadeStore.d.ts +10 -5
  88. package/lib/store/CascadeStore.js +102 -42
  89. package/lib/store/RelationAuth.d.ts +96 -96
  90. package/lib/store/RelationAuth.js +1336 -1336
  91. package/lib/store/SyncRowStore.d.ts +29 -29
  92. package/lib/store/SyncRowStore.js +50 -50
  93. package/lib/store/TriggerExecutor.d.ts +41 -38
  94. package/lib/store/TriggerExecutor.js +133 -124
  95. package/lib/store/actionAuth.d.ts +4 -4
  96. package/lib/store/actionAuth.js +25 -25
  97. package/lib/store/actionDef.d.ts +10 -10
  98. package/lib/store/actionDef.js +4 -4
  99. package/lib/store/checker.d.ts +26 -26
  100. package/lib/store/checker.js +487 -487
  101. package/lib/store/filter.d.ts +85 -85
  102. package/lib/store/filter.js +1652 -1651
  103. package/lib/store/modi.d.ts +13 -13
  104. package/lib/store/modi.js +254 -254
  105. package/lib/store/relation.d.ts +12 -12
  106. package/lib/store/relation.js +67 -67
  107. package/lib/timers/oper.d.ts +18 -18
  108. package/lib/timers/oper.js +57 -57
  109. package/lib/timers/vaccum.d.ts +20 -20
  110. package/lib/timers/vaccum.js +111 -111
  111. package/lib/triggers/index.d.ts +5 -5
  112. package/lib/triggers/index.js +8 -8
  113. package/lib/types/Action.d.ts +20 -20
  114. package/lib/types/AppLoader.d.ts +17 -17
  115. package/lib/types/AppLoader.js +10 -10
  116. package/lib/types/Auth.d.ts +70 -70
  117. package/lib/types/Cluster.d.ts +5 -5
  118. package/lib/types/Cluster.js +2 -2
  119. package/lib/types/Connector.d.ts +38 -38
  120. package/lib/types/Connector.js +2 -2
  121. package/lib/types/DataType.d.ts +25 -25
  122. package/lib/types/DataType.js +6 -6
  123. package/lib/types/Demand.d.ts +89 -88
  124. package/lib/types/Demand.js +10 -10
  125. package/lib/types/Endpoint.d.ts +11 -11
  126. package/lib/types/Entity.d.ts +209 -203
  127. package/lib/types/Entity.js +15 -15
  128. package/lib/types/EntityDesc.d.ts +9 -9
  129. package/lib/types/EntityDesc.js +2 -2
  130. package/lib/types/Environment.d.ts +90 -88
  131. package/lib/types/Environment.js +2 -2
  132. package/lib/types/Exception.d.ts +147 -147
  133. package/lib/types/Exception.js +406 -406
  134. package/lib/types/Expression.d.ts +163 -163
  135. package/lib/types/Expression.js +397 -397
  136. package/lib/types/Geo.d.ts +18 -18
  137. package/lib/types/Locale.d.ts +25 -25
  138. package/lib/types/Logger.d.ts +6 -6
  139. package/lib/types/Polyfill.d.ts +24 -24
  140. package/lib/types/Port.d.ts +18 -18
  141. package/lib/types/RowStore.d.ts +19 -18
  142. package/lib/types/RowStore.js +33 -33
  143. package/lib/types/Storage.d.ts +58 -58
  144. package/lib/types/Style.d.ts +11 -11
  145. package/lib/types/Timer.d.ts +20 -14
  146. package/lib/types/Trigger.d.ts +118 -124
  147. package/lib/types/Trigger.js +35 -58
  148. package/lib/types/Watcher.d.ts +19 -19
  149. package/lib/types/index.d.ts +26 -26
  150. package/lib/types/index.js +29 -29
  151. package/lib/types/schema/DataTypes.d.ts +34 -34
  152. package/lib/utils/SimpleConnector.d.ts +64 -64
  153. package/lib/utils/SimpleConnector.js +2 -2
  154. package/lib/utils/assert.d.ts +1 -0
  155. package/lib/utils/assert.js +9 -9
  156. package/lib/utils/concurrent.d.ts +15 -15
  157. package/lib/utils/concurrent.js +63 -63
  158. package/lib/utils/date.js +18 -18
  159. package/lib/utils/domain.d.ts +1 -1
  160. package/lib/utils/domain.js +11 -11
  161. package/lib/utils/geo.js +24 -24
  162. package/lib/utils/lodash.d.ts +24 -24
  163. package/lib/utils/lodash.js +46 -46
  164. package/lib/utils/mask.js +34 -34
  165. package/lib/utils/money.d.ts +6 -6
  166. package/lib/utils/money.js +51 -51
  167. package/lib/utils/projection.d.ts +4 -4
  168. package/lib/utils/projection.js +15 -15
  169. package/lib/utils/random/random.js +19 -19
  170. package/lib/utils/random/random.mp.js +14 -14
  171. package/lib/utils/random/random.native.d.ts +1 -1
  172. package/lib/utils/random/random.native.js +14 -14
  173. package/lib/utils/random/random.web.js +11 -11
  174. package/lib/utils/string.d.ts +28 -28
  175. package/lib/utils/string.js +69 -69
  176. package/lib/utils/url/index.d.ts +7 -7
  177. package/lib/utils/url/index.js +8 -8
  178. package/lib/utils/url/index.mp.d.ts +3 -4
  179. package/lib/utils/url/index.mp.js +8 -8
  180. package/lib/utils/url/index.native.d.ts +12 -12
  181. package/lib/utils/url/index.native.js +7 -7
  182. package/lib/utils/url/index.web.d.ts +12 -12
  183. package/lib/utils/url/index.web.js +7 -7
  184. package/lib/utils/url/whatwg-url/index.d.ts +3 -0
  185. package/lib/utils/url/whatwg-url/index.js +16 -0
  186. package/lib/utils/url/whatwg-url/lib/URL-impl.d.ts +20 -0
  187. package/lib/utils/url/whatwg-url/lib/URL-impl.js +175 -0
  188. package/lib/utils/url/whatwg-url/lib/URL.d.ts +1 -0
  189. package/lib/utils/url/whatwg-url/lib/URL.js +298 -0
  190. package/lib/utils/url/whatwg-url/lib/URLSearchParams-impl.d.ts +19 -0
  191. package/lib/utils/url/whatwg-url/lib/URLSearchParams-impl.js +126 -0
  192. package/lib/utils/url/whatwg-url/lib/URLSearchParams.d.ts +1 -0
  193. package/lib/utils/url/whatwg-url/lib/URLSearchParams.js +426 -0
  194. package/lib/utils/url/whatwg-url/lib/infra.d.ts +12 -0
  195. package/lib/utils/url/whatwg-url/lib/infra.js +25 -0
  196. package/lib/utils/url/whatwg-url/lib/url-state-machine.d.ts +24 -0
  197. package/lib/utils/url/whatwg-url/lib/url-state-machine.js +1238 -0
  198. package/lib/utils/url/whatwg-url/lib/urlencoded.d.ts +15 -0
  199. package/lib/utils/url/whatwg-url/lib/urlencoded.js +162 -0
  200. package/lib/utils/url/whatwg-url/lib/utils.d.ts +37 -0
  201. package/lib/utils/url/whatwg-url/lib/utils.js +101 -0
  202. package/lib/utils/uuid.d.ts +17 -17
  203. package/lib/utils/uuid.js +218 -218
  204. package/lib/utils/validator.d.ts +26 -26
  205. package/lib/utils/validator.js +131 -131
  206. package/lib/utils/version.js +21 -21
  207. package/package.json +3 -3
@@ -1,1336 +1,1336 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUserRelationsByActions = exports.RelationAuth = void 0;
4
- const tslib_1 = require("tslib");
5
- const assert_1 = tslib_1.__importDefault(require("assert"));
6
- const types_1 = require("../types");
7
- const AsyncRowStore_1 = require("./AsyncRowStore");
8
- const filter_1 = require("./filter");
9
- const relation_1 = require("./relation");
10
- const action_1 = require("../actions/action");
11
- const lodash_1 = require("../utils/lodash");
12
- const entities_1 = require("../compiler/entities");
13
- class RelationAuth {
14
- authDeduceRelationMap;
15
- schema;
16
- static SPECIAL_ENTITIES = entities_1.SYSTEM_RESERVE_ENTITIES;
17
- selectFreeEntities;
18
- updateFreeDict;
19
- constructor(schema, authDeduceRelationMap, selectFreeEntities, updateFreeDict) {
20
- this.schema = schema;
21
- this.selectFreeEntities = selectFreeEntities || [];
22
- this.updateFreeDict = updateFreeDict || {};
23
- this.authDeduceRelationMap = Object.assign({}, authDeduceRelationMap, {
24
- modi: 'entity',
25
- });
26
- }
27
- // 前台检查filter是否满足relation约束
28
- checkRelationSync(entity, operation, context) {
29
- if (context.isRoot()) {
30
- return;
31
- }
32
- this.checkActions2(entity, operation, context);
33
- }
34
- // 后台检查filter是否满足relation约束
35
- async checkRelationAsync(entity, operation, context) {
36
- if (context.isRoot()) {
37
- return;
38
- }
39
- await this.checkActions2(entity, operation, context);
40
- }
41
- checkUserRelation(context, action, filter) {
42
- const userId = context.getCurrentUserId();
43
- let filter2 = {
44
- destRelation: {
45
- userRelation$relation: filter,
46
- },
47
- };
48
- if (action === 'create') {
49
- const { entity, entityId, relationId } = filter;
50
- if (relationId) {
51
- // 如果指定relation,则测试该relation上是否可行
52
- filter2 = {
53
- destRelationId: relationId,
54
- };
55
- }
56
- else {
57
- // 否则为测试“能否”有权限管理的资格,此时只要有一个就可以
58
- (0, assert_1.default)(entity);
59
- filter2 = {
60
- destRelation: {
61
- entity,
62
- }
63
- };
64
- }
65
- }
66
- else {
67
- (0, assert_1.default)(action === 'remove');
68
- // 如果一次删除多个userRelation,接下来的流程判断是只有一个relationAuth满足就会通过,这样可能会有错判 by Xc 20231019
69
- (0, assert_1.default)(typeof filter.id === 'string', '当前只支持指定id的用户关系删除');
70
- }
71
- const relationAuths = context.select('relationAuth', {
72
- data: {
73
- id: 1,
74
- path: {
75
- id: 1,
76
- sourceEntity: 1,
77
- destEntity: 1,
78
- value: 1,
79
- recursive: 1,
80
- },
81
- sourceRelationId: 1,
82
- sourceRelation: {
83
- id: 1,
84
- entity: 1,
85
- entityId: 1,
86
- },
87
- destRelationId: 1,
88
- destRelation: {
89
- id: 1,
90
- entity: 1,
91
- entityId: 1,
92
- },
93
- },
94
- filter: filter2,
95
- }, { dontCollect: true });
96
- const checkRelationAuth = (relationAuth) => {
97
- const { destRelation, sourceRelationId, path } = relationAuth;
98
- let destEntityFilter = this.makePathFilter(destRelation.entity, path, this.schema, {
99
- userRelation$entity: {
100
- userId,
101
- relationId: sourceRelationId,
102
- },
103
- });
104
- if (action === 'create') {
105
- const { entity, entityId } = filter;
106
- (0, assert_1.default)(entity && typeof entity === 'string');
107
- if (entityId) {
108
- Object.assign(destEntityFilter, {
109
- id: entityId,
110
- });
111
- }
112
- else {
113
- // userEntityGrant会有这种情况,限定某个对象的范围进行授权
114
- const { [entity]: entityFilter } = filter;
115
- (0, assert_1.default)(entityFilter);
116
- destEntityFilter = (0, filter_1.combineFilters)(entity, this.schema, [destEntityFilter, entityFilter]);
117
- }
118
- }
119
- else {
120
- destEntityFilter = (0, filter_1.combineFilters)(destRelation.entity, this.schema, [destEntityFilter, {
121
- userRelation$entity: filter,
122
- }]);
123
- }
124
- return context.count(destRelation.entity, {
125
- filter: destEntityFilter,
126
- }, { ignoreAttrMiss: true });
127
- };
128
- if (relationAuths instanceof Promise) {
129
- return relationAuths.then((ras) => Promise.all(ras.map(ra => checkRelationAuth(ra)))).then((result) => !!result.find(ele => {
130
- (0, assert_1.default)(typeof ele === 'number');
131
- return ele > 0;
132
- }));
133
- }
134
- const result = relationAuths.map(ra => checkRelationAuth(ra));
135
- return !!result.find(ele => ele > 0);
136
- }
137
- checkOperateSpecialEntities2(entity2, action, filter, context) {
138
- switch (entity2) {
139
- case 'userRelation': {
140
- (0, assert_1.default)(!(filter instanceof Array));
141
- return this.checkUserRelation(context, action, filter);
142
- }
143
- case 'user': {
144
- // 对用户的操作由应用自己去管理权限,这里只检查grant/revoke
145
- if (['grant', 'revoke'].includes(action)) {
146
- // assert(filter && Object.keys(filter).length === 1, 'grant/revoke只能操作userRelation$user');
147
- // assert(filter!.hasOwnProperty('userRelation$user'), 'grant/revoke只能操作userRelation$user');
148
- return true;
149
- }
150
- else {
151
- // 应用允许用户操作其它用户的逻辑请通过编写类型为relation的checker去控制,在这里不能加以限制
152
- return true;
153
- }
154
- }
155
- case 'modi': {
156
- /** 正常情况下对modi的生成是在触发器下openRootMode,不会走到这里
157
- * 但是有些例外,如extraFile如果在modi中创建,上传成功之后需要显式生成一条modi,这时对modi的
158
- * 检查可以转化为对其父entity的update权限检查
159
- */
160
- (0, assert_1.default)(action === 'create');
161
- const { entity, entityId } = filter;
162
- return this.checkOperation(entity, {
163
- action: 'update',
164
- data: {},
165
- filter: {
166
- id: entityId,
167
- },
168
- }, context);
169
- }
170
- case 'relation': {
171
- // 创建relation目前不支持,以后再说
172
- return false;
173
- }
174
- case 'userEntityGrant': {
175
- // userEntityGrant的创建相当于授权,领取相当于赋权
176
- if (['create', 'update', 'remove'].includes(action)) {
177
- if (action === 'create') {
178
- const { relationEntity, relationEntityFilter, relationIds } = filter;
179
- return this.checkOperateSpecialEntities2('userRelation', 'create', {
180
- entity: relationEntity,
181
- [relationEntity]: relationEntityFilter,
182
- relationId: {
183
- $in: relationIds,
184
- },
185
- }, context);
186
- }
187
- return this.checkOperateSpecialEntities2('userRelation', 'action', {
188
- relation: {
189
- userEntityGrant$relation: filter,
190
- },
191
- }, context);
192
- }
193
- return true;
194
- }
195
- default: {
196
- (0, assert_1.default)(false, `对象${entity2}的权限控制没有加以控制`);
197
- }
198
- }
199
- }
200
- getDeducedEntityFilters(entity, filter, actions, context) {
201
- const entityFilters = [
202
- {
203
- entity,
204
- filter,
205
- actions,
206
- }
207
- ];
208
- if (this.authDeduceRelationMap[entity]) {
209
- (0, assert_1.default)(this.authDeduceRelationMap[entity] === 'entity');
210
- let { entity: deduceEntity, entityId: deduceEntityId } = filter;
211
- let deduceFilter = {};
212
- if (deduceEntity && deduceEntityId) {
213
- deduceFilter = { id: deduceEntityId };
214
- }
215
- else {
216
- // 也可能是用cascade方式进行查找,这里有时候filter上会带有两个不同的entity目标,尚未处理(todo!)
217
- const { ref } = this.schema[entity].attributes.entity;
218
- (0, assert_1.default)(ref instanceof Array);
219
- for (const refEntity of ref) {
220
- if (filter[refEntity]) {
221
- deduceEntity = refEntity;
222
- deduceFilter = filter[refEntity];
223
- break;
224
- }
225
- }
226
- }
227
- const getRecursiveDeducedFilters = (deduceEntity, deduceFilter) => {
228
- const excludeActions = action_1.readOnlyActions.concat([ /* 'create', 'remove' */]);
229
- const updateActions = this.schema[deduceEntity].actions.filter((a) => !excludeActions.includes(a));
230
- /* if (!RelationAuth.SPECIAL_ENTITIES.includes(deduceEntity as string)) {
231
- return this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions, context);
232
- }
233
- return []; */
234
- return this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions, context);
235
- };
236
- if (deduceEntity && deduceFilter) {
237
- const deducedSelections = getRecursiveDeducedFilters(deduceEntity, deduceFilter);
238
- if (deducedSelections instanceof Promise) {
239
- return deducedSelections.then((ds) => {
240
- entityFilters.push(...ds);
241
- return entityFilters;
242
- });
243
- }
244
- entityFilters.push(...deducedSelections);
245
- return entityFilters;
246
- }
247
- else {
248
- /**
249
- * 这种情况说明从filter中无法确定相应的deduceFilter,需要查找该实体对应的entity/entityId来进行推导。
250
- * 这种情况一般发生在entity1 -> entity2上,此时entity2应该是一个固定id查询的filter
251
- * 在这里先假设如果碰到了list类型的filter,直接不使用deduce路径上的对象来推导
252
- */
253
- const rows2 = context.select(entity, {
254
- data: {
255
- id: 1,
256
- entity: 1,
257
- entityId: 1,
258
- },
259
- filter,
260
- indexFrom: 0,
261
- count: 10,
262
- }, { dontCollect: true, blockTrigger: true });
263
- const dealWithData = (rows) => {
264
- // 这里如果entity指向不同的实体,一般出现这样的查询,则其权限应当不由这条deduce路径处理
265
- // 同上,如果找到的行数大于1行,说明deduce路径上的对象不确定,也暂不处理 by Xc 20230725
266
- if (rows.length > 1 || rows.length === 0) {
267
- if (process.env.NODE_ENV === 'development') {
268
- console.warn(`进行deduce推导时找到了${rows.length}行${entity}数据`);
269
- }
270
- return entityFilters;
271
- }
272
- const { entity: deducedEntity, entityId: deducedEntityId } = rows[0];
273
- if (!deducedEntity || !deducedEntityId) {
274
- // 这种情况会出现在前台缓存里
275
- return entityFilters;
276
- }
277
- const result = getRecursiveDeducedFilters(deducedEntity, {
278
- id: deducedEntityId,
279
- });
280
- if (result instanceof Promise) {
281
- return result.then((r2) => {
282
- entityFilters.push(...r2);
283
- return entityFilters;
284
- });
285
- }
286
- entityFilters.push(...result);
287
- return entityFilters;
288
- };
289
- if (rows2 instanceof Promise) {
290
- return rows2.then((r2) => dealWithData(r2));
291
- }
292
- return dealWithData(rows2);
293
- }
294
- }
295
- return entityFilters;
296
- }
297
- /**
298
- * 对于selection,解构出最底层的对象,如果最底层的对象可以被访问,则父对象一定可以
299
- * 但对于deduce的子对象,不必再向底层查看(假设deduce对象一般都位于树的最底层附近)
300
- * @param entity
301
- * @param operation
302
- */
303
- destructSelection(entity, selection) {
304
- const leafSelections = [];
305
- const destructInner = (entity2, selection2) => {
306
- const { data, filter } = selection2;
307
- let hasOneToMany = false;
308
- for (const attr in data) {
309
- const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
310
- if (rel instanceof Array) {
311
- const [e, foreignKey] = rel;
312
- if (foreignKey) {
313
- (0, assert_1.default)(!this.authDeduceRelationMap[e]);
314
- hasOneToMany = true;
315
- destructInner(e, {
316
- data: data[attr].data,
317
- filter: (0, filter_1.combineFilters)(e, this.schema, [{
318
- [foreignKey.slice(0, foreignKey.length - 2)]: filter,
319
- }, data[attr].filter || {}]),
320
- });
321
- }
322
- else {
323
- if (!this.authDeduceRelationMap[e]) {
324
- hasOneToMany = true;
325
- destructInner(e, {
326
- data: data[attr].data,
327
- filter: (0, filter_1.combineFilters)(e, this.schema, [{
328
- [entity2]: filter,
329
- }, data[attr].filter || {}]),
330
- });
331
- }
332
- else {
333
- (0, assert_1.default)(this.authDeduceRelationMap[e] === 'entity');
334
- }
335
- }
336
- }
337
- }
338
- if (!hasOneToMany) {
339
- leafSelections.push({
340
- entity: entity2,
341
- filter,
342
- });
343
- }
344
- };
345
- destructInner(entity, (0, lodash_1.cloneDeep)(selection));
346
- return leafSelections;
347
- }
348
- /**
349
- * 对于operation,解构出一个树形结构,以方便自顶向下的进行访问
350
- * 但对于deduce的子对象,不必再向底层查看
351
- * @param entity
352
- * @param selection
353
- */
354
- destructOperation(entity2, operation2, userId) {
355
- /**
356
- * 对create动作,把data中的cascade部分剔除后作为filter参与后续的检验
357
- * @param operation
358
- * @returns
359
- */
360
- const makeCreateFilter = (entity, operation) => {
361
- const { data, filter } = operation;
362
- (0, assert_1.default)(!(data instanceof Array));
363
- if (data) {
364
- const data2 = {};
365
- for (const attr in data) {
366
- const rel = (0, relation_1.judgeRelation)(this.schema, entity, attr);
367
- if (rel === 1) {
368
- // 只需要记住id和各种外键属性,不这样处理有些古怪的属性比如coordinate,其作为createdata和作为filter并不同构
369
- /* if ((['id', 'entity', 'entityId'].includes(attr) || this.schema[entity].attributes[attr as any]?.type === 'ref') && typeof data[attr] === 'string') {
370
- data2[attr] = data[attr];
371
- } */
372
- // 假设不再成立,userEntityGrant需要relationEntity这样的属性
373
- if (!['geometry', 'geography', 'st_geometry', 'st_point'].includes(this.schema[entity].attributes[attr]?.type)) {
374
- data2[attr] = data[attr];
375
- }
376
- }
377
- }
378
- return data2;
379
- }
380
- return filter;
381
- };
382
- const addChild = (node, path, child) => {
383
- // 在这里要把可以被node deduce出来的child处理掉
384
- const paths = path.split('$');
385
- (0, assert_1.default)(paths.length >= 2);
386
- if (this.authDeduceRelationMap[child.entity] === paths[1]) {
387
- (0, assert_1.default)(paths[1] === 'entity', '当前只支持entity外键上的deduce');
388
- return false;
389
- }
390
- if (node.children[path]) {
391
- if (node.children[path] instanceof Array) {
392
- node.children[path].push(child);
393
- }
394
- else {
395
- node.children[path] = [node.children[path], child];
396
- }
397
- }
398
- else {
399
- Object.assign(node.children, {
400
- [path]: child,
401
- });
402
- }
403
- return true;
404
- };
405
- const destructInner = (entity, operation,
406
- // extraFilter?: ED[T2]['Selection']['filter'],
407
- path, child, hasParent, extraFilter) => {
408
- const { action, data, filter } = operation;
409
- const filter2 = action === 'create' ? makeCreateFilter(entity, operation) : (0, lodash_1.cloneDeep)(filter);
410
- (0, assert_1.default)(filter2);
411
- if (extraFilter) {
412
- Object.assign(filter2, extraFilter);
413
- }
414
- // const filter3 = extraFilter ? combineFilters(entity, schema, [filter2, extraFilter]) : filter2;
415
- const me = {
416
- entity: entity,
417
- filter: filter2,
418
- children: {},
419
- action,
420
- };
421
- let root = me;
422
- // 如果当前对象是一个toModi的,意味着它的cascadeUpdate会全部被变为modi去缓存,因此不需要再向下检查了
423
- // modi被apply时,这些modi产生的更新才会被实际检查
424
- // 这里可能有问题,再思考思考 by Xc 20231111
425
- const isModiUpdate = this.schema[entity].toModi && action !== 'remove';
426
- if (child) {
427
- (0, assert_1.default)(path);
428
- addChild(me, path, child);
429
- }
430
- (0, assert_1.default)(!(data instanceof Array));
431
- for (const attr in data) {
432
- const rel = (0, relation_1.judgeRelation)(this.schema, entity, attr);
433
- if (rel === 2 && !isModiUpdate) {
434
- (0, assert_1.default)(root === me && !hasParent, 'cascadeUpdate必须是树结构,避免森林');
435
- const mtoOperation = data[attr];
436
- root = destructInner(attr, mtoOperation, `${entity}$entity`, me);
437
- }
438
- else if (typeof rel === 'string' && !isModiUpdate) {
439
- (0, assert_1.default)(root === me && !hasParent, 'cascadeUpdate必须是树结构,避免森林');
440
- root = destructInner(rel, data[attr], `${entity}$${attr}`, me);
441
- }
442
- else if (rel instanceof Array && !isModiUpdate) {
443
- const [e, f] = rel;
444
- const otmOperations = data[attr];
445
- /**
446
- * 这里目前在cascadeUpdate的过程中,只有当一对多个userRelation的操作需要将entity和entityId复制到子对象上
447
- * 因为对userRelation的判断是走的特殊路径,无法利用父对象的actionAuth
448
- * 其它对象情况不需要复制,因为应用中必须要能保证(前台传来的)父对象的filter不依赖于子对象的条件
449
- */
450
- let extraFilter = undefined;
451
- if (e === 'userRelation' && entity !== 'user') {
452
- me.userRelations = [];
453
- extraFilter = {
454
- entity,
455
- entityId: filter2.id,
456
- };
457
- const dealWithUserRelation = (userRelation) => {
458
- const { action, data } = userRelation;
459
- if (action === 'create') {
460
- const attrs = Object.keys(data);
461
- (0, assert_1.default)((0, lodash_1.difference)(attrs, Object.keys(this.schema.userRelation.attributes).concat('id')).length === 0);
462
- if (data.userId === userId) {
463
- me.userRelations?.push(data);
464
- }
465
- (0, assert_1.default)(filter2.id);
466
- }
467
- };
468
- if (otmOperations instanceof Array) {
469
- otmOperations.forEach((otmOperation) => dealWithUserRelation(otmOperation));
470
- }
471
- else {
472
- dealWithUserRelation(otmOperations);
473
- }
474
- }
475
- if (otmOperations instanceof Array) {
476
- otmOperations.forEach((otmOperation) => {
477
- const son = destructInner(e, otmOperation, undefined, undefined, true, extraFilter);
478
- addChild(me, attr, son);
479
- });
480
- }
481
- else {
482
- const son = destructInner(e, otmOperations, undefined, undefined, true, extraFilter);
483
- addChild(me, attr, son);
484
- }
485
- }
486
- }
487
- return root;
488
- };
489
- return destructInner(entity2, operation2);
490
- }
491
- makePathFilter(entity, path, schema, filter) {
492
- const { value, recursive } = path;
493
- if (value === '') {
494
- (0, assert_1.default)(!recursive);
495
- return filter;
496
- }
497
- const paths = value.split('.');
498
- const makeRecursiveFilter = (recursiveDepth) => {
499
- if (recursiveDepth > 0) {
500
- return {
501
- $or: [
502
- filter,
503
- {
504
- parent: makeRecursiveFilter(recursiveDepth - 1)
505
- }
506
- ]
507
- };
508
- }
509
- return filter;
510
- };
511
- const makeInner = (idx, e2) => {
512
- const attr = paths[idx];
513
- if (idx === paths.length) {
514
- if (!recursive) {
515
- return filter;
516
- }
517
- else {
518
- // 在最后一个对象上存在递归,用or连接处理
519
- const { recursiveDepth } = schema[e2];
520
- (0, assert_1.default)(recursiveDepth > 0);
521
- return makeRecursiveFilter(recursiveDepth);
522
- }
523
- }
524
- else {
525
- const rel = (0, relation_1.judgeRelation)(schema, e2, attr);
526
- let e3;
527
- if (rel === 2) {
528
- e3 = attr;
529
- }
530
- else if (typeof rel === 'string') {
531
- e3 = rel;
532
- }
533
- else {
534
- (0, assert_1.default)(rel instanceof Array);
535
- e3 = rel[0];
536
- }
537
- const f = makeInner(idx + 1, e3);
538
- return {
539
- [attr]: f,
540
- };
541
- }
542
- };
543
- return makeInner(0, entity);
544
- }
545
- /**
546
- * 对所有满足操作要求的actionAuth加以判断,找到可以满足当前用户身份的actionAuth
547
- * @param entity
548
- * @param filter
549
- * @param actionAuths
550
- * @param context
551
- * @return
552
- */
553
- filterActionAuths(entity, filter, actionAuths, context) {
554
- const result = actionAuths.map((ele) => {
555
- const { path, relation, relationId } = ele;
556
- // 在cache中,可能出现relation外键指向的对象为null的情况,要容错
557
- if (relationId) {
558
- if (relation) {
559
- const { userRelation$relation: userRelations } = relation;
560
- if (userRelations.length > 0) {
561
- const entityIds = (0, lodash_1.uniq)(userRelations.map(ele => ele.entityId));
562
- const pathFilter = this.makePathFilter(entity, path, this.schema, {
563
- id: entityIds.length > 0 ? {
564
- $in: entityIds,
565
- } : entityIds[0],
566
- });
567
- const contains = (0, filter_1.checkFilterContains)(entity, context, pathFilter, filter, true);
568
- if (contains instanceof Promise) {
569
- return contains.then((c) => {
570
- if (c) {
571
- return ele;
572
- }
573
- return;
574
- });
575
- }
576
- if (contains) {
577
- return ele;
578
- }
579
- return;
580
- }
581
- }
582
- return;
583
- }
584
- // 说明是通过userId关联
585
- const pathFilter = this.makePathFilter(entity, path, this.schema, {
586
- id: context.getCurrentUserId(),
587
- });
588
- const contains = (0, filter_1.checkFilterContains)(entity, context, pathFilter, filter, true);
589
- if (contains instanceof Promise) {
590
- return contains.then((c) => {
591
- if (c) {
592
- return ele;
593
- }
594
- return;
595
- });
596
- }
597
- if (contains) {
598
- return ele;
599
- }
600
- });
601
- if (result.find(ele => ele instanceof Promise)) {
602
- return Promise.all(result).then((r2) => r2.filter(ele => !!ele));
603
- }
604
- return result.filter(ele => !!ele);
605
- }
606
- /**
607
- * 对于有些特殊的查询(带很多$or的查询,多发生在系统级别),单个actionAuth无法满足,需要共同加以判定
608
- * @param entity
609
- * @param filter
610
- * @param actionAuths
611
- * @param context
612
- * @param actions
613
- */
614
- checkActionAuthInGroup(entity, filter, actionAuths, context) {
615
- const filters = actionAuths.filter(ele => ele.path.destEntity === entity).map((ele) => {
616
- const { path, relation, relationId } = ele;
617
- if (relationId) {
618
- (0, assert_1.default)(relation);
619
- const { userRelation$relation: userRelations } = relation;
620
- (0, assert_1.default)(userRelations.length > 0);
621
- const entityIds = (0, lodash_1.uniq)(userRelations.map(ele => ele.entityId));
622
- const pathFilter = this.makePathFilter(entity, path, this.schema, {
623
- id: entityIds.length > 0 ? {
624
- $in: entityIds,
625
- } : entityIds[0],
626
- });
627
- return pathFilter;
628
- }
629
- // 说明是通过userId关联
630
- return this.makePathFilter(entity, path, this.schema, {
631
- id: context.getCurrentUserId(),
632
- });
633
- });
634
- const groupFilter = (0, filter_1.combineFilters)(entity, this.schema, filters, true);
635
- if (groupFilter) {
636
- return (0, filter_1.checkFilterContains)(entity, context, groupFilter, filter, true);
637
- }
638
- return false;
639
- }
640
- checkSelection(entity, selection, context) {
641
- const leafSelections = this.destructSelection(entity, selection);
642
- const deducedLeafSelections = leafSelections.map(({ entity, filter }) => this.getDeducedEntityFilters(entity, filter, ['select'], context));
643
- const checkDeducedLeafSelections = (dlSelections2) => {
644
- const dlSelections = dlSelections2.filter((ele) => {
645
- const entities = ele.map(ele2 => ele2.entity);
646
- // 同一个leaf的deducedSelections中只要有一个能通过就足够了
647
- if ((0, lodash_1.intersection)(this.selectFreeEntities, entities).length > 0) {
648
- return false;
649
- }
650
- if ((0, lodash_1.intersection)(RelationAuth.SPECIAL_ENTITIES, entities).length > 0) {
651
- // todo
652
- return false;
653
- }
654
- return true;
655
- });
656
- if (dlSelections.length === 0) {
657
- return true;
658
- }
659
- if (!context.getCurrentUserId()) {
660
- throw new types_1.OakUnloggedInException();
661
- }
662
- const allEntities = [];
663
- dlSelections.forEach((ele) => ele.forEach(({ entity }) => {
664
- allEntities.push(entity);
665
- }));
666
- const actionAuths = context.select('actionAuth', {
667
- data: {
668
- id: 1,
669
- path: {
670
- id: 1,
671
- value: 1,
672
- sourceEntity: 1,
673
- destEntity: 1,
674
- recursive: 1,
675
- },
676
- deActions: 1,
677
- relation: {
678
- id: 1,
679
- userRelation$relation: {
680
- $entity: 'userRelation',
681
- data: {
682
- id: 1,
683
- entity: 1,
684
- entityId: 1,
685
- },
686
- filter: {
687
- userId: context.getCurrentUserId(),
688
- },
689
- },
690
- },
691
- },
692
- filter: {
693
- deActions: {
694
- $contains: 'select',
695
- },
696
- path: {
697
- destEntity: {
698
- $in: allEntities,
699
- },
700
- },
701
- $or: [
702
- {
703
- relation: {
704
- userRelation$relation: {
705
- userId: context.getCurrentUserId(),
706
- },
707
- }
708
- },
709
- {
710
- relationId: {
711
- $exists: false,
712
- },
713
- }
714
- ]
715
- }
716
- }, { dontCollect: true, ignoreAttrMiss: true });
717
- /**
718
- * 返回的结果中,第一层为leafNode,必须全通过,第二层为单个leafNode上的deduce,通过一个就可以
719
- * @param result
720
- * @returns
721
- */
722
- const checkResult = (result) => {
723
- let idx = 0;
724
- for (const r1 of result) {
725
- const r2 = r1.find(ele => ele === true);
726
- if (!r2) {
727
- if (process.env.NODE_ENV === 'development') {
728
- console.warn('对象的select权限被否决,请检查', dlSelections[idx]);
729
- }
730
- idx++;
731
- return false;
732
- }
733
- idx++;
734
- }
735
- return true;
736
- };
737
- if (actionAuths instanceof Promise) {
738
- (0, assert_1.default)(context instanceof AsyncRowStore_1.AsyncContext);
739
- return actionAuths.then((aas) => Promise.all(dlSelections.map((ele) => Promise.all(ele.map((ele2) => this.checkActionAuthInGroup(ele2.entity, ele2.filter, aas, context))))).then((result) => checkResult(result)));
740
- }
741
- return checkResult(dlSelections.map(ele => ele.map(ele2 => this.checkActionAuthInGroup(ele2.entity, ele2.filter, actionAuths, context))));
742
- };
743
- if (deducedLeafSelections[0] instanceof Promise) {
744
- return Promise.all(deducedLeafSelections)
745
- .then((dls) => checkDeducedLeafSelections(dls));
746
- }
747
- return checkDeducedLeafSelections(deducedLeafSelections);
748
- }
749
- /**
750
- * 此函数判定一个结点是否能通过权限检测,同时寻找该结点本身对象上成立的actionAuth,用于本结点子孙结点的快速检测
751
- * 如果结点因其deduce的对象通过了检测,其被推断对象的actionAuth无法用于更低对象的权限检测
752
- * @param node
753
- * @param context
754
- * @returns
755
- */
756
- findActionAuthsOnNode(node, context) {
757
- const { entity, filter, action, userRelations } = node;
758
- const deducedEntityFilters2 = this.getDeducedEntityFilters(entity, filter, [action], context);
759
- /**
760
- * 搜索判定是否允许自建对象,自建的条件是 path = '',destEntity === entity
761
- * @param actionAuths
762
- * @returns
763
- */
764
- const findOwnCreateUserRelation = (actionAuths) => {
765
- if (userRelations && userRelations.length > 0) {
766
- const ars = actionAuths.filter((ar) => !!userRelations.find((ur) => ur.relationId === ar.relationId) && ar.path.value === '' && ar.path.destEntity === entity);
767
- if (ars.length > 0) {
768
- return ars;
769
- }
770
- }
771
- };
772
- const actionAuthOnEntities = [];
773
- const dealWithDeducedEntityFilters = (deducedEntityFilters) => {
774
- const specialEntities = deducedEntityFilters.filter(ele => RelationAuth.SPECIAL_ENTITIES.includes(ele.entity));
775
- const unspecicalEntities = deducedEntityFilters.filter(ele => !RelationAuth.SPECIAL_ENTITIES.includes(ele.entity));
776
- const result = [];
777
- if (specialEntities.length > 0) {
778
- // 对于deduce出来的special对象,直接判定create应该问题不大,否则写起来太烦琐(具体情况遇到了再调试)
779
- result.push(...specialEntities.map(ele => this.checkOperateSpecialEntities2(ele.entity, ele.entity === entity ? node.action : 'create', ele.filter, context)));
780
- }
781
- if (unspecicalEntities.length > 0) {
782
- const allEntities = unspecicalEntities.map(ele => ele.entity);
783
- const allActions = (0, lodash_1.uniq)(unspecicalEntities.map(ele => ele.actions).flat());
784
- const actionAuths2 = context.select('actionAuth', {
785
- data: {
786
- id: 1,
787
- path: {
788
- id: 1,
789
- destEntity: 1,
790
- sourceEntity: 1,
791
- value: 1,
792
- recursive: 1,
793
- },
794
- deActions: 1,
795
- relation: {
796
- id: 1,
797
- userRelation$relation: {
798
- $entity: 'userRelation',
799
- data: {
800
- id: 1,
801
- entity: 1,
802
- entityId: 1,
803
- },
804
- filter: {
805
- userId: context.getCurrentUserId(),
806
- },
807
- },
808
- },
809
- },
810
- filter: {
811
- path: {
812
- destEntity: {
813
- $in: allEntities,
814
- }
815
- },
816
- deActions: {
817
- $overlaps: allActions,
818
- },
819
- }
820
- }, { dontCollect: true, ignoreAttrMiss: true });
821
- const checkActionAuths = (actionAuths) => {
822
- const created = findOwnCreateUserRelation(actionAuths);
823
- if (created) {
824
- actionAuthOnEntities.push(...created);
825
- return true;
826
- }
827
- const result = deducedEntityFilters.map((ele) => {
828
- const ars2 = actionAuths.filter(ele2 => ele2.path.destEntity === ele.entity && (0, lodash_1.intersection)(ele2.deActions, ele.actions).length > 0 // 这里只要overlap就可以了
829
- );
830
- const ars3 = this.filterActionAuths(ele.entity, ele.filter, ars2, context);
831
- const checkFilteredArs = (actionAuths2) => {
832
- if (actionAuths2.length > 0) {
833
- if (ele.entity === entity) {
834
- actionAuthOnEntities.push(...actionAuths2);
835
- }
836
- return true;
837
- }
838
- return false;
839
- };
840
- if (ars3 instanceof Promise) {
841
- return ars3.then((ars4) => checkFilteredArs(ars4));
842
- }
843
- return checkFilteredArs(ars3);
844
- });
845
- if (result.find(ele => ele instanceof Promise)) {
846
- return Promise.all(result).then((r2) => r2.includes(true));
847
- }
848
- return result.includes(true);
849
- };
850
- if (actionAuths2 instanceof Promise) {
851
- result.push(actionAuths2.then((ars2) => checkActionAuths(ars2)));
852
- }
853
- else {
854
- result.push(checkActionAuths(actionAuths2));
855
- }
856
- }
857
- if (result.find(ele => ele instanceof Promise)) {
858
- return Promise.all(result).then((r2) => {
859
- // r2中只有一个通过就能通过
860
- if (r2.includes(true)) {
861
- return actionAuthOnEntities;
862
- }
863
- return false;
864
- });
865
- }
866
- if (result.includes(true)) {
867
- return actionAuthOnEntities;
868
- }
869
- return false;
870
- };
871
- if (deducedEntityFilters2 instanceof Promise) {
872
- return deducedEntityFilters2.then((def2) => dealWithDeducedEntityFilters(def2));
873
- }
874
- return dealWithDeducedEntityFilters(deducedEntityFilters2);
875
- }
876
- checkOperationTree2(tree, context) {
877
- const checkNode = (node, actionAuths) => {
878
- const checkChildren = (legalPaths) => {
879
- const { children } = node;
880
- const childPath = Object.keys(children);
881
- if (childPath.length === 0) {
882
- return true;
883
- }
884
- const childResult = childPath.map((childPath) => {
885
- const child = children[childPath];
886
- const childEntity = child instanceof Array ? child[0].entity : child.entity;
887
- // 这里如果该子结点能deduce到父,则直接通过
888
- if (this.authDeduceRelationMap[childEntity]) {
889
- (0, assert_1.default)(this.authDeduceRelationMap[childEntity] === 'entity');
890
- const rel = (0, relation_1.judgeRelation)(this.schema, childEntity, childPath);
891
- if (rel === 2) {
892
- return true;
893
- }
894
- }
895
- const pathToParent = childPath.endsWith('$entity') ? node.entity : childPath.split('$')[1];
896
- if (child instanceof Array) {
897
- const childActions = child.map(ele => ele.action);
898
- const childLegalAuths = legalPaths.map((ele) => {
899
- const { path: { value: pv }, relationId } = ele;
900
- const pv2 = pv ? `${pathToParent}.${pv}` : pathToParent;
901
- return context.select('actionAuth', {
902
- data: {
903
- id: 1,
904
- },
905
- filter: {
906
- path: {
907
- value: pv2,
908
- destEntity: childEntity,
909
- },
910
- deActions: {
911
- $overlaps: childActions,
912
- },
913
- relationId: relationId || {
914
- $exists: false,
915
- },
916
- }
917
- }, { dontCollect: true });
918
- }).flat();
919
- if (childLegalAuths[0] instanceof Promise) {
920
- return Promise.all(childLegalAuths).then((clas) => child.map((c) => checkNode(c, clas)));
921
- }
922
- return child.map((c) => checkNode(c, childLegalAuths));
923
- }
924
- const childLegalAuths = legalPaths.map((ele) => {
925
- const { path: { value: pv }, relationId } = ele;
926
- const pv2 = pv ? `${pathToParent}.${pv}` : pathToParent;
927
- return context.select('actionAuth', {
928
- data: {
929
- id: 1,
930
- },
931
- filter: {
932
- path: {
933
- value: pv2,
934
- destEntity: childEntity,
935
- },
936
- deActions: {
937
- $overlaps: child.action,
938
- },
939
- relationId: relationId || {
940
- $exists: false,
941
- },
942
- }
943
- }, { dontCollect: true });
944
- }).flat();
945
- if (childLegalAuths[0] instanceof Promise) {
946
- return Promise.all(childLegalAuths).then((clas) => checkNode(child, clas.flat()));
947
- }
948
- return checkNode(child, childLegalAuths);
949
- }).flat();
950
- if (childResult[0] instanceof Promise) {
951
- return Promise.all(childResult).then((r) => !r.includes(false));
952
- }
953
- return !childResult.includes(false);
954
- };
955
- // 先根据parent传下来的合法auths来搜寻,只需要查找actionAuth,降低开销
956
- // 这里有可能父结点根据actionAuths能通过,但子结点需要重新搜索父结点上的新actionAuths才能通过吗?应该不存在这种情况。 by Xc 20230824
957
- if (actionAuths && actionAuths.length > 0) {
958
- return checkChildren(actionAuths);
959
- }
960
- // 没有能根据父亲传下来的actionAuth判定,只能自己找
961
- const result = this.findActionAuthsOnNode(node, context);
962
- const checkResult = (result2) => {
963
- if (result2 === false) {
964
- return false;
965
- }
966
- // 如果是对user对象操作通过,需要增添一条虚假的的actionAuth
967
- if (node.entity === 'user') {
968
- result2.push({
969
- id: 'temp',
970
- pathId: 'path_temp',
971
- path: {
972
- id: 'path_temp',
973
- destEntity: 'user',
974
- sourceEntity: 'any',
975
- value: '',
976
- $$createAt$$: 1,
977
- $$updateAt$$: 1,
978
- $$seq$$: 123,
979
- recursive: false,
980
- },
981
- $$createAt$$: 1,
982
- $$updateAt$$: 1,
983
- $$seq$$: 123,
984
- deActions: [node.action],
985
- });
986
- }
987
- return checkChildren(result2);
988
- };
989
- if (result instanceof Promise) {
990
- return result.then((r2) => checkResult(r2));
991
- }
992
- return checkResult(result);
993
- };
994
- return checkNode(tree);
995
- }
996
- checkOperation(entity, operation, context) {
997
- const { action, filter, data } = operation;
998
- if (this.updateFreeDict[entity] && this.updateFreeDict[entity].includes(action)) {
999
- return true;
1000
- }
1001
- const userId = context.getCurrentUserId();
1002
- if (!userId) {
1003
- throw new types_1.OakUnloggedInException();
1004
- }
1005
- if (!filter && (!data || action !== 'create')) {
1006
- if (process.env.NODE_ENV === 'development') {
1007
- console.warn('operation不能没有限制条件', operation);
1008
- }
1009
- return false;
1010
- }
1011
- const updateTree = this.destructOperation(entity, operation, userId);
1012
- return this.checkOperationTree2(updateTree, context);
1013
- }
1014
- /**
1015
- * 检查一个operation是否能被通过权限测试
1016
- * 一个cascadeOperation是一棵树形结构:
1017
- * * 对于select,只要叶子通过其父结点必然通过;
1018
- * * 对于update,自顶向下进行检查,若父亲被权限S通过,则只需要检查子对于S有没有相对路径上的actionAuth
1019
- * 另外在update中,还需要考虑自建userRelation的case(例如在电子商务网站上购买商品,创建订单同时创建用户和订单的关系)
1020
- * @param entity
1021
- * @param operation
1022
- * @param context
1023
- * @param actions
1024
- * @returns
1025
- */
1026
- checkActions2(entity, operation, context, actions) {
1027
- const { action } = operation;
1028
- if (!action || action_1.readOnlyActions.includes(action)) {
1029
- const result = this.checkSelection(entity, operation, context);
1030
- if (result instanceof Promise) {
1031
- return result.then((r) => {
1032
- if (!r) {
1033
- throw new types_1.OakUserInvisibleException();
1034
- }
1035
- });
1036
- }
1037
- if (!result) {
1038
- throw new types_1.OakUserInvisibleException();
1039
- }
1040
- }
1041
- else {
1042
- const result = this.checkOperation(entity, operation, context);
1043
- if (result instanceof Promise) {
1044
- return result.then((r) => {
1045
- if (!r) {
1046
- throw new types_1.OakUserUnpermittedException();
1047
- }
1048
- });
1049
- }
1050
- if (!result) {
1051
- throw new types_1.OakUserUnpermittedException();
1052
- }
1053
- }
1054
- }
1055
- }
1056
- exports.RelationAuth = RelationAuth;
1057
- ;
1058
- /**
1059
- * 获取有对entity进行actions操作权限的userRelation关系
1060
- * @param params
1061
- * @param context
1062
- * todo paths改成复数以后这里还未充分测试过
1063
- */
1064
- async function getUserRelationsByActions(params, context) {
1065
- const { entity, filter, actions, overlap } = params;
1066
- const actionAuthfilter = {
1067
- path: {
1068
- destEntity: entity,
1069
- },
1070
- };
1071
- if (overlap) {
1072
- Object.assign(actionAuthfilter, {
1073
- deActions: {
1074
- $overlaps: actions,
1075
- },
1076
- });
1077
- }
1078
- else {
1079
- Object.assign(actionAuthfilter, {
1080
- deActions: {
1081
- $contains: actions,
1082
- },
1083
- });
1084
- }
1085
- const actionAuths = await context.select('actionAuth', {
1086
- data: {
1087
- id: 1,
1088
- path: {
1089
- id: 1,
1090
- value: 1,
1091
- destEntity: 1,
1092
- recursive: 1,
1093
- },
1094
- relationId: 1,
1095
- relation: {
1096
- id: 1,
1097
- entity: 1,
1098
- },
1099
- },
1100
- filter: actionAuthfilter,
1101
- }, { dontCollect: true });
1102
- const getUserRelations = async (urAuths) => {
1103
- const makeRelationIterator = (path, relationIds, recursive) => {
1104
- (0, assert_1.default)(!recursive, 'recursive的情况还没处理,等跑出来再说, by Xc');
1105
- if (path === '') {
1106
- return {
1107
- projection: {
1108
- id: 1,
1109
- userRelation$entity: {
1110
- $entity: 'userRelation',
1111
- data: {
1112
- id: 1,
1113
- relationId: 1,
1114
- relation: {
1115
- id: 1,
1116
- name: 1,
1117
- },
1118
- entity: 1,
1119
- entityId: 1,
1120
- userId: 1,
1121
- },
1122
- filter: {
1123
- relationId: {
1124
- $in: relationIds,
1125
- },
1126
- },
1127
- },
1128
- },
1129
- getData: (d) => {
1130
- return d.userRelation$entity;
1131
- },
1132
- };
1133
- }
1134
- const paths = path.split('.');
1135
- const makeIter = (e, idx) => {
1136
- if (idx === paths.length) {
1137
- return {
1138
- projection: {
1139
- id: 1,
1140
- userRelation$entity: {
1141
- $entity: 'userRelation',
1142
- data: {
1143
- id: 1,
1144
- relationId: 1,
1145
- relation: {
1146
- id: 1,
1147
- name: 1,
1148
- },
1149
- entity: 1,
1150
- entityId: 1,
1151
- userId: 1,
1152
- },
1153
- filter: {
1154
- relationId: {
1155
- $in: relationIds,
1156
- },
1157
- },
1158
- }
1159
- },
1160
- getData: (d) => {
1161
- return d.userRelation$entity;
1162
- },
1163
- };
1164
- }
1165
- const attr = paths[idx];
1166
- const rel = (0, relation_1.judgeRelation)(context.getSchema(), e, attr);
1167
- if (rel === 2) {
1168
- const { projection, getData } = makeIter(attr, idx + 1);
1169
- return {
1170
- projection: {
1171
- id: 1,
1172
- [attr]: projection,
1173
- },
1174
- getData: (d) => d[attr] && getData(d[attr]),
1175
- };
1176
- }
1177
- else if (typeof rel === 'string') {
1178
- const { projection, getData } = makeIter(rel, idx + 1);
1179
- return {
1180
- projection: {
1181
- id: 1,
1182
- [attr]: projection,
1183
- },
1184
- getData: (d) => d[attr] && getData(d[attr]),
1185
- };
1186
- }
1187
- else {
1188
- (0, assert_1.default)(rel instanceof Array);
1189
- const [e2, fk] = rel;
1190
- const { projection, getData } = makeIter(e2, idx + 1);
1191
- return {
1192
- projection: {
1193
- id: 1,
1194
- [attr]: {
1195
- $entity: e2,
1196
- data: projection,
1197
- },
1198
- },
1199
- getData: (d) => d[attr] && d[attr].map((ele) => getData(ele)),
1200
- };
1201
- }
1202
- };
1203
- return makeIter(entity, 0);
1204
- };
1205
- // 相同的path可以groupBy掉
1206
- const urAuthDict2 = {};
1207
- urAuths.forEach((auth) => {
1208
- const { path, relationId } = auth;
1209
- const { value, recursive } = path;
1210
- if (!urAuthDict2[value]) {
1211
- urAuthDict2[value] = [[relationId], recursive];
1212
- }
1213
- else if (!urAuthDict2[value][0].includes(relationId)) {
1214
- (0, assert_1.default)(urAuthDict2[value][1] === recursive);
1215
- urAuthDict2[value][0].push(relationId);
1216
- }
1217
- });
1218
- const userRelations = await Promise.all(Object.keys(urAuthDict2).map(async (path) => {
1219
- const [relationIds, recursive] = urAuthDict2[path];
1220
- const { projection, getData } = makeRelationIterator(path, relationIds, recursive);
1221
- const rows = await context.select(entity, {
1222
- data: projection,
1223
- filter,
1224
- }, { dontCollect: true });
1225
- const urs = rows.map(ele => getData(ele)).flat().filter(ele => !!ele);
1226
- return urs;
1227
- }));
1228
- return userRelations.flat();
1229
- };
1230
- const getDirectUserEntities = async (directAuths) => {
1231
- const makeRelationIterator = (path) => {
1232
- const paths = path.split('.');
1233
- const makeIter = (e, idx) => {
1234
- const attr = paths[idx];
1235
- const rel = (0, relation_1.judgeRelation)(context.getSchema(), e, attr);
1236
- if (idx === paths.length - 1) {
1237
- if (rel === 2) {
1238
- (0, assert_1.default)(attr === 'user');
1239
- return {
1240
- projection: {
1241
- id: 1,
1242
- entity: 1,
1243
- entityId: 1,
1244
- },
1245
- getData: (d) => {
1246
- if (d) {
1247
- return {
1248
- entity: e,
1249
- entityId: d.id,
1250
- userId: d.entityId,
1251
- };
1252
- }
1253
- },
1254
- };
1255
- }
1256
- else {
1257
- (0, assert_1.default)(rel === 'user');
1258
- return {
1259
- projection: {
1260
- id: 1,
1261
- [`${attr}Id`]: 1,
1262
- },
1263
- getData: (d) => {
1264
- if (d) {
1265
- return {
1266
- entity: e,
1267
- entityId: d.id,
1268
- userId: d[`${attr}Id`]
1269
- };
1270
- }
1271
- },
1272
- };
1273
- }
1274
- }
1275
- if (rel === 2) {
1276
- const { projection, getData } = makeIter(attr, idx + 1);
1277
- return {
1278
- projection: {
1279
- id: 1,
1280
- [attr]: projection,
1281
- },
1282
- getData: (d) => d[attr] && getData(d[attr]),
1283
- };
1284
- }
1285
- else if (typeof rel === 'string') {
1286
- const { projection, getData } = makeIter(rel, idx + 1);
1287
- return {
1288
- projection: {
1289
- id: 1,
1290
- [attr]: projection,
1291
- },
1292
- getData: (d) => d[attr] && getData(d[attr]),
1293
- };
1294
- }
1295
- else {
1296
- (0, assert_1.default)(rel instanceof Array);
1297
- const [e2, fk] = rel;
1298
- const { projection, getData } = makeIter(e2, idx + 1);
1299
- return {
1300
- projection: {
1301
- id: 1,
1302
- [attr]: {
1303
- $entity: e2,
1304
- data: projection,
1305
- },
1306
- },
1307
- getData: (d) => d[attr] && d[attr].map((ele) => getData(ele)),
1308
- };
1309
- }
1310
- };
1311
- return makeIter(entity, 0);
1312
- };
1313
- const userEntities = await Promise.all(directAuths.map(async ({ path }) => {
1314
- const { value, recursive } = path;
1315
- (0, assert_1.default)(!recursive);
1316
- const { getData, projection } = makeRelationIterator(value);
1317
- const rows = await context.select(entity, {
1318
- data: projection,
1319
- filter,
1320
- }, { dontCollect: true });
1321
- const userEntities = rows.map(ele => getData(ele)).flat().filter(ele => !!ele);
1322
- return userEntities;
1323
- }));
1324
- return userEntities.flat();
1325
- };
1326
- const urAuths2 = actionAuths.filter(ele => !!ele.relationId // 有relation说明通过userRelation关联
1327
- );
1328
- const directAuths2 = actionAuths.filter(ele => !ele.relationId // 没relation说明通过user关联
1329
- );
1330
- const [userRelations, userEntities] = await Promise.all([getUserRelations(urAuths2), getDirectUserEntities(directAuths2)]);
1331
- return {
1332
- userRelations,
1333
- userEntities,
1334
- };
1335
- }
1336
- exports.getUserRelationsByActions = getUserRelationsByActions;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getUserRelationsByActions = exports.RelationAuth = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert_1 = tslib_1.__importDefault(require("assert"));
6
+ const types_1 = require("../types");
7
+ const AsyncRowStore_1 = require("./AsyncRowStore");
8
+ const filter_1 = require("./filter");
9
+ const relation_1 = require("./relation");
10
+ const action_1 = require("../actions/action");
11
+ const lodash_1 = require("../utils/lodash");
12
+ const entities_1 = require("../compiler/entities");
13
+ class RelationAuth {
14
+ authDeduceRelationMap;
15
+ schema;
16
+ static SPECIAL_ENTITIES = entities_1.SYSTEM_RESERVE_ENTITIES;
17
+ selectFreeEntities;
18
+ updateFreeDict;
19
+ constructor(schema, authDeduceRelationMap, selectFreeEntities, updateFreeDict) {
20
+ this.schema = schema;
21
+ this.selectFreeEntities = selectFreeEntities || [];
22
+ this.updateFreeDict = updateFreeDict || {};
23
+ this.authDeduceRelationMap = Object.assign({}, authDeduceRelationMap, {
24
+ modi: 'entity',
25
+ });
26
+ }
27
+ // 前台检查filter是否满足relation约束
28
+ checkRelationSync(entity, operation, context) {
29
+ if (context.isRoot()) {
30
+ return;
31
+ }
32
+ this.checkActions2(entity, operation, context);
33
+ }
34
+ // 后台检查filter是否满足relation约束
35
+ async checkRelationAsync(entity, operation, context) {
36
+ if (context.isRoot()) {
37
+ return;
38
+ }
39
+ await this.checkActions2(entity, operation, context);
40
+ }
41
+ checkUserRelation(context, action, filter) {
42
+ const userId = context.getCurrentUserId();
43
+ let filter2 = {
44
+ destRelation: {
45
+ userRelation$relation: filter,
46
+ },
47
+ };
48
+ if (action === 'create') {
49
+ const { entity, entityId, relationId } = filter;
50
+ if (relationId) {
51
+ // 如果指定relation,则测试该relation上是否可行
52
+ filter2 = {
53
+ destRelationId: relationId,
54
+ };
55
+ }
56
+ else {
57
+ // 否则为测试“能否”有权限管理的资格,此时只要有一个就可以
58
+ (0, assert_1.default)(entity);
59
+ filter2 = {
60
+ destRelation: {
61
+ entity,
62
+ }
63
+ };
64
+ }
65
+ }
66
+ else {
67
+ (0, assert_1.default)(action === 'remove');
68
+ // 如果一次删除多个userRelation,接下来的流程判断是只有一个relationAuth满足就会通过,这样可能会有错判 by Xc 20231019
69
+ (0, assert_1.default)(typeof filter.id === 'string', '当前只支持指定id的用户关系删除');
70
+ }
71
+ const relationAuths = context.select('relationAuth', {
72
+ data: {
73
+ id: 1,
74
+ path: {
75
+ id: 1,
76
+ sourceEntity: 1,
77
+ destEntity: 1,
78
+ value: 1,
79
+ recursive: 1,
80
+ },
81
+ sourceRelationId: 1,
82
+ sourceRelation: {
83
+ id: 1,
84
+ entity: 1,
85
+ entityId: 1,
86
+ },
87
+ destRelationId: 1,
88
+ destRelation: {
89
+ id: 1,
90
+ entity: 1,
91
+ entityId: 1,
92
+ },
93
+ },
94
+ filter: filter2,
95
+ }, { dontCollect: true });
96
+ const checkRelationAuth = (relationAuth) => {
97
+ const { destRelation, sourceRelationId, path } = relationAuth;
98
+ let destEntityFilter = this.makePathFilter(destRelation.entity, path, this.schema, {
99
+ userRelation$entity: {
100
+ userId,
101
+ relationId: sourceRelationId,
102
+ },
103
+ });
104
+ if (action === 'create') {
105
+ const { entity, entityId } = filter;
106
+ (0, assert_1.default)(entity && typeof entity === 'string');
107
+ if (entityId) {
108
+ Object.assign(destEntityFilter, {
109
+ id: entityId,
110
+ });
111
+ }
112
+ else {
113
+ // userEntityGrant会有这种情况,限定某个对象的范围进行授权
114
+ const { [entity]: entityFilter } = filter;
115
+ (0, assert_1.default)(entityFilter);
116
+ destEntityFilter = (0, filter_1.combineFilters)(entity, this.schema, [destEntityFilter, entityFilter]);
117
+ }
118
+ }
119
+ else {
120
+ destEntityFilter = (0, filter_1.combineFilters)(destRelation.entity, this.schema, [destEntityFilter, {
121
+ userRelation$entity: filter,
122
+ }]);
123
+ }
124
+ return context.count(destRelation.entity, {
125
+ filter: destEntityFilter,
126
+ }, { ignoreAttrMiss: true });
127
+ };
128
+ if (relationAuths instanceof Promise) {
129
+ return relationAuths.then((ras) => Promise.all(ras.map(ra => checkRelationAuth(ra)))).then((result) => !!result.find(ele => {
130
+ (0, assert_1.default)(typeof ele === 'number');
131
+ return ele > 0;
132
+ }));
133
+ }
134
+ const result = relationAuths.map(ra => checkRelationAuth(ra));
135
+ return !!result.find(ele => ele > 0);
136
+ }
137
+ checkOperateSpecialEntities2(entity2, action, filter, context) {
138
+ switch (entity2) {
139
+ case 'userRelation': {
140
+ (0, assert_1.default)(!(filter instanceof Array));
141
+ return this.checkUserRelation(context, action, filter);
142
+ }
143
+ case 'user': {
144
+ // 对用户的操作由应用自己去管理权限,这里只检查grant/revoke
145
+ if (['grant', 'revoke'].includes(action)) {
146
+ // assert(filter && Object.keys(filter).length === 1, 'grant/revoke只能操作userRelation$user');
147
+ // assert(filter!.hasOwnProperty('userRelation$user'), 'grant/revoke只能操作userRelation$user');
148
+ return true;
149
+ }
150
+ else {
151
+ // 应用允许用户操作其它用户的逻辑请通过编写类型为relation的checker去控制,在这里不能加以限制
152
+ return true;
153
+ }
154
+ }
155
+ case 'modi': {
156
+ /** 正常情况下对modi的生成是在触发器下openRootMode,不会走到这里
157
+ * 但是有些例外,如extraFile如果在modi中创建,上传成功之后需要显式生成一条modi,这时对modi的
158
+ * 检查可以转化为对其父entity的update权限检查
159
+ */
160
+ (0, assert_1.default)(action === 'create');
161
+ const { entity, entityId } = filter;
162
+ return this.checkOperation(entity, {
163
+ action: 'update',
164
+ data: {},
165
+ filter: {
166
+ id: entityId,
167
+ },
168
+ }, context);
169
+ }
170
+ case 'relation': {
171
+ // 创建relation目前不支持,以后再说
172
+ return false;
173
+ }
174
+ case 'userEntityGrant': {
175
+ // userEntityGrant的创建相当于授权,领取相当于赋权
176
+ if (['create', 'update', 'remove'].includes(action)) {
177
+ if (action === 'create') {
178
+ const { relationEntity, relationEntityFilter, relationIds } = filter;
179
+ return this.checkOperateSpecialEntities2('userRelation', 'create', {
180
+ entity: relationEntity,
181
+ [relationEntity]: relationEntityFilter,
182
+ relationId: {
183
+ $in: relationIds,
184
+ },
185
+ }, context);
186
+ }
187
+ return this.checkOperateSpecialEntities2('userRelation', 'action', {
188
+ relation: {
189
+ userEntityGrant$relation: filter,
190
+ },
191
+ }, context);
192
+ }
193
+ return true;
194
+ }
195
+ default: {
196
+ (0, assert_1.default)(false, `对象${entity2}的权限控制没有加以控制`);
197
+ }
198
+ }
199
+ }
200
+ getDeducedEntityFilters(entity, filter, actions, context) {
201
+ const entityFilters = [
202
+ {
203
+ entity,
204
+ filter,
205
+ actions,
206
+ }
207
+ ];
208
+ if (this.authDeduceRelationMap[entity]) {
209
+ (0, assert_1.default)(this.authDeduceRelationMap[entity] === 'entity');
210
+ let { entity: deduceEntity, entityId: deduceEntityId } = filter;
211
+ let deduceFilter = {};
212
+ if (deduceEntity && deduceEntityId) {
213
+ deduceFilter = { id: deduceEntityId };
214
+ }
215
+ else {
216
+ // 也可能是用cascade方式进行查找,这里有时候filter上会带有两个不同的entity目标,尚未处理(todo!)
217
+ const { ref } = this.schema[entity].attributes.entity;
218
+ (0, assert_1.default)(ref instanceof Array);
219
+ for (const refEntity of ref) {
220
+ if (filter[refEntity]) {
221
+ deduceEntity = refEntity;
222
+ deduceFilter = filter[refEntity];
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ const getRecursiveDeducedFilters = (deduceEntity, deduceFilter) => {
228
+ const excludeActions = action_1.readOnlyActions.concat([ /* 'create', 'remove' */]);
229
+ const updateActions = this.schema[deduceEntity].actions.filter((a) => !excludeActions.includes(a));
230
+ /* if (!RelationAuth.SPECIAL_ENTITIES.includes(deduceEntity as string)) {
231
+ return this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions, context);
232
+ }
233
+ return []; */
234
+ return this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions, context);
235
+ };
236
+ if (deduceEntity && deduceFilter) {
237
+ const deducedSelections = getRecursiveDeducedFilters(deduceEntity, deduceFilter);
238
+ if (deducedSelections instanceof Promise) {
239
+ return deducedSelections.then((ds) => {
240
+ entityFilters.push(...ds);
241
+ return entityFilters;
242
+ });
243
+ }
244
+ entityFilters.push(...deducedSelections);
245
+ return entityFilters;
246
+ }
247
+ else {
248
+ /**
249
+ * 这种情况说明从filter中无法确定相应的deduceFilter,需要查找该实体对应的entity/entityId来进行推导。
250
+ * 这种情况一般发生在entity1 -> entity2上,此时entity2应该是一个固定id查询的filter
251
+ * 在这里先假设如果碰到了list类型的filter,直接不使用deduce路径上的对象来推导
252
+ */
253
+ const rows2 = context.select(entity, {
254
+ data: {
255
+ id: 1,
256
+ entity: 1,
257
+ entityId: 1,
258
+ },
259
+ filter,
260
+ indexFrom: 0,
261
+ count: 10,
262
+ }, { dontCollect: true, blockTrigger: true });
263
+ const dealWithData = (rows) => {
264
+ // 这里如果entity指向不同的实体,一般出现这样的查询,则其权限应当不由这条deduce路径处理
265
+ // 同上,如果找到的行数大于1行,说明deduce路径上的对象不确定,也暂不处理 by Xc 20230725
266
+ if (rows.length > 1 || rows.length === 0) {
267
+ if (process.env.NODE_ENV === 'development') {
268
+ console.warn(`进行deduce推导时找到了${rows.length}行${entity}数据`);
269
+ }
270
+ return entityFilters;
271
+ }
272
+ const { entity: deducedEntity, entityId: deducedEntityId } = rows[0];
273
+ if (!deducedEntity || !deducedEntityId) {
274
+ // 这种情况会出现在前台缓存里
275
+ return entityFilters;
276
+ }
277
+ const result = getRecursiveDeducedFilters(deducedEntity, {
278
+ id: deducedEntityId,
279
+ });
280
+ if (result instanceof Promise) {
281
+ return result.then((r2) => {
282
+ entityFilters.push(...r2);
283
+ return entityFilters;
284
+ });
285
+ }
286
+ entityFilters.push(...result);
287
+ return entityFilters;
288
+ };
289
+ if (rows2 instanceof Promise) {
290
+ return rows2.then((r2) => dealWithData(r2));
291
+ }
292
+ return dealWithData(rows2);
293
+ }
294
+ }
295
+ return entityFilters;
296
+ }
297
+ /**
298
+ * 对于selection,解构出最底层的对象,如果最底层的对象可以被访问,则父对象一定可以
299
+ * 但对于deduce的子对象,不必再向底层查看(假设deduce对象一般都位于树的最底层附近)
300
+ * @param entity
301
+ * @param operation
302
+ */
303
+ destructSelection(entity, selection) {
304
+ const leafSelections = [];
305
+ const destructInner = (entity2, selection2) => {
306
+ const { data, filter } = selection2;
307
+ let hasOneToMany = false;
308
+ for (const attr in data) {
309
+ const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
310
+ if (rel instanceof Array) {
311
+ const [e, foreignKey] = rel;
312
+ if (foreignKey) {
313
+ (0, assert_1.default)(!this.authDeduceRelationMap[e]);
314
+ hasOneToMany = true;
315
+ destructInner(e, {
316
+ data: data[attr].data,
317
+ filter: (0, filter_1.combineFilters)(e, this.schema, [{
318
+ [foreignKey.slice(0, foreignKey.length - 2)]: filter,
319
+ }, data[attr].filter || {}]),
320
+ });
321
+ }
322
+ else {
323
+ if (!this.authDeduceRelationMap[e]) {
324
+ hasOneToMany = true;
325
+ destructInner(e, {
326
+ data: data[attr].data,
327
+ filter: (0, filter_1.combineFilters)(e, this.schema, [{
328
+ [entity2]: filter,
329
+ }, data[attr].filter || {}]),
330
+ });
331
+ }
332
+ else {
333
+ (0, assert_1.default)(this.authDeduceRelationMap[e] === 'entity');
334
+ }
335
+ }
336
+ }
337
+ }
338
+ if (!hasOneToMany) {
339
+ leafSelections.push({
340
+ entity: entity2,
341
+ filter,
342
+ });
343
+ }
344
+ };
345
+ destructInner(entity, (0, lodash_1.cloneDeep)(selection));
346
+ return leafSelections;
347
+ }
348
+ /**
349
+ * 对于operation,解构出一个树形结构,以方便自顶向下的进行访问
350
+ * 但对于deduce的子对象,不必再向底层查看
351
+ * @param entity
352
+ * @param selection
353
+ */
354
+ destructOperation(entity2, operation2, userId) {
355
+ /**
356
+ * 对create动作,把data中的cascade部分剔除后作为filter参与后续的检验
357
+ * @param operation
358
+ * @returns
359
+ */
360
+ const makeCreateFilter = (entity, operation) => {
361
+ const { data, filter } = operation;
362
+ (0, assert_1.default)(!(data instanceof Array));
363
+ if (data) {
364
+ const data2 = {};
365
+ for (const attr in data) {
366
+ const rel = (0, relation_1.judgeRelation)(this.schema, entity, attr);
367
+ if (rel === 1) {
368
+ // 只需要记住id和各种外键属性,不这样处理有些古怪的属性比如coordinate,其作为createdata和作为filter并不同构
369
+ /* if ((['id', 'entity', 'entityId'].includes(attr) || this.schema[entity].attributes[attr as any]?.type === 'ref') && typeof data[attr] === 'string') {
370
+ data2[attr] = data[attr];
371
+ } */
372
+ // 假设不再成立,userEntityGrant需要relationEntity这样的属性
373
+ if (!['geometry', 'geography', 'st_geometry', 'st_point'].includes(this.schema[entity].attributes[attr]?.type)) {
374
+ data2[attr] = data[attr];
375
+ }
376
+ }
377
+ }
378
+ return data2;
379
+ }
380
+ return filter;
381
+ };
382
+ const addChild = (node, path, child) => {
383
+ // 在这里要把可以被node deduce出来的child处理掉
384
+ const paths = path.split('$');
385
+ (0, assert_1.default)(paths.length >= 2);
386
+ if (this.authDeduceRelationMap[child.entity] === paths[1]) {
387
+ (0, assert_1.default)(paths[1] === 'entity', '当前只支持entity外键上的deduce');
388
+ return false;
389
+ }
390
+ if (node.children[path]) {
391
+ if (node.children[path] instanceof Array) {
392
+ node.children[path].push(child);
393
+ }
394
+ else {
395
+ node.children[path] = [node.children[path], child];
396
+ }
397
+ }
398
+ else {
399
+ Object.assign(node.children, {
400
+ [path]: child,
401
+ });
402
+ }
403
+ return true;
404
+ };
405
+ const destructInner = (entity, operation,
406
+ // extraFilter?: ED[T2]['Selection']['filter'],
407
+ path, child, hasParent, extraFilter) => {
408
+ const { action, data, filter } = operation;
409
+ const filter2 = action === 'create' ? makeCreateFilter(entity, operation) : (0, lodash_1.cloneDeep)(filter);
410
+ (0, assert_1.default)(filter2);
411
+ if (extraFilter) {
412
+ Object.assign(filter2, extraFilter);
413
+ }
414
+ // const filter3 = extraFilter ? combineFilters(entity, schema, [filter2, extraFilter]) : filter2;
415
+ const me = {
416
+ entity: entity,
417
+ filter: filter2,
418
+ children: {},
419
+ action,
420
+ };
421
+ let root = me;
422
+ // 如果当前对象是一个toModi的,意味着它的cascadeUpdate会全部被变为modi去缓存,因此不需要再向下检查了
423
+ // modi被apply时,这些modi产生的更新才会被实际检查
424
+ // 这里可能有问题,再思考思考 by Xc 20231111
425
+ const isModiUpdate = this.schema[entity].toModi && action !== 'remove';
426
+ if (child) {
427
+ (0, assert_1.default)(path);
428
+ addChild(me, path, child);
429
+ }
430
+ (0, assert_1.default)(!(data instanceof Array));
431
+ for (const attr in data) {
432
+ const rel = (0, relation_1.judgeRelation)(this.schema, entity, attr);
433
+ if (rel === 2 && !isModiUpdate) {
434
+ (0, assert_1.default)(root === me && !hasParent, 'cascadeUpdate必须是树结构,避免森林');
435
+ const mtoOperation = data[attr];
436
+ root = destructInner(attr, mtoOperation, `${entity}$entity`, me);
437
+ }
438
+ else if (typeof rel === 'string' && !isModiUpdate) {
439
+ (0, assert_1.default)(root === me && !hasParent, 'cascadeUpdate必须是树结构,避免森林');
440
+ root = destructInner(rel, data[attr], `${entity}$${attr}`, me);
441
+ }
442
+ else if (rel instanceof Array && !isModiUpdate) {
443
+ const [e, f] = rel;
444
+ const otmOperations = data[attr];
445
+ /**
446
+ * 这里目前在cascadeUpdate的过程中,只有当一对多个userRelation的操作需要将entity和entityId复制到子对象上
447
+ * 因为对userRelation的判断是走的特殊路径,无法利用父对象的actionAuth
448
+ * 其它对象情况不需要复制,因为应用中必须要能保证(前台传来的)父对象的filter不依赖于子对象的条件
449
+ */
450
+ let extraFilter = undefined;
451
+ if (e === 'userRelation' && entity !== 'user') {
452
+ me.userRelations = [];
453
+ extraFilter = {
454
+ entity,
455
+ entityId: filter2.id,
456
+ };
457
+ const dealWithUserRelation = (userRelation) => {
458
+ const { action, data } = userRelation;
459
+ if (action === 'create') {
460
+ const attrs = Object.keys(data);
461
+ (0, assert_1.default)((0, lodash_1.difference)(attrs, Object.keys(this.schema.userRelation.attributes).concat('id')).length === 0);
462
+ if (data.userId === userId) {
463
+ me.userRelations?.push(data);
464
+ }
465
+ (0, assert_1.default)(filter2.id);
466
+ }
467
+ };
468
+ if (otmOperations instanceof Array) {
469
+ otmOperations.forEach((otmOperation) => dealWithUserRelation(otmOperation));
470
+ }
471
+ else {
472
+ dealWithUserRelation(otmOperations);
473
+ }
474
+ }
475
+ if (otmOperations instanceof Array) {
476
+ otmOperations.forEach((otmOperation) => {
477
+ const son = destructInner(e, otmOperation, undefined, undefined, true, extraFilter);
478
+ addChild(me, attr, son);
479
+ });
480
+ }
481
+ else {
482
+ const son = destructInner(e, otmOperations, undefined, undefined, true, extraFilter);
483
+ addChild(me, attr, son);
484
+ }
485
+ }
486
+ }
487
+ return root;
488
+ };
489
+ return destructInner(entity2, operation2);
490
+ }
491
+ makePathFilter(entity, path, schema, filter) {
492
+ const { value, recursive } = path;
493
+ if (value === '') {
494
+ (0, assert_1.default)(!recursive);
495
+ return filter;
496
+ }
497
+ const paths = value.split('.');
498
+ const makeRecursiveFilter = (recursiveDepth) => {
499
+ if (recursiveDepth > 0) {
500
+ return {
501
+ $or: [
502
+ filter,
503
+ {
504
+ parent: makeRecursiveFilter(recursiveDepth - 1)
505
+ }
506
+ ]
507
+ };
508
+ }
509
+ return filter;
510
+ };
511
+ const makeInner = (idx, e2) => {
512
+ const attr = paths[idx];
513
+ if (idx === paths.length) {
514
+ if (!recursive) {
515
+ return filter;
516
+ }
517
+ else {
518
+ // 在最后一个对象上存在递归,用or连接处理
519
+ const { recursiveDepth } = schema[e2];
520
+ (0, assert_1.default)(recursiveDepth > 0);
521
+ return makeRecursiveFilter(recursiveDepth);
522
+ }
523
+ }
524
+ else {
525
+ const rel = (0, relation_1.judgeRelation)(schema, e2, attr);
526
+ let e3;
527
+ if (rel === 2) {
528
+ e3 = attr;
529
+ }
530
+ else if (typeof rel === 'string') {
531
+ e3 = rel;
532
+ }
533
+ else {
534
+ (0, assert_1.default)(rel instanceof Array);
535
+ e3 = rel[0];
536
+ }
537
+ const f = makeInner(idx + 1, e3);
538
+ return {
539
+ [attr]: f,
540
+ };
541
+ }
542
+ };
543
+ return makeInner(0, entity);
544
+ }
545
+ /**
546
+ * 对所有满足操作要求的actionAuth加以判断,找到可以满足当前用户身份的actionAuth
547
+ * @param entity
548
+ * @param filter
549
+ * @param actionAuths
550
+ * @param context
551
+ * @return
552
+ */
553
+ filterActionAuths(entity, filter, actionAuths, context) {
554
+ const result = actionAuths.map((ele) => {
555
+ const { path, relation, relationId } = ele;
556
+ // 在cache中,可能出现relation外键指向的对象为null的情况,要容错
557
+ if (relationId) {
558
+ if (relation) {
559
+ const { userRelation$relation: userRelations } = relation;
560
+ if (userRelations.length > 0) {
561
+ const entityIds = (0, lodash_1.uniq)(userRelations.map(ele => ele.entityId));
562
+ const pathFilter = this.makePathFilter(entity, path, this.schema, {
563
+ id: entityIds.length > 0 ? {
564
+ $in: entityIds,
565
+ } : entityIds[0],
566
+ });
567
+ const contains = (0, filter_1.checkFilterContains)(entity, context, pathFilter, filter, true);
568
+ if (contains instanceof Promise) {
569
+ return contains.then((c) => {
570
+ if (c) {
571
+ return ele;
572
+ }
573
+ return;
574
+ });
575
+ }
576
+ if (contains) {
577
+ return ele;
578
+ }
579
+ return;
580
+ }
581
+ }
582
+ return;
583
+ }
584
+ // 说明是通过userId关联
585
+ const pathFilter = this.makePathFilter(entity, path, this.schema, {
586
+ id: context.getCurrentUserId(),
587
+ });
588
+ const contains = (0, filter_1.checkFilterContains)(entity, context, pathFilter, filter, true);
589
+ if (contains instanceof Promise) {
590
+ return contains.then((c) => {
591
+ if (c) {
592
+ return ele;
593
+ }
594
+ return;
595
+ });
596
+ }
597
+ if (contains) {
598
+ return ele;
599
+ }
600
+ });
601
+ if (result.find(ele => ele instanceof Promise)) {
602
+ return Promise.all(result).then((r2) => r2.filter(ele => !!ele));
603
+ }
604
+ return result.filter(ele => !!ele);
605
+ }
606
+ /**
607
+ * 对于有些特殊的查询(带很多$or的查询,多发生在系统级别),单个actionAuth无法满足,需要共同加以判定
608
+ * @param entity
609
+ * @param filter
610
+ * @param actionAuths
611
+ * @param context
612
+ * @param actions
613
+ */
614
+ checkActionAuthInGroup(entity, filter, actionAuths, context) {
615
+ const filters = actionAuths.filter(ele => ele.path.destEntity === entity).map((ele) => {
616
+ const { path, relation, relationId } = ele;
617
+ if (relationId) {
618
+ (0, assert_1.default)(relation);
619
+ const { userRelation$relation: userRelations } = relation;
620
+ (0, assert_1.default)(userRelations.length > 0);
621
+ const entityIds = (0, lodash_1.uniq)(userRelations.map(ele => ele.entityId));
622
+ const pathFilter = this.makePathFilter(entity, path, this.schema, {
623
+ id: entityIds.length > 0 ? {
624
+ $in: entityIds,
625
+ } : entityIds[0],
626
+ });
627
+ return pathFilter;
628
+ }
629
+ // 说明是通过userId关联
630
+ return this.makePathFilter(entity, path, this.schema, {
631
+ id: context.getCurrentUserId(),
632
+ });
633
+ });
634
+ const groupFilter = (0, filter_1.combineFilters)(entity, this.schema, filters, true);
635
+ if (groupFilter) {
636
+ return (0, filter_1.checkFilterContains)(entity, context, groupFilter, filter, true);
637
+ }
638
+ return false;
639
+ }
640
+ checkSelection(entity, selection, context) {
641
+ const leafSelections = this.destructSelection(entity, selection);
642
+ const deducedLeafSelections = leafSelections.map(({ entity, filter }) => this.getDeducedEntityFilters(entity, filter, ['select'], context));
643
+ const checkDeducedLeafSelections = (dlSelections2) => {
644
+ const dlSelections = dlSelections2.filter((ele) => {
645
+ const entities = ele.map(ele2 => ele2.entity);
646
+ // 同一个leaf的deducedSelections中只要有一个能通过就足够了
647
+ if ((0, lodash_1.intersection)(this.selectFreeEntities, entities).length > 0) {
648
+ return false;
649
+ }
650
+ if ((0, lodash_1.intersection)(RelationAuth.SPECIAL_ENTITIES, entities).length > 0) {
651
+ // todo
652
+ return false;
653
+ }
654
+ return true;
655
+ });
656
+ if (dlSelections.length === 0) {
657
+ return true;
658
+ }
659
+ if (!context.getCurrentUserId()) {
660
+ throw new types_1.OakUnloggedInException();
661
+ }
662
+ const allEntities = [];
663
+ dlSelections.forEach((ele) => ele.forEach(({ entity }) => {
664
+ allEntities.push(entity);
665
+ }));
666
+ const actionAuths = context.select('actionAuth', {
667
+ data: {
668
+ id: 1,
669
+ path: {
670
+ id: 1,
671
+ value: 1,
672
+ sourceEntity: 1,
673
+ destEntity: 1,
674
+ recursive: 1,
675
+ },
676
+ deActions: 1,
677
+ relation: {
678
+ id: 1,
679
+ userRelation$relation: {
680
+ $entity: 'userRelation',
681
+ data: {
682
+ id: 1,
683
+ entity: 1,
684
+ entityId: 1,
685
+ },
686
+ filter: {
687
+ userId: context.getCurrentUserId(),
688
+ },
689
+ },
690
+ },
691
+ },
692
+ filter: {
693
+ deActions: {
694
+ $contains: 'select',
695
+ },
696
+ path: {
697
+ destEntity: {
698
+ $in: allEntities,
699
+ },
700
+ },
701
+ $or: [
702
+ {
703
+ relation: {
704
+ userRelation$relation: {
705
+ userId: context.getCurrentUserId(),
706
+ },
707
+ }
708
+ },
709
+ {
710
+ relationId: {
711
+ $exists: false,
712
+ },
713
+ }
714
+ ]
715
+ }
716
+ }, { dontCollect: true, ignoreAttrMiss: true });
717
+ /**
718
+ * 返回的结果中,第一层为leafNode,必须全通过,第二层为单个leafNode上的deduce,通过一个就可以
719
+ * @param result
720
+ * @returns
721
+ */
722
+ const checkResult = (result) => {
723
+ let idx = 0;
724
+ for (const r1 of result) {
725
+ const r2 = r1.find(ele => ele === true);
726
+ if (!r2) {
727
+ if (process.env.NODE_ENV === 'development') {
728
+ console.warn('对象的select权限被否决,请检查', dlSelections[idx]);
729
+ }
730
+ idx++;
731
+ return false;
732
+ }
733
+ idx++;
734
+ }
735
+ return true;
736
+ };
737
+ if (actionAuths instanceof Promise) {
738
+ (0, assert_1.default)(context instanceof AsyncRowStore_1.AsyncContext);
739
+ return actionAuths.then((aas) => Promise.all(dlSelections.map((ele) => Promise.all(ele.map((ele2) => this.checkActionAuthInGroup(ele2.entity, ele2.filter, aas, context))))).then((result) => checkResult(result)));
740
+ }
741
+ return checkResult(dlSelections.map(ele => ele.map(ele2 => this.checkActionAuthInGroup(ele2.entity, ele2.filter, actionAuths, context))));
742
+ };
743
+ if (deducedLeafSelections[0] instanceof Promise) {
744
+ return Promise.all(deducedLeafSelections)
745
+ .then((dls) => checkDeducedLeafSelections(dls));
746
+ }
747
+ return checkDeducedLeafSelections(deducedLeafSelections);
748
+ }
749
+ /**
750
+ * 此函数判定一个结点是否能通过权限检测,同时寻找该结点本身对象上成立的actionAuth,用于本结点子孙结点的快速检测
751
+ * 如果结点因其deduce的对象通过了检测,其被推断对象的actionAuth无法用于更低对象的权限检测
752
+ * @param node
753
+ * @param context
754
+ * @returns
755
+ */
756
+ findActionAuthsOnNode(node, context) {
757
+ const { entity, filter, action, userRelations } = node;
758
+ const deducedEntityFilters2 = this.getDeducedEntityFilters(entity, filter, [action], context);
759
+ /**
760
+ * 搜索判定是否允许自建对象,自建的条件是 path = '',destEntity === entity
761
+ * @param actionAuths
762
+ * @returns
763
+ */
764
+ const findOwnCreateUserRelation = (actionAuths) => {
765
+ if (userRelations && userRelations.length > 0) {
766
+ const ars = actionAuths.filter((ar) => !!userRelations.find((ur) => ur.relationId === ar.relationId) && ar.path.value === '' && ar.path.destEntity === entity);
767
+ if (ars.length > 0) {
768
+ return ars;
769
+ }
770
+ }
771
+ };
772
+ const actionAuthOnEntities = [];
773
+ const dealWithDeducedEntityFilters = (deducedEntityFilters) => {
774
+ const specialEntities = deducedEntityFilters.filter(ele => RelationAuth.SPECIAL_ENTITIES.includes(ele.entity));
775
+ const unspecicalEntities = deducedEntityFilters.filter(ele => !RelationAuth.SPECIAL_ENTITIES.includes(ele.entity));
776
+ const result = [];
777
+ if (specialEntities.length > 0) {
778
+ // 对于deduce出来的special对象,直接判定create应该问题不大,否则写起来太烦琐(具体情况遇到了再调试)
779
+ result.push(...specialEntities.map(ele => this.checkOperateSpecialEntities2(ele.entity, ele.entity === entity ? node.action : 'create', ele.filter, context)));
780
+ }
781
+ if (unspecicalEntities.length > 0) {
782
+ const allEntities = unspecicalEntities.map(ele => ele.entity);
783
+ const allActions = (0, lodash_1.uniq)(unspecicalEntities.map(ele => ele.actions).flat());
784
+ const actionAuths2 = context.select('actionAuth', {
785
+ data: {
786
+ id: 1,
787
+ path: {
788
+ id: 1,
789
+ destEntity: 1,
790
+ sourceEntity: 1,
791
+ value: 1,
792
+ recursive: 1,
793
+ },
794
+ deActions: 1,
795
+ relation: {
796
+ id: 1,
797
+ userRelation$relation: {
798
+ $entity: 'userRelation',
799
+ data: {
800
+ id: 1,
801
+ entity: 1,
802
+ entityId: 1,
803
+ },
804
+ filter: {
805
+ userId: context.getCurrentUserId(),
806
+ },
807
+ },
808
+ },
809
+ },
810
+ filter: {
811
+ path: {
812
+ destEntity: {
813
+ $in: allEntities,
814
+ }
815
+ },
816
+ deActions: {
817
+ $overlaps: allActions,
818
+ },
819
+ }
820
+ }, { dontCollect: true, ignoreAttrMiss: true });
821
+ const checkActionAuths = (actionAuths) => {
822
+ const created = findOwnCreateUserRelation(actionAuths);
823
+ if (created) {
824
+ actionAuthOnEntities.push(...created);
825
+ return true;
826
+ }
827
+ const result = deducedEntityFilters.map((ele) => {
828
+ const ars2 = actionAuths.filter(ele2 => ele2.path.destEntity === ele.entity && (0, lodash_1.intersection)(ele2.deActions, ele.actions).length > 0 // 这里只要overlap就可以了
829
+ );
830
+ const ars3 = this.filterActionAuths(ele.entity, ele.filter, ars2, context);
831
+ const checkFilteredArs = (actionAuths2) => {
832
+ if (actionAuths2.length > 0) {
833
+ if (ele.entity === entity) {
834
+ actionAuthOnEntities.push(...actionAuths2);
835
+ }
836
+ return true;
837
+ }
838
+ return false;
839
+ };
840
+ if (ars3 instanceof Promise) {
841
+ return ars3.then((ars4) => checkFilteredArs(ars4));
842
+ }
843
+ return checkFilteredArs(ars3);
844
+ });
845
+ if (result.find(ele => ele instanceof Promise)) {
846
+ return Promise.all(result).then((r2) => r2.includes(true));
847
+ }
848
+ return result.includes(true);
849
+ };
850
+ if (actionAuths2 instanceof Promise) {
851
+ result.push(actionAuths2.then((ars2) => checkActionAuths(ars2)));
852
+ }
853
+ else {
854
+ result.push(checkActionAuths(actionAuths2));
855
+ }
856
+ }
857
+ if (result.find(ele => ele instanceof Promise)) {
858
+ return Promise.all(result).then((r2) => {
859
+ // r2中只有一个通过就能通过
860
+ if (r2.includes(true)) {
861
+ return actionAuthOnEntities;
862
+ }
863
+ return false;
864
+ });
865
+ }
866
+ if (result.includes(true)) {
867
+ return actionAuthOnEntities;
868
+ }
869
+ return false;
870
+ };
871
+ if (deducedEntityFilters2 instanceof Promise) {
872
+ return deducedEntityFilters2.then((def2) => dealWithDeducedEntityFilters(def2));
873
+ }
874
+ return dealWithDeducedEntityFilters(deducedEntityFilters2);
875
+ }
876
+ checkOperationTree2(tree, context) {
877
+ const checkNode = (node, actionAuths) => {
878
+ const checkChildren = (legalPaths) => {
879
+ const { children } = node;
880
+ const childPath = Object.keys(children);
881
+ if (childPath.length === 0) {
882
+ return true;
883
+ }
884
+ const childResult = childPath.map((childPath) => {
885
+ const child = children[childPath];
886
+ const childEntity = child instanceof Array ? child[0].entity : child.entity;
887
+ // 这里如果该子结点能deduce到父,则直接通过
888
+ if (this.authDeduceRelationMap[childEntity]) {
889
+ (0, assert_1.default)(this.authDeduceRelationMap[childEntity] === 'entity');
890
+ const rel = (0, relation_1.judgeRelation)(this.schema, childEntity, childPath);
891
+ if (rel === 2) {
892
+ return true;
893
+ }
894
+ }
895
+ const pathToParent = childPath.endsWith('$entity') ? node.entity : childPath.split('$')[1];
896
+ if (child instanceof Array) {
897
+ const childActions = child.map(ele => ele.action);
898
+ const childLegalAuths = legalPaths.map((ele) => {
899
+ const { path: { value: pv }, relationId } = ele;
900
+ const pv2 = pv ? `${pathToParent}.${pv}` : pathToParent;
901
+ return context.select('actionAuth', {
902
+ data: {
903
+ id: 1,
904
+ },
905
+ filter: {
906
+ path: {
907
+ value: pv2,
908
+ destEntity: childEntity,
909
+ },
910
+ deActions: {
911
+ $overlaps: childActions,
912
+ },
913
+ relationId: relationId || {
914
+ $exists: false,
915
+ },
916
+ }
917
+ }, { dontCollect: true });
918
+ }).flat();
919
+ if (childLegalAuths[0] instanceof Promise) {
920
+ return Promise.all(childLegalAuths).then((clas) => child.map((c) => checkNode(c, clas)));
921
+ }
922
+ return child.map((c) => checkNode(c, childLegalAuths));
923
+ }
924
+ const childLegalAuths = legalPaths.map((ele) => {
925
+ const { path: { value: pv }, relationId } = ele;
926
+ const pv2 = pv ? `${pathToParent}.${pv}` : pathToParent;
927
+ return context.select('actionAuth', {
928
+ data: {
929
+ id: 1,
930
+ },
931
+ filter: {
932
+ path: {
933
+ value: pv2,
934
+ destEntity: childEntity,
935
+ },
936
+ deActions: {
937
+ $overlaps: child.action,
938
+ },
939
+ relationId: relationId || {
940
+ $exists: false,
941
+ },
942
+ }
943
+ }, { dontCollect: true });
944
+ }).flat();
945
+ if (childLegalAuths[0] instanceof Promise) {
946
+ return Promise.all(childLegalAuths).then((clas) => checkNode(child, clas.flat()));
947
+ }
948
+ return checkNode(child, childLegalAuths);
949
+ }).flat();
950
+ if (childResult[0] instanceof Promise) {
951
+ return Promise.all(childResult).then((r) => !r.includes(false));
952
+ }
953
+ return !childResult.includes(false);
954
+ };
955
+ // 先根据parent传下来的合法auths来搜寻,只需要查找actionAuth,降低开销
956
+ // 这里有可能父结点根据actionAuths能通过,但子结点需要重新搜索父结点上的新actionAuths才能通过吗?应该不存在这种情况。 by Xc 20230824
957
+ if (actionAuths && actionAuths.length > 0) {
958
+ return checkChildren(actionAuths);
959
+ }
960
+ // 没有能根据父亲传下来的actionAuth判定,只能自己找
961
+ const result = this.findActionAuthsOnNode(node, context);
962
+ const checkResult = (result2) => {
963
+ if (result2 === false) {
964
+ return false;
965
+ }
966
+ // 如果是对user对象操作通过,需要增添一条虚假的的actionAuth
967
+ if (node.entity === 'user') {
968
+ result2.push({
969
+ id: 'temp',
970
+ pathId: 'path_temp',
971
+ path: {
972
+ id: 'path_temp',
973
+ destEntity: 'user',
974
+ sourceEntity: 'any',
975
+ value: '',
976
+ $$createAt$$: 1,
977
+ $$updateAt$$: 1,
978
+ $$seq$$: 123,
979
+ recursive: false,
980
+ },
981
+ $$createAt$$: 1,
982
+ $$updateAt$$: 1,
983
+ $$seq$$: 123,
984
+ deActions: [node.action],
985
+ });
986
+ }
987
+ return checkChildren(result2);
988
+ };
989
+ if (result instanceof Promise) {
990
+ return result.then((r2) => checkResult(r2));
991
+ }
992
+ return checkResult(result);
993
+ };
994
+ return checkNode(tree);
995
+ }
996
+ checkOperation(entity, operation, context) {
997
+ const { action, filter, data } = operation;
998
+ if (this.updateFreeDict[entity] && this.updateFreeDict[entity].includes(action)) {
999
+ return true;
1000
+ }
1001
+ const userId = context.getCurrentUserId();
1002
+ if (!userId) {
1003
+ throw new types_1.OakUnloggedInException();
1004
+ }
1005
+ if (!filter && (!data || action !== 'create')) {
1006
+ if (process.env.NODE_ENV === 'development') {
1007
+ console.warn('operation不能没有限制条件', operation);
1008
+ }
1009
+ return false;
1010
+ }
1011
+ const updateTree = this.destructOperation(entity, operation, userId);
1012
+ return this.checkOperationTree2(updateTree, context);
1013
+ }
1014
+ /**
1015
+ * 检查一个operation是否能被通过权限测试
1016
+ * 一个cascadeOperation是一棵树形结构:
1017
+ * * 对于select,只要叶子通过其父结点必然通过;
1018
+ * * 对于update,自顶向下进行检查,若父亲被权限S通过,则只需要检查子对于S有没有相对路径上的actionAuth
1019
+ * 另外在update中,还需要考虑自建userRelation的case(例如在电子商务网站上购买商品,创建订单同时创建用户和订单的关系)
1020
+ * @param entity
1021
+ * @param operation
1022
+ * @param context
1023
+ * @param actions
1024
+ * @returns
1025
+ */
1026
+ checkActions2(entity, operation, context, actions) {
1027
+ const { action } = operation;
1028
+ if (!action || action_1.readOnlyActions.includes(action)) {
1029
+ const result = this.checkSelection(entity, operation, context);
1030
+ if (result instanceof Promise) {
1031
+ return result.then((r) => {
1032
+ if (!r) {
1033
+ throw new types_1.OakUserInvisibleException();
1034
+ }
1035
+ });
1036
+ }
1037
+ if (!result) {
1038
+ throw new types_1.OakUserInvisibleException();
1039
+ }
1040
+ }
1041
+ else {
1042
+ const result = this.checkOperation(entity, operation, context);
1043
+ if (result instanceof Promise) {
1044
+ return result.then((r) => {
1045
+ if (!r) {
1046
+ throw new types_1.OakUserUnpermittedException();
1047
+ }
1048
+ });
1049
+ }
1050
+ if (!result) {
1051
+ throw new types_1.OakUserUnpermittedException();
1052
+ }
1053
+ }
1054
+ }
1055
+ }
1056
+ exports.RelationAuth = RelationAuth;
1057
+ ;
1058
+ /**
1059
+ * 获取有对entity进行actions操作权限的userRelation关系
1060
+ * @param params
1061
+ * @param context
1062
+ * todo paths改成复数以后这里还未充分测试过
1063
+ */
1064
+ async function getUserRelationsByActions(params, context) {
1065
+ const { entity, filter, actions, overlap } = params;
1066
+ const actionAuthfilter = {
1067
+ path: {
1068
+ destEntity: entity,
1069
+ },
1070
+ };
1071
+ if (overlap) {
1072
+ Object.assign(actionAuthfilter, {
1073
+ deActions: {
1074
+ $overlaps: actions,
1075
+ },
1076
+ });
1077
+ }
1078
+ else {
1079
+ Object.assign(actionAuthfilter, {
1080
+ deActions: {
1081
+ $contains: actions,
1082
+ },
1083
+ });
1084
+ }
1085
+ const actionAuths = await context.select('actionAuth', {
1086
+ data: {
1087
+ id: 1,
1088
+ path: {
1089
+ id: 1,
1090
+ value: 1,
1091
+ destEntity: 1,
1092
+ recursive: 1,
1093
+ },
1094
+ relationId: 1,
1095
+ relation: {
1096
+ id: 1,
1097
+ entity: 1,
1098
+ },
1099
+ },
1100
+ filter: actionAuthfilter,
1101
+ }, { dontCollect: true });
1102
+ const getUserRelations = async (urAuths) => {
1103
+ const makeRelationIterator = (path, relationIds, recursive) => {
1104
+ (0, assert_1.default)(!recursive, 'recursive的情况还没处理,等跑出来再说, by Xc');
1105
+ if (path === '') {
1106
+ return {
1107
+ projection: {
1108
+ id: 1,
1109
+ userRelation$entity: {
1110
+ $entity: 'userRelation',
1111
+ data: {
1112
+ id: 1,
1113
+ relationId: 1,
1114
+ relation: {
1115
+ id: 1,
1116
+ name: 1,
1117
+ },
1118
+ entity: 1,
1119
+ entityId: 1,
1120
+ userId: 1,
1121
+ },
1122
+ filter: {
1123
+ relationId: {
1124
+ $in: relationIds,
1125
+ },
1126
+ },
1127
+ },
1128
+ },
1129
+ getData: (d) => {
1130
+ return d.userRelation$entity;
1131
+ },
1132
+ };
1133
+ }
1134
+ const paths = path.split('.');
1135
+ const makeIter = (e, idx) => {
1136
+ if (idx === paths.length) {
1137
+ return {
1138
+ projection: {
1139
+ id: 1,
1140
+ userRelation$entity: {
1141
+ $entity: 'userRelation',
1142
+ data: {
1143
+ id: 1,
1144
+ relationId: 1,
1145
+ relation: {
1146
+ id: 1,
1147
+ name: 1,
1148
+ },
1149
+ entity: 1,
1150
+ entityId: 1,
1151
+ userId: 1,
1152
+ },
1153
+ filter: {
1154
+ relationId: {
1155
+ $in: relationIds,
1156
+ },
1157
+ },
1158
+ }
1159
+ },
1160
+ getData: (d) => {
1161
+ return d.userRelation$entity;
1162
+ },
1163
+ };
1164
+ }
1165
+ const attr = paths[idx];
1166
+ const rel = (0, relation_1.judgeRelation)(context.getSchema(), e, attr);
1167
+ if (rel === 2) {
1168
+ const { projection, getData } = makeIter(attr, idx + 1);
1169
+ return {
1170
+ projection: {
1171
+ id: 1,
1172
+ [attr]: projection,
1173
+ },
1174
+ getData: (d) => d[attr] && getData(d[attr]),
1175
+ };
1176
+ }
1177
+ else if (typeof rel === 'string') {
1178
+ const { projection, getData } = makeIter(rel, idx + 1);
1179
+ return {
1180
+ projection: {
1181
+ id: 1,
1182
+ [attr]: projection,
1183
+ },
1184
+ getData: (d) => d[attr] && getData(d[attr]),
1185
+ };
1186
+ }
1187
+ else {
1188
+ (0, assert_1.default)(rel instanceof Array);
1189
+ const [e2, fk] = rel;
1190
+ const { projection, getData } = makeIter(e2, idx + 1);
1191
+ return {
1192
+ projection: {
1193
+ id: 1,
1194
+ [attr]: {
1195
+ $entity: e2,
1196
+ data: projection,
1197
+ },
1198
+ },
1199
+ getData: (d) => d[attr] && d[attr].map((ele) => getData(ele)),
1200
+ };
1201
+ }
1202
+ };
1203
+ return makeIter(entity, 0);
1204
+ };
1205
+ // 相同的path可以groupBy掉
1206
+ const urAuthDict2 = {};
1207
+ urAuths.forEach((auth) => {
1208
+ const { path, relationId } = auth;
1209
+ const { value, recursive } = path;
1210
+ if (!urAuthDict2[value]) {
1211
+ urAuthDict2[value] = [[relationId], recursive];
1212
+ }
1213
+ else if (!urAuthDict2[value][0].includes(relationId)) {
1214
+ (0, assert_1.default)(urAuthDict2[value][1] === recursive);
1215
+ urAuthDict2[value][0].push(relationId);
1216
+ }
1217
+ });
1218
+ const userRelations = await Promise.all(Object.keys(urAuthDict2).map(async (path) => {
1219
+ const [relationIds, recursive] = urAuthDict2[path];
1220
+ const { projection, getData } = makeRelationIterator(path, relationIds, recursive);
1221
+ const rows = await context.select(entity, {
1222
+ data: projection,
1223
+ filter,
1224
+ }, { dontCollect: true });
1225
+ const urs = rows.map(ele => getData(ele)).flat().filter(ele => !!ele);
1226
+ return urs;
1227
+ }));
1228
+ return userRelations.flat();
1229
+ };
1230
+ const getDirectUserEntities = async (directAuths) => {
1231
+ const makeRelationIterator = (path) => {
1232
+ const paths = path.split('.');
1233
+ const makeIter = (e, idx) => {
1234
+ const attr = paths[idx];
1235
+ const rel = (0, relation_1.judgeRelation)(context.getSchema(), e, attr);
1236
+ if (idx === paths.length - 1) {
1237
+ if (rel === 2) {
1238
+ (0, assert_1.default)(attr === 'user');
1239
+ return {
1240
+ projection: {
1241
+ id: 1,
1242
+ entity: 1,
1243
+ entityId: 1,
1244
+ },
1245
+ getData: (d) => {
1246
+ if (d) {
1247
+ return {
1248
+ entity: e,
1249
+ entityId: d.id,
1250
+ userId: d.entityId,
1251
+ };
1252
+ }
1253
+ },
1254
+ };
1255
+ }
1256
+ else {
1257
+ (0, assert_1.default)(rel === 'user');
1258
+ return {
1259
+ projection: {
1260
+ id: 1,
1261
+ [`${attr}Id`]: 1,
1262
+ },
1263
+ getData: (d) => {
1264
+ if (d) {
1265
+ return {
1266
+ entity: e,
1267
+ entityId: d.id,
1268
+ userId: d[`${attr}Id`]
1269
+ };
1270
+ }
1271
+ },
1272
+ };
1273
+ }
1274
+ }
1275
+ if (rel === 2) {
1276
+ const { projection, getData } = makeIter(attr, idx + 1);
1277
+ return {
1278
+ projection: {
1279
+ id: 1,
1280
+ [attr]: projection,
1281
+ },
1282
+ getData: (d) => d[attr] && getData(d[attr]),
1283
+ };
1284
+ }
1285
+ else if (typeof rel === 'string') {
1286
+ const { projection, getData } = makeIter(rel, idx + 1);
1287
+ return {
1288
+ projection: {
1289
+ id: 1,
1290
+ [attr]: projection,
1291
+ },
1292
+ getData: (d) => d[attr] && getData(d[attr]),
1293
+ };
1294
+ }
1295
+ else {
1296
+ (0, assert_1.default)(rel instanceof Array);
1297
+ const [e2, fk] = rel;
1298
+ const { projection, getData } = makeIter(e2, idx + 1);
1299
+ return {
1300
+ projection: {
1301
+ id: 1,
1302
+ [attr]: {
1303
+ $entity: e2,
1304
+ data: projection,
1305
+ },
1306
+ },
1307
+ getData: (d) => d[attr] && d[attr].map((ele) => getData(ele)),
1308
+ };
1309
+ }
1310
+ };
1311
+ return makeIter(entity, 0);
1312
+ };
1313
+ const userEntities = await Promise.all(directAuths.map(async ({ path }) => {
1314
+ const { value, recursive } = path;
1315
+ (0, assert_1.default)(!recursive);
1316
+ const { getData, projection } = makeRelationIterator(value);
1317
+ const rows = await context.select(entity, {
1318
+ data: projection,
1319
+ filter,
1320
+ }, { dontCollect: true });
1321
+ const userEntities = rows.map(ele => getData(ele)).flat().filter(ele => !!ele);
1322
+ return userEntities;
1323
+ }));
1324
+ return userEntities.flat();
1325
+ };
1326
+ const urAuths2 = actionAuths.filter(ele => !!ele.relationId // 有relation说明通过userRelation关联
1327
+ );
1328
+ const directAuths2 = actionAuths.filter(ele => !ele.relationId // 没relation说明通过user关联
1329
+ );
1330
+ const [userRelations, userEntities] = await Promise.all([getUserRelations(urAuths2), getDirectUserEntities(directAuths2)]);
1331
+ return {
1332
+ userRelations,
1333
+ userEntities,
1334
+ };
1335
+ }
1336
+ exports.getUserRelationsByActions = getUserRelationsByActions;