@@ -42,6 +42,10 @@ final class QueryService implements QueryServiceInterface
42
42
{
43
43
use LoggerAwareTrait;
44
44
45
+ private const ALLOWED_PATHS_KEY = 'allowedPaths ' ;
46
+
47
+ private const DECLINED_PATHS_KEY = 'declinedPaths ' ;
48
+
45
49
public function __construct (
46
50
private readonly PermissionServiceInterface $ permissionService ,
47
51
private readonly WorkspaceServiceInterface $ workspaceService ,
@@ -72,27 +76,16 @@ public function getWorkspaceQuery(string $workspaceType, ?User $user, string $pe
72
76
73
77
private function getWorkspaceGroupsQuery (string $ workspaceType , ?User $ user , string $ permission ): BoolQuery
74
78
{
75
- $ workspaceGroups = $ this ->getGroupedWorkspaces (
76
- $ workspaceType ,
77
- $ user
78
- );
79
+ $ group = $ this ->getGroupedWorkspaces ($ workspaceType , $ user );
79
80
80
- if (empty ($ workspaceGroups )) {
81
+ if (empty ($ group )) {
81
82
return $ this ->createNoWorkspaceAllowedQuery ();
82
83
}
83
84
84
- $ workspacesQuery = new BoolQuery ();
85
-
86
- foreach ($ workspaceGroups as $ group ) {
87
- $ workspacesQuery ->addCondition (
88
- ConditionType::SHOULD ->value ,
89
- [
90
- 'bool ' => $ this ->createWorkspacesGroupQuery ($ workspaceType , $ group , $ permission )->toArray (),
91
- ]
92
- );
93
- }
94
-
95
- return $ workspacesQuery ;
85
+ return $ this ->createWorkspacesGroupQuery (
86
+ $ workspaceType ,
87
+ $ this ->getCategorizedWorkspacePaths ($ group , $ permission )
88
+ );
96
89
}
97
90
98
91
private function getGroupedWorkspaces (string $ workspaceType , ?User $ user ): array
@@ -107,27 +100,26 @@ private function getGroupedWorkspaces(string $workspaceType, ?User $user): array
107
100
$ user
108
101
);
109
102
110
- if (!empty ($ userWorkspaces )) {
111
- $ groupedWorkspaces [] = $ userWorkspaces ;
103
+ /** @var WorkspaceInterface $userWorkspace */
104
+ foreach ($ userWorkspaces as $ userWorkspace ) {
105
+ $ groupedWorkspaces [$ userWorkspace ->getPath ()] = $ userWorkspace ;
112
106
}
113
107
114
108
foreach ($ user ->getRoles () as $ roleId ) {
115
- $ roleWorkspaces = $ this ->workspaceService ->getRoleWorkspaces (
116
- $ workspaceType ,
117
- $ roleId
118
- );
119
-
120
- if (!empty ($ roleWorkspaces )) {
121
- $ groupedWorkspaces [] = $ roleWorkspaces ;
109
+ $ roleWorkspaces = $ this ->workspaceService ->getRoleWorkspaces ($ workspaceType , $ roleId );
110
+ /** @var WorkspaceInterface $roleWorkspace */
111
+ foreach ($ roleWorkspaces as $ roleWorkspace ) {
112
+ if (!isset ($ groupedWorkspaces [$ roleWorkspace ->getPath ()])) {
113
+ $ groupedWorkspaces [$ roleWorkspace ->getPath ()] = $ roleWorkspace ;
114
+ }
122
115
}
123
116
}
124
117
125
118
return $ groupedWorkspaces ;
126
119
}
127
120
128
- private function createWorkspacesGroupQuery ( string $ workspaceType , array $ group , string $ permission ): BoolQuery
121
+ private function getCategorizedWorkspacePaths ( array $ group , string $ permission ): array
129
122
{
130
-
131
123
$ allowedPaths = [];
132
124
$ declinedPaths = [];
133
125
@@ -143,71 +135,39 @@ private function createWorkspacesGroupQuery(string $workspaceType, array $group,
143
135
144
136
$ allowedPaths = array_unique ($ allowedPaths );
145
137
$ declinedPaths = array_unique ($ declinedPaths );
146
- $ declinedPaths = $ this ->evaluateDeclinedPaths ($ workspaceType , $ allowedPaths , $ declinedPaths );
138
+ $ declinedPaths = $ this ->keepDeclinedPathsWithinAllowed ($ declinedPaths , $ allowedPaths );
139
+
140
+ return [
141
+ self ::ALLOWED_PATHS_KEY => $ allowedPaths ,
142
+ self ::DECLINED_PATHS_KEY => $ declinedPaths ,
143
+ ];
144
+ }
145
+
146
+ private function createWorkspacesGroupQuery (string $ workspaceType , array $ categorizedPaths ): BoolQuery
147
+ {
148
+ $ allowedPaths = $ categorizedPaths [self ::ALLOWED_PATHS_KEY ];
149
+ $ originalDeclinedPaths = $ categorizedPaths [self ::DECLINED_PATHS_KEY ];
150
+ $ declinedPaths = $ this ->evaluateDeclinedPaths ($ workspaceType , $ allowedPaths , $ originalDeclinedPaths );
147
151
148
152
if (empty ($ allowedPaths )) {
149
153
return $ this ->createNoWorkspaceAllowedQuery ();
150
154
}
151
155
152
156
$ excludedPaths = $ this ->evaluateExcludedPaths ($ allowedPaths , $ declinedPaths );
153
157
$ excludedFullPaths = $ this ->evaluateExcludedFullPaths ($ allowedPaths , $ declinedPaths );
154
- $ additionalIncludedPaths = [];
155
158
156
159
$ query = new BoolQuery ();
157
160
161
+ $ this ->addQueryByMainPath ($ query , $ allowedPaths );
158
162
$ allowedMainPaths = $ this ->pathService ->removeSubPaths ($ allowedPaths );
159
163
160
- if (count ($ allowedMainPaths ) === 1 && $ allowedMainPaths [0 ] === '/ ' ) {
161
- $ query ->addCondition (
162
- ConditionType::SHOULD ->value ,
163
- [
164
- 'exists ' => [
165
- 'field ' => SystemField::FULL_PATH ->getPath (),
166
- ],
167
- ]
168
- );
169
- } else {
170
- $ query ->addCondition (
171
- ConditionType::SHOULD ->value ,
172
- [
173
- 'terms ' => [
174
- SystemField::FULL_PATH ->getPath () => $ allowedMainPaths ,
175
- ],
176
- ]
177
- );
178
- }
179
-
180
164
if (count ($ excludedFullPaths ) > 0 ) {
181
-
182
- $ query ->addCondition (
183
- ConditionType::MUST_NOT ->value ,
184
- [
185
- 'terms ' => [
186
- SystemField::FULL_PATH ->getPath () => $ this ->pathService ->removeSubPaths ($ excludedFullPaths ),
187
- ],
188
- ]
189
- );
165
+ $ this ->addQueryToExcludeFullPaths ($ query , $ excludedFullPaths );
190
166
}
191
167
168
+ $ additionalIncludedPaths = [];
192
169
if (count ($ excludedPaths ) > 0 ) {
193
- $ query ->addCondition (
194
- ConditionType::MUST_NOT ->value ,
195
- [
196
- 'terms ' => [
197
- SystemField::PATH ->getPath ('keyword ' )
198
- => $ this ->pathService ->appendSlashes ($ excludedPaths ),
199
- ],
200
- ]
201
- );
202
-
203
- $ query ->addCondition (
204
- ConditionType::MUST_NOT ->value ,
205
- [
206
- 'terms ' => [
207
- SystemField::FULL_PATH ->getPath ('keyword ' ) => $ excludedPaths ,
208
- ],
209
- ]
210
- );
170
+ $ this ->addQueryForExcludedPaths ($ query , $ excludedPaths );
211
171
212
172
/* we need to explicitly include all allowed sub paths
213
173
as all direct children are excluded by the condition above */
@@ -221,24 +181,108 @@ private function createWorkspacesGroupQuery(string $workspaceType, array $group,
221
181
as otherwise it will not be possible to navigate to the allowed paths in the tree */
222
182
$ additionalIncludedPaths = array_merge (
223
183
$ additionalIncludedPaths ,
224
- $ this ->pathService ->getAllParentPaths ($ allowedMainPaths )
184
+ $ this ->pathService ->getAllParentPaths ($ allowedMainPaths ),
185
+ $ this ->getAllDeclinedParentPaths ($ originalDeclinedPaths , $ allowedPaths )
225
186
);
187
+ $ additionalIncludedPaths = array_unique ($ additionalIncludedPaths );
226
188
227
189
if (count ($ additionalIncludedPaths )) {
190
+ return $ this ->addQueryForAdditionalIncludedPaths ($ query , $ additionalIncludedPaths );
191
+ }
228
192
229
- return new BoolQuery ([
230
- ConditionType::SHOULD ->value => [
231
- $ query ,
232
- [
233
- 'terms ' => [
234
- SystemField::FULL_PATH ->getPath ('keyword ' ) => $ additionalIncludedPaths ,
235
- ],
193
+ return $ query ;
194
+ }
195
+
196
+ private function keepDeclinedPathsWithinAllowed (array $ declinedPaths , array $ allowedPaths ): array
197
+ {
198
+ foreach ($ declinedPaths as $ index => $ declinedPath ) {
199
+ $ isIncluded = false ;
200
+ foreach ($ allowedPaths as $ allowedPath ) {
201
+ if ($ declinedPath === $ allowedPath || $ this ->pathService ->isSubPath ($ declinedPath , $ allowedPath )) {
202
+ $ isIncluded = true ;
203
+ }
204
+ }
205
+ if (!$ isIncluded ) {
206
+ unset($ declinedPaths [$ index ]);
207
+ }
208
+ }
209
+
210
+ return $ declinedPaths ;
211
+ }
212
+
213
+ private function addQueryByMainPath (BoolQuery $ query , array $ allowedPaths ): void
214
+ {
215
+ $ allowedMainPaths = $ this ->pathService ->removeSubPaths ($ allowedPaths );
216
+
217
+ if (count ($ allowedMainPaths ) === 1 && $ allowedMainPaths [0 ] === '/ ' ) {
218
+ $ query ->addCondition (
219
+ ConditionType::SHOULD ->value ,
220
+ [
221
+ 'exists ' => [
222
+ 'field ' => SystemField::FULL_PATH ->getPath (),
236
223
],
237
- ],
238
- ]);
224
+ ]
225
+ );
226
+
227
+ return ;
239
228
}
240
229
241
- return $ query ;
230
+ $ query ->addCondition (
231
+ ConditionType::SHOULD ->value ,
232
+ [
233
+ 'terms ' => [
234
+ SystemField::FULL_PATH ->getPath () => $ allowedMainPaths ,
235
+ ],
236
+ ]
237
+ );
238
+ }
239
+
240
+ private function addQueryToExcludeFullPaths (BoolQuery $ query , array $ excludedFullPaths ): void
241
+ {
242
+ $ query ->addCondition (
243
+ ConditionType::MUST_NOT ->value ,
244
+ [
245
+ 'terms ' => [
246
+ SystemField::FULL_PATH ->getPath () => $ this ->pathService ->removeSubPaths ($ excludedFullPaths ),
247
+ ],
248
+ ]
249
+ );
250
+ }
251
+
252
+ private function addQueryForExcludedPaths (BoolQuery $ query , array $ excludedPaths ): void
253
+ {
254
+ $ query ->addCondition (
255
+ ConditionType::MUST_NOT ->value ,
256
+ [
257
+ 'terms ' => [
258
+ SystemField::PATH ->getPath ('keyword ' )
259
+ => $ this ->pathService ->appendSlashes ($ excludedPaths ),
260
+ ],
261
+ ]
262
+ );
263
+
264
+ $ query ->addCondition (
265
+ ConditionType::MUST_NOT ->value ,
266
+ [
267
+ 'terms ' => [
268
+ SystemField::FULL_PATH ->getPath ('keyword ' ) => $ excludedPaths ,
269
+ ],
270
+ ]
271
+ );
272
+ }
273
+
274
+ private function addQueryForAdditionalIncludedPaths (BoolQuery $ query , array $ additionalIncludedPaths ): BoolQuery
275
+ {
276
+ return new BoolQuery ([
277
+ ConditionType::SHOULD ->value => [
278
+ $ query ,
279
+ [
280
+ 'terms ' => [
281
+ SystemField::FULL_PATH ->getPath ('keyword ' ) => $ additionalIncludedPaths ,
282
+ ],
283
+ ],
284
+ ],
285
+ ]);
242
286
}
243
287
244
288
/**
@@ -296,6 +340,9 @@ private function evaluateDeclinedPaths(string $workspaceType, array $allowedPath
296
340
$ result = $ this ->searchIndexService ->search ($ search , $ indexName );
297
341
$ buckets = $ result ->getAggregation ('paths ' )?->getBuckets() ?? [];
298
342
foreach ($ buckets as $ bucket ) {
343
+ if ($ bucket ->getKey () === '/ ' ) {
344
+ continue ;
345
+ }
299
346
$ declinedPaths [] = rtrim ($ bucket ->getKey (), '/ ' );
300
347
}
301
348
}
@@ -358,4 +405,28 @@ private function createNoWorkspaceAllowedQuery(): BoolQuery
358
405
],
359
406
]);
360
407
}
408
+
409
+ private function getAllDeclinedParentPaths (array $ declinedPaths , array $ allowedPaths ): array
410
+ {
411
+ if (empty ($ declinedPaths )) {
412
+ return [];
413
+ }
414
+
415
+ $ allowedParentPaths = $ this ->pathService ->getAllParentPaths ($ allowedPaths , false );
416
+ $ declinedParentPaths = [];
417
+ foreach ($ allowedParentPaths as $ allowedParentPath ) {
418
+ foreach ($ declinedPaths as $ declinedPath ) {
419
+ if ($ allowedParentPath === $ declinedPath ||
420
+ $ this ->pathService ->isSubPath ($ allowedParentPath , $ declinedPath )
421
+ ) {
422
+ $ declinedParentPaths [] = $ allowedParentPath ;
423
+ }
424
+ }
425
+ }
426
+
427
+ $ declinedParentPaths = array_unique ($ declinedParentPaths );
428
+ sort ($ declinedParentPaths );
429
+
430
+ return $ declinedParentPaths ;
431
+ }
361
432
}
0 commit comments