Completed
Push — master ( 2079de...41fdc1 )
by Maxence
02:55
created

CirclesRequestBuilder::generateLimit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 1
eloc 7
nc 1
nop 5
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\Query\QueryBuilder;
32
use OC\L10N\L10N;
33
use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
34
use OCA\Circles\Model\Circle;
35
use OCA\Circles\Model\FederatedLink;
36
use OCA\Circles\Model\Member;
37
use OCA\Circles\Model\SharingFrame;
38
use OCA\Circles\Service\ConfigService;
39
use OCA\Circles\Service\MiscService;
40
use OCP\DB\QueryBuilder\IQueryBuilder;
41
use OCP\IDBConnection;
42
43
class CirclesRequestBuilder extends CoreRequestBuilder {
44
45
46
	/** @var MembersRequest */
47
	protected $membersRequest;
48
49
	/**
50
	 * CirclesRequestBuilder constructor.
51
	 *
52
	 * {@inheritdoc}
53
	 * @param MembersRequest $membersRequest
54
	 */
55
	public function __construct(
56
		L10N $l10n, IDBConnection $connection, MembersRequest $membersRequest,
57
		ConfigService $configService, MiscService $miscService
58
	) {
59
		parent::__construct($l10n, $connection, $configService, $miscService);
60
		$this->membersRequest = $membersRequest;
61
	}
62
63
64
	/**
65
	 * Left Join the Groups table
66
	 *
67
	 * @param IQueryBuilder $qb
68
	 * @param string $field
69
	 */
70
	protected function leftJoinGroups(IQueryBuilder &$qb, $field) {
71
		$expr = $qb->expr();
72
73
		$qb->leftJoin(
74
			$this->default_select_alias, CoreRequestBuilder::TABLE_GROUPS, 'g',
75
			$expr->eq($field, 'g.circle_id')
76
		);
77
	}
78
79
	/**
80
	 * Limit the search to a non-personal circle
81
	 *
82
	 * @param IQueryBuilder $qb
83
	 */
84
	protected function limitToNonPersonalCircle(IQueryBuilder &$qb) {
85
		$expr = $qb->expr();
86
87
		$qb->andWhere(
88
			$expr->neq('c.type', $qb->createNamedParameter(Circle::CIRCLES_PERSONAL))
89
		);
90
	}
91
92
93
	/**
94
	 * @param IQueryBuilder $qb
95
	 * @param string $circleUniqueId
96
	 * @param $userId
97
	 * @param $type
98
	 * @param $name
99
	 *
100
	 * @throws ConfigNoCircleAvailableException
101
	 */
102
	protected function limitRegardingCircleType(
103
		IQueryBuilder &$qb, $userId, $circleUniqueId, $type, $name
104
	) {
105
		$orTypes = $this->generateLimit($qb, $circleUniqueId, $userId, $type, $name);
106
		if (sizeof($orTypes) === 0) {
107
			throw new ConfigNoCircleAvailableException(
108
				$this->l10n->t(
109
					'You cannot use the Circles Application until your administrator has allowed at least one type of circles'
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 111 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
110
				)
111
			);
112
		}
113
114
		$orXTypes = $qb->expr()
115
					   ->orX();
116
		foreach ($orTypes as $orType) {
117
			$orXTypes->add($orType);
118
		}
119
120
		$qb->andWhere($orXTypes);
121
	}
122
123
124
	/**
125
	 * @param IQueryBuilder $qb
126
	 * @param string $circleUniqueId
127
	 * @param $userId
128
	 * @param $type
129
	 * @param $name
130
	 *
131
	 * @return array
132
	 */
133
	private function generateLimit(IQueryBuilder &$qb, $circleUniqueId, $userId, $type, $name) {
134
		$orTypes = [];
135
		array_push($orTypes, $this->generateLimitPersonal($qb, $userId, $type));
136
		array_push($orTypes, $this->generateLimitSecret($qb, $circleUniqueId, $type, $name));
137
		array_push($orTypes, $this->generateLimitClosed($qb, $type));
138
		array_push($orTypes, $this->generateLimitPublic($qb, $type));
139
140
		return array_filter($orTypes);
141
	}
142
143
144
	/**
145
	 * @param IQueryBuilder $qb
146
	 * @param int|string $userId
147
	 * @param int $type
148
	 *
149
	 * @return \OCP\DB\QueryBuilder\ICompositeExpression
150
	 */
151
	private function generateLimitPersonal(IQueryBuilder $qb, $userId, $type) {
152
		if (!(Circle::CIRCLES_PERSONAL & (int)$type)) {
153
			return null;
154
		}
155
		$expr = $qb->expr();
156
157
		/** @noinspection PhpMethodParametersCountMismatchInspection */
158
		return $expr->andX(
159
			$expr->eq('c.type', $qb->createNamedParameter(Circle::CIRCLES_PERSONAL)),
160
			$expr->eq('o.user_id', $qb->createNamedParameter((string)$userId))
161
		);
162
	}
163
164
165
	/**
166
	 * @param IQueryBuilder $qb
167
	 * @param string $circleUniqueId
168
	 * @param int $type
169
	 * @param string $name
170
	 *
171
	 * @return string
172
	 */
173
	private function generateLimitSecret(IQueryBuilder $qb, $circleUniqueId, $type, $name) {
174
		if (!(Circle::CIRCLES_SECRET & (int)$type)) {
175
			return null;
176
		}
177
		$expr = $qb->expr();
178
179
		$orX = $expr->orX($expr->gte('u.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
180
		$orX->add($expr->eq('c.name', $qb->createNamedParameter($name)))
181
			->add(
182
				$expr->eq(
183
					$qb->createNamedParameter($circleUniqueId),
184
					$qb->createFunction(
185
						'SUBSTR(`c`.`unique_id`, 1, ' . Circle::UNIQUEID_SHORT_LENGTH . ')'
186
					)
187
				)
188
			);
189
190
		if ($this->leftJoinedNCGroupAndUser) {
191
			$orX->add($expr->gte('g.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
192
		}
193
194
		/** @noinspection PhpMethodParametersCountMismatchInspection */
195
		$sqb = $expr->andX(
196
			$expr->eq('c.type', $qb->createNamedParameter(Circle::CIRCLES_SECRET)),
197
			$expr->orX($orX)
198
		);
199
200
		return $sqb;
201
	}
202
203
204
	/**
205
	 * @param IQueryBuilder $qb
206
	 * @param int $type
207
	 *
208
	 * @return string
209
	 */
210 View Code Duplication
	private function generateLimitClosed(IQueryBuilder $qb, $type) {
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...
211
		if (!(Circle::CIRCLES_CLOSED & (int)$type)) {
212
			return null;
213
		}
214
215
		return $qb->expr()
216
				  ->eq(
217
					  'c.type',
218
					  $qb->createNamedParameter(Circle::CIRCLES_CLOSED)
219
				  );
220
	}
221
222
223
	/**
224
	 * @param IQueryBuilder $qb
225
	 * @param int $type
226
	 *
227
	 * @return string
228
	 */
229 View Code Duplication
	private function generateLimitPublic(IQueryBuilder $qb, $type) {
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...
230
		if (!(Circle::CIRCLES_PUBLIC & (int)$type)) {
231
			return null;
232
		}
233
234
		return $qb->expr()
235
				  ->eq(
236
					  'c.type',
237
					  $qb->createNamedParameter(Circle::CIRCLES_PUBLIC)
238
				  );
239
	}
240
241
242
	/**
243
	 * add a request to the members list, using the current user ID.
244
	 * will returns level and stuff.
245
	 *
246
	 * @param IQueryBuilder $qb
247
	 * @param string $userId
248
	 */
249 View Code Duplication
	protected function leftJoinUserIdAsViewer(IQueryBuilder &$qb, $userId) {
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...
250
251
		if ($qb->getType() !== QueryBuilder::SELECT) {
252
			return;
253
		}
254
255
		$expr = $qb->expr();
256
		$pf = '`' . $this->default_select_alias . '`.';
257
258
		/** @noinspection PhpMethodParametersCountMismatchInspection */
259
		$qb->selectAlias('u.user_id', 'viewer_userid')
260
		   ->selectAlias('u.status', 'viewer_status')
261
		   ->selectAlias('u.level', 'viewer_level')
262
		   ->leftJoin(
263
			   $this->default_select_alias, CoreRequestBuilder::TABLE_MEMBERS, 'u',
264
			   $expr->andX(
265
				   $expr->eq(
266
					   'u.circle_id',
267
					   $qb->createFunction(
268
						   'SUBSTR(' . $pf . '`unique_id`, 1, ' . Circle::UNIQUEID_SHORT_LENGTH
269
						   . ')'
270
					   )
271
				   ),
272
				   $expr->eq('u.user_id', $qb->createNamedParameter($userId)),
273
				   $expr->eq('u.user_type', $qb->createNamedParameter(Member::TYPE_USER))
274
			   )
275
		   );
276
	}
277
278
	/**
279
	 * Left Join members table to get the owner of the circle.
280
	 *
281
	 * @param IQueryBuilder $qb
282
	 */
283 View Code Duplication
	protected function leftJoinOwner(IQueryBuilder &$qb) {
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...
284
285
		if ($qb->getType() !== QueryBuilder::SELECT) {
286
			return;
287
		}
288
289
		$expr = $qb->expr();
290
		$pf = '`' . $this->default_select_alias . '`.';
291
292
		/** @noinspection PhpMethodParametersCountMismatchInspection */
293
		$qb->selectAlias('o.user_id', 'owner_userid')
294
		   ->selectAlias('o.status', 'owner_status')
295
		   ->selectAlias('o.level', 'owner_level')
296
		   ->leftJoin(
297
			   $this->default_select_alias, CoreRequestBuilder::TABLE_MEMBERS, 'o',
298
			   $expr->andX(
299
				   $expr->eq(
300
					   $qb->createFunction(
301
						   'SUBSTR(' . $pf . '`unique_id`, 1, ' . Circle::UNIQUEID_SHORT_LENGTH
302
						   . ')'
303
					   )
304
					   , 'o.circle_id'
305
				   ),
306
				   $expr->eq('o.level', $qb->createNamedParameter(Member::LEVEL_OWNER)),
307
				   $expr->eq('o.user_type', $qb->createNamedParameter(Member::TYPE_USER))
308
			   )
309
		   );
310
	}
311
312
313
	/**
314
	 * Left Join circle table to get more information about the circle.
315
	 *
316
	 * @param IQueryBuilder $qb
317
	 */
318
	protected function leftJoinCircle(IQueryBuilder &$qb) {
319
320
		if ($qb->getType() !== QueryBuilder::SELECT) {
321
			return;
322
		}
323
324
		$expr = $qb->expr();
325
		$pf = $this->default_select_alias . '.';
326
327
		/** @noinspection PhpMethodParametersCountMismatchInspection */
328
		$qb->selectAlias('lc.type', 'circle_type')
329
		   ->selectAlias('lc.name', 'circle_name')
330
		   ->leftJoin(
331
			   $this->default_select_alias, CoreRequestBuilder::TABLE_CIRCLES, 'lc',
332
			   $expr->eq($pf . 'circle_id', 'lc.id')
333
		   );
334
	}
335
336
337
	/**
338
	 * Base of the Sql Select request for Shares
339
	 *
340
	 * @return IQueryBuilder
341
	 */
342
	protected function getLinksSelectSql() {
343
		$qb = $this->dbConnection->getQueryBuilder();
344
345
		/** @noinspection PhpMethodParametersCountMismatchInspection */
346
		$qb->select('id', 'status', 'address', 'token', 'circle_id', 'unique_id', 'creation')
347
		   ->from(self::TABLE_LINKS, 'l');
348
349
		$this->default_select_alias = 'l';
350
351
		return $qb;
352
	}
353
354
355
	/**
356
	 * Base of the Sql Select request for Shares
357
	 *
358
	 * @return IQueryBuilder
359
	 */
360
	protected function getSharesSelectSql() {
361
		$qb = $this->dbConnection->getQueryBuilder();
362
363
		/** @noinspection PhpMethodParametersCountMismatchInspection */
364
		$qb->select(
365
			's.circle_id', 's.source', 's.type', 's.author', 's.cloud_id', 's.payload',
366
			's.creation', 's.headers', 's.unique_id'
367
		)
368
		   ->from(self::TABLE_SHARES, 's');
369
370
		$this->default_select_alias = 's';
371
372
		return $qb;
373
	}
374
375
376
	/**
377
	 * Base of the Sql Insert request for Shares
378
	 *
379
	 * @return IQueryBuilder
380
	 */
381 View Code Duplication
	protected function getSharesInsertSql() {
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...
382
		$qb = $this->dbConnection->getQueryBuilder();
383
		$qb->insert(self::TABLE_SHARES)
384
		   ->setValue('creation', $qb->createFunction('NOW()'));
385
386
		return $qb;
387
	}
388
389
390
	/**
391
	 * Base of the Sql Update request for Shares
392
	 *
393
	 * @param string $uniqueId
394
	 *
395
	 * @return IQueryBuilder
396
	 */
397 View Code Duplication
	protected function getSharesUpdateSql($uniqueId) {
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...
398
		$qb = $this->dbConnection->getQueryBuilder();
399
		$qb->update(self::TABLE_SHARES)
400
		   ->where(
401
			   $qb->expr()
402
				  ->eq('unique_id', $qb->createNamedParameter((string)$uniqueId))
403
		   );
404
405
		return $qb;
406
	}
407
408
409
	/**
410
	 * Base of the Sql Insert request for Shares
411
	 *
412
	 *
413
	 * @return IQueryBuilder
414
	 */
415 View Code Duplication
	protected function getCirclesInsertSql() {
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...
416
		$qb = $this->dbConnection->getQueryBuilder();
417
		$qb->insert(self::TABLE_CIRCLES)
418
		   ->setValue('creation', $qb->createFunction('NOW()'));
419
420
		return $qb;
421
	}
422
423
424
	/**
425
	 * Base of the Sql Update request for Shares
426
	 *
427
	 * @param int $uniqueId
428
	 *
429
	 * @return IQueryBuilder
430
	 */
431 View Code Duplication
	protected function getCirclesUpdateSql($uniqueId) {
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...
432
		$qb = $this->dbConnection->getQueryBuilder();
433
		$qb->update(self::TABLE_CIRCLES)
434
		   ->where(
435
			   $qb->expr()
436
				  ->eq('unique_id', $qb->createNamedParameter($uniqueId))
437
		   );
438
439
		return $qb;
440
	}
441
442
443
	/**
444
	 * Base of the Sql Delete request
445
	 *
446
	 * @param string $circleUniqueId
447
	 *
448
	 * @return IQueryBuilder
449
	 */
450 View Code Duplication
	protected function getCirclesDeleteSql($circleUniqueId) {
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...
451
		$qb = $this->dbConnection->getQueryBuilder();
452
		$qb->delete(self::TABLE_CIRCLES)
453
		   ->where(
454
			   $qb->expr()
455
				  ->eq(
456
					  $qb->createFunction(
457
						  'SUBSTR(`unique_id`, 1, ' . Circle::UNIQUEID_SHORT_LENGTH . ')'
458
					  ),
459
					  $qb->createNamedParameter($circleUniqueId)
460
				  )
461
		   );
462
463
		return $qb;
464
	}
465
466
467
	/**
468
	 * @return IQueryBuilder
469
	 */
470
	protected function getCirclesSelectSql() {
471
		$qb = $this->dbConnection->getQueryBuilder();
472
473
		/** @noinspection PhpMethodParametersCountMismatchInspection */
474
		$qb->selectDistinct('c.unique_id')
475
		   ->addSelect(
476
			   'c.id', 'c.name', 'c.description', 'c.settings', 'c.type', 'c.creation'
477
		   )
478
		   ->from(CoreRequestBuilder::TABLE_CIRCLES, 'c');
479
		$this->default_select_alias = 'c';
480
481
		return $qb;
482
	}
483
484
485
	/**
486
	 * @param array $data
487
	 *
488
	 * @return Circle
489
	 */
490
	protected function parseCirclesSelectSql($data) {
491
492
		$circle = new Circle();
493
		$circle->setId($data['id']);
494
		$circle->setUniqueId($data['unique_id']);
495
		$circle->setName($data['name']);
496
		$circle->setDescription($data['description']);
497
		$circle->setSettings($data['settings']);
498
		$circle->setType($data['type']);
499
		$circle->setCreation($data['creation']);
500
501 View Code Duplication
		if (key_exists('viewer_level', $data)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
502
			$user = new Member($data['viewer_userid'], Member::TYPE_USER, $circle->getUniqueId());
503
			$user->setStatus($data['viewer_status']);
504
			$user->setLevel($data['viewer_level']);
505
			$circle->setViewer($user);
506
		}
507
508 View Code Duplication
		if (key_exists('owner_level', $data)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
509
			$owner = new Member($data['owner_userid'], Member::TYPE_USER, $circle->getUniqueId());
510
			$owner->setStatus($data['owner_status']);
511
			$owner->setLevel($data['owner_level']);
512
			$circle->setOwner($owner);
513
		}
514
515
		return $circle;
516
	}
517
518
519
	/**
520
	 * @param array $data
521
	 *
522
	 * @return SharingFrame
523
	 */
524
	protected function parseSharesSelectSql($data) {
525
		$frame = new SharingFrame($data['source'], $data['type']);
526
527
		$circle = new Circle();
528
		$circle->setUniqueId($data['circle_id']);
529
		if (key_exists('circle_type', $data)) {
530
			$circle->setType($data['circle_type']);
531
			$circle->setName($data['circle_name']);
532
		}
533
534
		$frame->setCircle($circle);
535
536
		$frame->setAuthor($data['author']);
537
		$frame->setCloudId($data['cloud_id']);
538
		$frame->setPayload(json_decode($data['payload'], true));
539
		$frame->setCreation($data['creation']);
540
		$frame->setHeaders(json_decode($data['headers'], true));
541
		$frame->setUniqueId($data['unique_id']);
542
543
		return $frame;
544
	}
545
546
547
	/**
548
	 * @param array $data
549
	 *
550
	 * @return FederatedLink
551
	 */
552
	protected function parseLinksSelectSql($data) {
553
		$link = new FederatedLink();
554
		$link->setId($data['id'])
555
			 ->setUniqueId($data['unique_id'])
556
			 ->setStatus($data['status'])
557
			 ->setCreation($data['creation'])
558
			 ->setAddress($data['address'])
559
			 ->setToken($data['token'])
560
			 ->setCircleId($data['circle_id']);
561
562
		return $link;
563
	}
564
565
566
}