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

MembersRequest::unlinkAllFromGroup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 1
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
	 * Returns members generated from Contacts that are not 'checked' (as not sent existing shares).
135
	 *
136
	 *
137
	 * @return Member[]
138
	 */
139
	public function forceGetAllRecentContactEdit() {
140
		$qb = $this->getMembersSelectSql();
141
		$this->limitToUserType($qb, Member::TYPE_CONTACT);
142
143
		$expr = $qb->expr();
144
		$orX = $expr->orX();
145
		$orX->add($expr->isNull('contact_checked'));
146
		$orX->add($expr->neq('contact_checked', $qb->createNamedParameter('1')));
147
		$qb->andWhere($orX);
148
149
		$members = [];
150
		$cursor = $qb->execute();
151
		while ($data = $cursor->fetch()) {
152
			$members[] = $this->parseMembersSelectSql($data);
153
		}
154
		$cursor->closeCursor();
155
156
		return $members;
157
	}
158
159
160
	/**
161
	 * @param Member $member
162
	 * @param bool $check
163
	 */
164
	public function checkMember(Member $member, bool $check) {
165
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
166
		$qb->set('contact_checked', $qb->createNamedParameter(($check) ? 1 : 0));
167
168
		$qb->execute();
169
	}
170
171
172
	/**
173
	 * @param string $circleUniqueId
174
	 * @param Member $viewer
175
	 *
176
	 * @return Member[]
177
	 * @throws \Exception
178
	 */
179
	public function getMembers($circleUniqueId, Member $viewer) {
180
		try {
181
			$viewer->hasToBeMember();
182
183
			$members = $this->forceGetMembers($circleUniqueId, Member::LEVEL_NONE);
184
			if (!$viewer->isLevel(Member::LEVEL_MODERATOR)) {
185
				array_map(
186
					function(Member $m) {
187
						$m->setNote('');
188
					}, $members
189
				);
190
			}
191
192
			return $members;
193
		} catch (\Exception $e) {
194
			return [];
195
		}
196
	}
197
198
199
	/**
200
	 * forceGetGroup();
201
	 *
202
	 * returns group information as a member within a Circle.
203
	 *
204
	 * WARNING: This function does not filters data regarding the current user/viewer.
205
	 *          In case of interaction with users, Please use getGroup() instead.
206
	 *
207
	 * @param string $circleUniqueId
208
	 * @param string $groupId
209
	 *
210
	 * @return Member
211
	 * @throws MemberDoesNotExistException
212
	 */
213 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...
214
		$qb = $this->getGroupsSelectSql();
215
216
		$this->limitToGroupId($qb, $groupId);
217
		$this->limitToCircleId($qb, $circleUniqueId);
218
219
		$cursor = $qb->execute();
220
		$data = $cursor->fetch();
221
		if ($data === false) {
222
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
223
		}
224
225
		$group = $this->parseGroupsSelectSql($data);
226
		$cursor->closeCursor();
227
228
		return $group;
229
	}
230
231
232
	/**
233
	 * includeGroupMembers();
234
	 *
235
	 * This function will get members of a circle throw NCGroups and fill the result an existing
236
	 * Members List. In case of duplicate, higher level will be kept.
237
	 *
238
	 * @param Member[] $members
239
	 * @param string $circleUniqueId
240
	 * @param int $level
241
	 */
242
	private function includeGroupMembers(array &$members, $circleUniqueId, $level) {
243
244
		$groupMembers = $this->forceGetGroupMembers($circleUniqueId, $level);
245
		$this->avoidDuplicateMembers($members, $groupMembers);
246
	}
247
248
249
	/**
250
	 * avoidDuplicateMembers();
251
	 *
252
	 * Use this function to add members to the list (1st argument), keeping the higher level in case
253
	 * of duplicate
254
	 *
255
	 * @param Member[] $members
256
	 * @param Member[] $groupMembers
257
	 */
258
	public function avoidDuplicateMembers(array &$members, array $groupMembers) {
259
		foreach ($groupMembers as $member) {
260
			$index = $this->indexOfMember($members, $member->getUserId());
261
			if ($index === -1) {
262
				array_push($members, $member);
263
			} else if ($members[$index]->getLevel() < $member->getLevel()) {
264
				$members[$index] = $member;
265
			}
266
		}
267
	}
268
269
270
	/**
271
	 * returns the index of a specific UserID in a Members List
272
	 *
273
	 * @param array $members
274
	 * @param $userId
275
	 *
276
	 * @return int
277
	 */
278
	private function indexOfMember(array $members, $userId) {
279
280
		foreach ($members as $k => $member) {
281
			if ($member->getUserId() === $userId) {
282
				return intval($k);
283
			}
284
		}
285
286
		return -1;
287
	}
288
289
290
	/**
291
	 * Check if a fresh member can be generated (by addMember/joinCircle)
292
	 *
293
	 * @param string $circleUniqueId
294
	 * @param string $name
295
	 * @param $type
296
	 *
297
	 * @return Member
298
	 * @throws MemberAlreadyExistsException
299
	 * @throws \Exception
300
	 */
301
	public function getFreshNewMember($circleUniqueId, $name, $type) {
302
303
		try {
304
305
			$member = $this->forceGetMember($circleUniqueId, $name, $type);
306
307
		} catch (MemberDoesNotExistException $e) {
308
			$member = new Member($name, $type, $circleUniqueId);
309
			$this->createMember($member);
310
		}
311
312
//		if ($member->alreadyExistOrJoining()) {
313
//			throw new MemberAlreadyExistsException(
314
//				$this->l10n->t('This user is already a member of the circle')
315
//			);
316
//		}
317
318
		return $member;
319
	}
320
321
322
	/**
323
	 * Returns members list of all Group Members of a Circle. The Level of the linked group will be
324
	 * assigned to each entry
325
	 *
326
	 * NOTE: Can contains duplicate.
327
	 *
328
	 * WARNING: This function does not filters data regarding the current user/viewer.
329
	 *          Do not use in case of direct interaction with users.
330
	 *
331
	 * @param string $circleUniqueId
332
	 * @param int $level
333
	 *
334
	 * @return Member[]
335
	 */
336
	public function forceGetGroupMembers($circleUniqueId, $level = Member::LEVEL_MEMBER) {
337
		$qb = $this->getGroupsSelectSql();
338
339
		$this->limitToLevel($qb, $level);
340
		$this->limitToCircleId($qb, $circleUniqueId);
341
		$this->limitToNCGroupUser($qb);
342
343
		$members = [];
344
		$cursor = $qb->execute();
345
		while ($data = $cursor->fetch()) {
346
			$members[] = $this->parseGroupsSelectSql($data);
347
		}
348
		$cursor->closeCursor();
349
350
		return $members;
351
	}
352
353
354
	/**
355
	 * returns all users from a Group as a list of Members.
356
	 *
357
	 * @param Member $group
358
	 *
359
	 * @return Member[]
360
	 */
361
	public function getGroupMemberMembers(Member $group) {
362
		/** @var IGroup $grp */
363
		$grp = $this->groupManager->get($group->getUserId());
364
		if ($grp === null) {
365
			return [];
366
		}
367
368
		$members = [];
369
		$users = $grp->getUsers();
370
		foreach ($users as $user) {
371
			$member = clone $group;
372
			//Member::fromJSON($this->l10n, json_encode($group));
373
			$member->setType(Member::TYPE_USER);
374
			$member->setUserId($user->getUID());
375
			$members[] = $member;
376
		}
377
378
		return $members;
379
	}
380
381
382
	/**
383
	 * return the higher level group linked to a circle, that include the userId.
384
	 *
385
	 * WARNING: This function does not filters data regarding the current user/viewer.
386
	 *          In case of direct interaction with users, Please don't use this.
387
	 *
388
	 * @param string $circleUniqueId
389
	 * @param string $userId
390
	 *
391
	 * @return Member
392
	 */
393
	public function forceGetHigherLevelGroupFromUser($circleUniqueId, $userId) {
394
		$qb = $this->getGroupsSelectSql();
395
396
		$this->limitToCircleId($qb, $circleUniqueId);
397
		$this->limitToNCGroupUser($qb, $userId);
398
399
		/** @var Member $group */
400
		$group = null;
401
402
		$cursor = $qb->execute();
403
		while ($data = $cursor->fetch()) {
404
			$entry = $this->parseGroupsSelectSql($data);
405
			if ($group === null || $entry->getLevel() > $group->getLevel()) {
406
				$group = $entry;
407
			}
408
		}
409
		$cursor->closeCursor();
410
411
		return $group;
412
	}
413
414
415
	/**
416
	 * Insert Member into database.
417
	 *
418
	 * @param Member $member
419
	 *
420
	 * @throws MemberAlreadyExistsException
421
	 */
422
	public function createMember(Member $member) {
423
		try {
424
			$qb = $this->getMembersInsertSql();
425
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
426
			   ->setValue('user_id', $qb->createNamedParameter($member->getUserId()))
427
			   ->setValue('user_type', $qb->createNamedParameter($member->getType()))
428
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
429
			   ->setValue('status', $qb->createNamedParameter($member->getStatus()))
430
			   ->setValue('contact_id', $qb->createNamedParameter($member->getContactId()))
431
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
432
433
			$qb->execute();
434
		} 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...
435
			throw new MemberAlreadyExistsException(
436
				$this->l10n->t('This user is already a member of the circle')
437
			);
438
		}
439
	}
440
441
442
	/**
443
	 * @param string $circleUniqueId
444
	 * @param Member $viewer
445
	 *
446
	 * @return Member[]
447
	 * @throws MemberDoesNotExistException
448
	 */
449
	public function getGroupsFromCircle($circleUniqueId, Member $viewer) {
450
451
		if ($viewer->getLevel() < Member::LEVEL_MEMBER) {
452
			return [];
453
		}
454
455
		$qb = $this->getGroupsSelectSql();
456
		$this->limitToCircleId($qb, $circleUniqueId);
457
		$this->limitToLevel($qb, Member::LEVEL_MEMBER);
458
459
		$cursor = $qb->execute();
460
		$groups = [];
461
		while ($data = $cursor->fetch()) {
462
			if ($viewer->getLevel() < Member::LEVEL_MODERATOR) {
463
				$data['note'] = '';
464
			}
465
			$groups[] = $this->parseGroupsSelectSql($data);
466
		}
467
		$cursor->closeCursor();
468
469
		return $groups;
470
	}
471
472
473
	/**
474
	 * Insert Member into database.
475
	 *
476
	 * @param Member $member
477
	 *
478
	 * @throws MemberAlreadyExistsException
479
	 */
480
	public function insertGroup(Member $member) {
481
		try {
482
			$qb = $this->getGroupsInsertSql();
483
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
484
			   ->setValue('group_id', $qb->createNamedParameter($member->getUserId()))
485
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
486
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
487
488
			$qb->execute();
489
		} catch (UniqueConstraintViolationException $e) {
490
			throw new MemberAlreadyExistsException(
491
				$this->l10n->t('This user is already a member of the circle')
492
			);
493
		}
494
	}
495
496
497
	/**
498
	 * update database entry for a specific Member.
499
	 *
500
	 * @param Member $member
501
	 */
502
	public function updateMember(Member $member) {
503
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
504
		$qb->set('level', $qb->createNamedParameter($member->getLevel()))
505
		   ->set('status', $qb->createNamedParameter($member->getStatus()));
506
507
		$qb->execute();
508
	}
509
510
	/**
511
	 * update database entry for a specific Member.
512
	 *
513
	 * @param Member $member
514
	 */
515
	public function updateContactMeta(Member $member) {
516
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
517
		$qb->set('contact_meta', $qb->createNamedParameter(json_encode($member->getContactMeta())));
518
519
		$qb->execute();
520
	}
521
522
523
	/**
524
	 * removeAllFromCircle();
525
	 *
526
	 * Remove All members from a Circle. Used when deleting a Circle.
527
	 *
528
	 * @param string $uniqueCircleId
529
	 */
530
	public function removeAllFromCircle($uniqueCircleId) {
531
		$qb = $this->getMembersDeleteSql();
532
		$expr = $qb->expr();
533
534
		$qb->where($expr->eq('circle_id', $qb->createNamedParameter($uniqueCircleId)));
535
		$qb->execute();
536
	}
537
538
539
	/**
540
	 * removeAllMembershipsFromUser();
541
	 *
542
	 * remove All membership from a User. Used when removing a User from the Cloud.
543
	 *
544
	 * @param string $userId
545
	 */
546
	public function removeAllMembershipsFromUser($userId) {
547
		if ($userId === '') {
548
			return;
549
		}
550
551
		$qb = $this->getMembersDeleteSql();
552
		$expr = $qb->expr();
553
554
		/** @noinspection PhpMethodParametersCountMismatchInspection */
555
		$qb->where(
556
			$expr->andX(
557
				$expr->eq('user_id', $qb->createNamedParameter($userId)),
558
				$expr->eq('user_type', $qb->createNamedParameter(Member::TYPE_USER))
559
			)
560
		);
561
562
		$qb->execute();
563
	}
564
565
566
	/**
567
	 * remove member, identified by its id, type and circleId
568
	 *
569
	 * @param Member $member
570
	 */
571
	public function removeMember(Member $member) {
572
		$qb = $this->getMembersDeleteSql();
573
		$this->limitToCircleId($qb, $member->getCircleId());
574
		$this->limitToUserId($qb, $member->getUserId());
575
		$this->limitToUserType($qb, $member->getType());
576
		if ($member->getContactId() !== '') {
577
			$this->limitToContactId($qb, $member->getContactId());
578
		}
579
580
		$qb->execute();
581
	}
582
583
	/**
584
	 * update database entry for a specific Group.
585
	 *
586
	 * @param Member $member
587
	 *
588
	 * @return bool
589
	 */
590
	public function updateGroup(Member $member) {
591
		$qb = $this->getGroupsUpdateSql($member->getCircleId(), $member->getUserId());
592
		$qb->set('level', $qb->createNamedParameter($member->getLevel()));
593
		$qb->execute();
594
595
		return true;
596
	}
597
598
599
	public function unlinkAllFromGroup($groupId) {
600
		$qb = $this->getGroupsDeleteSql($groupId);
601
		$qb->execute();
602
	}
603
604
605
	/**
606
	 * @param string $contactId
607
	 *
608
	 * @return Member[]
609
	 */
610
	public function getMembersByContactId(string $contactId = ''): array {
611
		$qb = $this->getMembersSelectSql();
612
		if ($contactId === '') {
613
			$expr = $qb->expr();
614
			$qb->andWhere($expr->neq('contact_id', $qb->createNamedParameter('')));
615
		} else {
616
			$this->limitToContactId($qb, $contactId);
617
		}
618
619
		$members = [];
620
		$cursor = $qb->execute();
621
		while ($data = $cursor->fetch()) {
622
			$member = $this->parseMembersSelectSql($data);
623
			$members[] = $member;
624
		}
625
		$cursor->closeCursor();
626
627
		return $members;
628
	}
629
630
631
	/**
632
	 * @param string $circleId
633
	 * @param string $contactId
634
	 * @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...
635
	 * @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...
636
	 *
637
	 * @return Member
638
	 * @throws MemberDoesNotExistException
639
	 */
640 View Code Duplication
	public function getContactMember(string $circleId, string $contactId): Member {
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...
641
		$qb = $this->getMembersSelectSql();
642
		$this->limitToContactId($qb, $contactId);
643
		$this->limitToCircleId($qb, $circleId);
644
645
		$cursor = $qb->execute();
646
		$data = $cursor->fetch();
647
		$cursor->closeCursor();
648
649
		if ($data === false) {
650
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
651
		}
652
653
		return $this->parseMembersSelectSql($data);
654
	}
655
656
657
	/**
658
	 * @param string $contactId
659
	 *
660
	 * @return Member[]
661
	 */
662
	public function getLocalContactMembers(string $contactId): array {
663
		$qb = $this->getMembersSelectSql();
664
		$this->limitToContactId($qb, $contactId);
665
		$this->limitToUserType($qb, Member::TYPE_USER);
666
667
		$members = [];
668
		$cursor = $qb->execute();
669
		while ($data = $cursor->fetch()) {
670
			$members[] = $this->parseMembersSelectSql($data);
671
		}
672
		$cursor->closeCursor();
673
674
		return $members;
675
	}
676
677
678
	/**
679
	 * @param string $contactId
680
	 * @param int $type
681
	 */
682
	public function removeMembersByContactId(string $contactId, int $type = 0) {
683
		$this->miscService->log($contactId);
684
		if ($contactId === '') {
685
			return;
686
		}
687
688
		$qb = $this->getMembersDeleteSql();
689
		$this->limitToContactId($qb, $contactId);
690
		if ($type > 0) {
691
			$this->limitToUserType($qb, $type);
692
		}
693
694
		$qb->execute();
695
	}
696
697
}
698
699