Completed
Push — master ( 060fe4...9de15f )
by Maxence
02:41
created

MembersRequest::forceGetMember()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 19
Ratio 100 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 19
loc 19
rs 9.4285
cc 2
eloc 12
nc 2
nop 3
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 OC\User\NoUserException;
33
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
34
use OCA\Circles\Exceptions\MemberDoesNotExistException;
35
use OCA\Circles\Model\Member;
36
use OCP\IGroup;
37
38
class MembersRequest extends MembersRequestBuilder {
39
40
41
	/**
42
	 * Returns information about a member.
43
	 *
44
	 * WARNING: This function does not filters data regarding the current user/viewer.
45
	 *          In case of interaction with users, Please use MembersService->getMember() instead.
46
	 *
47
	 * @param string $circleUniqueId
48
	 * @param string $userId
49
	 * @param $type
50
	 *
51
	 * @return Member
52
	 * @throws MemberDoesNotExistException
53
	 */
54 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...
55
		$qb = $this->getMembersSelectSql();
56
57
		$this->limitToUserId($qb, $userId);
58
		$this->limitToType($qb, $type);
59
		$this->limitToCircleId($qb, $circleUniqueId);
60
61
		$cursor = $qb->execute();
62
		$data = $cursor->fetch();
63
		$cursor->closeCursor();
64
65
		if ($data === false) {
66
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
67
		}
68
69
		$member = $this->parseMembersSelectSql($data);
70
71
		return $member;
72
	}
73
74
75
	/**
76
	 * Returns members list of a circle, based on their level.
77
	 *
78
	 * WARNING: This function does not filters data regarding the current user/viewer.
79
	 *          In case of interaction with users, Please use getMembers() instead.
80
	 *
81
	 * @param string $circleUniqueId
82
	 * @param int $level
83
	 * @param bool $includeGroupMembers
84
	 *
85
	 * @return Member[]
86
	 */
87
	public function forceGetMembers(
88
		$circleUniqueId, $level = Member::LEVEL_MEMBER, $includeGroupMembers = false
89
	) {
90
91
		$qb = $this->getMembersSelectSql();
92
93
		$this->limitToMembersAndAlmost($qb);
94
		$this->limitToLevel($qb, $level);
95
		$this->limitToCircleId($qb, $circleUniqueId);
96
97
		$members = [];
98
		$cursor = $qb->execute();
99
		while ($data = $cursor->fetch()) {
100
			$members[] = $this->parseMembersSelectSql($data);
101
		}
102
		$cursor->closeCursor();
103
104
		if ($this->configService->isLinkedGroupsAllowed() && $includeGroupMembers === true) {
105
			$this->includeGroupMembers($members, $circleUniqueId, $level);
106
		}
107
108
		return $members;
109
	}
110
111
112
	/**
113
	 * @param string $circleUniqueId
114
	 * @param Member $viewer
115
	 *
116
	 * @return Member[]
117
	 * @throws \Exception
118
	 */
119
	public function getMembers($circleUniqueId, Member $viewer) {
120
		try {
121
			$viewer->hasToBeMember();
122
123
			$members = $this->forceGetMembers($circleUniqueId, Member::LEVEL_NONE);
124
			if (!$viewer->isLevel(Member::LEVEL_MODERATOR)) {
125
				array_map(
126
					function(Member $m) {
127
						$m->setNote('');
128
					}, $members
129
				);
130
			}
131
132
			return $members;
133
		} catch (\Exception $e) {
134
			return [];
135
		}
136
	}
137
138
139
	/**
140
	 * forceGetGroup();
141
	 *
142
	 * returns group information as a member within a Circle.
143
	 *
144
	 * WARNING: This function does not filters data regarding the current user/viewer.
145
	 *          In case of interaction with users, Please use getGroup() instead.
146
	 *
147
	 * @param string $circleUniqueId
148
	 * @param string $groupId
149
	 *
150
	 * @return Member
151
	 * @throws MemberDoesNotExistException
152
	 */
153 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...
154
		$qb = $this->getGroupsSelectSql();
155
156
		$this->limitToGroupId($qb, $groupId);
157
		$this->limitToCircleId($qb, $circleUniqueId);
158
159
		$cursor = $qb->execute();
160
		$data = $cursor->fetch();
161
		if ($data === false) {
162
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
163
		}
164
165
		$group = $this->parseGroupsSelectSql($data);
166
		$cursor->closeCursor();
167
168
		return $group;
169
	}
170
171
172
	/**
173
	 * includeGroupMembers();
174
	 *
175
	 * This function will get members of a circle throw NCGroups and fill the result an existing
176
	 * Members List. In case of duplicate, higher level will be kept.
177
	 *
178
	 * @param Member[] $members
179
	 * @param string $circleUniqueId
180
	 * @param int $level
181
	 */
182
	private function includeGroupMembers(array &$members, $circleUniqueId, $level) {
183
184
		$groupMembers = $this->forceGetGroupMembers($circleUniqueId, $level);
185
		$this->avoidDuplicateMembers($members, $groupMembers);
186
	}
187
188
189
	/**
190
	 * avoidDuplicateMembers();
191
	 *
192
	 * Use this function to add members to the list (1st argument), keeping the higher level in case
193
	 * of duplicate
194
	 *
195
	 * @param Member[] $members
196
	 * @param Member[] $groupMembers
197
	 */
198
	public function avoidDuplicateMembers(array &$members, array $groupMembers) {
199
		foreach ($groupMembers as $member) {
200
			$index = $this->indexOfMember($members, $member->getUserId());
201
			if ($index === -1) {
202
				array_push($members, $member);
203
			} else if ($members[$index]->getLevel() < $member->getLevel()) {
204
				$members[$index] = $member;
205
			}
206
		}
207
	}
208
209
210
	/**
211
	 * returns the index of a specific UserID in a Members List
212
	 *
213
	 * @param array $members
214
	 * @param $userId
215
	 *
216
	 * @return int
217
	 */
218
	private function indexOfMember(array $members, $userId) {
219
220
		foreach ($members as $k => $member) {
221
			if ($member->getUserId() === $userId) {
222
				return intval($k);
223
			}
224
		}
225
226
		return -1;
227
	}
228
229
230
	/**
231
	 * Check if a fresh member can be generated (by addMember/joinCircle)
232
	 *
233
	 * @param string $circleUniqueId
234
	 * @param string $name
235
	 * @param $type
236
	 *
237
	 * @return Member
238
	 * @throws MemberAlreadyExistsException
239
	 * @throws \Exception
240
	 */
241
	public function getFreshNewMember($circleUniqueId, $name, $type) {
242
243
		try {
244
			if ($type === Member::TYPE_USER) {
245
				$name = $this->miscService->getRealUserId($name);
246
			}
247
248
			$member = $this->forceGetMember($circleUniqueId, $name, $type);
249
250
		} catch (NoUserException $e) {
0 ignored issues
show
Bug introduced by
The class OC\User\NoUserException 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...
251
			throw new NoUserException($this->l10n->t("This user does not exist"));
252
		} catch (MemberDoesNotExistException $e) {
253
			$member = new Member($name, $type, $circleUniqueId);
254
			$this->createMember($member);
255
		}
256
257
//		if ($member->alreadyExistOrJoining()) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
258
//			throw new MemberAlreadyExistsException(
259
//				$this->l10n->t('This user is already a member of the circle')
260
//			);
261
//		}
262
263
		return $member;
264
	}
265
266
267
	/**
268
	 * Returns members list of all Group Members of a Circle. The Level of the linked group will be
269
	 * assigned to each entry
270
	 *
271
	 * NOTE: Can contains duplicate.
272
	 *
273
	 * WARNING: This function does not filters data regarding the current user/viewer.
274
	 *          Do not use in case of direct interaction with users.
275
	 *
276
	 * @param string $circleUniqueId
277
	 * @param int $level
278
	 *
279
	 * @return Member[]
280
	 */
281
	public function forceGetGroupMembers($circleUniqueId, $level = Member::LEVEL_MEMBER) {
282
		$qb = $this->getGroupsSelectSql();
283
284
		$this->limitToLevel($qb, $level);
285
		$this->limitToCircleId($qb, $circleUniqueId);
286
		$this->limitToNCGroupUser($qb);
287
288
		$members = [];
289
		$cursor = $qb->execute();
290
		while ($data = $cursor->fetch()) {
291
			$members[] = $this->parseGroupsSelectSql($data);
292
		}
293
		$cursor->closeCursor();
294
295
		return $members;
296
	}
297
298
299
	/**
300
	 * returns all users from a Group as a list of Members.
301
	 *
302
	 * @param Member $group
303
	 *
304
	 * @return Member[]
305
	 */
306
	public function getGroupMemberMembers(Member $group) {
307
		/** @var IGroup $grp */
308
		$grp = $this->groupManager->get($group->getUserId());
309
		if ($grp === null) {
310
			return [];
311
		}
312
313
		$members = [];
314
		$users = $grp->getUsers();
315
		foreach ($users as $user) {
316
			$member = clone $group;
317
			//Member::fromJSON($this->l10n, json_encode($group));
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
318
			$member->setType(Member::TYPE_USER);
319
			$member->setUserId($user->getUID());
320
			$members[] = $member;
321
		}
322
323
		return $members;
324
	}
325
326
327
	/**
328
	 * return the higher level group linked to a circle, that include the userId.
329
	 *
330
	 * WARNING: This function does not filters data regarding the current user/viewer.
331
	 *          In case of direct interaction with users, Please don't use this.
332
	 *
333
	 * @param string $circleUniqueId
334
	 * @param string $userId
335
	 *
336
	 * @return Member
337
	 */
338
	public function forceGetHigherLevelGroupFromUser($circleUniqueId, $userId) {
339
		$qb = $this->getGroupsSelectSql();
340
341
		$this->limitToCircleId($qb, $circleUniqueId);
342
		$this->limitToNCGroupUser($qb, $userId);
343
344
		/** @var Member $group */
345
		$group = null;
346
347
		$cursor = $qb->execute();
348
		while ($data = $cursor->fetch()) {
349
			$entry = $this->parseGroupsSelectSql($data);
350
			if ($group === null || $entry->getLevel() > $group->getLevel()) {
351
				$group = $entry;
352
			}
353
		}
354
		$cursor->closeCursor();
355
356
		return $group;
357
	}
358
359
360
	/**
361
	 * Insert Member into database.
362
	 *
363
	 * @param Member $member
364
	 *
365
	 * @throws MemberAlreadyExistsException
366
	 */
367
	public function createMember(Member $member) {
368
369
		try {
370
			$qb = $this->getMembersInsertSql();
371
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
372
			   ->setValue('user_id', $qb->createNamedParameter($member->getUserId()))
373
			   ->setValue('type', $qb->createNamedParameter($member->getType()))
374
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
375
			   ->setValue('status', $qb->createNamedParameter($member->getStatus()))
376
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
377
378
			$qb->execute();
379
		} 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...
380
			throw new MemberAlreadyExistsException(
381
				$this->l10n->t('This user is already a member of the circle')
382
			);
383
		}
384
	}
385
386
387
	/**
388
	 * @param string $circleUniqueId
389
	 * @param Member $viewer
390
	 *
391
	 * @return Member[]
392
	 * @throws MemberDoesNotExistException
393
	 */
394
	public function getGroupsFromCircle($circleUniqueId, Member $viewer) {
395
396
		if ($viewer->getLevel() < Member::LEVEL_MEMBER) {
397
			return [];
398
		}
399
400
		$qb = $this->getGroupsSelectSql();
401
		$this->limitToCircleId($qb, $circleUniqueId);
402
		$this->limitToLevel($qb, Member::LEVEL_MEMBER);
403
404
		$cursor = $qb->execute();
405
		$groups = [];
406
		while ($data = $cursor->fetch()) {
407
			if ($viewer->getLevel() < Member::LEVEL_MODERATOR) {
408
				$data['note'] = '';
409
			}
410
			$groups[] = $this->parseGroupsSelectSql($data);
411
		}
412
		$cursor->closeCursor();
413
414
		return $groups;
415
	}
416
417
418
	/**
419
	 * Insert Member into database.
420
	 *
421
	 * @param Member $member
422
	 *
423
	 * @throws MemberAlreadyExistsException
424
	 */
425
	public function insertGroup(Member $member) {
426
		try {
427
			$qb = $this->getGroupsInsertSql();
428
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
429
			   ->setValue('group_id', $qb->createNamedParameter($member->getUserId()))
430
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
431
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
432
433
			$qb->execute();
434
		} catch (UniqueConstraintViolationException $e) {
435
			throw new MemberAlreadyExistsException(
436
				$this->l10n->t('This user is already a member of the circle')
437
			);
438
		}
439
	}
440
441
442
	/**
443
	 * update database entry for a specific Member.
444
	 *
445
	 * @param Member $member
446
	 */
447
	public function updateMember(Member $member) {
448
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
449
		$qb->set('level', $qb->createNamedParameter($member->getLevel()))
450
		   ->set('status', $qb->createNamedParameter($member->getStatus()));
451
452
		$qb->execute();
453
	}
454
455
456
	/**
457
	 * removeAllFromCircle();
458
	 *
459
	 * Remove All members from a Circle. Used when deleting a Circle.
460
	 *
461
	 * @param string $uniqueCircleId
462
	 */
463
	public function removeAllFromCircle($uniqueCircleId) {
464
		$qb = $this->getMembersDeleteSql($uniqueCircleId);
465
		$qb->execute();
466
	}
467
468
469
	/**
470
	 * removeAllFromUser();
471
	 *
472
	 * remove All membership from a User. Used when removing a User from the Cloud.
473
	 *
474
	 * @param $userId
475
	 */
476
	public function removeAllFromUser($userId) {
477
		if ($userId === '') {
478
			return;
479
		}
480
481
		$qb = $this->getMembersDeleteSql('', Member::TYPE_USER, $userId);
482
		$qb->execute();
483
	}
484
485
486
	/**
487
	 * update database entry for a specific Group.
488
	 *
489
	 * @param Member $member
490
	 *
491
	 * @return bool
492
	 */
493
	public function updateGroup(Member $member) {
494
495
		$qb = $this->getGroupsUpdateSql($member->getCircleId(), $member->getUserId());
496
		$qb->set('level', $qb->createNamedParameter($member->getLevel()));
497
		$qb->execute();
498
499
		return true;
500
	}
501
502
503
	public function unlinkAllFromGroup($groupId) {
504
		$qb = $this->getGroupsDeleteSql($groupId);
505
		$qb->execute();
506
	}
507
508
}