Completed
Push — master ( 70edb2...6362ed )
by Maxence
02:18
created

GroupsService::levelGroup()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 32
Code Lines 19

Duplication

Lines 32
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 32
loc 32
rs 8.439
cc 5
eloc 19
nc 12
nop 3
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 OCA\Circles\Db\CirclesRequest;
31
use OCA\Circles\Db\MembersRequest;
32
use OCA\Circles\Exceptions\CircleTypeNotValidException;
33
use OCA\Circles\Exceptions\GroupCannotBeOwnerException;
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\IGroupManager;
40
use OCP\IL10N;
41
42
class GroupsService {
43
44
	/** @var string */
45
	private $userId;
46
47
	/** @var IL10N */
48
	private $l10n;
49
50
	/** @var IGroupManager */
51
	private $groupManager;
52
53
	/** @var CirclesRequest */
54
	private $circlesRequest;
55
56
	/** @var MembersRequest */
57
	private $membersRequest;
58
59
	/** @var EventsService */
60
	private $eventsService;
61
62
	/** @var MiscService */
63
	private $miscService;
64
65
	/**
66
	 * GroupsService constructor.
67
	 *
68
	 * @param string $userId
69
	 * @param IL10N $l10n
70
	 * @param IGroupManager $groupManager
71
	 * @param CirclesRequest $circlesRequest
72
	 * @param MembersRequest $membersRequest
73
	 * @param EventsService $eventsService
74
	 * @param MiscService $miscService
75
	 */
76
	public function __construct(
77
		$userId, IL10N $l10n, IGroupManager $groupManager, CirclesRequest $circlesRequest,
78
		MembersRequest $membersRequest, EventsService $eventsService, MiscService $miscService
79
	) {
80
		$this->userId = $userId;
81
		$this->l10n = $l10n;
82
		$this->groupManager = $groupManager;
83
		$this->circlesRequest = $circlesRequest;
84
		$this->membersRequest = $membersRequest;
85
		$this->eventsService = $eventsService;
86
		$this->miscService = $miscService;
87
	}
88
89
90
	/**
91
	 * @param string $circleUniqueId
92
	 * @param string $groupId
93
	 *
94
	 * @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...
95
	 * @throws \Exception
96
	 */
97
	public function linkGroup($circleUniqueId, $groupId) {
98
99
		try {
100
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
101
			$circle->getHigherViewer()
102
				   ->hasToBeAdmin();
103
104
			$group = $this->getFreshNewMember($circleUniqueId, $groupId);
105
		} catch (\Exception $e) {
106
			throw $e;
107
		}
108
109
		$group->setLevel(Member::LEVEL_MEMBER);
110
		$this->membersRequest->updateGroup($group);
0 ignored issues
show
Bug introduced by
It seems like $group defined by $this->getFreshNewMember...rcleUniqueId, $groupId) on line 104 can be null; however, OCA\Circles\Db\MembersRequest::updateGroup() 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...
111
112
		$this->eventsService->onGroupLink($circle, $group);
0 ignored issues
show
Bug introduced by
It seems like $group defined by $this->getFreshNewMember...rcleUniqueId, $groupId) on line 104 can be null; however, OCA\Circles\Service\EventsService::onGroupLink() 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
		return $this->membersRequest->getGroupsFromCircle(
115
			$circleUniqueId, $circle->getHigherViewer()
116
		);
117
	}
118
119
120
	/**
121
	 * Check if a fresh member can be generated (by linkGroup)
122
	 *
123
	 * @param $circleId
124
	 * @param $groupId
125
	 *
126
	 * @return null|Member
127
	 * @throws MemberAlreadyExistsException
128
	 * @throws GroupDoesNotExistException
129
	 */
130
	private function getFreshNewMember($circleId, $groupId) {
131
132
		if (!$this->groupManager->groupExists($groupId)) {
133
			throw new GroupDoesNotExistException($this->l10n->t("This group does not exist"));
134
		}
135
136
		try {
137
			$member = $this->membersRequest->forceGetGroup($circleId, $groupId);
138
		} catch (MemberDoesNotExistException $e) {
139
			$member = new Member($this->l10n, '', $circleId);
140
			$member->setGroupId($groupId);
141
			$this->membersRequest->insertGroup($member);
142
		}
143
144
		if ($member->getLevel() > Member::LEVEL_NONE) {
145
			throw new MemberAlreadyExistsException(
146
				$this->l10n->t('This group is already linked to the circle')
147
			);
148
		}
149
150
		return $member;
151
	}
152
153
154
	/**
155
	 * @param string $circleUniqueId
156
	 * @param string $groupId
157
	 * @param int $level
158
	 *
159
	 * @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...
160
	 * @throws \Exception
161
	 */
162 View Code Duplication
	public function levelGroup($circleUniqueId, $groupId, $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...
163
164
		$level = (int)$level;
165
		try {
166
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
167
			if ($circle->getType() === Circle::CIRCLES_PERSONAL) {
168
				throw new CircleTypeNotValidException(
169
					$this->l10n->t('You cannot edit level in a personal circle')
170
				);
171
			}
172
173
			$group = $this->membersRequest->forceGetGroup($circle->getUniqueId(), $groupId);
174
			if ($group->getLevel() !== $level) {
175
				if ($level === Member::LEVEL_OWNER) {
176
					throw new GroupCannotBeOwnerException(
177
						$this->l10n->t('Group cannot be set as owner of a circle')
178
					);
179
				} else {
180
					$this->editGroupLevel($circle, $group, $level);
181
				}
182
183
				$this->eventsService->onGroupLevel($circle, $group);
184
			}
185
186
			return $this->membersRequest->getGroupsFromCircle(
187
				$circle->getUniqueId(), $circle->getHigherViewer()
188
			);
189
		} catch (\Exception $e) {
190
			throw $e;
191
		}
192
193
	}
194
195
196
	/**
197
	 * @param Circle $circle
198
	 * @param Member $group
199
	 * @param $level
200
	 *
201
	 * @throws \Exception
202
	 */
203
	private function editGroupLevel(Circle $circle, Member &$group, $level) {
204
		try {
205
			$isMod = $circle->getHigherViewer();
206
			$isMod->hasToBeAdmin();
207
			$isMod->hasToBeHigherLevel($level);
208
209
			$group->hasToBeMember();
210
			$group->cantBeOwner();
211
			$isMod->hasToBeHigherLevel($group->getLevel());
212
213
			$group->setLevel($level);
214
			$this->membersRequest->updateGroup($group);
215
216
		} catch (\Exception $e) {
217
			throw $e;
218
		}
219
	}
220
221
222
	/**
223
	 * @param string $circleUniqueId
224
	 * @param string $groupId
225
	 *
226
	 * @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...
227
	 * @throws \Exception
228
	 */
229
	public function unlinkGroup($circleUniqueId, $groupId) {
230
		try {
231
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
232
			$circle->getHigherViewer()
233
				   ->hasToBeAdmin();
234
235
			$group = $this->membersRequest->forceGetGroup($circleUniqueId, $groupId);
236
			$group->cantBeOwner();
237
			$circle->getHigherViewer()
238
				   ->hasToBeHigherLevel($group->getLevel());
239
240
			$group->setLevel(Member::LEVEL_NONE);
241
			$this->membersRequest->updateGroup($group);
242
243
244
			$this->eventsService->onGroupUnlink($circle, $group);
245
246
		} catch (\Exception $e) {
247
			throw $e;
248
		}
249
250
		return $this->membersRequest->getGroupsFromCircle(
251
			$circle->getUniqueId(), $circle->getHigherViewer()
252
		);
253
	}
254
255
256
	/**
257
	 * When a group is removed, remove it from all Circles
258
	 *
259
	 * @param string $groupId
260
	 */
261
	public function onGroupRemoved($groupId) {
262
		$this->membersRequest->unlinkAllFromGroup($groupId);
263
	}
264
265
266
}