Completed
Pull Request — master (#94)
by Maxence
02:28
created

MembersService   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 323
Duplicated Lines 17.96 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 8
Bugs 0 Features 1
Metric Value
wmc 31
lcom 1
cbo 9
dl 58
loc 323
rs 9.8
c 8
b 0
f 1

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 19 19 1
A addMember() 22 22 3
A getMember() 0 12 2
B getFreshNewMember() 0 22 4
A memberAlreadyExist() 0 6 3
B importMembersFromGroup() 0 32 6
A switchOwner() 0 16 2
A removeMember() 0 23 2
B levelMember() 0 28 5
A editMemberLevel() 17 17 2
A onUserRemoved() 0 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Circles - bring cloud-users closer
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
namespace OCA\Circles\Service;
28
29
30
use OC\User\NoUserException;
31
use OCA\Circles\Db\CirclesMapper;
32
use OCA\Circles\Db\MembersMapper;
33
use OCA\Circles\Exceptions\CircleTypeNotValid;
34
use OCA\Circles\Exceptions\GroupDoesNotExistException;
35
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
36
use OCA\Circles\Exceptions\MemberDoesNotExistException;
37
use OCA\Circles\Model\Circle;
38
use \OCA\Circles\Model\Member;
39
use OCP\IL10N;
40
use OCP\IUserManager;
41
42
class MembersService {
43
44
	/** @var string */
45
	private $userId;
46
47
	/** @var IL10N */
48
	private $l10n;
49
50
	/** @var IUserManager */
51
	private $userManager;
52
53
	/** @var ConfigService */
54
	private $configService;
55
56
	/** @var CirclesMapper */
57
	private $dbCircles;
58
59
	/** @var MembersMapper */
60
	private $dbMembers;
61
62
	/** @var EventsService */
63
	private $eventsService;
64
65
	/** @var MiscService */
66
	private $miscService;
67
68 View Code Duplication
	public function __construct(
69
		$userId,
70
		IL10N $l10n,
71
		IUserManager $userManager,
72
		ConfigService $configService,
73
		DatabaseService $databaseService,
74
		EventsService $eventsService,
75
		MiscService $miscService
76
	) {
77
		$this->userId = $userId;
78
		$this->l10n = $l10n;
79
		$this->userManager = $userManager;
80
		$this->configService = $configService;
81
		$this->eventsService = $eventsService;
82
		$this->miscService = $miscService;
83
84
		$this->dbCircles = $databaseService->getCirclesMapper();
85
		$this->dbMembers = $databaseService->getMembersMapper();
86
	}
87
88
89
	/**
90
	 * @param $circleId
91
	 * @param $name
92
	 *
93
	 * @return array
94
	 * @throws \Exception
95
	 */
96 View Code Duplication
	public function addMember($circleId, $name) {
97
98
		try {
99
			$circle = $this->dbCircles->getDetailsFromCircle($circleId, $this->userId);
100
			$this->dbMembers->getMemberFromCircle($circleId, $this->userId)
101
							->hasToBeModerator();
102
		} catch (\Exception $e) {
103
			throw $e;
104
		}
105
106
		try {
107
			$member = $this->getFreshNewMember($circleId, $name);
108
		} catch (\Exception $e) {
109
			throw $e;
110
		}
111
		$member->inviteToCircle($circle->getType());
112
		$this->dbMembers->editMember($member);
113
114
		$this->eventsService->onMemberNew($circle, $member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by $this->getFreshNewMember($circleId, $name) on line 107 can be null; however, OCA\Circles\Service\EventsService::onMemberNew() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
115
116
		return $this->dbMembers->getMembersFromCircle($circleId, $circle->getUser());
117
	}
118
119
120
	/**
121
	 * @param int $circleId
122
	 * @param string $groupId
123
	 *
124
	 * @return array
125
	 * @throws \Exception
126
	 */
127
	public function importMembersFromGroup($circleId, $groupId) {
128
129
		try {
130
			$circle = $this->dbCircles->getDetailsFromCircle($circleId, $this->userId);
131
			$this->dbMembers->getMemberFromCircle($circleId, $this->userId)
132
							->hasToBeModerator();
133
		} catch (\Exception $e) {
134
			throw $e;
135
		}
136
137
		$group = \OC::$server->getGroupManager()
138
							 ->get($groupId);
139
		if ($group === null) {
140
			throw new GroupDoesNotExistException('This group does not exist');
141
		}
142
143
		foreach ($group->getUsers() as $user) {
144
			try {
145
				$member = $this->getFreshNewMember($circleId, $user->getUID());
146
147
				$member->inviteToCircle($circle->getType());
148
				$this->dbMembers->editMember($member);
149
150
				$this->eventsService->onMemberNew($circle, $member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by $this->getFreshNewMember...cleId, $user->getUID()) on line 145 can be null; however, OCA\Circles\Service\EventsService::onMemberNew() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
151
			} catch (MemberAlreadyExistsException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
152
			} catch (\Exception $e) {
153
				throw $e;
154
			}
155
		}
156
157
		return $this->dbMembers->getMembersFromCircle($circleId, $circle->getUser());
158
	}
159
160
161
	/**
162
	 * getMember();
163
	 *
164
	 * Will return any data of a user related to a circle (as a Member). User can be a 'non-member'
165
	 *
166
	 * @param $circleId
167
	 * @param $userId
168
	 *
169
	 * @return Member
0 ignored issues
show
Documentation introduced by
Should the return type not be Member|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
170
	 * @throws \Exception
171
	 */
172
	public function getMember($circleId, $userId) {
173
174
		try {
175
			$this->dbMembers->getMemberFromCircle($circleId, $this->userId)
176
							->hasToBeMember();
177
			$member = $this->dbMembers->getMemberFromCircle($circleId, $userId);
178
		} catch (\Exception $e) {
179
			throw $e;
180
		}
181
182
		return $member;
183
	}
184
185
186
	/**
187
	 * Check if a fresh member can be generated (by addMember)
188
	 *
189
	 * @param $circleId
190
	 * @param $name
191
	 *
192
	 * @return null|Member
193
	 * @throws MemberAlreadyExistsException
194
	 * @throws NoUserException
195
	 */
196
	private function getFreshNewMember($circleId, $name) {
197
198
		if (!$this->userManager->userExists($name)) {
199
			throw new NoUserException($this->l10n->t("This user does not exist"));
200
		}
201
202
		try {
203
			$member = $this->dbMembers->getMemberFromCircle($circleId, $name);
204
205
		} catch (MemberDoesNotExistException $e) {
206
			$member = new Member($this->l10n, $name, $circleId);
207
			$this->dbMembers->add($member);
208
		}
209
210
		if ($this->memberAlreadyExist($member)) {
0 ignored issues
show
Bug introduced by
It seems like $member defined by $this->dbMembers->getMem...ircle($circleId, $name) on line 203 can be null; however, OCA\Circles\Service\Memb...e::memberAlreadyExist() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
211
			throw new MemberAlreadyExistsException(
212
				$this->l10n->t('This user is already a member of the circle')
213
			);
214
		}
215
216
		return $member;
217
	}
218
219
220
	/**
221
	 * return if member already exists
222
	 *
223
	 * @param Member $member
224
	 *
225
	 * @return bool
226
	 */
227
	private function memberAlreadyExist($member) {
228
		return ($member->getLevel() > Member::LEVEL_NONE
229
				|| ($member->getStatus() !== Member::STATUS_NONMEMBER
230
					&& $member->getStatus() !== Member::STATUS_REQUEST)
231
		);
232
	}
233
234
235
	/**
236
	 * @param int $circleId
237
	 * @param string $name
238
	 * @param int $level
239
	 *
240
	 * @return array
241
	 * @throws \Exception
242
	 */
243
	public function levelMember($circleId, $name, $level) {
244
245
		$level = (int)$level;
246
		try {
247
			$circle = $this->dbCircles->getDetailsFromCircle($circleId, $this->userId);
248
			if ($circle->getType() === Circle::CIRCLES_PERSONAL) {
249
				throw new CircleTypeNotValid(
250
					$this->l10n->t('You cannot edit level in a personal circle')
251
				);
252
			}
253
254
			$member = $this->dbMembers->getMemberFromCircle($circle->getId(), $name);
255
			if ($member->getLevel() !== $level) {
256
				if ($level === Member::LEVEL_OWNER) {
257
					$this->switchOwner($circle, $member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by $this->dbMembers->getMem...circle->getId(), $name) on line 254 can be null; however, OCA\Circles\Service\MembersService::switchOwner() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
258
				} else {
259
					$this->editMemberLevel($circle, $member, $level);
0 ignored issues
show
Bug introduced by
It seems like $member defined by $this->dbMembers->getMem...circle->getId(), $name) on line 254 can be null; however, OCA\Circles\Service\Memb...vice::editMemberLevel() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
260
				}
261
262
				$this->eventsService->onMemberLevel($circle, $member);
263
			}
264
265
			return $this->dbMembers->getMembersFromCircle($circleId, $circle->getUser());
266
		} catch (\Exception $e) {
267
			throw $e;
268
		}
269
270
	}
271
272
273
	/**
274
	 * @param Circle $circle
275
	 * @param Member $member
276
	 * @param $level
277
	 *
278
	 * @throws \Exception
279
	 */
280 View Code Duplication
	private function editMemberLevel(Circle $circle, Member &$member, $level) {
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...
281
		try {
282
			$isMod = $this->dbMembers->getMemberFromCircle($circle->getId(), $this->userId);
283
			$isMod->hasToBeModerator();
284
			$isMod->hasToBeHigherLevel($level);
285
286
			$member->hasToBeMember();
287
			$member->cantBeOwner();
288
			$isMod->hasToBeHigherLevel($member->getLevel());
289
290
			$member->setLevel($level);
291
			$this->dbMembers->editMember($member);
292
		} catch (\Exception $e) {
293
			throw $e;
294
		}
295
296
	}
297
298
	/**
299
	 * @param Circle $circle
300
	 * @param Member $member
301
	 *
302
	 * @throws \Exception
303
	 */
304
	public function switchOwner(Circle $circle, Member &$member) {
305
		try {
306
			$isMod = $this->dbMembers->getMemberFromCircle($circle->getId(), $this->userId);
307
			$isMod->hasToBeOwner();
308
309
			$member->cantBeOwner();
310
			$member->setLevel(Member::LEVEL_OWNER);
311
			$this->dbMembers->editMember($member);
312
313
			$isMod->setLevel(Member::LEVEL_ADMIN);
314
			$this->dbMembers->editMember($isMod);
315
316
		} catch (\Exception $e) {
317
			throw $e;
318
		}
319
	}
320
321
322
	/**
323
	 * @param $circleId
324
	 * @param $name
325
	 *
326
	 * @return array
327
	 * @throws \Exception
328
	 */
329
	public function removeMember($circleId, $name) {
330
331
		try {
332
			$isMod = $this->dbMembers->getMemberFromCircle($circleId, $this->userId);
333
			$isMod->hasToBeModerator();
334
335
			$member = $this->dbMembers->getMemberFromCircle($circleId, $name);
336
			$member->cantBeOwner();
337
338
			$isMod->hasToBeHigherLevel($member->getLevel());
339
		} catch (\Exception $e) {
340
			throw $e;
341
		}
342
343
		$member->setStatus(Member::STATUS_NONMEMBER);
344
		$member->setLevel(Member::LEVEL_NONE);
345
		$this->dbMembers->editMember($member);
346
347
		$circle = $this->dbCircles->getDetailsFromCircle($circleId, $this->userId);
348
		$this->eventsService->onMemberLeaving($circle, $member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by $this->dbMembers->getMem...ircle($circleId, $name) on line 335 can be null; however, OCA\Circles\Service\Even...vice::onMemberLeaving() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
349
350
		return $this->dbMembers->getMembersFromCircle($circleId, $circle->getUser());
351
	}
352
353
354
	/**
355
	 * When a user is removed, remove him from all Circles
356
	 *
357
	 * @param $userId
358
	 */
359
	public function onUserRemoved($userId) {
360
		$this->dbMembers->removeAllFromUserId($userId);
361
	}
362
363
364
}