SystemService   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 31
eloc 46
dl 0
loc 132
ccs 0
cts 76
cp 0
rs 9.92
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A isValidEmail() 0 2 2
A validateEmailAddress() 0 7 4
A __construct() 0 6 1
A getSiteUsers() 0 8 4
A getSiteUsersAndGroups() 0 11 3
C validatePublicUsername() 0 50 17
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\TooShortException;
27
use OCA\Polls\Exceptions\InvalidUsernameException;
28
use OCA\Polls\Exceptions\InvalidEmailAddress;
29
30
use OCA\Polls\Db\ShareMapper;
31
use OCA\Polls\Db\VoteMapper;
32
use OCA\Polls\Model\Circle;
33
use OCA\Polls\Model\Contact;
34
use OCA\Polls\Model\ContactGroup;
35
use OCA\Polls\Model\Email;
36
use OCA\Polls\Model\Group;
37
use OCA\Polls\Model\User;
38
use OCA\Polls\Model\UserGroupClass;
39
40
class SystemService {
41
42
	/** @var VoteMapper */
43
	private $voteMapper;
44
45
	/** @var ShareMapper */
46
	private $shareMapper;
47
48
	public function __construct(
49
		VoteMapper $voteMapper,
50
		ShareMapper $shareMapper
51
	) {
52
		$this->voteMapper = $voteMapper;
53
		$this->shareMapper = $shareMapper;
54
	}
55
56
	/**
57
	 * Validate string as email address
58
	 *
59
	 * @return bool
60
	 */
61
	private static function isValidEmail(string $emailAddress): bool {
62
		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;
63
	}
64
65
	/**
66
	 * Validate email address and throw an exception
67
	 * return true, if email address is a valid
68
	 *
69
	 * @return true
70
	 */
71
	public static function validateEmailAddress(string $emailAddress, bool $emptyIsValid = false): bool {
72
		if (!$emailAddress && $emptyIsValid) {
73
			return true;
74
		} elseif (!self::isValidEmail($emailAddress)) {
75
			throw new InvalidEmailAddress;
76
		}
77
		return true;
78
	}
79
80
	/**
81
	 * Get a list of users
82
	 * @param string $query
83
	 * @param string[] $skip
84
	 */
85
	public static function getSiteUsers(string $query = '', array $skip = []): array {
86
		$users = [];
87
		foreach (\OC::$server->getUserManager()->searchDisplayName($query) as $user) {
88
			if (!in_array($user->getUID(), $skip) && $user->isEnabled()) {
89
				$users[] = new User($user->getUID());
90
			}
91
		}
92
		return $users;
93
	}
94
95
	/**
96
	 * Get a combined list of users, groups, circles, contact groups and contacts
97
	 *
98
	 * @return (Circle|Email|Group|User|Contact|ContactGroup|mixed)[]
99
	 *
100
	 * @psalm-return array<array-key, Circle|Email|Group|User|Contact|ContactGroup|mixed>
101
	 */
102
	public function getSiteUsersAndGroups(string $query = ''): array {
103
		$list = [];
104
		if ($query !== '') {
105
			if (self::isValidEmail($query)) {
106
				$list[] = new Email($query);
107
			}
108
109
			$list = array_merge($list, UserGroupClass::search($query));
110
		}
111
112
		return $list;
113
	}
114
115
	/**
116
	 * Validate it the user name is reserved
117
	 * return false, if this username already exists as a user or as
118
	 * a participant of the poll
119
	 *
120
	 * @return true
121
	 */
122
	public function validatePublicUsername(string $userName, string $token): bool {
123
		$share = $this->shareMapper->findByToken($token);
124
125
		if ($share->getDisplayName() === $userName) {
126
			return true;
127
		}
128
129
		$userName = strtolower(trim($userName));
130
131
		// return forbidden, if the length of the userame is lower than 3 characters
132
		if (strlen($userName) < 3) {
133
			throw new TooShortException('Username must have at least 3 characters');
134
		}
135
136
		// get all groups
137
		foreach (Group::search() as $group) {
138
			if ($userName === strtolower(trim($group->getId()))
139
				|| $userName === strtolower(trim($group->getDisplayName()))) {
140
				throw new InvalidUsernameException;
141
			}
142
		}
143
144
		// get all users
145
		foreach (User::search($userName) as $user) {
146
			if ($userName === strtolower(trim($user->getId()))
147
				|| $userName === strtolower(trim($user->getDisplayName()))) {
148
				throw new InvalidUsernameException;
149
			}
150
		}
151
152
		// get all participants
153
		foreach ($this->voteMapper->findParticipantsByPoll($share->getPollId()) as $vote) {
154
			if ($vote->getUserId()) {
155
				if ($userName === strtolower(trim($vote->getUserId()))) {
156
					throw new InvalidUsernameException;
157
				}
158
			}
159
		}
160
161
		// get all shares for this poll
162
		foreach ($this->shareMapper->findByPoll($share->getPollId()) as $share) {
163
			if ($share->getUserId() && $share->getType() !== Circle::TYPE) {
164
				if ($userName === strtolower(trim($share->getUserId()))
165
					|| $userName === strtolower(trim($share->getDisplayName()))) {
166
					throw new InvalidUsernameException;
167
				}
168
			}
169
		}
170
		// return true, if username is allowed
171
		return true;
172
	}
173
}
174