Completed
Push — master ( f9a32b...1fc0d2 )
by Maxence
04:23
created

CirclesRequestBuilder::parseCirclesSelectSql()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 27
Code Lines 20

Duplication

Lines 12
Ratio 44.44 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 12
loc 27
rs 8.8571
cc 3
eloc 20
nc 4
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\Query\QueryBuilder;
32
use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
33
use OCA\Circles\Model\Circle;
34
use OCA\Circles\Model\Member;
35
use OCA\Circles\Model\SharingFrame;
36
use OCA\Circles\Service\ConfigService;
37
use OCA\Circles\Service\MiscService;
38
use OCP\DB\QueryBuilder\IQueryBuilder;
39
use OCP\IDBConnection;
40
use OCP\IL10N;
41
42
class CirclesRequestBuilder extends CoreRequestBuilder {
43
44
45
	/** @var MembersRequest */
46
	protected $membersRequest;
47
48
	/**
49
	 * CirclesRequestBuilder constructor.
50
	 *
51
	 * {@inheritdoc}
52
	 * @param MembersRequest $membersRequest
53
	 */
54
	public function __construct(
55
		IL10N $l10n, IDBConnection $connection, MembersRequest $membersRequest,
56
		ConfigService $configService, MiscService $miscService
57
	) {
58
		parent::__construct($l10n, $connection, $configService, $miscService);
59
		$this->membersRequest = $membersRequest;
60
	}
61
62
63
	/**
64
	 * Left Join the Groups table
65
	 *
66
	 * @param IQueryBuilder $qb
67
	 * @param string $field
68
	 */
69
	protected function leftJoinGroups(IQueryBuilder &$qb, $field) {
70
		$expr = $qb->expr();
71
72
		$qb->leftJoin(
73
			$this->default_select_alias, CoreRequestBuilder::TABLE_GROUPS, 'g',
74
			$expr->eq($field, 'g.circle_id')
75
		);
76
	}
77
78
	/**
79
	 * Limit the search to a non-personal circle
80
	 *
81
	 * @param IQueryBuilder $qb
82
	 */
83
	protected function limitToNonPersonalCircle(IQueryBuilder &$qb) {
84
		$expr = $qb->expr();
85
86
		$qb->andWhere(
87
			$expr->neq('c.type', $qb->createNamedParameter(Circle::CIRCLES_PERSONAL))
88
		);
89
	}
90
91
92
	/**
93
	 * @param IQueryBuilder $qb
94
	 * @param string $circleUniqueId
95
	 * @param $userId
96
	 * @param $type
97
	 * @param $name
98
	 *
99
	 * @throws ConfigNoCircleAvailableException
100
	 */
101
	protected function limitRegardingCircleType(
102
		IQueryBuilder &$qb, $userId, $circleUniqueId, $type, $name
103
	) {
104
		$orTypes = $this->generateLimit($qb, $circleUniqueId, $userId, $type, $name);
105
		if (sizeof($orTypes) === 0) {
106
			throw new ConfigNoCircleAvailableException(
107
				$this->l10n->t(
108
					'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...
109
				)
110
			);
111
		}
112
113
		$orXTypes = $qb->expr()
114
					   ->orX();
115
		foreach ($orTypes as $orType) {
116
			$orXTypes->add($orType);
117
		}
118
119
		$qb->andWhere($orXTypes);
120
	}
121
122
123
	/**
124
	 * @param IQueryBuilder $qb
125
	 * @param string $circleUniqueId
126
	 * @param $userId
127
	 * @param $type
128
	 * @param $name
129
	 *
130
	 * @return array
131
	 */
132
	private function generateLimit(IQueryBuilder &$qb, $circleUniqueId, $userId, $type, $name) {
133
		$orTypes = [];
134
		array_push($orTypes, $this->generateLimitPersonal($qb, $userId, $type));
135
		array_push($orTypes, $this->generateLimitSecret($qb, $circleUniqueId, $type, $name));
136
		array_push($orTypes, $this->generateLimitClosed($qb, $type));
137
		array_push($orTypes, $this->generateLimitPublic($qb, $type));
138
139
		return array_filter($orTypes);
140
	}
141
142
143
	/**
144
	 * @param IQueryBuilder $qb
145
	 * @param int|string $userId
146
	 * @param int $type
147
	 *
148
	 * @return \OCP\DB\QueryBuilder\ICompositeExpression
149
	 */
150
	private function generateLimitPersonal(IQueryBuilder $qb, $userId, $type) {
151
		if (!(Circle::CIRCLES_PERSONAL & (int)$type)) {
152
			return null;
153
		}
154
		$expr = $qb->expr();
155
156
		/** @noinspection PhpMethodParametersCountMismatchInspection */
157
		return $expr->andX(
158
			$expr->eq('c.type', $qb->createNamedParameter(Circle::CIRCLES_PERSONAL)),
159
			$expr->eq('o.user_id', $qb->createNamedParameter((string)$userId))
160
		);
161
	}
162
163
164
	/**
165
	 * @param IQueryBuilder $qb
166
	 * @param string $circleUniqueId
167
	 * @param int $type
168
	 * @param string $name
169
	 *
170
	 * @return string
171
	 */
172
	private function generateLimitSecret(IQueryBuilder $qb, $circleUniqueId, $type, $name) {
173
		if (!(Circle::CIRCLES_SECRET & (int)$type)) {
174
			return null;
175
		}
176
		$expr = $qb->expr();
177
178
		$orX = $expr->orX($expr->gte('u.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
179
		$orX->add($expr->eq('c.name', $qb->createNamedParameter($name)))
180
			->add(
181
				$expr->eq(
182
					$qb->createNamedParameter($circleUniqueId),
183
					$qb->createFunction(
184
						'SUBSTR(`c`.`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH . ')'
185
					)
186
				)
187
			);
188
189
		if ($this->leftJoinedNCGroupAndUser) {
190
			$orX->add($expr->gte('g.level', $qb->createNamedParameter(Member::LEVEL_MEMBER)));
191
		}
192
193
		/** @noinspection PhpMethodParametersCountMismatchInspection */
194
		$sqb = $expr->andX(
195
			$expr->eq('c.type', $qb->createNamedParameter(Circle::CIRCLES_SECRET)),
196
			$expr->orX($orX)
197
		);
198
199
		return $sqb;
200
	}
201
202
203
	/**
204
	 * @param IQueryBuilder $qb
205
	 * @param int $type
206
	 *
207
	 * @return string
208
	 */
209 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...
210
		if (!(Circle::CIRCLES_CLOSED & (int)$type)) {
211
			return null;
212
		}
213
214
		return $qb->expr()
215
				  ->eq(
216
					  'c.type',
217
					  $qb->createNamedParameter(Circle::CIRCLES_CLOSED)
218
				  );
219
	}
220
221
222
	/**
223
	 * @param IQueryBuilder $qb
224
	 * @param int $type
225
	 *
226
	 * @return string
227
	 */
228 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...
229
		if (!(Circle::CIRCLES_PUBLIC & (int)$type)) {
230
			return null;
231
		}
232
233
		return $qb->expr()
234
				  ->eq(
235
					  'c.type',
236
					  $qb->createNamedParameter(Circle::CIRCLES_PUBLIC)
237
				  );
238
	}
239
240
241
	/**
242
	 * add a request to the members list, using the current user ID.
243
	 * will returns level and stuff.
244
	 *
245
	 * @param IQueryBuilder $qb
246
	 * @param string $userId
247
	 */
248 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...
249
250
		if ($qb->getType() !== QueryBuilder::SELECT) {
251
			return;
252
		}
253
254
		$expr = $qb->expr();
255
		$pf = '`' . $this->default_select_alias . '`.';
256
257
		/** @noinspection PhpMethodParametersCountMismatchInspection */
258
		$qb->selectAlias('u.user_id', 'viewer_userid')
259
		   ->selectAlias('u.status', 'viewer_status')
260
		   ->selectAlias('u.level', 'viewer_level')
261
		   ->leftJoin(
262
			   $this->default_select_alias, CoreRequestBuilder::TABLE_MEMBERS, 'u',
263
			   $expr->andX(
264
				   $expr->eq(
265
					   'u.circle_id',
266
					   $qb->createFunction(
267
						   'SUBSTR(' . $pf . '`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH
268
						   . ')'
269
					   )
270
				   ),
271
				   $expr->eq('u.user_id', $qb->createNamedParameter($userId)),
272
				   $expr->eq('u.user_type', $qb->createNamedParameter(Member::TYPE_USER))
273
			   )
274
		   );
275
	}
276
277
	/**
278
	 * Left Join members table to get the owner of the circle.
279
	 *
280
	 * @param IQueryBuilder $qb
281
	 */
282 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...
283
284
		if ($qb->getType() !== QueryBuilder::SELECT) {
285
			return;
286
		}
287
288
		$expr = $qb->expr();
289
		$pf = '`' . $this->default_select_alias . '`.';
290
291
		/** @noinspection PhpMethodParametersCountMismatchInspection */
292
		$qb->selectAlias('o.user_id', 'owner_userid')
293
		   ->selectAlias('o.status', 'owner_status')
294
		   ->selectAlias('o.level', 'owner_level')
295
		   ->leftJoin(
296
			   $this->default_select_alias, CoreRequestBuilder::TABLE_MEMBERS, 'o',
297
			   $expr->andX(
298
				   $expr->eq(
299
					   $qb->createFunction(
300
						   'SUBSTR(' . $pf . '`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH
301
						   . ')'
302
					   )
303
					   , 'o.circle_id'
304
				   ),
305
				   $expr->eq('o.level', $qb->createNamedParameter(Member::LEVEL_OWNER)),
306
				   $expr->eq('o.user_type', $qb->createNamedParameter(Member::TYPE_USER))
307
			   )
308
		   );
309
	}
310
311
312
	/**
313
	 * Left Join circle table to get more information about the circle.
314
	 *
315
	 * @param IQueryBuilder $qb
316
	 */
317
	protected function leftJoinCircle(IQueryBuilder &$qb) {
318
319
		if ($qb->getType() !== QueryBuilder::SELECT) {
320
			return;
321
		}
322
323
		$expr = $qb->expr();
324
		$pf = $this->default_select_alias . '.';
325
326
		/** @noinspection PhpMethodParametersCountMismatchInspection */
327
		$qb->selectAlias('lc.type', 'circle_type')
328
		   ->selectAlias('lc.name', 'circle_name')
329
		   ->leftJoin(
330
			   $this->default_select_alias, CoreRequestBuilder::TABLE_CIRCLES, 'lc',
331
			   $expr->eq(
332
				   $pf . 'circle_id',
333
				   $qb->createFunction(
334
					   'SUBSTR(`lc`.`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH . ')'
335
				   )
336
			   )
337
		   );
338
	}
339
340
341
	/**
342
	 * Base of the Sql Select request for Shares
343
	 *
344
	 * @return IQueryBuilder
345
	 */
346
	protected function getSharesSelectSql() {
347
		$qb = $this->dbConnection->getQueryBuilder();
348
349
		/** @noinspection PhpMethodParametersCountMismatchInspection */
350
		$qb->select(
351
			's.circle_id', 's.source', 's.type', 's.author', 's.cloud_id', 's.payload',
352
			's.creation', 's.headers', 's.unique_id'
353
		)
354
		   ->from(self::TABLE_SHARES, 's');
355
356
		$this->default_select_alias = 's';
357
358
		return $qb;
359
	}
360
361
362
	/**
363
	 * Base of the Sql Insert request for Shares
364
	 *
365
	 * @return IQueryBuilder
366
	 */
367 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...
368
		$qb = $this->dbConnection->getQueryBuilder();
369
		$qb->insert(self::TABLE_SHARES)
370
		   ->setValue('creation', $qb->createFunction('NOW()'));
371
372
		return $qb;
373
	}
374
375
376
	/**
377
	 * Base of the Sql Update request for Shares
378
	 *
379
	 * @param string $uniqueId
380
	 *
381
	 * @return IQueryBuilder
382
	 */
383 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...
384
		$qb = $this->dbConnection->getQueryBuilder();
385
		$qb->update(self::TABLE_SHARES)
386
		   ->where(
387
			   $qb->expr()
388
				  ->eq('unique_id', $qb->createNamedParameter((string)$uniqueId))
389
		   );
390
391
		return $qb;
392
	}
393
394
395
	/**
396
	 * Base of the Sql Insert request for Shares
397
	 *
398
	 *
399
	 * @return IQueryBuilder
400
	 */
401 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...
402
		$qb = $this->dbConnection->getQueryBuilder();
403
		$qb->insert(self::TABLE_CIRCLES)
404
		   ->setValue('creation', $qb->createFunction('NOW()'));
405
406
		return $qb;
407
	}
408
409
410
	/**
411
	 * Base of the Sql Update request for Shares
412
	 *
413
	 * @param int $uniqueId
414
	 *
415
	 * @return IQueryBuilder
416
	 */
417 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...
418
		$qb = $this->dbConnection->getQueryBuilder();
419
		$qb->update(self::TABLE_CIRCLES)
420
		   ->where(
421
			   $qb->expr()
422
				  ->eq('unique_id', $qb->createNamedParameter($uniqueId))
423
		   );
424
425
		return $qb;
426
	}
427
428
429
	/**
430
	 * Base of the Sql Delete request
431
	 *
432
	 * @param string $circleUniqueId
433
	 *
434
	 * @return IQueryBuilder
435
	 */
436 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...
437
		$qb = $this->dbConnection->getQueryBuilder();
438
		$qb->delete(self::TABLE_CIRCLES)
439
		   ->where(
440
			   $qb->expr()
441
				  ->eq(
442
					  $qb->createFunction(
443
						  'SUBSTR(`unique_id`, 1, ' . Circle::SHORT_UNIQUE_ID_LENGTH . ')'
444
					  ),
445
					  $qb->createNamedParameter($circleUniqueId)
446
				  )
447
		   );
448
449
		return $qb;
450
	}
451
452
453
	/**
454
	 * @return IQueryBuilder
455
	 */
456
	protected function getCirclesSelectSql() {
457
		$qb = $this->dbConnection->getQueryBuilder();
458
459
		/** @noinspection PhpMethodParametersCountMismatchInspection */
460
		$qb->selectDistinct('c.unique_id')
461
		   ->addSelect(
462
			   'c.id', 'c.name', 'c.description', 'c.settings', 'c.type', 'c.creation'
463
		   )
464
		   ->from(CoreRequestBuilder::TABLE_CIRCLES, 'c');
465
		$this->default_select_alias = 'c';
466
467
		return $qb;
468
	}
469
470
471
	/**
472
	 * @param array $data
473
	 *
474
	 * @return Circle
475
	 */
476
	protected function parseCirclesSelectSql($data) {
477
478
		$circle = new Circle();
479
		$circle->setId($data['id']);
480
		$circle->setUniqueId($data['unique_id']);
481
		$circle->setName($data['name']);
482
		$circle->setDescription($data['description']);
483
		$circle->setSettings($data['settings']);
484
		$circle->setType($data['type']);
485
		$circle->setCreation($data['creation']);
486
487 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...
488
			$user = new Member($data['viewer_userid'], Member::TYPE_USER, $circle->getUniqueId());
489
			$user->setStatus($data['viewer_status']);
490
			$user->setLevel($data['viewer_level']);
491
			$circle->setViewer($user);
492
		}
493
494 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...
495
			$owner = new Member($data['owner_userid'], Member::TYPE_USER, $circle->getUniqueId());
496
			$owner->setStatus($data['owner_status']);
497
			$owner->setLevel($data['owner_level']);
498
			$circle->setOwner($owner);
499
		}
500
501
		return $circle;
502
	}
503
504
505
	/**
506
	 * @param array $data
507
	 *
508
	 * @return SharingFrame
509
	 */
510
	protected function parseSharesSelectSql($data) {
511
		$frame = new SharingFrame($data['source'], $data['type']);
512
513
		$circle = new Circle();
514
		$circle->setUniqueId($data['circle_id']);
515
		if (key_exists('circle_type', $data)) {
516
			$circle->setType($data['circle_type']);
517
			$circle->setName($data['circle_name']);
518
		}
519
520
		$frame->setCircle($circle);
521
522
		$frame->setAuthor($data['author']);
523
		$frame->setCloudId($data['cloud_id']);
524
		$frame->setPayload(json_decode($data['payload'], true));
525
		$frame->setCreation($data['creation']);
526
		$frame->setHeaders(json_decode($data['headers'], true));
527
		$frame->setUniqueId($data['unique_id']);
528
529
		return $frame;
530
	}
531
532
533
}