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

SystemService   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 7
Bugs 2 Features 1
Metric Value
wmc 41
eloc 75
dl 0
loc 225
ccs 0
cts 151
cp 0
rs 9.1199
c 7
b 2
f 1

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\Service\CirclesService;
34
use OCA\Polls\Service\ContactsService;
35
use OCA\Polls\Db\Share;
36
use OCA\Polls\Db\ShareMapper;
37
use OCA\Polls\Db\VoteMapper;
38
use OCA\Polls\Model\User;
39
40
class SystemService {
41
42
	/** @var IGroupManager */
43
	private $groupManager;
44
45
	/** @var IUserManager */
46
	private $userManager;
47
48
	/** @var CirclesService */
49
	private $circlesService;
50
51
	/** @var ContactsService */
52
	private $contactsService;
53
54
	/** @var VoteMapper */
55
	private $voteMapper;
56
57
	/** @var ShareMapper */
58
	private $shareMapper;
59
60
	/**
61
	 * SystemService constructor.
62
	 * @param IGroupManager $groupManager
63
	 * @param IUserManager $userManager
64
	 * @param CirclesService $circlesService,
65
	 * @param ContactsService $contactsService,
66
	 * @param VoteMapper $voteMapper
67
	 * @param ShareMapper $shareMapper
68
	 */
69
	public function __construct(
70
		IGroupManager $groupManager,
71
		IUserManager $userManager,
72
		VoteMapper $voteMapper,
73
		CirclesService $circlesService,
74
		ContactsService $contactsService,
75
		ShareMapper $shareMapper
76
	) {
77
		$this->groupManager = $groupManager;
78
		$this->userManager = $userManager;
79
		$this->voteMapper = $voteMapper;
80
		$this->circlesService = $circlesService;
81
		$this->contactsService = $contactsService;
82
		$this->shareMapper = $shareMapper;
83
	}
84
85
	/**
86
	 * Validate string as email address
87
	 * @NoAdminRequired
88
	 * @param string $emailAddress
89
	 * @return bool
90
	 */
91
	private function isValidEmail($emailAddress) {
92
		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;
93
	}
94
95
96
	/**
97
	 * Get a list of users
98
	 * @NoAdminRequired
99
	 * @param string $query
100
	 * @param array $skip - usernames to skip in return array
101
	 * @return User[]
102
	 */
103
	public function getSiteUsers($query = '', $skip = []) {
104
		$users = [];
105
		foreach ($this->userManager->searchDisplayName($query) as $user) {
106
			if (!in_array($user->getUID(), $skip) && $user->isEnabled()) {
107
				$users[] = new User(User::TYPE_USER, $user->getUID());
108
			}
109
		}
110
		return $users;
111
	}
112
113
	/**
114
	 * Get a list of user groups
115
	 * @NoAdminRequired
116
	 * @param string $query
117
	 * @param array $skip - group names to skip in return array
118
	 * @return User[]
119
	 */
120
	public function getSiteGroups($query = '', $skip = []) {
121
		$groups = [];
122
		foreach ($this->groupManager->search($query) as $group) {
123
			if (!in_array($group->getGID(), $skip)) {
124
				$groups[] = new User(User::TYPE_GROUP, $group->getGID());
125
			}
126
		}
127
		return $groups;
128
	}
129
130
	/**
131
	 * Get a combined list of NC users, groups and contacts
132
	 * @NoAdminRequired
133
	 * @param string $query
134
	 * @param bool $getGroups - search in groups
135
	 * @param bool $getUsers - search in site users
136
	 * @param bool $getContacts - search in contacs
137
	 * @param bool $getContactGroups - search in contacs
138
	 * @param array $skipGroups - group names to skip in return array
139
	 * @param array $skipUsers - user names to skip in return array
140
	 * @return Array
141
	 */
142
	public function getSiteUsersAndGroups(
143
		$query = '',
144
		$getGroups = true,
145
		$getUsers = true,
146
		$getContacts = true,
147
		$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

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