Completed
Push — master ( 9a7804...897cf1 )
by Maxence
03:04
created

leftJoinShareInitiator()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 18
nc 1
nop 1
1
<?php
2
3
/**
4
 * Circles - Bring cloud-users closer together.
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Maxence Lange <[email protected]>
10
 * @copyright 2017
11
 * @license GNU AGPL version 3 or any later version
12
 *
13
 * This program is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License as
15
 * published by the Free Software Foundation, either version 3 of the
16
 * License, or (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 */
27
28
namespace OCA\Circles\Db;
29
30
31
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
32
use Doctrine\DBAL\Query\QueryBuilder;
33
use OCA\Circles\Model\Circle;
34
use OCA\Circles\Model\Member;
35
use OCP\DB\QueryBuilder\IQueryBuilder;
36
use OCP\IDBConnection;
37
use OCP\Share;
38
use OCP\Share\IShare;
39
40
class CircleProviderRequestBuilder {
41
42
43
	/** @var IDBConnection */
44
	protected $dbConnection;
45
46
47
	/**
48
	 * returns the SQL request to get a specific share from the fileId and circleId
49
	 *
50
	 * @param int $fileId
51
	 * @param int $circleId
52
	 *
53
	 * @return IQueryBuilder
54
	 */
55
	protected function findShareParentSql($fileId, $circleId) {
56
57
		$qb = $this->getBaseSelectSql();
58
		$this->limitToShareParent($qb);
59
		$this->limitToCircle($qb, $circleId);
60
		$this->limitToFiles($qb, $fileId);
61
62
		return $qb;
63
	}
64
65
66
	/**
67
	 * Limit the request to a Circle.
68
	 *
69
	 * @param IQueryBuilder $qb
70
	 * @param int $circleId
71
	 */
72
	protected function limitToCircle(IQueryBuilder &$qb, $circleId) {
73
		$expr = $qb->expr();
74
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
75
76
		$qb->andWhere($expr->eq($pf . 'share_with', $qb->createNamedParameter($circleId)));
77
	}
78
79
80
	/**
81
	 * Limit the request to the Share by its Id.
82
	 *
83
	 * @param IQueryBuilder $qb
84
	 * @param $shareId
85
	 */
86
	protected function limitToShare(IQueryBuilder &$qb, $shareId) {
87
		$expr = $qb->expr();
88
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
89
90
		$qb->andWhere($expr->eq($pf . 'id', $qb->createNamedParameter($shareId)));
91
	}
92
93
94
	/**
95
	 * Limit the request to the top share (no children)
96
	 *
97
	 * @param IQueryBuilder $qb
98
	 */
99
	protected function limitToShareParent(IQueryBuilder &$qb) {
100
		$expr = $qb->expr();
101
102
		$qb->andWhere($expr->isNull('parent'));
103
	}
104
105
106
	/**
107
	 * limit the request to the children of a share
108
	 *
109
	 * @param IQueryBuilder $qb
110
	 * @param $userId
111
	 * @param int $parentId
112
	 */
113
	protected function limitToShareChildren(IQueryBuilder &$qb, $userId, $parentId = -1) {
114
		$expr = $qb->expr();
115
		$qb->andWhere($expr->eq('share_with', $qb->createNamedParameter($userId)));
116
117
		if ($parentId > -1) {
118
			$qb->andWhere($expr->eq('parent', $qb->createNamedParameter($parentId)));
119
		} else {
120
			$qb->andWhere($expr->isNotNull('parent'));
121
		}
122
	}
123
124
125
	/**
126
	 * limit the request to the share itself AND its children.
127
	 * perfect if you want to delete everything related to a share
128
	 *
129
	 * @param IQueryBuilder $qb
130
	 * @param $circleId
131
	 */
132
	protected function limitToShareAndChildren(IQueryBuilder &$qb, $circleId) {
133
		$expr = $qb->expr();
134
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
135
136
		/** @noinspection PhpMethodParametersCountMismatchInspection */
137
		$qb->andWhere(
138
			$expr->orX(
139
				$expr->eq($pf . 'parent', $qb->createNamedParameter($circleId)),
140
				$expr->eq($pf . 'id', $qb->createNamedParameter($circleId))
141
			)
142
		);
143
	}
144
145
146
	/**
147
	 * limit the request to a fileId.
148
	 *
149
	 * @param IQueryBuilder $qb
150
	 * @param $files
151
	 *
152
	 * @internal param $fileId
153
	 */
154
	protected function limitToFiles(IQueryBuilder &$qb, $files) {
155
156
		if (!is_array($files)) {
157
			$files = array($files);
158
		}
159
160
		$expr = $qb->expr();
161
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
162
		$qb->andWhere(
163
			$expr->in(
164
				$pf . 'file_source',
165
				$qb->createNamedParameter($files, IQueryBuilder::PARAM_INT_ARRAY)
166
			)
167
		);
168
	}
169
170
171
	/**
172
	 * @param IQueryBuilder $qb
173
	 * @param int $limit
174
	 * @param int $offset
175
	 */
176
	protected function limitToPage(IQueryBuilder &$qb, $limit = -1, $offset = 0) {
177
		if ($limit !== -1) {
178
			$qb->setMaxResults($limit);
179
		}
180
181
		$qb->setFirstResult($offset);
182
	}
183
184
185
	/**
186
	 * limit the request to a userId
187
	 *
188
	 * @param IQueryBuilder $qb
189
	 * @param string $userId
190
	 * @param bool $reShares
191
	 */
192
	protected function limitToShareOwner(IQueryBuilder &$qb, $userId, $reShares = false) {
193
		$expr = $qb->expr();
194
		$pf = ($qb->getType() === QueryBuilder::SELECT) ? 's.' : '';
195
196
		if ($reShares === false) {
197
			$qb->andWhere($expr->eq($pf . 'uid_initiator', $qb->createNamedParameter($userId)));
198
		} else {
199
			/** @noinspection PhpMethodParametersCountMismatchInspection */
200
			$qb->andWhere(
201
				$expr->orX(
202
					$expr->eq($pf . 'uid_owner', $qb->createNamedParameter($userId)),
203
					$expr->eq($pf . 'uid_initiator', $qb->createNamedParameter($userId))
204
				)
205
			);
206
		}
207
	}
208
209
210
	/**
211
	 * link circle field
212
	 *
213
	 * @deprecated
214
	 *
215
	 * @param IQueryBuilder $qb
216
	 * @param int $shareId
217
	 */
218
	protected function linkCircleField(IQueryBuilder &$qb, $shareId = -1) {
219
		$expr = $qb->expr();
220
221
		$qb->from(CoreRequestBuilder::TABLE_CIRCLES, 'c');
222
223
		$tmpOrX = $expr->eq(
224
			's.share_with',
225
			$qb->createFunction('LEFT(c.unique_id, ' . Circle::UNIQUEID_SHORT_LENGTH . ')')
226
		);
227
228
		if ($shareId === -1) {
229
			$qb->andWhere($tmpOrX);
230
231
			return;
232
		}
233
234
		/** @noinspection PhpMethodParametersCountMismatchInspection */
235
		$qb->andWhere(
236
			$expr->orX(
237
				$tmpOrX,
238
				$expr->eq('s.parent', $qb->createNamedParameter($shareId))
239
			)
240
		);
241
	}
242
243
244
	/**
245
	 * @param IQueryBuilder $qb
246
	 */
247
	protected function linkToCircleOwner(IQueryBuilder &$qb) {
248
		$expr = $qb->expr();
249
250
		/** @noinspection PhpMethodParametersCountMismatchInspection */
251
		$qb->leftJoin(
252
			'c', 'circles_members', 'mo', $expr->andX(
253
			$expr->eq(
254
				'mo.circle_id',
255
				$qb->createFunction('LEFT(c.unique_id, ' . Circle::UNIQUEID_SHORT_LENGTH . ')')
256
			),
257
			$expr->eq('mo.level', $qb->createNamedParameter(Member::LEVEL_OWNER))
258
		)
259
		);
260
	}
261
262
263
	/**
264
	 * Link to member (userId) of circle
265
	 *
266
	 * @param IQueryBuilder $qb
267
	 * @param string $userId
268
	 * @param bool $groupMemberAllowed
269
	 */
270
	protected function linkToMember(IQueryBuilder &$qb, $userId, $groupMemberAllowed) {
271
		$expr = $qb->expr();
272
273
		$qb->from(CoreRequestBuilder::TABLE_MEMBERS, 'm');
274
275
276
		$orX = $expr->orX();
277
		$orX->add($this->exprLinkToMemberAsCircleMember($qb, $userId));
278
		if ($groupMemberAllowed === true) {
279
			$orX->add($this->exprLinkToMemberAsGroupMember($qb, $userId));
280
		}
281
282
		$qb->andWhere($orX);
283
284
	}
285
286
287
	/**
288
	 * generate CompositeExpression to link to a Member as a Real Circle Member
289
	 *
290
	 * @param IQueryBuilder $qb
291
	 * @param string $userId
292
	 *
293
	 * @return \OCP\DB\QueryBuilder\ICompositeExpression
294
	 */
295
	private function exprLinkToMemberAsCircleMember(IQueryBuilder &$qb, $userId) {
296
297
		$expr = $qb->expr();
298
		$andX = $expr->andX();
299
300
		$andX->add($expr->eq('m.user_id', $qb->createNamedParameter($userId)));
301
		$andX->add(
302
			$expr->eq(
303
				'm.circle_id',
304
				$qb->createFunction(
305
					'LEFT(c.unique_id, ' . Circle::UNIQUEID_SHORT_LENGTH . ')'
306
				)
307
			)
308
		);
309
		$andX->add($expr->gte('m.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
310
311
		return $andX;
312
	}
313
314
315
	/**
316
	 * generate CompositeExpression to link to a Member as a Group Member (core NC)
317
	 *
318
	 * @param IQueryBuilder $qb
319
	 * @param string $userId
320
	 *
321
	 * @return \OCP\DB\QueryBuilder\ICompositeExpression
322
	 */
323
	private function exprLinkToMemberAsGroupMember(IQueryBuilder &$qb, $userId) {
324
		$expr = $qb->expr();
325
326
327
		$qb->leftJoin(
328
			'c', CoreRequestBuilder::TABLE_GROUPS, 'g',
329
			$expr->andX(
330
				$expr->eq(
331
					'g.circle_id',
332
					$qb->createFunction('LEFT(c.unique_id, ' . Circle::UNIQUEID_SHORT_LENGTH . ')')
333
				),
334
				$expr->gte('g.level', $qb->createNamedParameter(Member::LEVEL_MEMBER))
335
			)
336
		);
337
338
		$qb->leftJoin(
339
			'g', CoreRequestBuilder::NC_TABLE_GROUP_USER, 'ncgu',
340
			$expr->eq('ncgu.gid', 'g.group_id')
341
		);
342
343
		return $expr->andX($expr->eq('ncgu.uid', $qb->createNamedParameter($userId)));
344
	}
345
346
347
	/**
348
	 * left join to get more data about the initiator of the share
349
	 *
350
	 * @param IQueryBuilder $qb
351
	 */
352
	protected function leftJoinShareInitiator(IQueryBuilder &$qb) {
353
		$expr = $qb->expr();
354
355
		$qb->selectAlias('src_m.level', 'initiator_circle_level');
356
		/** @noinspection PhpMethodParametersCountMismatchInspection */
357
		$qb->leftJoin(
358
			's', CoreRequestBuilder::TABLE_MEMBERS, 'src_m',
359
			$expr->andX(
360
				$expr->eq('s.uid_initiator', 'src_m.user_id'),
361
				$expr->eq('s.share_with', 'src_m.circle_id')
362
			)
363
		);
364
365
		$qb->selectAlias('src_g.level', 'initiator_group_level');
366
		$qb->leftJoin(
367
			's', CoreRequestBuilder::NC_TABLE_GROUP_USER, 'src_ncgu',
368
			$expr->eq('s.uid_initiator', 'src_ncgu.uid')
369
		);
370
		/** @noinspection PhpMethodParametersCountMismatchInspection */
371
		$qb->leftJoin(
372
			's', 'circles_groups', 'src_g',
373
			$expr->andX(
374
				$expr->gte('src_g.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)),
375
				$expr->eq('src_ncgu.gid', 'src_g.group_id'),
376
				$req = $expr->eq('s.share_with', 'src_g.circle_id')
377
			)
378
		);
379
	}
380
381
382
	/**
383
	 * Link to all members of circle
384
	 *
385
	 * @param IQueryBuilder $qb
386
	 */
387
	protected function joinCircleMembers(IQueryBuilder &$qb) {
388
		$expr = $qb->expr();
389
390
		$qb->from(CoreRequestBuilder::TABLE_MEMBERS, 'm');
391
		$qb->andWhere($expr->eq('s.share_with', 'm.circle_id'));
392
	}
393
394
395
	/**
396
	 * Link to storage/filecache
397
	 *
398
	 * @param IQueryBuilder $qb
399
	 * @param string $userId
400
	 */
401
	protected function linkToFileCache(IQueryBuilder &$qb, $userId) {
402
		$expr = $qb->expr();
403
404
		/** @noinspection PhpMethodParametersCountMismatchInspection */
405
		$qb->leftJoin('s', 'filecache', 'f', $expr->eq('s.file_source', 'f.fileid'))
406
		   ->leftJoin('f', 'storages', 'st', $expr->eq('f.storage', 'st.numeric_id'))
407
		   ->leftJoin(
408
			   's', 'share', 's2', $expr->andX(
409
			   $expr->eq('s.id', 's2.parent'),
410
			   $expr->eq('s2.share_with', $qb->createNamedParameter($userId))
411
		   )
412
		   );
413
414
		$qb->selectAlias('s2.id', 'parent_id');
415
		$qb->selectAlias('s2.file_target', 'parent_target');
416
		$qb->selectAlias('s2.permissions', 'parent_perms');
417
418
	}
419
420
421
	/**
422
	 * add share to the database and return the ID
423
	 *
424
	 * @param IShare $share
425
	 *
426
	 * @return IQueryBuilder
427
	 */
428
	protected function getBaseInsertSql($share) {
429
		$qb = $this->dbConnection->getQueryBuilder();
430
		$qb->insert('share')
431
		   ->setValue('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE))
432
		   ->setValue('item_type', $qb->createNamedParameter($share->getNodeType()))
433
		   ->setValue('item_source', $qb->createNamedParameter($share->getNodeId()))
434
		   ->setValue('file_source', $qb->createNamedParameter($share->getNodeId()))
435
		   ->setValue('file_target', $qb->createNamedParameter($share->getTarget()))
436
		   ->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()))
437
		   ->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
438
		   ->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
439
		   ->setValue('permissions', $qb->createNamedParameter($share->getPermissions()))
440
		   ->setValue('token', $qb->createNamedParameter($share->getToken()))
441
		   ->setValue('stime', $qb->createFunction('UNIX_TIMESTAMP()'));
442
443
		return $qb;
444
	}
445
446
447
	/**
448
	 * generate and return a base sql request.
449
	 *
450
	 * @param int $shareId
451
	 *
452
	 * @return IQueryBuilder
453
	 */
454
	protected function getBaseSelectSql($shareId = -1) {
455
		$qb = $this->dbConnection->getQueryBuilder();
456
457
		/** @noinspection PhpMethodParametersCountMismatchInspection */
458
		$qb->select(
459
			's.id', 's.share_type', 's.share_with', 's.uid_owner', 's.uid_initiator',
460
			's.parent', 's.item_type', 's.item_source', 's.item_target', 's.file_source',
461
			's.file_target', 's.permissions', 's.stime', 's.accepted', 's.expiration',
462
			's.token', 's.mail_send', 'c.type AS circle_type', 'c.name AS circle_name',
463
			'mo.user_id AS circle_owner'
464
		);
465
		$this->linkToCircleOwner($qb);
466
		$this->joinShare($qb);
467
468
		// TODO: Left-join circle and REMOVE this line
469
		$this->linkCircleField($qb, $shareId);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\Circles\Db\CirclePro...lder::linkCircleField() has been deprecated.

This method has been deprecated.

Loading history...
470
471
		return $qb;
472
	}
473
474
475
	/**
476
	 * Generate and return a base sql request
477
	 * This one should be used to retrieve a complete list of users (ie. access list).
478
	 *
479
	 * @return IQueryBuilder
480
	 */
481
	protected function getAccessListBaseSelectSql() {
482
		$qb = $this->dbConnection->getQueryBuilder();
483
484
		/** @noinspection PhpMethodParametersCountMismatchInspection */
485
		$qb->select(
486
			'm.user_id', 's.file_source', 's.file_target'
487
		);
488
		$this->joinCircleMembers($qb);
489
		$this->joinShare($qb);
490
491
		return $qb;
492
	}
493
494
495
	protected function getCompleteSelectSql() {
496
		$qb = $this->dbConnection->getQueryBuilder();
497
498
		/** @noinspection PhpMethodParametersCountMismatchInspection */
499
		$qb->selectDistinct('s.id')
500
		   ->addSelect(
501
			   's.*', 'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage',
502
			   'f.path_hash', 'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart',
503
			   'f.size', 'f.mtime', 'f.storage_mtime', 'f.encrypted', 'f.unencrypted_size',
504
			   'f.etag', 'f.checksum', 'c.type AS circle_type', 'c.name AS circle_name',
505
			   'mo.user_id AS circle_owner'
506
		   )
507
		   ->selectAlias('st.id', 'storage_string_id');
508
509
510
		$this->linkToCircleOwner($qb);
511
		$this->joinShare($qb);
512
		$this->linkCircleField($qb);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\Circles\Db\CirclePro...lder::linkCircleField() has been deprecated.

This method has been deprecated.

Loading history...
513
514
515
		return $qb;
516
	}
517
518
519
	/**
520
	 * @param IQueryBuilder $qb
521
	 */
522
	private function joinShare(IQueryBuilder &$qb) {
523
		$expr = $qb->expr();
524
525
		/** @noinspection PhpMethodParametersCountMismatchInspection */
526
		$qb->from('share', 's')
527
		   ->where($expr->eq('s.share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)))
528
		   ->andWhere(
529
			   $expr->orX(
530
				   $expr->eq('s.item_type', $qb->createNamedParameter('file')),
531
				   $expr->eq('s.item_type', $qb->createNamedParameter('folder'))
532
			   )
533
		   );
534
	}
535
536
537
	/**
538
	 * generate and return a base sql request.
539
	 *
540
	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
541
	 */
542 View Code Duplication
	protected function getBaseDeleteSql() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
543
		$qb = $this->dbConnection->getQueryBuilder();
544
		$expr = $qb->expr();
545
546
		$qb->delete('share')
547
		   ->where($expr->eq('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)));
548
549
		return $qb;
550
	}
551
552
553
	/**
554
	 * generate and return a base sql request.
555
	 *
556
	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
557
	 */
558 View Code Duplication
	protected function getBaseUpdateSql() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
559
		$qb = $this->dbConnection->getQueryBuilder();
560
		$expr = $qb->expr();
561
562
		$qb->update('share')
563
		   ->where($expr->eq('share_type', $qb->createNamedParameter(Share::SHARE_TYPE_CIRCLE)));
564
565
		return $qb;
566
	}
567
}
568