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

GroupsService::getFreshNewMember()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 13
nc 5
nop 2
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\Db\MembersRequest;
34
use OCA\Circles\Exceptions\CircleTypeNotValid;
35
use OCA\Circles\Exceptions\GroupCannotBeOwnerException;
36
use OCA\Circles\Exceptions\GroupDoesNotExistException;
37
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
38
use OCA\Circles\Exceptions\MemberDoesNotExistException;
39
use OCA\Circles\Model\Circle;
40
use \OCA\Circles\Model\Member;
41
use OCP\IGroupManager;
42
use OCP\IL10N;
43
use OCP\IUserManager;
44
45
class GroupsService {
46
47
	/** @var string */
48
	private $userId;
49
50
	/** @var IL10N */
51
	private $l10n;
52
53
	/** @var IGroupManager */
54
	private $groupManager;
55
56
	/** @var MembersRequest */
57
	private $membersRequest;
58
	/** @var CirclesMapper */
59
	private $dbCircles;
60
61
	/** @var MembersMapper */
62
	private $dbMembers;
63
64
	/** @var MiscService */
65
	private $miscService;
66
67
	/**
68
	 * GroupsService constructor.
69
	 *
70
	 * @param string $userId
71
	 * @param IL10N $l10n
72
	 * @param IGroupManager $groupManager
73
	 * @param DatabaseService $databaseService ,
74
	 * @param MembersRequest $membersRequest
75
	 * @param MiscService $miscService
76
	 */
77 View Code Duplication
	public function __construct(
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...
78
		$userId, IL10N $l10n, IGroupManager $groupManager, DatabaseService $databaseService,
79
		MembersRequest $membersRequest, MiscService $miscService
80
	) {
81
		$this->userId = $userId;
82
		$this->l10n = $l10n;
83
		$this->groupManager = $groupManager;
84
		$this->membersRequest = $membersRequest;
85
		$this->miscService = $miscService;
86
87
		$this->dbCircles = $databaseService->getCirclesMapper();
88
		$this->dbMembers = $databaseService->getMembersMapper();
89
	}
90
91
92
	/**
93
	 * @param $circleId
94
	 * @param $groupId
95
	 *
96
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Member[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
97
	 * @throws \Exception
98
	 */
99
	public function linkGroup($circleId, $groupId) {
100
101
		try {
102
			$circle = $this->dbCircles->getDetailsFromCircle($circleId, $this->userId);
103
			$this->dbMembers->getMemberFromCircle($circleId, $this->userId)
104
							->hasToBeAdmin();
105
106
			$group = $this->getFreshNewMember($circleId, $groupId);
107
		} catch (\Exception $e) {
108
			throw $e;
109
		}
110
111
		$group->setLevel(Member::LEVEL_MEMBER);
112
		$this->membersRequest->editGroup($group);
0 ignored issues
show
Bug introduced by
It seems like $group defined by $this->getFreshNewMember($circleId, $groupId) on line 106 can be null; however, OCA\Circles\Db\MembersRequest::editGroup() 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...
113
114
//		$this->eventsService->onMemberNew($circle, $group);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
115
		return $this->membersRequest->getGroups($circleId, $circle->getUser());
116
	}
117
118
119
	/**
120
	 * Check if a fresh member can be generated (by linkGroup)
121
	 *
122
	 * @param $circleId
123
	 * @param $groupId
124
	 *
125
	 * @return null|Member
126
	 * @throws MemberAlreadyExistsException
127
	 * @throws GroupDoesNotExistException
128
	 */
129
	private function getFreshNewMember($circleId, $groupId) {
130
131
		if (!$this->groupManager->groupExists($groupId)) {
132
			throw new GroupDoesNotExistException($this->l10n->t("This group does not exist"));
133
		}
134
135
		try {
136
			$member = $this->membersRequest->forceGetGroup($circleId, $groupId);
137
		} catch (MemberDoesNotExistException $e) {
138
			$member = new Member($this->l10n, '', $circleId);
139
			$member->setGroupId($groupId);
140
			$this->membersRequest->insertGroup($member);
141
		}
142
143
		if ($member->getLevel() > Member::LEVEL_NONE) {
144
			throw new MemberAlreadyExistsException(
145
				$this->l10n->t('This group is already linked to the circle')
146
			);
147
		}
148
149
		return $member;
150
	}
151
152
153
	/**
154
	 * @param int $circleId
155
	 * @param string $groupId
156
	 * @param int $level
157
	 *
158
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Member[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
159
	 * @throws \Exception
160
	 */
161
	public function levelGroup($circleId, $groupId, $level) {
162
163
		$level = (int)$level;
164
		try {
165
			$circle = $this->dbCircles->getDetailsFromCircle($circleId, $this->userId);
166
			if ($circle->getType() === Circle::CIRCLES_PERSONAL) {
167
				throw new CircleTypeNotValid(
168
					$this->l10n->t('You cannot edit level in a personal circle')
169
				);
170
			}
171
172
			$group = $this->membersRequest->forceGetGroup($circle->getId(), $groupId);
173
			if ($group->getLevel() !== $level) {
174
				if ($level === Member::LEVEL_OWNER) {
175
					throw new GroupCannotBeOwnerException(
176
						$this->l10n->t('Group cannot be set as owner of a circle')
177
					);
178
				} else {
179
					$this->editGroupLevel($circle, $group, $level);
0 ignored issues
show
Bug introduced by
It seems like $group defined by $this->membersRequest->f...cle->getId(), $groupId) on line 172 can be null; however, OCA\Circles\Service\Grou...rvice::editGroupLevel() 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...
180
				}
181
182
//				$this->eventsService->onMemberLevel($circle, $member);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
183
			}
184
185
			return $this->membersRequest->getGroups($circle->getId(), $circle->getUser());
186
		} catch (\Exception $e) {
187
			throw $e;
188
		}
189
190
	}
191
192
193
	/**
194
	 * @param Circle $circle
195
	 * @param Member $group
196
	 * @param $level
197
	 *
198
	 * @throws \Exception
199
	 */
200 View Code Duplication
	private function editGroupLevel(Circle $circle, Member &$group, $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...
201
		try {
202
			$isMod = $this->dbMembers->getMemberFromCircle($circle->getId(), $this->userId);
203
			$isMod->hasToBeAdmin();
204
			$isMod->hasToBeHigherLevel($level);
205
206
			$group->hasToBeMember();
207
			$group->cantBeOwner();
208
			$isMod->hasToBeHigherLevel($group->getLevel());
209
210
			$group->setLevel($level);
211
			$this->membersRequest->editGroup($group);
212
		} catch (\Exception $e) {
213
			throw $e;
214
		}
215
	}
216
217
218
	/**
219
	 * @param int $circleId
220
	 * @param string $groupId
221
	 *
222
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Member[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
223
	 * @throws \Exception
224
	 */
225
	public function unlinkGroup($circleId, $groupId) {
226
		try {
227
			$isMod = $this->dbMembers->getMemberFromCircle($circleId, $this->userId);
228
			$isMod->hasToBeAdmin();
229
230
			$group = $this->membersRequest->forceGetGroup($circleId, $groupId);
231
			$group->cantBeOwner();
232
			$isMod->hasToBeHigherLevel($group->getLevel());
233
234
			$group->setLevel(Member::LEVEL_NONE);
235
			$this->membersRequest->editGroup($group);
0 ignored issues
show
Bug introduced by
It seems like $group defined by $this->membersRequest->f...up($circleId, $groupId) on line 230 can be null; however, OCA\Circles\Db\MembersRequest::editGroup() 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...
236
237
			$circle = $this->dbCircles->getDetailsFromCircle($circleId, $this->userId);
238
239
			//		$this->eventsService->onMemberLeaving($circle, $member);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
240
241
		} catch (\Exception $e) {
242
			throw $e;
243
		}
244
245
		return $this->membersRequest->getGroups($circle->getId(), $circle->getUser());
246
	}
247
248
249
	/**
250
	 * When a group is removed, remove it from all Circles
251
	 *
252
	 * @param string $groupId
253
	 */
254
	public function onGroupRemoved($groupId) {
255
		$this->membersRequest->unlinkAllFromGroupId($groupId);
256
	}
257
258
259
}