Completed
Pull Request — master (#609)
by Maxence
02:38
created

CoreQueryBuilder::leftJoinInvitedBy()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\Db;
33
34
35
use daita\MySmallPhpTools\Db\Nextcloud\nc22\NC22ExtendedQueryBuilder;
36
use daita\MySmallPhpTools\Traits\TArrayTools;
37
use Doctrine\DBAL\Query\QueryBuilder;
38
use OC;
39
use OCA\Circles\Exceptions\RequestBuilderException;
40
use OCA\Circles\IFederatedModel;
41
use OCA\Circles\IFederatedUser;
42
use OCA\Circles\Model\Circle;
43
use OCA\Circles\Model\Federated\RemoteInstance;
44
use OCA\Circles\Model\FederatedUser;
45
use OCA\Circles\Model\Member;
46
use OCA\Circles\Service\ConfigService;
47
use OCP\DB\QueryBuilder\ICompositeExpression;
48
use OCP\DB\QueryBuilder\IQueryBuilder;
49
50
51
/**
52
 * Class CoreQueryBuilder
53
 *
54
 * @package OCA\Circles\Db
55
 */
56
class CoreQueryBuilder extends NC22ExtendedQueryBuilder {
57
58
59
	use TArrayTools;
60
61
62
	const SINGLE = 'single';
63
	const CIRCLE = 'circle';
64
	const MEMBER = 'member';
65
	const OWNER = 'owner';
66
	const FEDERATED_EVENT = 'federatedevent';
67
	const REMOTE = 'remote';
68
	const BASED_ON = 'basedon';
69
	const INITIATOR = 'initiator';
70
	const MEMBERSHIPS = 'memberships';
71
	const UPSTREAM_MEMBERSHIPS = 'upstreammemberships';
72
	const INHERITANCE_FROM = 'inheritancefrom';
73
	const INHERITED_BY = 'inheritedby';
74
	const INVITED_BY = 'invitedby';
75
	const MOUNT = 'mount';
76
	const MOUNTPOINT = 'mountpoint';
77
	const SHARE = 'share';
78
	const FILE_CACHE = 'filecache';
79
	const STORAGES = 'storages';
80
	const OPTIONS = 'options';
81
	const HELPER = 'circleshelper';
82
83
84
	public static $SQL_PATH = [
85
		self::SINGLE => [
86
			self::MEMBER
87
		],
88
		self::CIRCLE => [
89
			self::OPTIONS   => [
90
				'getPersonalCircle' => true
91
			],
92
			self::MEMBER,
93
			self::OWNER     => [
94
				self::BASED_ON
95
			],
96
			self::MEMBERSHIPS,
97
			self::INITIATOR => [
98
				self::BASED_ON,
99
				self::INHERITED_BY => [
100
					self::MEMBERSHIPS
101
				]
102
			],
103
			self::REMOTE    => [
104
				self::MEMBER,
105
				self::CIRCLE => [
106
					self::OWNER
107
				]
108
			]
109
		],
110
		self::MEMBER => [
111
			self::MEMBERSHIPS,
112
			self::INHERITANCE_FROM,
113
			self::CIRCLE     => [
114
				self::OPTIONS   => [
115
					'getData' => true
116
				],
117
				self::OWNER,
118
				self::MEMBERSHIPS,
119
				self::INITIATOR => [
120
					self::OPTIONS      => [
121
						'mustBeMember' => true,
122
						'canBeVisitor' => false
123
					],
124
					self::BASED_ON,
125
					self::INHERITED_BY => [
126
						self::MEMBERSHIPS
127
					],
128
					self::INVITED_BY => [
129
						self::OWNER,
130
						self::BASED_ON
131
					]
132
				]
133
			],
134
			self::BASED_ON   => [
135
				self::OWNER,
136
				self::MEMBERSHIPS,
137
				self::INITIATOR => [
138
					self::BASED_ON,
139
					self::INHERITED_BY => [
140
						self::MEMBERSHIPS
141
					]
142
				]
143
			],
144
			self::REMOTE     => [
145
				self::MEMBER,
146
				self::CIRCLE => [
147
					self::OWNER
148
				]
149
			],
150
			self::INVITED_BY => [
151
				self::OWNER,
152
				self::BASED_ON
153
			]
154
		],
155
		self::SHARE  => [
156
			self::SHARE,
157
			self::FILE_CACHE           => [
158
				self::STORAGES
159
			],
160
			self::UPSTREAM_MEMBERSHIPS => [
161
				self::MEMBERSHIPS,
162
				self::INHERITED_BY => [
163
					self::BASED_ON
164
				],
165
				self::SHARE,
166
			],
167
			self::MEMBERSHIPS,
168
			self::INHERITANCE_FROM,
169
			self::INHERITED_BY         => [
170
				self::BASED_ON
171
			],
172
			self::CIRCLE               => [
173
				self::OWNER
174
			],
175
			self::INITIATOR            => [
176
				self::BASED_ON,
177
				self::INHERITED_BY => [
178
					self::MEMBERSHIPS
179
				]
180
			]
181
		],
182
		self::REMOTE => [
183
			self::MEMBER
184
		],
185
		self::MOUNT  => [
186
			self::MEMBER    => [
187
				self::REMOTE
188
			],
189
			self::INITIATOR => [
190
				self::INHERITED_BY => [
191
					self::MEMBERSHIPS
192
				]
193
			],
194
			self::MOUNTPOINT,
195
			self::MEMBERSHIPS
196
		],
197
		self::HELPER => [
198
			self::MEMBERSHIPS,
199
			self::INITIATOR => [
200
				self::INHERITED_BY => [
201
					self::MEMBERSHIPS
202
				]
203
			],
204
			self::CIRCLE    => [
205
				self::OPTIONS => [
206
					'getPersonalCircle' => true
207
				],
208
				self::MEMBER,
209
				self::OWNER   => [
210
					self::BASED_ON
211
				]
212
			]
213
		]
214
	];
215
216
217
	/** @var ConfigService */
218
	private $configService;
219
220
221
	/** @var array */
222
	private $options = [];
223
224
225
	/**
226
	 * CoreQueryBuilder constructor.
227
	 */
228
	public function __construct() {
229
		parent::__construct();
230
231
		$this->configService = OC::$server->get(ConfigService::class);
232
	}
233
234
235
	/**
236
	 * @param IFederatedModel $federatedModel
237
	 *
238
	 * @return string
239
	 */
240
	public function getInstance(IFederatedModel $federatedModel): string {
241
		$instance = $federatedModel->getInstance();
242
243
		return ($this->configService->isLocalInstance($instance)) ? '' : $instance;
244
	}
245
246
247
	/**
248
	 * @param string $id
249
	 */
250
	public function limitToCircleId(string $id): void {
251
		$this->limitToDBField('circle_id', $id, true);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
252
	}
253
254
	/**
255
	 * @param string $name
256
	 */
257
	public function limitToName(string $name): void {
258
		$this->limitToDBField('name', $name);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
259
	}
260
261
	/**
262
	 * @param int $config
263
	 */
264
	public function limitToConfig(int $config): void {
265
		$this->limitToDBFieldInt('config', $config);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
266
	}
267
268
	/**
269
	 * @param int $source
270
	 */
271
	public function limitToSource(int $source): void {
272
		$this->limitToDBFieldInt('source', $source);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
273
	}
274
275
	/**
276
	 * @param int $config
277
	 * @param string $alias
278
	 */
279
	public function limitToConfigFlag(int $config, string $alias = ''): void {
280
		$this->limitBitwise('config', $config, $alias);
281
	}
282
283
284
	/**
285
	 * @param string $singleId
286
	 */
287
	public function limitToSingleId(string $singleId): void {
288
		$this->limitToDBField('single_id', $singleId, true);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
289
	}
290
291
292
	/**
293
	 * @param string $itemId
294
	 */
295
	public function limitToItemId(string $itemId): void {
296
		$this->limitToDBField('item_id', $itemId, true);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
297
	}
298
299
300
	/**
301
	 * @param string $host
302
	 */
303
	public function limitToInstance(string $host): void {
304
		$this->limitToDBField('instance', $host, false);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
305
	}
306
307
308
	/**
309
	 * @param int $userType
310
	 */
311
	public function limitToUserType(int $userType): void {
312
		$this->limitToDBFieldInt('user_type', $userType);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
313
	}
314
315
316
	/**
317
	 * @param int $shareType
318
	 */
319
	public function limitToShareType(int $shareType): void {
320
		$this->limitToDBFieldInt('share_type', $shareType);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
321
	}
322
323
324
	/**
325
	 * @param string $shareWith
326
	 */
327
	public function limitToShareWith(string $shareWith): void {
328
		$this->limitToDBField('share_with', $shareWith);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...ilder::limitToDBField() has been deprecated with message: - use limit();

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
329
	}
330
331
332
	/**
333
	 * @param int $nodeId
334
	 */
335
	public function limitToFileSource(int $nodeId): void {
336
		$this->limitToDBFieldInt('file_source', $nodeId);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
337
	}
338
339
	/**
340
	 * @param array $files
341
	 */
342
	public function limitToFileSourceArray(array $files): void {
343
		$this->limitToDBFieldInArray('file_source', $files);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...limitToDBFieldInArray() has been deprecated with message: - use limitInArray()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
344
	}
345
346
347
	/**
348
	 * @param int $shareId
349
	 */
350
	public function limitToShareParent(int $shareId): void {
351
		$this->limitToDBFieldInt('parent', $shareId);
0 ignored issues
show
Deprecated Code introduced by
The method daita\MySmallPhpTools\Db...er::limitToDBFieldInt() has been deprecated with message: - use limitInt()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
352
	}
353
354
355
	/**
356
	 * @param Circle $circle
357
	 */
358
	public function filterCircle(Circle $circle): void {
359
		if ($this->getType() !== QueryBuilder::SELECT) {
360
			return;
361
		}
362
363
		if ($circle->getDisplayName() !== '') {
364
			$this->searchInDBField('display_name', '%' . $circle->getDisplayName() . '%');
365
		}
366
	}
367
368
369
	/**
370
	 * left join RemoteInstance based on a Member
371
	 */
372
	public function leftJoinRemoteInstance(string $alias): void {
373
		$expr = $this->expr();
374
375
		try {
376
			$aliasRemoteInstance = $this->generateAlias($alias, self::REMOTE);
377
			$this->generateRemoteInstanceSelectAlias($aliasRemoteInstance)
378
				 ->leftJoin(
379
					 $alias, CoreRequestBuilder::TABLE_REMOTE, $aliasRemoteInstance,
380
					 $expr->eq($alias . '.instance', $aliasRemoteInstance . '.instance')
381
				 );
382
		} catch (RequestBuilderException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
383
		}
384
	}
385
386
387
	/**
388
	 * @param string $alias
389
	 * @param RemoteInstance $remoteInstance
390
	 * @param bool $filterSensitiveData
391
	 * @param string $aliasCircle
392
	 *
393
	 * @throws RequestBuilderException
394
	 */
395
	public function limitToRemoteInstance(
396
		string $alias,
397
		RemoteInstance $remoteInstance,
398
		bool $filterSensitiveData = true,
399
		string $aliasCircle = ''
400
	): void {
401
402
		if ($aliasCircle === '') {
403
			$aliasCircle = $alias;
404
		}
405
406
		$this->leftJoinRemoteInstanceIncomingRequest($alias, $remoteInstance);
407
		$this->leftJoinMemberFromInstance($alias, $remoteInstance, $aliasCircle);
408
		$this->leftJoinMemberFromRemoteCircle($alias, $remoteInstance, $aliasCircle);
409
		$this->limitRemoteVisibility($alias, $filterSensitiveData, $aliasCircle);
410
	}
411
412
413
	/**
414
	 * Left join RemoteInstance based on an incoming request
415
	 *
416
	 * @param string $alias
417
	 * @param RemoteInstance $remoteInstance
418
	 *
419
	 * @throws RequestBuilderException
420
	 */
421
	public function leftJoinRemoteInstanceIncomingRequest(
422
		string $alias,
423
		RemoteInstance $remoteInstance
424
	): void {
425
		if ($this->getType() !== QueryBuilder::SELECT) {
426
			return;
427
		}
428
429
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
430
		$expr = $this->expr();
431
		$this->leftJoin(
432
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_REMOTE, $aliasRemote,
433
			$expr->eq($aliasRemote . '.instance', $this->createNamedParameter($remoteInstance->getInstance()))
434
		);
435
	}
436
437
438
	/**
439
	 * left join members to check memberships of someone from instance
440
	 *
441
	 * @param string $alias
442
	 * @param RemoteInstance $remoteInstance
443
	 * @param string $aliasCircle
444
	 *
445
	 * @throws RequestBuilderException
446
	 */
447
	private function leftJoinMemberFromInstance(
448
		string $alias, RemoteInstance $remoteInstance, string $aliasCircle
449
	) {
450
		if ($this->getType() !== QueryBuilder::SELECT) {
451
			return;
452
		}
453
454
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
455
		$aliasRemoteMember = $this->generateAlias($aliasRemote, self::MEMBER);
456
457
		$expr = $this->expr();
458
		$this->leftJoin(
459
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteMember,
460
			$expr->andX(
461
				$expr->eq($aliasRemoteMember . '.circle_id', $aliasCircle . '.unique_id'),
462
				$expr->eq(
463
					$aliasRemoteMember . '.instance',
464
					$this->createNamedParameter($remoteInstance->getInstance())
465
				),
466
				$expr->gte($aliasRemoteMember . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
467
			)
468
		);
469
	}
470
471
472
	/**
473
	 * left join circle is member of a circle from remote instance
474
	 *
475
	 * @param string $alias
476
	 * @param RemoteInstance $remoteInstance
477
	 * @param string $aliasCircle
478
	 *
479
	 * @throws RequestBuilderException
480
	 */
481
	private function leftJoinMemberFromRemoteCircle(
482
		string $alias,
483
		RemoteInstance $remoteInstance,
484
		string $aliasCircle
485
	) {
486
		if ($this->getType() !== QueryBuilder::SELECT) {
487
			return;
488
		}
489
490
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
491
		$aliasRemoteCircle = $this->generateAlias($aliasRemote, self::CIRCLE);
492
		$aliasRemoteCircleOwner = $this->generateAlias($aliasRemoteCircle, self::OWNER);
493
494
		$expr = $this->expr();
495
		$this->leftJoin(
496
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteCircle,
497
			$expr->andX(
498
				$expr->eq($aliasRemoteCircle . '.single_id', $aliasCircle . '.unique_id'),
499
				$expr->emptyString($aliasRemoteCircle . '.instance'),
500
				$expr->gte($aliasRemoteCircle . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
501
			)
502
		);
503
		$this->leftJoin(
504
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasRemoteCircleOwner,
505
			$expr->andX(
506
				$expr->eq($aliasRemoteCircle . '.circle_id', $aliasRemoteCircleOwner . '.circle_id'),
507
				$expr->eq(
508
					$aliasRemoteCircleOwner . '.instance',
509
					$this->createNamedParameter($remoteInstance->getInstance())
510
				),
511
				$expr->eq(
512
					$aliasRemoteCircleOwner . '.level', $this->createNamedParameter(Member::LEVEL_OWNER)
513
				)
514
			)
515
		);
516
	}
517
518
519
	/**
520
	 * - global_scale: visibility on all Circles
521
	 * - trusted: visibility on all FEDERATED Circle if owner is local
522
	 * - external: visibility on all FEDERATED Circle if owner is local and:
523
	 *    - with if Circle contains at least one member from the remote instance
524
	 *    - one circle from the remote instance contains the local circle as member, and confirmed (using
525
	 *      sync locally)
526
	 * - passive: like external, but the members list will only contains member from the local instance and
527
	 * from the remote instance.
528
	 *
529
	 * @param string $alias
530
	 * @param bool $sensitive
531
	 * @param string $aliasCircle
532
	 *
533
	 * @throws RequestBuilderException
534
	 */
535
	protected function limitRemoteVisibility(string $alias, bool $sensitive, string $aliasCircle) {
536
		$aliasRemote = $this->generateAlias($alias, self::REMOTE);
537
		$aliasOwner = $this->generateAlias($aliasCircle, self::OWNER);
538
		$aliasRemoteMember = $this->generateAlias($aliasRemote, self::MEMBER);
539
		$aliasRemoteCircle = $this->generateAlias($aliasRemote, self::CIRCLE);
540
		$aliasRemoteCircleOwner = $this->generateAlias($aliasRemoteCircle, self::OWNER);
541
542
		$expr = $this->expr();
543
		$orX = $expr->orX();
544
		$orX->add(
545
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_GLOBALSCALE))
546
		);
547
548
		$orExtOrPassive = $expr->orX();
549
		$orExtOrPassive->add(
550
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_EXTERNAL))
551
		);
552
		if (!$sensitive) {
553
			$orExtOrPassive->add(
554
				$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_PASSIVE))
555
			);
556
		} else {
557
			if ($this->getDefaultSelectAlias() === CoreQueryBuilder::MEMBER) {
558
				$orExtOrPassive->add($this->limitRemoteVisibility_Sensitive_Members($aliasRemote));
559
			}
560
		}
561
562
		$orInstance = $expr->orX();
563
		$orInstance->add($expr->isNotNull($aliasRemoteMember . '.instance'));
564
		$orInstance->add($expr->isNotNull($aliasRemoteCircleOwner . '.instance'));
565
566
		$andExternal = $expr->andX();
567
		$andExternal->add($orExtOrPassive);
568
		$andExternal->add($orInstance);
569
570
		$orExtOrTrusted = $expr->orX();
571
		$orExtOrTrusted->add($andExternal);
572
		$orExtOrTrusted->add(
573
			$expr->eq($aliasRemote . '.type', $this->createNamedParameter(RemoteInstance::TYPE_TRUSTED))
574
		);
575
576
		$andTrusted = $expr->andX();
577
		$andTrusted->add($orExtOrTrusted);
578
		$andTrusted->add($this->exprLimitBitwise('config', Circle::CFG_FEDERATED, $aliasCircle));
579
		$andTrusted->add($expr->emptyString($aliasOwner . '.instance'));
580
		$orX->add($andTrusted);
581
582
		$this->andWhere($orX);
583
	}
584
585
586
	/**
587
	 * @param string $alias
588
	 * @param Member $member
589
	 *
590
	 * @throws RequestBuilderException
591
	 */
592
	public function limitToDirectMembership(string $alias, Member $member): void {
593
		if ($this->getType() !== QueryBuilder::SELECT) {
594
			return;
595
		}
596
597
		$aliasMember = $this->generateAlias($alias, self::MEMBER, $options);
598
		$getData = $this->getBool('getData', $options, false);
599
600
		$expr = $this->expr();
601
		if ($getData) {
602
			$this->generateMemberSelectAlias($aliasMember);
603
		}
604
		$this->leftJoin(
605
			$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
606
			$expr->eq($aliasMember . '.circle_id', $alias . '.unique_id')
607
		);
608
609
		$this->filterDirectMembership($aliasMember, $member);
610
	}
611
612
613
	/**
614
	 * @param string $aliasMember
615
	 * @param Member $member
616
	 */
617
	public function filterDirectMembership(string $aliasMember, Member $member): void {
618
		if ($this->getType() !== QueryBuilder::SELECT) {
619
			return;
620
		}
621
622
		$expr = $this->expr();
623
		$andX = $expr->andX();
624
625
		if ($member->getUserId() !== '') {
626
			$andX->add(
627
				$expr->eq($aliasMember . '.user_id', $this->createNamedParameter($member->getUserId()))
628
			);
629
		}
630
631
		if ($member->getSingleId() !== '') {
632
			$andX->add(
633
				$expr->eq($aliasMember . '.single_id', $this->createNamedParameter($member->getSingleId()))
634
			);
635
		}
636
637
		if ($member->getUserType() > 0) {
638
			$andX->add(
639
				$expr->eq($aliasMember . '.user_type', $this->createNamedParameter($member->getUserType()))
640
			);
641
		}
642
643
		$andX->add(
644
			$expr->eq($aliasMember . '.instance', $this->createNamedParameter($this->getInstance($member)))
645
		);
646
647
		if ($member->getLevel() > 0) {
648
			$andX->add(
649
				$expr->gte(
650
					$aliasMember . '.level',
651
					$this->createNamedParameter($member->getLevel(), IQueryBuilder::PARAM_INT)
652
				)
653
			);
654
		}
655
656
		$this->andWhere($andX);
657
	}
658
659
660
	/**
661
	 * @param string $alias
662
	 * @param IFederatedUser|null $initiator
663
	 * @param string $field
664
	 * @param string $helpedAlias
0 ignored issues
show
Documentation introduced by
There is no parameter named $helpedAlias. Did you maybe mean $helperAlias?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
665
	 *
666
	 * @throws RequestBuilderException
667
	 */
668
	public function leftJoinCircle(
669
		string $alias,
670
		?IFederatedUser $initiator = null,
671
		string $field = 'circle_id',
672
		string $helperAlias = ''
673
	): void {
674
		if ($this->getType() !== QueryBuilder::SELECT) {
675
			return;
676
		}
677
678
		$helperAlias = ($helperAlias !== '') ? $helperAlias : $alias;
679
		$aliasCircle = $this->generateAlias($alias, self::CIRCLE, $options);
680
		$getData = $this->getBool('getData', $options, false);
681
		$expr = $this->expr();
682
683
		if ($getData) {
684
			$this->generateCircleSelectAlias($aliasCircle);
685
		}
686
687
		$this->leftJoin(
688
			$helperAlias,
689
			CoreRequestBuilder::TABLE_CIRCLE,
690
			$aliasCircle,
691
			$expr->eq($aliasCircle . '.unique_id', $helperAlias . '.' . $field)
692
		);
693
694
		if (!is_null($initiator)) {
695
			$this->limitToInitiator($aliasCircle, $initiator);
696
		}
697
698
		$this->leftJoinOwner($aliasCircle);
699
	}
700
701
702
	/**
703
	 * @param string $aliasMember
704
	 *
705
	 * @throws RequestBuilderException
706
	 */
707
	public function leftJoinInvitedBy(string $aliasMember): void {
708
		if ($this->getType() !== QueryBuilder::SELECT) {
709
			return;
710
		}
711
712
		try {
713
			$aliasInvitedBy = $this->generateAlias($aliasMember, self::INVITED_BY);
714
		} catch (RequestBuilderException $e) {
715
			return;
716
		}
717
718
		$expr = $this->expr();
719
		$this->generateCircleSelectAlias($aliasInvitedBy)
720
			 ->leftJoin(
721
				 $aliasMember, CoreRequestBuilder::TABLE_CIRCLE, $aliasInvitedBy,
722
				 $expr->eq($aliasMember . '.invited_by', $aliasInvitedBy . '.unique_id')
723
			 );
724
725
		$this->leftJoinOwner($aliasInvitedBy);
726
	}
727
728
729
	/**
730
	 * @param string $aliasMember
731
	 * @param IFederatedUser|null $initiator
732
	 *
733
	 * @throws RequestBuilderException
734
	 */
735
	public function leftJoinBasedOn(
736
		string $aliasMember,
737
		?IFederatedUser $initiator = null
738
	): void {
739
		if ($this->getType() !== QueryBuilder::SELECT) {
740
			return;
741
		}
742
743
		try {
744
			$aliasBasedOn = $this->generateAlias($aliasMember, self::BASED_ON, $options);
745
		} catch (RequestBuilderException $e) {
746
			return;
747
		}
748
749
		$expr = $this->expr();
750
		$this->generateCircleSelectAlias($aliasBasedOn)
751
			 ->leftJoin(
752
				 $aliasMember, CoreRequestBuilder::TABLE_CIRCLE, $aliasBasedOn,
753
				 $expr->eq($aliasBasedOn . '.unique_id', $aliasMember . '.single_id')
754
			 );
755
756
		if (!is_null($initiator)) {
757
			$this->leftJoinInitiator($aliasBasedOn, $initiator);
758
			$this->leftJoinOwner($aliasBasedOn);
759
		}
760
	}
761
762
763
	/**
764
	 * @param string $alias
765
	 * @param string $field
766
	 *
767
	 * @throws RequestBuilderException
768
	 */
769
	public function leftJoinOwner(string $alias, string $field = 'unique_id'): void {
770
		if ($this->getType() !== QueryBuilder::SELECT) {
771
			return;
772
		}
773
774
		try {
775
			$aliasMember = $this->generateAlias($alias, self::OWNER, $options);
776
			$getData = $this->getBool('getData', $options, false);
0 ignored issues
show
Unused Code introduced by
$getData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
777
		} catch (RequestBuilderException $e) {
778
			return;
779
		}
780
781
		$expr = $this->expr();
782
		$this->generateMemberSelectAlias($aliasMember)
783
			 ->leftJoin(
784
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
785
				 $expr->andX(
786
					 $expr->eq($aliasMember . '.circle_id', $alias . '.' . $field),
787
					 $expr->eq(
788
						 $aliasMember . '.level',
789
						 $this->createNamedParameter(Member::LEVEL_OWNER, self::PARAM_INT)
790
					 )
791
				 )
792
			 );
793
794
		$this->leftJoinBasedOn($aliasMember);
795
	}
796
797
798
	/**
799
	 * @param string $alias
800
	 * @param string $fieldCircleId
801
	 * @param string $fieldSingleId
802
	 *
803
	 * @throws RequestBuilderException
804
	 */
805
	public function leftJoinMember(
806
		string $alias,
807
		string $fieldCircleId = 'circle_id',
808
		string $fieldSingleId = 'single_id'
809
	): void {
810
		if ($this->getType() !== QueryBuilder::SELECT) {
811
			return;
812
		}
813
814
		try {
815
			$aliasMember = $this->generateAlias($alias, self::MEMBER, $options);
816
			$getData = $this->getBool('getData', $options, false);
0 ignored issues
show
Unused Code introduced by
$getData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
817
		} catch (RequestBuilderException $e) {
818
			return;
819
		}
820
821
		$expr = $this->expr();
822
		$this->generateMemberSelectAlias($aliasMember)
823
			 ->leftJoin(
824
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasMember,
825
				 $expr->andX(
826
					 $expr->eq($aliasMember . '.circle_id', $alias . '.' . $fieldCircleId),
827
					 $expr->eq($aliasMember . '.single_id', $alias . '.' . $fieldSingleId),
828
					 $expr->gte(
829
						 $aliasMember . '.level',
830
						 $this->createNamedParameter(Member::LEVEL_MEMBER, self::PARAM_INT)
831
					 )
832
				 )
833
			 );
834
835
		$this->leftJoinRemoteInstance($aliasMember);
836
		$this->leftJoinBasedOn($aliasMember);
837
	}
838
839
840
	/**
841
	 * if 'getData' is true, will returns 'inheritanceBy': the Member at the end of a sub-chain of
842
	 * memberships (based on $field for Top Circle's singleId)
843
	 *
844
	 * @param string $alias
845
	 * @param string $field
846
	 * @param string $aliasInheritedBy
847
	 *
848
	 * @throws RequestBuilderException
849
	 */
850
	public function leftJoinInheritedMembers(
851
		string $alias,
852
		string $field = '',
853
		string $aliasInheritedBy = ''
854
	): void {
855
		$expr = $this->expr();
856
857
		$field = ($field === '') ? 'circle_id' : $field;
858
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
859
860
		$this->leftJoin(
861
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership,
862
			$expr->eq($aliasMembership . '.circle_id', $alias . '.' . $field)
863
		);
864
865
//		if (!$this->getBool('getData', $options, false)) {
866
//			return;
867
//		}
868
869
		if ($aliasInheritedBy === '') {
870
			$aliasInheritedBy = $this->generateAlias($alias, self::INHERITED_BY);
871
		}
872
		$this->generateMemberSelectAlias($aliasInheritedBy)
873
			 ->leftJoin(
874
				 $alias, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritedBy,
875
				 $expr->andX(
876
					 $expr->eq($aliasMembership . '.inheritance_last', $aliasInheritedBy . '.circle_id'),
877
					 $expr->eq($aliasMembership . '.single_id', $aliasInheritedBy . '.single_id')
878
				 )
879
			 );
880
881
		$this->leftJoinBasedOn($aliasInheritedBy);
882
	}
883
884
885
	/**
886
	 * @throws RequestBuilderException
887
	 */
888
	public function limitToInheritedMemberships(string $alias, string $singleId, string $field = ''): void {
889
		$expr = $this->expr();
890
		$field = ($field === '') ? 'circle_id' : $field;
891
		$aliasUpstreamMembership = $this->generateAlias($alias, self::UPSTREAM_MEMBERSHIPS, $options);
892
		$this->leftJoin(
893
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasUpstreamMembership,
894
			$expr->eq($aliasUpstreamMembership . '.single_id', $this->createNamedParameter($singleId))
895
		);
896
897
		$orX = $expr->orX(
898
			$expr->eq($aliasUpstreamMembership . '.circle_id', $alias . '.' . $field),
899
			$expr->eq($alias . '.' . $field, $this->createNamedParameter($singleId))
900
		);
901
902
		$this->andWhere($orX);
903
	}
904
905
906
	/**
907
	 * limit the request to Members and Sub Members of a Circle.
908
	 *
909
	 * @param string $alias
910
	 * @param string $singleId
911
	 *
912
	 * @throws RequestBuilderException
913
	 */
914
	public function limitToMembersByInheritance(string $alias, string $singleId): void {
915
		$this->leftJoinMembersByInheritance($alias);
916
917
		$expr = $this->expr();
918
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS);
919
		$this->andWhere($expr->eq($aliasMembership . '.circle_id', $this->createNamedParameter($singleId)));
920
	}
921
922
923
	/**
924
	 * if 'getData' is true, will returns 'inheritanceFrom': the Circle-As-Member of the Top Circle
925
	 * that explain the membership of a Member (based on $field for singleId) to a specific Circle
926
	 *
927
	 * // TODO: returns the link/path ?
928
	 *
929
	 * @param string $alias
930
	 * @param string $field
931
	 *
932
	 * @throws RequestBuilderException
933
	 */
934
	public function leftJoinMembersByInheritance(string $alias, string $field = ''): void {
935
		$expr = $this->expr();
936
937
		$field = ($field === '') ? 'circle_id' : $field;
938
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
939
940
		$this->leftJoin(
941
			$alias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership,
942
//			$expr->andX(
943
			$expr->eq($aliasMembership . '.inheritance_last', $alias . '.' . $field)
944
//				$expr->eq($aliasMembership . '.single_id', $alias . '.single_id')
945
//			)
946
		);
947
948
		if (!$this->getBool('getData', $options, false)) {
949
			return;
950
		}
951
952
		$aliasInheritanceFrom = $this->generateAlias($alias, self::INHERITANCE_FROM);
953
		$this->generateMemberSelectAlias($aliasInheritanceFrom)
954
			 ->leftJoin(
955
				 $aliasMembership, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritanceFrom,
956
				 $expr->andX(
957
					 $expr->eq($aliasMembership . '.circle_id', $aliasInheritanceFrom . '.circle_id'),
958
					 $expr->eq($aliasMembership . '.inheritance_first', $aliasInheritanceFrom . '.single_id')
959
				 )
960
			 );
961
	}
962
963
964
	/**
965
	 * limit the result to the point of view of a FederatedUser
966
	 *
967
	 * @param string $alias
968
	 * @param IFederatedUser $user
969
	 * @param string $field
970
	 * @param string $helperAlias
971
	 *
972
	 * @return ICompositeExpression
973
	 * @throws RequestBuilderException
974
	 */
975
	public function limitToInitiator(
976
		string $alias,
977
		IFederatedUser $user,
978
		string $field = '',
979
		string $helperAlias = ''
980
	): ICompositeExpression {
981
		$this->leftJoinInitiator($alias, $user, $field, $helperAlias);
982
		$where = $this->limitInitiatorVisibility($alias);
983
984
		$aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options);
985
		if ($this->getBool('getData', $options, false)) {
986
			$this->leftJoinBasedOn($aliasInitiator);
987
		}
988
989
		return $where;
990
	}
991
992
993
	/**
994
	 * Left join members to filter userId as initiator.
995
	 *
996
	 * @param string $alias
997
	 * @param IFederatedUser $initiator
998
	 * @param string $field
999
	 * @param string $helperAlias
1000
	 *
1001
	 * @throws RequestBuilderException
1002
	 */
1003
	public function leftJoinInitiator(
1004
		string $alias,
1005
		IFederatedUser $initiator,
1006
		string $field = '',
1007
		string $helperAlias = ''
1008
	): void {
1009
		if ($this->getType() !== QueryBuilder::SELECT) {
1010
			return;
1011
		}
1012
1013
		$expr = $this->expr();
1014
		$field = ($field === '') ? 'unique_id' : $field;
1015
		$helperAlias = ($helperAlias !== '') ? $helperAlias : $alias;
1016
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
1017
1018
		$this->leftJoin(
1019
			$helperAlias,
1020
			CoreRequestBuilder::TABLE_MEMBERSHIP,
1021
			$aliasMembership,
1022
			$expr->andX(
1023
				$this->exprLimit('single_id', $initiator->getSingleId(), $aliasMembership),
1024
				$expr->eq($aliasMembership . '.circle_id', $helperAlias . '.' . $field)
1025
			)
1026
		);
1027
1028
		if (!$this->getBool('getData', $options, false)) {
1029
			return;
1030
		}
1031
1032
		try {
1033
			$aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options);
1034
			$this->leftJoin(
1035
				$aliasMembership, CoreRequestBuilder::TABLE_MEMBER, $aliasInitiator,
1036
				$expr->andX(
1037
					$expr->eq($aliasMembership . '.inheritance_first', $aliasInitiator . '.single_id'),
1038
					$expr->eq($aliasMembership . '.circle_id', $aliasInitiator . '.circle_id')
1039
				)
1040
			);
1041
1042
			$aliasInheritedBy = $this->generateAlias($aliasInitiator, self::INHERITED_BY);
1043
			$this->leftJoin(
1044
				$aliasInitiator, CoreRequestBuilder::TABLE_MEMBER, $aliasInheritedBy,
1045
				$expr->andX(
1046
					$expr->eq($aliasMembership . '.single_id', $aliasInheritedBy . '.single_id'),
1047
					$expr->eq($aliasMembership . '.inheritance_last', $aliasInheritedBy . '.circle_id')
1048
				)
1049
			);
1050
1051
			$default = [];
1052
			if ($this->getBool('canBeVisitor', $options, false)) {
1053
				$default = [
1054
					'user_id'   => $initiator->getUserId(),
1055
					'single_id' => $initiator->getSingleId(),
1056
					'user_type' => $initiator->getUserType(),
1057
					'instance'  => $initiator->getInstance()
1058
				];
1059
			}
1060
			$this->generateMemberSelectAlias($aliasInitiator, $default);
1061
1062
			$this->generateMemberSelectAlias($aliasInheritedBy);
1063
			$aliasInheritedByMembership = $this->generateAlias($aliasInheritedBy, self::MEMBERSHIPS);
1064
			$this->generateMembershipSelectAlias($aliasMembership, $aliasInheritedByMembership);
1065
		} catch (RequestBuilderException $e) {
1066
			\OC::$server->getLogger()->log(3, '-- ' . $e->getMessage());
1067
		}
1068
	}
1069
1070
1071
	/**
1072
	 * @param string $alias
1073
	 *
1074
	 * @return ICompositeExpression
1075
	 * @throws RequestBuilderException
1076
	 */
1077
	protected function limitInitiatorVisibility(string $alias): ICompositeExpression {
1078
		$aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options);
1079
		$getPersonalCircle = $this->getBool('getPersonalCircle', $options, false);
1080
1081
		$expr = $this->expr();
1082
1083
		// Visibility to non-member is
1084
		// - 0 (default), if initiator is member
1085
		// - 2 (Personal), if initiator is owner)
1086
		// - 4 (Visible to everyone)
1087
		$orX = $expr->orX();
1088
		$orX->add(
1089
			$expr->andX(
1090
				$expr->gte($aliasMembership . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER))
1091
			)
1092
		);
1093
1094
		if ($getPersonalCircle) {
1095
			$orX->add(
1096
				$expr->andX(
1097
					$this->exprLimitBitwise('config', Circle::CFG_PERSONAL, $alias),
1098
					$expr->eq($aliasMembership . '.level', $this->createNamedParameter(Member::LEVEL_OWNER))
1099
				)
1100
			);
1101
		}
1102
		if (!$this->getBool('mustBeMember', $options, true)) {
1103
			$orX->add($this->exprLimitBitwise('config', Circle::CFG_VISIBLE, $alias));
1104
		}
1105
		if ($this->getBool('canBeVisitor', $options, false)) {
1106
			// TODO: should find a better way, also filter on remote initiator on non-federated ?
1107
			$orX->add($expr->gte($alias . '.config', $this->createNamedParameter(0)));
1108
		}
1109
		if ($this->getBool('canBeVisitorOnOpen', $options, false)) {
1110
			$andOpen = $expr->andX();
1111
			$andOpen->add($this->exprLimitBitwise('config', Circle::CFG_OPEN, $alias));
1112
			$andOpen->add($this->exprFilterBitwise('config', Circle::CFG_REQUEST, $alias));
1113
			$orX->add($andOpen);
1114
		}
1115
1116
		$this->andWhere($orX);
1117
1118
		return $orX;
1119
//		$orTypes = $this->generateLimit($qb, $circleUniqueId, $userId, $type, $name, $forceAll);
1120
//		if (sizeof($orTypes) === 0) {
1121
//			throw new ConfigNoCircleAvailableException(
1122
//				$this->l10n->t(
1123
//					'You cannot use the Circles Application until your administrator has allowed at least one type of circles'
1124
//				)
1125
//			);
1126
//		}
1127
1128
//		$orXTypes = $this->expr()
1129
//						 ->orX();
1130
//		foreach ($orTypes as $orType) {
1131
//			$orXTypes->add($orType);
1132
//		}
1133
//
1134
//		$qb->andWhere($orXTypes);
1135
	}
1136
1137
1138
	/**
1139
	 * CFG_SINGLE, CFG_HIDDEN and CFG_BACKEND means hidden from listing.
1140
	 *
1141
	 * @param string $aliasCircle
1142
	 * @param int $flag
1143
	 */
1144
	public function filterCircles(
1145
		string $aliasCircle,
1146
		int $flag = Circle::CFG_SINGLE | Circle::CFG_HIDDEN | Circle::CFG_BACKEND
1147
	): void {
1148
		if ($flag === 0) {
1149
			return;
1150
		}
1151
1152
		$expr = $this->expr();
1153
		$hide = $expr->andX();
1154
		foreach (Circle::$DEF_CFG as $cfg => $v) {
1155
			if ($flag & $cfg) {
1156
				$hide->add($this->exprFilterBitwise('config', $cfg, $aliasCircle));
1157
			}
1158
		}
1159
1160
		$this->andWhere($hide);
1161
	}
1162
1163
1164
	/**
1165
	 * Limit visibility on Sensitive information when search for members.
1166
	 *
1167
	 * @param string $alias
1168
	 *
1169
	 * @return ICompositeExpression
1170
	 */
1171
	private function limitRemoteVisibility_Sensitive_Members(string $alias): ICompositeExpression {
1172
		$expr = $this->expr();
1173
		$andPassive = $expr->andX();
1174
		$andPassive->add(
1175
			$expr->eq($alias . '.type', $this->createNamedParameter(RemoteInstance::TYPE_PASSIVE))
1176
		);
1177
1178
		$orMemberOrLevel = $expr->orX();
1179
		$orMemberOrLevel->add(
1180
			$expr->eq($this->getDefaultSelectAlias() . '.instance', $alias . '.instance')
1181
		);
1182
		// TODO: do we need this ? (display members from the local instance)
1183
		$orMemberOrLevel->add(
1184
			$expr->emptyString($this->getDefaultSelectAlias() . '.instance')
1185
		);
1186
1187
		$orMemberOrLevel->add(
1188
			$expr->eq(
1189
				$this->getDefaultSelectAlias() . '.level',
1190
				$this->createNamedParameter(Member::LEVEL_OWNER)
1191
			)
1192
		);
1193
		$andPassive->add($orMemberOrLevel);
1194
1195
		return $andPassive;
1196
	}
1197
1198
1199
1200
	/**
1201
	 * Link to storage/filecache
1202
	 *
1203
	 * @param string $aliasShare
1204
	 *
1205
	 * @throws RequestBuilderException
1206
	 */
1207
	public function leftJoinFileCache(string $aliasShare) {
1208
		$expr = $this->expr();
1209
1210
		$aliasFileCache = $this->generateAlias($aliasShare, self::FILE_CACHE);
1211
		$aliasStorages = $this->generateAlias($aliasFileCache, self::STORAGES);
1212
1213
		$this->generateSelectAlias(
1214
			CoreRequestBuilder::$outsideTables[CoreRequestBuilder::TABLE_FILE_CACHE],
0 ignored issues
show
Bug introduced by
The property outsideTables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1215
			$aliasFileCache,
1216
			$aliasFileCache,
1217
			[]
1218
		)
1219
			 ->generateSelectAlias(
1220
				 CoreRequestBuilder::$outsideTables[CoreRequestBuilder::TABLE_STORAGES],
0 ignored issues
show
Bug introduced by
The property outsideTables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1221
				 $aliasStorages,
1222
				 $aliasStorages,
1223
				 []
1224
			 )
1225
			 ->leftJoin(
1226
				 $aliasShare, CoreRequestBuilder::TABLE_FILE_CACHE, $aliasFileCache,
1227
				 $expr->eq($aliasShare . '.file_source', $aliasFileCache . '.fileid')
1228
			 )
1229
			 ->leftJoin(
1230
				 $aliasFileCache, CoreRequestBuilder::TABLE_STORAGES, $aliasStorages,
1231
				 $expr->eq($aliasFileCache . '.storage', $aliasStorages . '.numeric_id')
1232
			 );
1233
	}
1234
1235
1236
	/**
1237
	 * @param string $aliasShare
1238
	 * @param string $aliasShareMemberships
1239
	 *
1240
	 * @throws RequestBuilderException
1241
	 */
1242
	public function leftJoinShareChild(string $aliasShare, string $aliasShareMemberships = '') {
1243
		$expr = $this->expr();
1244
1245
		$aliasShareChild = $this->generateAlias($aliasShare, self::SHARE);
1246
		if ($aliasShareMemberships === '') {
1247
			$aliasShareMemberships = $this->generateAlias($aliasShare, self::MEMBERSHIPS, $options);
1248
		}
1249
1250
		$this->leftJoin(
1251
			$aliasShareMemberships, CoreRequestBuilder::TABLE_SHARE, $aliasShareChild,
1252
			$expr->andX(
1253
				$expr->eq($aliasShareChild . '.parent', $aliasShare . '.id'),
1254
				$expr->eq($aliasShareChild . '.share_with', $aliasShareMemberships . '.single_id')
1255
			)
1256
		);
1257
1258
		$this->generateSelectAlias(
1259
			['id', 'file_target', 'permissions'],
1260
			$aliasShareChild,
1261
			'child_',
1262
			[]
1263
		);
1264
1265
//		$this->selectAlias($aliasShareParent . '.permissions', 'parent_perms');
1266
	}
1267
1268
1269
	/**
1270
	 * @param string $alias
1271
	 * @param FederatedUser $federatedUser
1272
	 * @param bool $reshares
1273
	 */
1274
	public function limitToShareOwner(string $alias, FederatedUser $federatedUser, bool $reshares): void {
1275
		$expr = $this->expr();
1276
1277
		$orX = $expr->orX($this->exprLimit('uid_initiator', $federatedUser->getUserId(), $alias));
1278
1279
		if ($reshares) {
1280
			$orX->add($this->exprLimit('uid_owner', $federatedUser->getUserId(), $alias));
1281
		}
1282
1283
		$this->andWhere($orX);
1284
	}
1285
1286
1287
	/**
1288
	 * @param string $aliasMount
1289
	 * @param string $aliasMountMemberships
1290
	 *
1291
	 * @throws RequestBuilderException
1292
	 */
1293
	public function leftJoinMountpoint(string $aliasMount, string $aliasMountMemberships = '') {
1294
		$expr = $this->expr();
1295
1296
		$aliasMountpoint = $this->generateAlias($aliasMount, self::MOUNTPOINT);
1297
		if ($aliasMountMemberships === '') {
1298
			$aliasMountMemberships = $this->generateAlias($aliasMount, self::MEMBERSHIPS, $options);
1299
		}
1300
1301
		$this->leftJoin(
1302
			$aliasMountMemberships, CoreRequestBuilder::TABLE_MOUNTPOINT, $aliasMountpoint,
1303
			$expr->andX(
1304
				$expr->eq($aliasMountpoint . '.mount_id', $aliasMount . '.mount_id'),
1305
				$expr->eq($aliasMountpoint . '.single_id', $aliasMountMemberships . '.single_id')
1306
			)
1307
		);
1308
1309
		$this->selectAlias($aliasMountpoint . '.mountpoint', $aliasMountpoint . '_mountpoint');
1310
		$this->selectAlias($aliasMountpoint . '.mountpoint_hash', $aliasMountpoint . '_mountpoint_hash');
1311
	}
1312
1313
1314
	/**
1315
	 * @param string $alias
1316
	 * @param array $default
1317
	 *
1318
	 * @return CoreQueryBuilder
1319
	 */
1320
	private function generateCircleSelectAlias(string $alias, array $default = []): self {
1321
		$this->generateSelectAlias(
1322
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_CIRCLE],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1323
			$alias,
1324
			$alias,
1325
			$default
1326
		);
1327
1328
		return $this;
1329
	}
1330
1331
	/**
1332
	 * @param string $alias
1333
	 * @param array $default
1334
	 *
1335
	 * @return $this
1336
	 */
1337
	private function generateMemberSelectAlias(string $alias, array $default = []): self {
1338
		$this->generateSelectAlias(
1339
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_MEMBER],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1340
			$alias,
1341
			$alias,
1342
			$default
1343
		);
1344
1345
		return $this;
1346
	}
1347
1348
1349
	/**
1350
	 * @param string $alias
1351
	 * @param array $default
1352
	 * @param string $prefix
1353
	 *
1354
	 * @return $this
1355
	 */
1356
	private function generateMembershipSelectAlias(
1357
		string $alias,
1358
		string $prefix = '',
1359
		array $default = []
1360
	): self {
1361
		$this->generateSelectAlias(
1362
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_MEMBERSHIP],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1363
			$alias,
1364
			($prefix === '') ? $alias : $prefix,
1365
			$default
1366
		);
1367
1368
		return $this;
1369
	}
1370
1371
1372
	/**
1373
	 * @param string $alias
1374
	 * @param array $default
1375
	 *
1376
	 * @return $this
1377
	 */
1378
	private function generateRemoteInstanceSelectAlias(string $alias, array $default = []): self {
1379
		$this->generateSelectAlias(
1380
			CoreRequestBuilder::$tables[CoreRequestBuilder::TABLE_REMOTE],
0 ignored issues
show
Bug introduced by
The property tables cannot be accessed from this context as it is declared private in class OCA\Circles\Db\CoreRequestBuilder.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1381
			$alias,
1382
			$alias,
1383
			$default
1384
		);
1385
1386
		return $this;
1387
	}
1388
1389
1390
	/**
1391
	 * @param array $path
1392
	 * @param array $options
1393
	 */
1394
	public function setOptions(array $path, array $options): void {
1395
		$options = [self::OPTIONS => $options];
1396
		foreach (array_reverse($path) as $item) {
1397
			$options = [$item => $options];
1398
		}
1399
1400
		$this->options = $options;
1401
	}
1402
1403
1404
	/**
1405
	 * @param string $base
1406
	 * @param string $extension
1407
	 * @param array|null $options
1408
	 *
1409
	 * @return string
1410
	 * @throws RequestBuilderException
1411
	 */
1412
	public function generateAlias(string $base, string $extension, ?array &$options = []): string {
1413
		$search = str_replace('_', '.', $base);
1414
		$path = $search . '.' . $extension;
1415
		if (!$this->validKey($path, self::$SQL_PATH)
1416
			&& !in_array($extension, $this->getArray($search, self::$SQL_PATH))) {
1417
			throw new RequestBuilderException($extension . ' not found in ' . $search);
1418
		}
1419
1420
		if (!is_array($options)) {
1421
			$options = [];
1422
		}
1423
1424
		$optionPath = '';
1425
		foreach (explode('.', $path) as $p) {
1426
			$optionPath = trim($optionPath . '.' . $p, '.');
1427
			$options = array_merge(
1428
				$options,
1429
				$this->getArray($optionPath . '.' . self::OPTIONS, self::$SQL_PATH),
1430
				$this->getArray($optionPath . '.' . self::OPTIONS, $this->options)
1431
			);
1432
		}
1433
1434
		return $base . '_' . $extension;
1435
	}
1436
1437
1438
	/**
1439
	 * @param string $prefix
1440
	 *
1441
	 * @return array
1442
	 */
1443
	public function getAvailablePath(string $prefix): array {
1444
		$prefix = trim($prefix, '_');
1445
		$search = str_replace('_', '.', $prefix);
1446
1447
		$path = [];
1448
		foreach ($this->getArray($search, self::$SQL_PATH) as $arr => $item) {
1449
			if (is_numeric($arr)) {
1450
				$k = $item;
1451
			} else {
1452
				$k = $arr;
1453
			}
1454
			$path[$k] = $prefix . '_' . $k . '_';
1455
		}
1456
1457
		return $path;
1458
	}
1459
1460
}
1461
1462