Completed
Pull Request — master (#9261)
by John
34:10 queued 10:11
created

Group::addUser()   B

Complexity

Conditions 7
Paths 13

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
nc 13
nop 1
dl 0
loc 21
rs 7.551
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bart Visscher <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Morris Jobke <[email protected]>
9
 * @author Robin Appelman <[email protected]>
10
 * @author Robin McCorkell <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 * @author Vincent Petry <[email protected]>
13
 *
14
 * @license AGPL-3.0
15
 *
16
 * This code is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License, version 3,
18
 * as published by the Free Software Foundation.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License, version 3,
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
27
 *
28
 */
29
30
namespace OC\Group;
31
32
use OCP\IGroup;
33
use OCP\IUser;
34
35
class Group implements IGroup {
36
	/** @var null|string  */
37
	protected $displayName;
38
39
	/**
40
	 * @var string $id
41
	 */
42
	private $gid;
43
44
	/**
45
	 * @var \OC\User\User[] $users
46
	 */
47
	private $users = array();
48
49
	/**
50
	 * @var bool $usersLoaded
51
	 */
52
	private $usersLoaded;
53
54
	/**
55
	 * @var \OC\Group\Backend[]|\OC\Group\Database[] $backend
56
	 */
57
	private $backends;
58
59
	/**
60
	 * @var \OC\Hooks\PublicEmitter $emitter
61
	 */
62
	private $emitter;
63
64
	/**
65
	 * @var \OC\User\Manager $userManager
66
	 */
67
	private $userManager;
68
69
	/**
70
	 * @param string $gid
71
	 * @param \OC\Group\Backend[] $backends
72
	 * @param \OC\User\Manager $userManager
73
	 * @param \OC\Hooks\PublicEmitter $emitter
74
	 * @param string $displayName
75
	 */
76
	public function __construct($gid, $backends, $userManager, $emitter = null, $displayName = null) {
77
		$this->gid = $gid;
78
		$this->backends = $backends;
79
		$this->userManager = $userManager;
80
		$this->emitter = $emitter;
81
		$this->displayName = $displayName;
82
	}
83
84
	public function getGID() {
85
		return $this->gid;
86
	}
87
88
	public function getDisplayName() {
89
		if (is_null($this->displayName)) {
90
			return $this->gid;
91
		}
92
		return $this->displayName;
93
	}
94
95
	/**
96
	 * get all users in the group
97
	 *
98
	 * @return \OC\User\User[]
99
	 */
100
	public function getUsers() {
101
		if ($this->usersLoaded) {
102
			return $this->users;
103
		}
104
105
		$userIds = array();
106
		foreach ($this->backends as $backend) {
107
			$diff = array_diff(
108
				$backend->usersInGroup($this->gid),
109
				$userIds
110
			);
111
			if ($diff) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $diff of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
112
				$userIds = array_merge($userIds, $diff);
113
			}
114
		}
115
116
		$this->users = $this->getVerifiedUsers($userIds);
117
		$this->usersLoaded = true;
118
		return $this->users;
119
	}
120
121
	/**
122
	 * check if a user is in the group
123
	 *
124
	 * @param IUser $user
125
	 * @return bool
126
	 */
127
	public function inGroup(IUser $user) {
128
		if (isset($this->users[$user->getUID()])) {
129
			return true;
130
		}
131
		foreach ($this->backends as $backend) {
132
			if ($backend->inGroup($user->getUID(), $this->gid)) {
133
				$this->users[$user->getUID()] = $user;
134
				return true;
135
			}
136
		}
137
		return false;
138
	}
139
140
	/**
141
	 * add a user to the group
142
	 *
143
	 * @param IUser $user
144
	 */
145
	public function addUser(IUser $user) {
146
		if ($this->inGroup($user)) {
147
			return;
148
		}
149
150
		if ($this->emitter) {
151
			$this->emitter->emit('\OC\Group', 'preAddUser', array($this, $user));
152
		}
153
		foreach ($this->backends as $backend) {
154
			if ($backend->implementsActions(\OC\Group\Backend::ADD_TO_GROUP)) {
155
				$backend->addToGroup($user->getUID(), $this->gid);
156
				if ($this->users) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->users of type OC\User\User[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
157
					$this->users[$user->getUID()] = $user;
158
				}
159
				if ($this->emitter) {
160
					$this->emitter->emit('\OC\Group', 'postAddUser', array($this, $user));
161
				}
162
				return;
163
			}
164
		}
165
	}
166
167
	/**
168
	 * remove a user from the group
169
	 *
170
	 * @param \OC\User\User $user
171
	 */
172
	public function removeUser($user) {
173
		$result = false;
174
		if ($this->emitter) {
175
			$this->emitter->emit('\OC\Group', 'preRemoveUser', array($this, $user));
176
		}
177
		foreach ($this->backends as $backend) {
178
			if ($backend->implementsActions(\OC\Group\Backend::REMOVE_FROM_GOUP) and $backend->inGroup($user->getUID(), $this->gid)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
179
				$backend->removeFromGroup($user->getUID(), $this->gid);
180
				$result = true;
181
			}
182
		}
183
		if ($result) {
184
			if ($this->emitter) {
185
				$this->emitter->emit('\OC\Group', 'postRemoveUser', array($this, $user));
186
			}
187
			if ($this->users) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->users of type OC\User\User[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
188
				foreach ($this->users as $index => $groupUser) {
189
					if ($groupUser->getUID() === $user->getUID()) {
190
						unset($this->users[$index]);
191
						return;
192
					}
193
				}
194
			}
195
		}
196
	}
197
198
	/**
199
	 * search for users in the group by userid
200
	 *
201
	 * @param string $search
202
	 * @param int $limit
203
	 * @param int $offset
204
	 * @return \OC\User\User[]
205
	 */
206 View Code Duplication
	public function searchUsers($search, $limit = null, $offset = null) {
207
		$users = array();
208
		foreach ($this->backends as $backend) {
209
			$userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset);
210
			$users += $this->getVerifiedUsers($userIds);
211
			if (!is_null($limit) and $limit <= 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
212
				return array_values($users);
213
			}
214
		}
215
		return array_values($users);
216
	}
217
218
	/**
219
	 * returns the number of users matching the search string
220
	 *
221
	 * @param string $search
222
	 * @return int|bool
223
	 */
224 View Code Duplication
	public function count($search = '') {
225
		$users = false;
226
		foreach ($this->backends as $backend) {
227
			if($backend->implementsActions(\OC\Group\Backend::COUNT_USERS)) {
228
				if($users === false) {
229
					//we could directly add to a bool variable, but this would
230
					//be ugly
231
					$users = 0;
232
				}
233
				$users += $backend->countUsersInGroup($this->gid, $search);
0 ignored issues
show
Bug introduced by
The method countUsersInGroup() does not exist on OC\Group\Backend. Did you maybe mean inGroup()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
234
			}
235
		}
236
		return $users;
0 ignored issues
show
Bug Compatibility introduced by
The expression return $users; of type integer|double|false is incompatible with the return type declared by the interface OCP\IGroup::count of type integer|boolean as it can also be of type double which is not included in this return type.
Loading history...
237
	}
238
239
	/**
240
	 * returns the number of disabled users
241
	 *
242
	 * @return int|bool
243
	 */
244 View Code Duplication
	public function countDisabled() {
245
		$users = false;
246
		foreach ($this->backends as $backend) {
247
			if($backend->implementsActions(\OC\Group\Backend::COUNT_DISABLED)) {
248
				if($users === false) {
249
					//we could directly add to a bool variable, but this would
250
					//be ugly
251
					$users = 0;
252
				}
253
				$users += $backend->countUsersInGroup($this->gid);
0 ignored issues
show
Bug introduced by
The method countUsersInGroup() does not exist on OC\Group\Backend. Did you maybe mean inGroup()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
254
			}
255
		}
256
		return $users;
257
	}
258
259
	/**
260
	 * search for users in the group by displayname
261
	 *
262
	 * @param string $search
263
	 * @param int $limit
264
	 * @param int $offset
265
	 * @return \OC\User\User[]
266
	 */
267 View Code Duplication
	public function searchDisplayName($search, $limit = null, $offset = null) {
268
		$users = array();
269
		foreach ($this->backends as $backend) {
270
			$userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset);
271
			$users = $this->getVerifiedUsers($userIds);
272
			if (!is_null($limit) and $limit <= 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
273
				return array_values($users);
274
			}
275
		}
276
		return array_values($users);
277
	}
278
279
	/**
280
	 * delete the group
281
	 *
282
	 * @return bool
283
	 */
284
	public function delete() {
285
		// Prevent users from deleting group admin
286
		if ($this->getGID() === 'admin') {
287
			return false;
288
		}
289
290
		$result = false;
291
		if ($this->emitter) {
292
			$this->emitter->emit('\OC\Group', 'preDelete', array($this));
293
		}
294
		foreach ($this->backends as $backend) {
295
			if ($backend->implementsActions(\OC\Group\Backend::DELETE_GROUP)) {
296
				$result = true;
297
				$backend->deleteGroup($this->gid);
298
			}
299
		}
300
		if ($result and $this->emitter) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
301
			$this->emitter->emit('\OC\Group', 'postDelete', array($this));
302
		}
303
		return $result;
304
	}
305
306
	/**
307
	 * returns all the Users from an array that really exists
308
	 * @param string[] $userIds an array containing user IDs
309
	 * @return \OC\User\User[] an Array with the userId as Key and \OC\User\User as value
310
	 */
311
	private function getVerifiedUsers($userIds) {
312
		if (!is_array($userIds)) {
313
			return array();
314
		}
315
		$users = array();
316
		foreach ($userIds as $userId) {
317
			$user = $this->userManager->get($userId);
318
			if (!is_null($user)) {
319
				$users[$userId] = $user;
320
			}
321
		}
322
		return $users;
323
	}
324
}
325