Passed
Pull Request — master (#1038)
by René
03:48
created

SystemService::getContactsGroups()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 20
dl 0
loc 26
rs 9.2888
c 1
b 0
f 1
cc 5
nc 4
nop 1
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
37
class SystemService {
38
39
	/** @var IGroupManager */
40
	private $groupManager;
41
42
	/** @var IUserManager */
43
	private $userManager;
44
45
	/** @var VoteMapper */
46
	private $voteMapper;
47
48
	/** @var ShareMapper */
49
	private $shareMapper;
50
51
	/**
52
	 * SystemService constructor.
53
	 * @param IGroupManager $groupManager
54
	 * @param IUserManager $userManager
55
	 * @param VoteMapper $voteMapper
56
	 * @param ShareMapper $shareMapper
57
	 */
58
	public function __construct(
59
		IGroupManager $groupManager,
60
		IUserManager $userManager,
61
		VoteMapper $voteMapper,
62
		ShareMapper $shareMapper
63
	) {
64
		$this->groupManager = $groupManager;
65
		$this->userManager = $userManager;
66
		$this->voteMapper = $voteMapper;
67
		$this->shareMapper = $shareMapper;
68
	}
69
70
	/**
71
	 * Validate string as email address
72
	 * @NoAdminRequired
73
	 * @param string $emailAddress
74
	 * @return bool
75
	 */
76
	private function isValidEmail($emailAddress) {
77
		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;
78
	}
79
80
81
	/**
82
	 * Get a list of users
83
	 * @NoAdminRequired
84
	 * @param string $query
85
	 * @param array $skip - usernames to skip in return array
86
	 * @return Array
87
	 */
88
	public function getSiteUsers($query = '', $skip = []) {
89
		$users = [];
90
		foreach ($this->userManager->searchDisplayName($query) as $user) {
91
			if (!in_array($user->getUID(), $skip) && $user->isEnabled()) {
92
				$users[] = [
93
					'id' => $user->getUID(),
94
					'user' => $user->getUID(),
95
					'displayName' => $user->getDisplayName(),
96
					'organisation' => '',
97
					'emailAddress' => $user->getEMailAddress(),
98
					'desc' => 'User',
99
					'type' => 'user',
100
					'icon' => 'icon-user',
101
					'avatarURL' => '',
102
					'avatar' => '',
103
					'lastLogin' => $user->getLastLogin(),
104
					'cloudId' => $user->getCloudId()
105
				];
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 Array
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
				try {
123
					// seems to work only from NC19 on
124
					$displayName = $group->getDisplayName();
125
				} catch (\Exception $e) {
126
					// fallback
127
					$displayName = $group->getGID();
128
				}
129
130
				$groups[] = [
131
					'id' => $group->getGID(),
132
					'user' => $group->getGID(),
133
					'organisation' => '',
134
					'displayName' => $displayName,
135
					'emailAddress' => '',
136
					'desc' => 'Group',
137
					'type' => 'group',
138
					'icon' => 'icon-group',
139
					'avatarURL' => '',
140
					'avatar' => '',
141
					'lastLogin' => '',
142
					'cloudId' => ''
143
144
				];
145
			}
146
		}
147
		return $groups;
148
	}
149
150
	/**
151
	 * Get a list of contacts
152
	 * @NoAdminRequired
153
	 * @param string $query
154
	 * @return Array
155
	 */
156
	public function getContacts($query = '') {
157
		$contacts = [];
158
		foreach (\OC::$server->getContactsManager()->search($query, ['FN', 'EMAIL', 'ORG', 'CATEGORIES']) as $contact) {
159
			if (!array_key_exists('isLocalSystemBook', $contact) && array_key_exists('EMAIL', $contact)) {
160
				$emailAdresses = $contact['EMAIL'];
161
162
				if (!is_array($emailAdresses)) {
163
					$emailAdresses = [$emailAdresses];
164
				} else {
165
					// take the first eMail address for now
166
					$emailAdresses = [$emailAdresses[0]];
167
				}
168
169
				foreach ($emailAdresses as $emailAddress) {
170
					$contacts[] = [
171
						'id' => $contact['UID'],
172
						'user' => $contact['FN'],
173
						'displayName' => $contact['FN'],
174
						'organisation' => isset($contact['ORG']) ? $contact['ORG'] : '',
175
						'emailAddress' => $emailAddress,
176
						'desc' => 'Contact',
177
						'type' => 'contact',
178
						'icon' => 'icon-mail',
179
						'avatarURL' => '',
180
						'avatar' => '',
181
						'lastLogin' => '',
182
						'cloudId' => '',
183
					];
184
				}
185
			}
186
		}
187
		return $contacts;
188
	}
189
190
	/**
191
	 * Get a list of contacts
192
	 * @NoAdminRequired
193
	 * @param string $query
194
	 * @return Array
195
	 */
196
	public function getContactsGroupMembers($query = '') {
197
		$contacts = [];
198
		foreach (\OC::$server->getContactsManager()->search($query, ['CATEGORIES']) as $contact) {
199
			if (
200
				   !array_key_exists('isLocalSystemBook', $contact)
201
				&& array_key_exists('EMAIL', $contact)
202
				&& in_array($query, explode(',', $contact['CATEGORIES']))
203
			) {
204
				$emailAdresses = $contact['EMAIL'];
205
206
				if (!is_array($emailAdresses)) {
207
					$emailAdresses = [$emailAdresses];
208
				} else {
209
					// take the first eMail address for now
210
					$emailAdresses = [$emailAdresses[0]];
211
				}
212
213
				foreach ($emailAdresses as $emailAddress) {
214
					$contacts[] = [
215
						'id' => $contact['UID'],
216
						'user' => $contact['FN'],
217
						'displayName' => $contact['FN'],
218
						'organisation' => isset($contact['ORG']) ? $contact['ORG'] : '',
219
						'emailAddress' => $emailAddress,
220
						'desc' => 'Contact',
221
						'type' => 'contact',
222
						'icon' => 'icon-mail',
223
						'avatarURL' => '',
224
						'avatar' => '',
225
						'lastLogin' => '',
226
						'cloudId' => '',
227
					];
228
				}
229
			}
230
		}
231
		return $contacts;
232
	}
233
234
	/**
235
	 * Get a list of contact groups
236
	 * @NoAdminRequired
237
	 * @param string $query
238
	 * @return Array
239
	 */
240
	public function getContactsGroups($query = '') {
241
		$contactGroups = [];
242
		$foundContacts = [];
243
244
		foreach (\OC::$server->getContactsManager()->search($query, ['CATEGORIES']) as $contact) {
245
			foreach (explode(',', $contact['CATEGORIES']) as $contactGroup) {
246
				if (strpos($contactGroup, $query) === 0 && !in_array($contactGroup, $foundContacts)) {
247
					$foundContacts[] = $contactGroup;
248
					$contactGroups[] = [
249
						'id' => 'contactgroup_' +$contactGroup,
250
						'user' => $contactGroup,
251
						'displayName' => $contactGroup,
252
						'organisation' => '',
253
						'emailAddress' => '',
254
						'desc' => 'Contact Group',
255
						'type' => 'contactGroup',
256
						'icon' => 'icon-group',
257
						'avatarURL' => '',
258
						'avatar' => '',
259
						'lastLogin' => '',
260
						'cloudId' => '',
261
					];
262
				};
263
			}
264
		}
265
		return $contactGroups;
266
	}
267
268
269
	/**
270
	 * Get a combined list of NC users, groups and contacts
271
	 * @NoAdminRequired
272
	 * @param string $query
273
	 * @param bool $getGroups - search in groups
274
	 * @param bool $getUsers - search in site users
275
	 * @param bool $getContacts - search in contacs
276
	 * @param bool $getContactGroups - search in contacs
277
	 * @param array $skipGroups - group names to skip in return array
278
	 * @param array $skipUsers - user names to skip in return array
279
	 * @return Array
280
	 */
281
	public function getSiteUsersAndGroups(
282
		$query = '',
283
		$getGroups = true,
284
		$getUsers = true,
285
		$getContacts = true,
286
		$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

286
		/** @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...
287
		$getMail = false,
288
		$skipGroups = [],
289
		$skipUsers = []
290
	) {
291
		$list = [];
292
293
		if ($getMail && $this->isValidEmail($query)) {
294
			$list[] = [
295
				'id' => '',
296
				'user' => '',
297
				'organisation' => '',
298
				'displayName' => '',
299
				'emailAddress' => $query,
300
				'desc' => $query,
301
				'type' => 'email',
302
				'icon' => 'icon-mail',
303
				'avatarURL' => '',
304
				'avatar' => '',
305
				'lastLogin' => '',
306
				'cloudId' => ''
307
308
			];
309
		}
310
		if ($getGroups) {
311
			$list = array_merge($list, $this->getSiteGroups($query, $skipGroups));
312
		}
313
314
		if ($getUsers) {
315
			$list = array_merge($list, $this->getSiteUsers($query, $skipUsers));
316
		}
317
318
		if (\OC::$server->getContactsManager()->isEnabled()) {
319
			if ($getContacts) {
320
				$list = array_merge($list, $this->getContacts($query, $skipUsers));
0 ignored issues
show
Unused Code introduced by
The call to OCA\Polls\Service\SystemService::getContacts() has too many arguments starting with $skipUsers. ( Ignorable by Annotation )

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

320
				$list = array_merge($list, $this->/** @scrutinizer ignore-call */ getContacts($query, $skipUsers));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
321
			}
322
323
			if ($getContacts) {
324
				$list = array_merge($list, $this->getContactsGroups($query, $skipGroups));
0 ignored issues
show
Unused Code introduced by
The call to OCA\Polls\Service\System...ce::getContactsGroups() has too many arguments starting with $skipGroups. ( Ignorable by Annotation )

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

324
				$list = array_merge($list, $this->/** @scrutinizer ignore-call */ getContactsGroups($query, $skipGroups));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
325
			}
326
		}
327
328
		return $list;
329
	}
330
331
	/**
332
	 * Validate it the user name is reservrd
333
	 * return false, if this username already exists as a user or as
334
	 * a participant of the poll
335
	 * @NoAdminRequired
336
	 * @return Boolean
337
	 * @throws InvalidEmailAddress
338
	 */
339
	public function validateEmailAddress($emailAddress) {
340
		if (!$this->isValidEmail($emailAddress)) {
341
			throw new InvalidEmailAddress;
342
		}
343
		return true;
344
	}
345
346
347
	/**
348
	 * Validate it the user name is reservrd
349
	 * return false, if this username already exists as a user or as
350
	 * a participant of the poll
351
	 * @NoAdminRequired
352
	 * @return Boolean
353
	 * @throws NotAuthorizedException
354
	 * @throws TooShortException
355
	 * @throws InvalidUsernameException
356
	 */
357
	public function validatePublicUsername($pollId, $userName, $token) {
358
359
		// return forbidden, if $pollId does not match the share's pollId, force int compare
360
		if (intval($this->shareMapper->findByToken($token)->getPollId()) !== intVal($pollId)) {
361
			throw new NotAuthorizedException;
362
		}
363
364
		// return forbidden, if the length of the userame is lower than 3 characters
365
		if (strlen(trim($userName)) < 3) {
366
			return new TooShortException('Username must have at least 3 characters');
367
		}
368
369
		$list = [];
370
371
		// get all groups
372
		$groups = $this->groupManager->search('');
373
		foreach ($groups as $group) {
374
			$list[] = [
375
				'id' => $group->getGID(),
376
				'user' => $group->getGID(),
377
				'type' => 'group',
378
				'displayName' => $group->getGID(),
379
			];
380
		}
381
382
		// get all users
383
		$users = $this->userManager->searchDisplayName('');
384
		foreach ($users as $user) {
385
			$list[] = [
386
				'id' => $user->getUID(),
387
				'user' => $user->getUID(),
388
				'type' => 'user',
389
				'displayName' => $user->getDisplayName(),
390
			];
391
		}
392
393
		// get all participants
394
		$votes = $this->voteMapper->findParticipantsByPoll($pollId);
395
		foreach ($votes as $vote) {
396
			if ($vote->getUserId() !== '' && $vote->getUserId() !== null) {
397
				$list[] = [
398
					'id' => $vote->getUserId(),
399
					'user' => $vote->getUserId(),
400
					'type' => 'participant',
401
					'displayName' => $vote->getUserId(),
402
				];
403
			}
404
		}
405
406
		// get all shares for this poll
407
		$shares = $this->shareMapper->findByPoll($pollId);
408
		foreach ($shares as $share) {
409
			if ($share->getUserId() !== '' && $share->getUserId() !== null) {
410
				$list[] = [
411
					'id' => $share->getUserId(),
412
					'user' => $share->getUserId(),
413
					'type' => 'share',
414
					'displayName' => $share->getUserId(),
415
				];
416
			}
417
		}
418
419
		// check if the username is contained inside the generated list
420
		// return forbidden, if list contains requested username
421
		foreach ($list as $element) {
422
			if (strtolower(trim($userName)) === strtolower(trim($element['id'])) || strtolower(trim($userName)) === strtolower(trim($element['displayName']))) {
423
				throw new InvalidUsernameException;
424
			}
425
		}
426
427
		// return true, if username is allowed
428
		return true;
429
	}
430
}
431