Completed
Pull Request — master (#1038)
by René
04:22
created

SystemService::isValidEmail()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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