Completed
Pull Request — master (#1038)
by René
06:20
created

SystemService::getContacts()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 32
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

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

285
		/** @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...
286
		$getMail = false,
287
		$skipGroups = [],
288
		$skipUsers = []
289
	) {
290
		$list = [];
291
292
		if ($getMail && $this->isValidEmail($query)) {
293
			$list[] = [
294
				'id' => '',
295
				'user' => '',
296
				'organisation' => '',
297
				'displayName' => '',
298
				'emailAddress' => $query,
299
				'desc' => $query,
300
				'type' => 'email',
301
				'icon' => 'icon-mail',
302
				'avatarURL' => '',
303
				'avatar' => '',
304
				'lastLogin' => '',
305
				'cloudId' => ''
306
307
			];
308
		}
309
		if ($getGroups) {
310
			$list = array_merge($list, $this->getSiteGroups($query, $skipGroups));
311
		}
312
313
		if ($getUsers) {
314
			$list = array_merge($list, $this->getSiteUsers($query, $skipUsers));
315
		}
316
317
		if (\OC::$server->getContactsManager()->isEnabled()) {
318
			if ($getContacts) {
319
				$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

319
				$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...
320
			}
321
322
			if ($getContacts) {
323
				$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

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