Completed
Pull Request — master (#347)
by Maxence
02:22
created

MembersRequest::forceGetHigherLevelGroupFromUser()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 20
rs 9.6
cc 4
nc 3
nop 2
1
<?php
2
/**
3
 * Circles - Bring cloud-users closer together.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
28
namespace OCA\Circles\Db;
29
30
31
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
32
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
33
use OCA\Circles\Exceptions\MemberDoesNotExistException;
34
use OCA\Circles\Model\Member;
35
use OCP\IGroup;
36
37
class MembersRequest extends MembersRequestBuilder {
38
39
40
	/**
41
	 * Returns information about a member.
42
	 *
43
	 * WARNING: This function does not filters data regarding the current user/viewer.
44
	 *          In case of interaction with users, Please use MembersService->getMember() instead.
45
	 *
46
	 * @param string $circleUniqueId
47
	 * @param string $userId
48
	 * @param $type
49
	 *
50
	 * @return Member
51
	 * @throws MemberDoesNotExistException
52
	 */
53 View Code Duplication
	public function forceGetMember($circleUniqueId, $userId, $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...
54
		$qb = $this->getMembersSelectSql();
55
56
		$this->limitToUserId($qb, $userId);
57
		$this->limitToUserType($qb, $type);
58
		$this->limitToCircleId($qb, $circleUniqueId);
59
60
		$cursor = $qb->execute();
61
		$data = $cursor->fetch();
62
		$cursor->closeCursor();
63
64
		if ($data === false) {
65
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
66
		}
67
68
		$member = $this->parseMembersSelectSql($data);
69
70
		return $member;
71
	}
72
73
74
	/**
75
	 * Returns members list of a circle, based on their level.
76
	 *
77
	 * WARNING: This function does not filters data regarding the current user/viewer.
78
	 *          In case of interaction with users, Please use getMembers() instead.
79
	 *
80
	 * @param string $circleUniqueId
81
	 * @param int $level
82
	 * @param bool $incGroup
83
	 *
84
	 * @return Member[]
85
	 */
86
	public function forceGetMembers($circleUniqueId, $level = Member::LEVEL_MEMBER, $incGroup = false) {
87
88
		$qb = $this->getMembersSelectSql();
89
		$this->limitToMembersAndAlmost($qb);
90
		$this->limitToLevel($qb, $level);
91
92
		$this->limitToCircleId($qb, $circleUniqueId);
93
94
		$members = [];
95
		$cursor = $qb->execute();
96
		while ($data = $cursor->fetch()) {
97
			$members[] = $this->parseMembersSelectSql($data);
98
		}
99
		$cursor->closeCursor();
100
101
		if ($this->configService->isLinkedGroupsAllowed() && $incGroup === true) {
102
			$this->includeGroupMembers($members, $circleUniqueId, $level);
103
		}
104
105
		return $members;
106
	}
107
108
109
	/**
110
	 * Returns all members.
111
	 *
112
	 * WARNING: This function does not filters data regarding the current user/viewer.
113
	 *          In case of interaction with users, Please use getMembers() instead.
114
	 *
115
	 *
116
	 * @return Member[]
117
	 */
118
	public function forceGetAllMembers() {
119
120
		$qb = $this->getMembersSelectSql();
121
122
		$members = [];
123
		$cursor = $qb->execute();
124
		while ($data = $cursor->fetch()) {
125
			$members[] = $this->parseMembersSelectSql($data);
126
		}
127
		$cursor->closeCursor();
128
129
		return $members;
130
	}
131
132
133
	/**
134
	 * @param string $circleUniqueId
135
	 * @param Member $viewer
136
	 *
137
	 * @return Member[]
138
	 * @throws \Exception
139
	 */
140
	public function getMembers($circleUniqueId, Member $viewer) {
141
		try {
142
			$viewer->hasToBeMember();
143
144
			$members = $this->forceGetMembers($circleUniqueId, Member::LEVEL_NONE);
145
			if (!$viewer->isLevel(Member::LEVEL_MODERATOR)) {
146
				array_map(
147
					function(Member $m) {
148
						$m->setNote('');
149
					}, $members
150
				);
151
			}
152
153
			return $members;
154
		} catch (\Exception $e) {
155
			return [];
156
		}
157
	}
158
159
160
	/**
161
	 * forceGetGroup();
162
	 *
163
	 * returns group information as a member within a Circle.
164
	 *
165
	 * WARNING: This function does not filters data regarding the current user/viewer.
166
	 *          In case of interaction with users, Please use getGroup() instead.
167
	 *
168
	 * @param string $circleUniqueId
169
	 * @param string $groupId
170
	 *
171
	 * @return Member
172
	 * @throws MemberDoesNotExistException
173
	 */
174 View Code Duplication
	public function forceGetGroup($circleUniqueId, $groupId) {
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...
175
		$qb = $this->getGroupsSelectSql();
176
177
		$this->limitToGroupId($qb, $groupId);
178
		$this->limitToCircleId($qb, $circleUniqueId);
179
180
		$cursor = $qb->execute();
181
		$data = $cursor->fetch();
182
		if ($data === false) {
183
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
184
		}
185
186
		$group = $this->parseGroupsSelectSql($data);
187
		$cursor->closeCursor();
188
189
		return $group;
190
	}
191
192
193
	/**
194
	 * includeGroupMembers();
195
	 *
196
	 * This function will get members of a circle throw NCGroups and fill the result an existing
197
	 * Members List. In case of duplicate, higher level will be kept.
198
	 *
199
	 * @param Member[] $members
200
	 * @param string $circleUniqueId
201
	 * @param int $level
202
	 */
203
	private function includeGroupMembers(array &$members, $circleUniqueId, $level) {
204
205
		$groupMembers = $this->forceGetGroupMembers($circleUniqueId, $level);
206
		$this->avoidDuplicateMembers($members, $groupMembers);
207
	}
208
209
210
	/**
211
	 * avoidDuplicateMembers();
212
	 *
213
	 * Use this function to add members to the list (1st argument), keeping the higher level in case
214
	 * of duplicate
215
	 *
216
	 * @param Member[] $members
217
	 * @param Member[] $groupMembers
218
	 */
219
	public function avoidDuplicateMembers(array &$members, array $groupMembers) {
220
		foreach ($groupMembers as $member) {
221
			$index = $this->indexOfMember($members, $member->getUserId());
222
			if ($index === -1) {
223
				array_push($members, $member);
224
			} else if ($members[$index]->getLevel() < $member->getLevel()) {
225
				$members[$index] = $member;
226
			}
227
		}
228
	}
229
230
231
	/**
232
	 * returns the index of a specific UserID in a Members List
233
	 *
234
	 * @param array $members
235
	 * @param $userId
236
	 *
237
	 * @return int
238
	 */
239
	private function indexOfMember(array $members, $userId) {
240
241
		foreach ($members as $k => $member) {
242
			if ($member->getUserId() === $userId) {
243
				return intval($k);
244
			}
245
		}
246
247
		return -1;
248
	}
249
250
251
	/**
252
	 * Check if a fresh member can be generated (by addMember/joinCircle)
253
	 *
254
	 * @param string $circleUniqueId
255
	 * @param string $name
256
	 * @param $type
257
	 *
258
	 * @return Member
259
	 * @throws MemberAlreadyExistsException
260
	 * @throws \Exception
261
	 */
262
	public function getFreshNewMember($circleUniqueId, $name, $type) {
263
264
		try {
265
266
			$member = $this->forceGetMember($circleUniqueId, $name, $type);
267
268
		} catch (MemberDoesNotExistException $e) {
269
			$member = new Member($name, $type, $circleUniqueId);
270
			$this->createMember($member);
271
		}
272
273
//		if ($member->alreadyExistOrJoining()) {
274
//			throw new MemberAlreadyExistsException(
275
//				$this->l10n->t('This user is already a member of the circle')
276
//			);
277
//		}
278
279
		return $member;
280
	}
281
282
283
	/**
284
	 * Returns members list of all Group Members of a Circle. The Level of the linked group will be
285
	 * assigned to each entry
286
	 *
287
	 * NOTE: Can contains duplicate.
288
	 *
289
	 * WARNING: This function does not filters data regarding the current user/viewer.
290
	 *          Do not use in case of direct interaction with users.
291
	 *
292
	 * @param string $circleUniqueId
293
	 * @param int $level
294
	 *
295
	 * @return Member[]
296
	 */
297
	public function forceGetGroupMembers($circleUniqueId, $level = Member::LEVEL_MEMBER) {
298
		$qb = $this->getGroupsSelectSql();
299
300
		$this->limitToLevel($qb, $level);
301
		$this->limitToCircleId($qb, $circleUniqueId);
302
		$this->limitToNCGroupUser($qb);
303
304
		$members = [];
305
		$cursor = $qb->execute();
306
		while ($data = $cursor->fetch()) {
307
			$members[] = $this->parseGroupsSelectSql($data);
308
		}
309
		$cursor->closeCursor();
310
311
		return $members;
312
	}
313
314
315
	/**
316
	 * returns all users from a Group as a list of Members.
317
	 *
318
	 * @param Member $group
319
	 *
320
	 * @return Member[]
321
	 */
322
	public function getGroupMemberMembers(Member $group) {
323
		/** @var IGroup $grp */
324
		$grp = $this->groupManager->get($group->getUserId());
325
		if ($grp === null) {
326
			return [];
327
		}
328
329
		$members = [];
330
		$users = $grp->getUsers();
331
		foreach ($users as $user) {
332
			$member = clone $group;
333
			//Member::fromJSON($this->l10n, json_encode($group));
334
			$member->setType(Member::TYPE_USER);
335
			$member->setUserId($user->getUID());
336
			$members[] = $member;
337
		}
338
339
		return $members;
340
	}
341
342
343
	/**
344
	 * return the higher level group linked to a circle, that include the userId.
345
	 *
346
	 * WARNING: This function does not filters data regarding the current user/viewer.
347
	 *          In case of direct interaction with users, Please don't use this.
348
	 *
349
	 * @param string $circleUniqueId
350
	 * @param string $userId
351
	 *
352
	 * @return Member
353
	 */
354
	public function forceGetHigherLevelGroupFromUser($circleUniqueId, $userId) {
355
		$qb = $this->getGroupsSelectSql();
356
357
		$this->limitToCircleId($qb, $circleUniqueId);
358
		$this->limitToNCGroupUser($qb, $userId);
359
360
		/** @var Member $group */
361
		$group = null;
362
363
		$cursor = $qb->execute();
364
		while ($data = $cursor->fetch()) {
365
			$entry = $this->parseGroupsSelectSql($data);
366
			if ($group === null || $entry->getLevel() > $group->getLevel()) {
367
				$group = $entry;
368
			}
369
		}
370
		$cursor->closeCursor();
371
372
		return $group;
373
	}
374
375
376
	/**
377
	 * Insert Member into database.
378
	 *
379
	 * @param Member $member
380
	 *
381
	 * @throws MemberAlreadyExistsException
382
	 */
383
	public function createMember(Member $member) {
384
		try {
385
			$qb = $this->getMembersInsertSql();
386
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
387
			   ->setValue('user_id', $qb->createNamedParameter($member->getUserId()))
388
			   ->setValue('user_type', $qb->createNamedParameter($member->getType()))
389
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
390
			   ->setValue('status', $qb->createNamedParameter($member->getStatus()))
391
			   ->setValue('contact_id', $qb->createNamedParameter($member->getContactId()))
392
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
393
394
			$qb->execute();
395
		} catch (UniqueConstraintViolationException $e) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\Exception\...raintViolationException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
396
			throw new MemberAlreadyExistsException(
397
				$this->l10n->t('This user is already a member of the circle')
398
			);
399
		}
400
	}
401
402
403
	/**
404
	 * @param string $circleUniqueId
405
	 * @param Member $viewer
406
	 *
407
	 * @return Member[]
408
	 * @throws MemberDoesNotExistException
409
	 */
410
	public function getGroupsFromCircle($circleUniqueId, Member $viewer) {
411
412
		if ($viewer->getLevel() < Member::LEVEL_MEMBER) {
413
			return [];
414
		}
415
416
		$qb = $this->getGroupsSelectSql();
417
		$this->limitToCircleId($qb, $circleUniqueId);
418
		$this->limitToLevel($qb, Member::LEVEL_MEMBER);
419
420
		$cursor = $qb->execute();
421
		$groups = [];
422
		while ($data = $cursor->fetch()) {
423
			if ($viewer->getLevel() < Member::LEVEL_MODERATOR) {
424
				$data['note'] = '';
425
			}
426
			$groups[] = $this->parseGroupsSelectSql($data);
427
		}
428
		$cursor->closeCursor();
429
430
		return $groups;
431
	}
432
433
434
	/**
435
	 * Insert Member into database.
436
	 *
437
	 * @param Member $member
438
	 *
439
	 * @throws MemberAlreadyExistsException
440
	 */
441
	public function insertGroup(Member $member) {
442
		try {
443
			$qb = $this->getGroupsInsertSql();
444
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
445
			   ->setValue('group_id', $qb->createNamedParameter($member->getUserId()))
446
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
447
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
448
449
			$qb->execute();
450
		} catch (UniqueConstraintViolationException $e) {
451
			throw new MemberAlreadyExistsException(
452
				$this->l10n->t('This user is already a member of the circle')
453
			);
454
		}
455
	}
456
457
458
	/**
459
	 * update database entry for a specific Member.
460
	 *
461
	 * @param Member $member
462
	 */
463
	public function updateMember(Member $member) {
464
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
465
		$qb->set('level', $qb->createNamedParameter($member->getLevel()))
466
		   ->set('status', $qb->createNamedParameter($member->getStatus()));
467
468
		$qb->execute();
469
	}
470
471
472
	/**
473
	 * removeAllFromCircle();
474
	 *
475
	 * Remove All members from a Circle. Used when deleting a Circle.
476
	 *
477
	 * @param string $uniqueCircleId
478
	 */
479
	public function removeAllFromCircle($uniqueCircleId) {
480
		$qb = $this->getMembersDeleteSql();
481
		$expr = $qb->expr();
482
483
		$qb->where($expr->eq('circle_id', $qb->createNamedParameter($uniqueCircleId)));
484
		$qb->execute();
485
	}
486
487
488
	/**
489
	 * removeAllMembershipsFromUser();
490
	 *
491
	 * remove All membership from a User. Used when removing a User from the Cloud.
492
	 *
493
	 * @param string $userId
494
	 */
495
	public function removeAllMembershipsFromUser($userId) {
496
		if ($userId === '') {
497
			return;
498
		}
499
500
		$qb = $this->getMembersDeleteSql();
501
		$expr = $qb->expr();
502
503
		/** @noinspection PhpMethodParametersCountMismatchInspection */
504
		$qb->where(
505
			$expr->andX(
506
				$expr->eq('user_id', $qb->createNamedParameter($userId)),
507
				$expr->eq('user_type', $qb->createNamedParameter(Member::TYPE_USER))
508
			)
509
		);
510
511
		$qb->execute();
512
	}
513
514
515
	/**
516
	 * remove member, identified by its id, type and circleId
517
	 *
518
	 * @param Member $member
519
	 */
520
	public function removeMember(Member $member) {
521
		$qb = $this->getMembersDeleteSql();
522
		$this->limitToCircleId($qb, $member->getCircleId());
523
		$this->limitToUserId($qb, $member->getUserId());
524
		$this->limitToUserType($qb, $member->getType());
525
		if ($member->getContactId() !== '') {
526
			$this->limitToContactId($qb, $member->getContactId());
527
		}
528
529
		$qb->execute();
530
	}
531
532
	/**
533
	 * update database entry for a specific Group.
534
	 *
535
	 * @param Member $member
536
	 *
537
	 * @return bool
538
	 */
539
	public function updateGroup(Member $member) {
540
		$qb = $this->getGroupsUpdateSql($member->getCircleId(), $member->getUserId());
541
		$qb->set('level', $qb->createNamedParameter($member->getLevel()));
542
		$qb->execute();
543
544
		return true;
545
	}
546
547
548
	public function unlinkAllFromGroup($groupId) {
549
		$qb = $this->getGroupsDeleteSql($groupId);
550
		$qb->execute();
551
	}
552
553
554
	/**
555
	 * @param string $contactId
556
	 *
557
	 * @return Member[]
558
	 */
559
	public function getMembersByContactId(string $contactId): array {
560
		$qb = $this->getMembersSelectSql();
561
		$this->limitToContactId($qb, $contactId);
562
563
		$members = [];
564
		$cursor = $qb->execute();
565
		while ($data = $cursor->fetch()) {
566
			$member = $this->parseMembersSelectSql($data);
567
			$members[] = $member;
568
		}
569
		$cursor->closeCursor();
570
571
		return $members;
572
	}
573
574
575
	/**
576
	 * @param string $circleId
577
	 * @param string $contactId
578
	 * @param string $userId
0 ignored issues
show
Bug introduced by
There is no parameter named $userId. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

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

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

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

Loading history...
579
	 * @param int $type
0 ignored issues
show
Bug introduced by
There is no parameter named $type. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

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

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

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

Loading history...
580
	 *
581
	 * @return Member
582
	 * @throws MemberDoesNotExistException
583
	 */
584
	public function getContactMember(string $circleId, string $contactId): Member {
585
		$qb = $this->getMembersSelectSql();
586
		$this->limitToContactId($qb, $contactId);
587
		$this->limitToCircleId($qb, $circleId);
588
589
		$cursor = $qb->execute();
590
		$data = $cursor->fetch();
591
		$cursor->closeCursor();
592
593
		if ($data === false) {
594
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
595
		}
596
597
		return $this->parseMembersSelectSql($data);
598
	}
599
600
601
	/**
602
	 * @param string $contactId
603
	 *
604
	 * @return Member[]
605
	 */
606
	public function getLocalContactMembers(string $contactId): array {
607
		$qb = $this->getMembersSelectSql();
608
		$this->limitToContactId($qb, $contactId);
609
		$this->limitToUserType($qb, Member::TYPE_USER);
610
611
		$members = [];
612
		$cursor = $qb->execute();
613
		while ($data = $cursor->fetch()) {
614
			$members[] = $this->parseMembersSelectSql($data);
615
		}
616
		$cursor->closeCursor();
617
618
		return $members;
619
	}
620
621
622
	/**
623
	 * @param string $contactId
624
	 * @param int $type
625
	 */
626
	public function removeContactMembers(string $contactId, int $type = 0) {
627
		$qb = $this->getMembersDeleteSql();
628
		$this->limitToContactId($qb, $contactId);
629
		if ($type > 0) {
630
			$this->limitToUserType($qb, $type);
631
		}
632
633
		$qb->execute();
634
	}
635
636
}
637
638