Passed
Push — master ( dc3e05...4deff3 )
by Christoph
12:00 queued 10s
created

Manager::createUser()   B

Complexity

Conditions 7
Paths 11

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 14
nc 11
nop 2
dl 0
loc 27
rs 8.8333
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 Bjoern Schiessle <[email protected]>
7
 * @author Christoph Wurst <[email protected]>
8
 * @author Georg Ehrke <[email protected]>
9
 * @author Joas Schilling <[email protected]>
10
 * @author John Molakvoæ (skjnldsv) <[email protected]>
11
 * @author Jörn Friedrich Dreyer <[email protected]>
12
 * @author Lukas Reschke <[email protected]>
13
 * @author Morris Jobke <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 * @author Roeland Jago Douma <[email protected]>
16
 * @author Thomas Müller <[email protected]>
17
 * @author Vincent Chan <[email protected]>
18
 *
19
 * @license AGPL-3.0
20
 *
21
 * This code is free software: you can redistribute it and/or modify
22
 * it under the terms of the GNU Affero General Public License, version 3,
23
 * as published by the Free Software Foundation.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
 * GNU Affero General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Affero General Public License, version 3,
31
 * along with this program. If not, see <http://www.gnu.org/licenses/>
32
 *
33
 */
34
35
namespace OC\User;
36
37
use OC\HintException;
38
use OC\Hooks\PublicEmitter;
39
use OCP\DB\QueryBuilder\IQueryBuilder;
40
use OCP\EventDispatcher\IEventDispatcher;
41
use OCP\IConfig;
42
use OCP\IGroup;
43
use OCP\IUser;
44
use OCP\IUserBackend;
45
use OCP\IUserManager;
46
use OCP\Support\Subscription\IRegistry;
47
use OCP\User\Backend\IGetRealUIDBackend;
48
use OCP\User\Events\BeforeUserCreatedEvent;
49
use OCP\User\Events\UserCreatedEvent;
50
use OCP\UserInterface;
51
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
52
53
/**
54
 * Class Manager
55
 *
56
 * Hooks available in scope \OC\User:
57
 * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
58
 * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
59
 * - preDelete(\OC\User\User $user)
60
 * - postDelete(\OC\User\User $user)
61
 * - preCreateUser(string $uid, string $password)
62
 * - postCreateUser(\OC\User\User $user, string $password)
63
 * - change(\OC\User\User $user)
64
 * - assignedUserId(string $uid)
65
 * - preUnassignedUserId(string $uid)
66
 * - postUnassignedUserId(string $uid)
67
 *
68
 * @package OC\User
69
 */
70
class Manager extends PublicEmitter implements IUserManager {
0 ignored issues
show
Deprecated Code introduced by
The class OC\Hooks\PublicEmitter has been deprecated: 18.0.0 use events and the \OCP\EventDispatcher\IEventDispatcher service ( Ignorable by Annotation )

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

70
class Manager extends /** @scrutinizer ignore-deprecated */ PublicEmitter implements IUserManager {
Loading history...
71
	/**
72
	 * @var \OCP\UserInterface[] $backends
73
	 */
74
	private $backends = [];
75
76
	/**
77
	 * @var \OC\User\User[] $cachedUsers
78
	 */
79
	private $cachedUsers = [];
80
81
	/** @var IConfig */
82
	private $config;
83
84
	/** @var EventDispatcherInterface */
85
	private $dispatcher;
86
87
	/** @var IEventDispatcher */
88
	private $eventDispatcher;
89
90
	public function __construct(IConfig $config,
91
								EventDispatcherInterface $oldDispatcher,
92
								IEventDispatcher $eventDispatcher) {
93
		$this->config = $config;
94
		$this->dispatcher = $oldDispatcher;
95
		$cachedUsers = &$this->cachedUsers;
96
		$this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
97
			/** @var \OC\User\User $user */
98
			unset($cachedUsers[$user->getUID()]);
99
		});
100
		$this->eventDispatcher = $eventDispatcher;
101
	}
102
103
	/**
104
	 * Get the active backends
105
	 * @return \OCP\UserInterface[]
106
	 */
107
	public function getBackends() {
108
		return $this->backends;
109
	}
110
111
	/**
112
	 * register a user backend
113
	 *
114
	 * @param \OCP\UserInterface $backend
115
	 */
116
	public function registerBackend($backend) {
117
		$this->backends[] = $backend;
118
	}
119
120
	/**
121
	 * remove a user backend
122
	 *
123
	 * @param \OCP\UserInterface $backend
124
	 */
125
	public function removeBackend($backend) {
126
		$this->cachedUsers = [];
127
		if (($i = array_search($backend, $this->backends)) !== false) {
128
			unset($this->backends[$i]);
129
		}
130
	}
131
132
	/**
133
	 * remove all user backends
134
	 */
135
	public function clearBackends() {
136
		$this->cachedUsers = [];
137
		$this->backends = [];
138
	}
139
140
	/**
141
	 * get a user by user id
142
	 *
143
	 * @param string $uid
144
	 * @return \OC\User\User|null Either the user or null if the specified user does not exist
145
	 */
146
	public function get($uid) {
147
		if (is_null($uid) || $uid === '' || $uid === false) {
148
			return null;
149
		}
150
		if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
151
			return $this->cachedUsers[$uid];
152
		}
153
		foreach ($this->backends as $backend) {
154
			if ($backend->userExists($uid)) {
155
				return $this->getUserObject($uid, $backend);
156
			}
157
		}
158
		return null;
159
	}
160
161
	/**
162
	 * get or construct the user object
163
	 *
164
	 * @param string $uid
165
	 * @param \OCP\UserInterface $backend
166
	 * @param bool $cacheUser If false the newly created user object will not be cached
167
	 * @return \OC\User\User
168
	 */
169
	protected function getUserObject($uid, $backend, $cacheUser = true) {
170
		if ($backend instanceof IGetRealUIDBackend) {
171
			$uid = $backend->getRealUID($uid);
172
		}
173
174
		if (isset($this->cachedUsers[$uid])) {
175
			return $this->cachedUsers[$uid];
176
		}
177
178
		$user = new User($uid, $backend, $this->dispatcher, $this, $this->config);
179
		if ($cacheUser) {
180
			$this->cachedUsers[$uid] = $user;
181
		}
182
		return $user;
183
	}
184
185
	/**
186
	 * check if a user exists
187
	 *
188
	 * @param string $uid
189
	 * @return bool
190
	 */
191
	public function userExists($uid) {
192
		$user = $this->get($uid);
193
		return ($user !== null);
194
	}
195
196
	/**
197
	 * Check if the password is valid for the user
198
	 *
199
	 * @param string $loginName
200
	 * @param string $password
201
	 * @return mixed the User object on success, false otherwise
202
	 */
203
	public function checkPassword($loginName, $password) {
204
		$result = $this->checkPasswordNoLogging($loginName, $password);
205
206
		if ($result === false) {
0 ignored issues
show
introduced by
The condition $result === false is always false.
Loading history...
207
			\OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
208
		}
209
210
		return $result;
211
	}
212
213
	/**
214
	 * Check if the password is valid for the user
215
	 *
216
	 * @internal
217
	 * @param string $loginName
218
	 * @param string $password
219
	 * @return IUser|false the User object on success, false otherwise
220
	 */
221
	public function checkPasswordNoLogging($loginName, $password) {
222
		$loginName = str_replace("\0", '', $loginName);
223
		$password = str_replace("\0", '', $password);
224
225
		foreach ($this->backends as $backend) {
226
			if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
227
				$uid = $backend->checkPassword($loginName, $password);
0 ignored issues
show
Bug introduced by
The method checkPassword() does not exist on OCP\UserInterface. It seems like you code against a sub-type of said class. However, the method does not exist in OC\User\Backend or OCP\User\Backend\ABackend. Are you sure you never get one of those? ( Ignorable by Annotation )

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

227
				/** @scrutinizer ignore-call */ 
228
    $uid = $backend->checkPassword($loginName, $password);
Loading history...
228
				if ($uid !== false) {
229
					return $this->getUserObject($uid, $backend);
230
				}
231
			}
232
		}
233
234
		return false;
235
	}
236
237
	/**
238
	 * search by user id
239
	 *
240
	 * @param string $pattern
241
	 * @param int $limit
242
	 * @param int $offset
243
	 * @return \OC\User\User[]
244
	 */
245
	public function search($pattern, $limit = null, $offset = null) {
246
		$users = [];
247
		foreach ($this->backends as $backend) {
248
			$backendUsers = $backend->getUsers($pattern, $limit, $offset);
249
			if (is_array($backendUsers)) {
250
				foreach ($backendUsers as $uid) {
251
					$users[$uid] = $this->getUserObject($uid, $backend);
252
				}
253
			}
254
		}
255
256
		uasort($users, function ($a, $b) {
257
			/**
258
			 * @var \OC\User\User $a
259
			 * @var \OC\User\User $b
260
			 */
261
			return strcasecmp($a->getUID(), $b->getUID());
262
		});
263
		return $users;
264
	}
265
266
	/**
267
	 * search by displayName
268
	 *
269
	 * @param string $pattern
270
	 * @param int $limit
271
	 * @param int $offset
272
	 * @return \OC\User\User[]
273
	 */
274
	public function searchDisplayName($pattern, $limit = null, $offset = null) {
275
		$users = [];
276
		foreach ($this->backends as $backend) {
277
			$backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
278
			if (is_array($backendUsers)) {
279
				foreach ($backendUsers as $uid => $displayName) {
280
					$users[] = $this->getUserObject($uid, $backend);
281
				}
282
			}
283
		}
284
285
		usort($users, function ($a, $b) {
286
			/**
287
			 * @var \OC\User\User $a
288
			 * @var \OC\User\User $b
289
			 */
290
			return strcasecmp($a->getDisplayName(), $b->getDisplayName());
291
		});
292
		return $users;
293
	}
294
295
	/**
296
	 * @param string $uid
297
	 * @param string $password
298
	 * @throws \InvalidArgumentException
299
	 * @return bool|IUser the created user or false
300
	 */
301
	public function createUser($uid, $password) {
302
		// DI injection is not used here as IRegistry needs the user manager itself for user count and thus it would create a cyclic dependency
303
		if (\OC::$server->get(IRegistry::class)->delegateIsHardUserLimitReached()) {
304
			$l = \OC::$server->getL10N('lib');
305
			throw new HintException($l->t('The user limit has been reached and the user was not created.'));
306
		}
307
308
		$localBackends = [];
309
		foreach ($this->backends as $backend) {
310
			if ($backend instanceof Database) {
311
				// First check if there is another user backend
312
				$localBackends[] = $backend;
313
				continue;
314
			}
315
316
			if ($backend->implementsActions(Backend::CREATE_USER)) {
317
				return $this->createUserFromBackend($uid, $password, $backend);
318
			}
319
		}
320
321
		foreach ($localBackends as $backend) {
322
			if ($backend->implementsActions(Backend::CREATE_USER)) {
323
				return $this->createUserFromBackend($uid, $password, $backend);
324
			}
325
		}
326
327
		return false;
328
	}
329
330
	/**
331
	 * @param string $uid
332
	 * @param string $password
333
	 * @param UserInterface $backend
334
	 * @return IUser|null
335
	 * @throws \InvalidArgumentException
336
	 */
337
	public function createUserFromBackend($uid, $password, UserInterface $backend) {
338
		$l = \OC::$server->getL10N('lib');
339
340
		// Check the name for bad characters
341
		// Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
342
		if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
343
			throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
344
				. ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
345
		}
346
347
		// No empty username
348
		if (trim($uid) === '') {
349
			throw new \InvalidArgumentException($l->t('A valid username must be provided'));
350
		}
351
352
		// No whitespace at the beginning or at the end
353
		if (trim($uid) !== $uid) {
354
			throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
355
		}
356
357
		// Username only consists of 1 or 2 dots (directory traversal)
358
		if ($uid === '.' || $uid === '..') {
359
			throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
360
		}
361
362
		if (!$this->verifyUid($uid)) {
363
			throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
364
		}
365
366
		// No empty password
367
		if (trim($password) === '') {
368
			throw new \InvalidArgumentException($l->t('A valid password must be provided'));
369
		}
370
371
		// Check if user already exists
372
		if ($this->userExists($uid)) {
373
			throw new \InvalidArgumentException($l->t('The username is already being used'));
374
		}
375
376
		/** @deprecated 21.0.0 use BeforeUserCreatedEvent event with the IEventDispatcher instead */
377
		$this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
378
		$this->eventDispatcher->dispatchTyped(new BeforeUserCreatedEvent($uid, $password));
379
		$state = $backend->createUser($uid, $password);
0 ignored issues
show
Bug introduced by
The method createUser() does not exist on OCP\UserInterface. It seems like you code against a sub-type of said class. However, the method does not exist in OC\User\Backend or OCP\User\Backend\ABackend. Are you sure you never get one of those? ( Ignorable by Annotation )

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

379
		/** @scrutinizer ignore-call */ 
380
  $state = $backend->createUser($uid, $password);
Loading history...
380
		if ($state === false) {
381
			throw new \InvalidArgumentException($l->t('Could not create user'));
382
		}
383
		$user = $this->getUserObject($uid, $backend);
384
		if ($user instanceof IUser) {
0 ignored issues
show
introduced by
$user is always a sub-type of OCP\IUser.
Loading history...
385
			/** @deprecated 21.0.0 use UserCreatedEvent event with the IEventDispatcher instead */
386
			$this->emit('\OC\User', 'postCreateUser', [$user, $password]);
387
			$this->eventDispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
388
		}
389
		return $user;
390
	}
391
392
	/**
393
	 * returns how many users per backend exist (if supported by backend)
394
	 *
395
	 * @param boolean $hasLoggedIn when true only users that have a lastLogin
396
	 *                entry in the preferences table will be affected
397
	 * @return array|int an array of backend class as key and count number as value
398
	 *                if $hasLoggedIn is true only an int is returned
399
	 */
400
	public function countUsers($hasLoggedIn = false) {
401
		if ($hasLoggedIn) {
402
			return $this->countSeenUsers();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->countSeenUsers() returns the type integer which is incompatible with the return type mandated by OCP\IUserManager::countUsers() of array.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
403
		}
404
		$userCountStatistics = [];
405
		foreach ($this->backends as $backend) {
406
			if ($backend->implementsActions(Backend::COUNT_USERS)) {
407
				$backendUsers = $backend->countUsers();
0 ignored issues
show
Bug introduced by
The method countUsers() does not exist on OCP\UserInterface. It seems like you code against a sub-type of said class. However, the method does not exist in OC\User\Backend or OCP\User\Backend\ABackend. Are you sure you never get one of those? ( Ignorable by Annotation )

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

407
				/** @scrutinizer ignore-call */ 
408
    $backendUsers = $backend->countUsers();
Loading history...
408
				if ($backendUsers !== false) {
409
					if ($backend instanceof IUserBackend) {
410
						$name = $backend->getBackendName();
411
					} else {
412
						$name = get_class($backend);
413
					}
414
					if (isset($userCountStatistics[$name])) {
415
						$userCountStatistics[$name] += $backendUsers;
416
					} else {
417
						$userCountStatistics[$name] = $backendUsers;
418
					}
419
				}
420
			}
421
		}
422
		return $userCountStatistics;
423
	}
424
425
	/**
426
	 * returns how many users per backend exist in the requested groups (if supported by backend)
427
	 *
428
	 * @param IGroup[] $groups an array of gid to search in
429
	 * @return array|int an array of backend class as key and count number as value
430
	 *                if $hasLoggedIn is true only an int is returned
431
	 */
432
	public function countUsersOfGroups(array $groups) {
433
		$users = [];
434
		foreach ($groups as $group) {
435
			$usersIds = array_map(function ($user) {
436
				return $user->getUID();
437
			}, $group->getUsers());
438
			$users = array_merge($users, $usersIds);
439
		}
440
		return count(array_unique($users));
441
	}
442
443
	/**
444
	 * The callback is executed for each user on each backend.
445
	 * If the callback returns false no further users will be retrieved.
446
	 *
447
	 * @param \Closure $callback
448
	 * @param string $search
449
	 * @param boolean $onlySeen when true only users that have a lastLogin entry
450
	 *                in the preferences table will be affected
451
	 * @since 9.0.0
452
	 */
453
	public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
454
		if ($onlySeen) {
455
			$this->callForSeenUsers($callback);
456
		} else {
457
			foreach ($this->getBackends() as $backend) {
458
				$limit = 500;
459
				$offset = 0;
460
				do {
461
					$users = $backend->getUsers($search, $limit, $offset);
462
					foreach ($users as $uid) {
463
						if (!$backend->userExists($uid)) {
464
							continue;
465
						}
466
						$user = $this->getUserObject($uid, $backend, false);
467
						$return = $callback($user);
468
						if ($return === false) {
469
							break;
470
						}
471
					}
472
					$offset += $limit;
473
				} while (count($users) >= $limit);
474
			}
475
		}
476
	}
477
478
	/**
479
	 * returns how many users are disabled
480
	 *
481
	 * @return int
482
	 * @since 12.0.0
483
	 */
484
	public function countDisabledUsers(): int {
485
		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
486
		$queryBuilder->select($queryBuilder->func()->count('*'))
487
			->from('preferences')
488
			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
489
			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
490
			->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR));
491
492
493
		$result = $queryBuilder->execute();
494
		$count = $result->fetchColumn();
495
		$result->closeCursor();
496
497
		if ($count !== false) {
498
			$count = (int)$count;
499
		} else {
500
			$count = 0;
501
		}
502
503
		return $count;
504
	}
505
506
	/**
507
	 * returns how many users are disabled in the requested groups
508
	 *
509
	 * @param array $groups groupids to search
510
	 * @return int
511
	 * @since 14.0.0
512
	 */
513
	public function countDisabledUsersOfGroups(array $groups): int {
514
		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
515
		$queryBuilder->select($queryBuilder->createFunction('COUNT(DISTINCT ' . $queryBuilder->getColumnName('uid') . ')'))
516
			->from('preferences', 'p')
517
			->innerJoin('p', 'group_user', 'g', $queryBuilder->expr()->eq('p.userid', 'g.uid'))
518
			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
519
			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
520
			->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
521
			->andWhere($queryBuilder->expr()->in('gid', $queryBuilder->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)));
522
523
		$result = $queryBuilder->execute();
524
		$count = $result->fetchColumn();
525
		$result->closeCursor();
526
527
		if ($count !== false) {
528
			$count = (int)$count;
529
		} else {
530
			$count = 0;
531
		}
532
533
		return $count;
534
	}
535
536
	/**
537
	 * returns how many users have logged in once
538
	 *
539
	 * @return int
540
	 * @since 11.0.0
541
	 */
542
	public function countSeenUsers() {
543
		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
544
		$queryBuilder->select($queryBuilder->func()->count('*'))
545
			->from('preferences')
546
			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
547
			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
548
			->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
549
550
		$query = $queryBuilder->execute();
551
552
		$result = (int)$query->fetchColumn();
553
		$query->closeCursor();
554
555
		return $result;
556
	}
557
558
	/**
559
	 * @param \Closure $callback
560
	 * @psalm-param \Closure(\OCP\IUser):?bool $callback
561
	 * @since 11.0.0
562
	 */
563
	public function callForSeenUsers(\Closure $callback) {
564
		$limit = 1000;
565
		$offset = 0;
566
		do {
567
			$userIds = $this->getSeenUserIds($limit, $offset);
568
			$offset += $limit;
569
			foreach ($userIds as $userId) {
570
				foreach ($this->backends as $backend) {
571
					if ($backend->userExists($userId)) {
572
						$user = $this->getUserObject($userId, $backend, false);
573
						$return = $callback($user);
574
						if ($return === false) {
575
							return;
576
						}
577
						break;
578
					}
579
				}
580
			}
581
		} while (count($userIds) >= $limit);
582
	}
583
584
	/**
585
	 * Getting all userIds that have a listLogin value requires checking the
586
	 * value in php because on oracle you cannot use a clob in a where clause,
587
	 * preventing us from doing a not null or length(value) > 0 check.
588
	 *
589
	 * @param int $limit
590
	 * @param int $offset
591
	 * @return string[] with user ids
592
	 */
593
	private function getSeenUserIds($limit = null, $offset = null) {
594
		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
595
		$queryBuilder->select(['userid'])
596
			->from('preferences')
597
			->where($queryBuilder->expr()->eq(
598
				'appid', $queryBuilder->createNamedParameter('login'))
599
			)
600
			->andWhere($queryBuilder->expr()->eq(
601
				'configkey', $queryBuilder->createNamedParameter('lastLogin'))
602
			)
603
			->andWhere($queryBuilder->expr()->isNotNull('configvalue')
604
			);
605
606
		if ($limit !== null) {
607
			$queryBuilder->setMaxResults($limit);
608
		}
609
		if ($offset !== null) {
610
			$queryBuilder->setFirstResult($offset);
611
		}
612
		$query = $queryBuilder->execute();
613
		$result = [];
614
615
		while ($row = $query->fetch()) {
616
			$result[] = $row['userid'];
617
		}
618
619
		$query->closeCursor();
620
621
		return $result;
622
	}
623
624
	/**
625
	 * @param string $email
626
	 * @return IUser[]
627
	 * @since 9.1.0
628
	 */
629
	public function getByEmail($email) {
630
		$userIds = $this->config->getUsersForUserValueCaseInsensitive('settings', 'email', $email);
0 ignored issues
show
Bug introduced by
The method getUsersForUserValueCaseInsensitive() does not exist on OCP\IConfig. Did you maybe mean getUsersForUserValue()? ( Ignorable by Annotation )

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

630
		/** @scrutinizer ignore-call */ 
631
  $userIds = $this->config->getUsersForUserValueCaseInsensitive('settings', 'email', $email);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
631
632
		$users = array_map(function ($uid) {
633
			return $this->get($uid);
634
		}, $userIds);
635
636
		return array_values(array_filter($users, function ($u) {
637
			return ($u instanceof IUser);
638
		}));
639
	}
640
641
	private function verifyUid(string $uid): bool {
642
		$appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
643
644
		if (\in_array($uid, [
645
			'.htaccess',
646
			'files_external',
647
			'.ocdata',
648
			'owncloud.log',
649
			'nextcloud.log',
650
			$appdata], true)) {
651
			return false;
652
		}
653
654
		$dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
655
656
		return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
657
	}
658
}
659