Passed
Pull Request — master (#1128)
by René
04:35
created

SystemService   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 8
Bugs 3 Features 1
Metric Value
wmc 41
eloc 75
c 8
b 3
f 1
dl 0
loc 225
ccs 0
cts 149
cp 0
rs 9.1199

7 Methods

Rating   Name   Duplication   Size   Complexity  
A isValidEmail() 0 2 2
A validateEmailAddress() 0 5 2
A __construct() 0 14 1
A getSiteGroups() 0 8 3
A getSiteUsers() 0 8 4
B getSiteUsersAndGroups() 0 35 8
D validatePublicUsername() 0 60 21

How to fix   Complexity   

Complex Class

Complex classes like SystemService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SystemService, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Vinzenz Rosenkranz <[email protected]>
4
 *
5
 * @author René Gieling <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 *  This program is free software: you can redistribute it and/or modify
10
 *  it under the terms of the GNU Affero General Public License as
11
 *  published by the Free Software Foundation, either version 3 of the
12
 *  License, or (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU Affero General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU Affero General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OCA\Polls\Service;
25
26
use OCA\Polls\Exceptions\NotAuthorizedException;
27
use OCA\Polls\Exceptions\TooShortException;
28
use OCA\Polls\Exceptions\InvalidUsernameException;
29
use OCA\Polls\Exceptions\InvalidEmailAddress;
30
31
use OCP\IGroupManager;
32
use OCP\IUserManager;
33
use OCA\Polls\Db\Share;
34
use OCA\Polls\Db\ShareMapper;
35
use OCA\Polls\Db\VoteMapper;
36
use OCA\Polls\Model\User;
37
38
class SystemService {
39
40
	/** @var IGroupManager */
41
	private $groupManager;
42
43
	/** @var IUserManager */
44
	private $userManager;
45
46
	/** @var CirclesService */
47
	private $circlesService;
48
49
	/** @var ContactsService */
50
	private $contactsService;
51
52
	/** @var VoteMapper */
53
	private $voteMapper;
54
55
	/** @var ShareMapper */
56
	private $shareMapper;
57
58
	/**
59
	 * SystemService constructor.
60
	 * @param IGroupManager $groupManager
61
	 * @param IUserManager $userManager
62
	 * @param CirclesService $circlesService,
63
	 * @param ContactsService $contactsService,
64
	 * @param VoteMapper $voteMapper
65
	 * @param ShareMapper $shareMapper
66
	 */
67
	public function __construct(
68
		IGroupManager $groupManager,
69
		IUserManager $userManager,
70
		VoteMapper $voteMapper,
71
		CirclesService $circlesService,
72
		ContactsService $contactsService,
73
		ShareMapper $shareMapper
74
	) {
75
		$this->groupManager = $groupManager;
76
		$this->userManager = $userManager;
77
		$this->voteMapper = $voteMapper;
78
		$this->circlesService = $circlesService;
79
		$this->contactsService = $contactsService;
80
		$this->shareMapper = $shareMapper;
81
	}
82
83
	/**
84
	 * Validate string as email address
85
	 * @NoAdminRequired
86
	 * @param string $emailAddress
87
	 * @return bool
88
	 */
89
	private function isValidEmail($emailAddress) {
90
		return (!preg_match('/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/', $emailAddress)) ? false : true;
91
	}
92
93
94
	/**
95
	 * Get a list of users
96
	 * @NoAdminRequired
97
	 * @param string $query
98
	 * @param array $skip - usernames to skip in return array
99
	 * @return User[]
100
	 */
101
	public function getSiteUsers($query = '', $skip = []) {
102
		$users = [];
103
		foreach ($this->userManager->searchDisplayName($query) as $user) {
104
			if (!in_array($user->getUID(), $skip) && $user->isEnabled()) {
105
				$users[] = new User(User::TYPE_USER, $user->getUID());
106
			}
107
		}
108
		return $users;
109
	}
110
111
	/**
112
	 * Get a list of user groups
113
	 * @NoAdminRequired
114
	 * @param string $query
115
	 * @param array $skip - group names to skip in return array
116
	 * @return User[]
117
	 */
118
	public function getSiteGroups($query = '', $skip = []) {
119
		$groups = [];
120
		foreach ($this->groupManager->search($query) as $group) {
121
			if (!in_array($group->getGID(), $skip)) {
122
				$groups[] = new User(User::TYPE_GROUP, $group->getGID());
123
			}
124
		}
125
		return $groups;
126
	}
127
128
	/**
129
	 * Get a combined list of NC users, groups and contacts
130
	 * @NoAdminRequired
131
	 * @param string $query
132
	 * @param bool $getGroups - search in groups
133
	 * @param bool $getUsers - search in site users
134
	 * @param bool $getContacts - search in contacs
135
	 * @param bool $getContactGroups - search in contacs
136
	 * @param array $skipGroups - group names to skip in return array
137
	 * @param array $skipUsers - user names to skip in return array
138
	 * @return Array
139
	 */
140
	public function getSiteUsersAndGroups(
141
		$query = '',
142
		$getGroups = true,
143
		$getUsers = true,
144
		$getContacts = true,
145
		$getContactGroups = true,
0 ignored issues
show
Unused Code introduced by
The parameter $getContactGroups is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

145
		/** @scrutinizer ignore-unused */ $getContactGroups = true,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
146
		$getMail = false,
147
		$skipGroups = [],
148
		$skipUsers = []
149
	) {
150
		$list = [];
151
		if ($query !== '') {
152
			if ($getMail && $this->isValidEmail($query)) {
153
				$list[] = new User(User::TYPE_EMAIL, $query);
154
			}
155
156
			if ($getGroups) {
157
				$list = array_merge($list, $this->getSiteGroups($query, $skipGroups));
158
			}
159
160
			if ($getUsers) {
161
				$list = array_merge($list, $this->getSiteUsers($query, $skipUsers));
162
			}
163
164
			if ($getContacts) {
165
				$list = array_merge($list, $this->contactsService->getContacts($query));
166
			}
167
168
			if ($getContacts) {
169
				$list = array_merge($list, $this->contactsService->getContactsGroups($query));
170
			}
171
			$list = array_merge($list, $this->circlesService->getCircles($query));
172
		}
173
174
		return $list;
175
	}
176
177
	/**
178
	 * Validate it the user name is reservrd
179
	 * return false, if this username already exists as a user or as
180
	 * a participant of the poll
181
	 * @NoAdminRequired
182
	 * @return Boolean
183
	 * @throws InvalidEmailAddress
184
	 */
185
	public function validateEmailAddress($emailAddress) {
186
		if (!$this->isValidEmail($emailAddress)) {
187
			throw new InvalidEmailAddress;
188
		}
189
		return true;
190
	}
191
192
193
	/**
194
	 * Validate it the user name is reservrd
195
	 * return false, if this username already exists as a user or as
196
	 * a participant of the poll
197
	 * @NoAdminRequired
198
	 * @return Boolean
199
	 * @throws NotAuthorizedException
200
	 * @throws TooShortException
201
	 * @throws InvalidUsernameException
202
	 */
203
	public function validatePublicUsername($pollId, $userName, $token) {
204
		$userName = strtolower(trim($userName));
205
206
		// return forbidden, if $pollId does not match the share's pollId, force int compare
207
		if (intval($this->shareMapper->findByToken($token)->getPollId()) !== intVal($pollId)) {
208
			throw new NotAuthorizedException;
209
		}
210
211
		// return forbidden, if the length of the userame is lower than 3 characters
212
		if (strlen($userName) < 3) {
213
			return new TooShortException('Username must have at least 3 characters');
214
		}
215
		$list = [];
216
217
		// get all groups
218
		foreach ($this->getSiteGroups() as $user) {
219
			if ($userName === strtolower(trim($user->getUserId()))
220
				|| $userName === strtolower(trim($user->getDisplayName()))) {
221
				throw new InvalidUsernameException;
222
			}
223
			$list[] = $user;
224
		}
225
226
		// get all users
227
		foreach ($this->getSiteUsers() as $user) {
228
			if ($userName === strtolower(trim($user->getUserId()))
229
				|| $userName === strtolower(trim($user->getDisplayName()))) {
230
				throw new InvalidUsernameException;
231
			}
232
			$list[] = $user;
233
		}
234
235
		// get all participants
236
		foreach ($this->voteMapper->findParticipantsByPoll($pollId) as $vote) {
237
			if ($vote->getUserId() !== '' && $vote->getUserId() !== null) {
238
				$list[] = new User(User::TYPE_USER, $vote->getUserId());
239
				if ($userName === strtolower(trim(end($list)->getUserId()))
240
					|| $userName === strtolower(trim(end($list)->getDisplayName()))) {
241
					throw new InvalidUsernameException;
242
				}
243
			}
244
		}
245
246
		// get all shares for this poll
247
		foreach ($this->shareMapper->findByPoll($pollId) as $share) {
248
			if ($share->getUserId() !== ''
249
				&& $share->getUserId() !== null
250
				&& $share->getType() !== User::TYPE_CIRCLE) {
251
				$user = new User($share->getType(), $share->getUserId());
252
				\OC::$server->getLogger()->alert(json_encode($user));
253
				if ($userName === strtolower(trim($user->getUserId()))
254
					|| $userName === strtolower(trim($share->getDisplayName()))
255
					|| $userName === strtolower(trim($user->getDisplayName()))) {
256
					throw new InvalidUsernameException;
257
				}
258
				$list[] = new User($share->getType(), $share->getUserId());
259
			}
260
		}
261
		// return true, if username is allowed
262
		return true;
263
	}
264
}
265