Passed
Push — master ( 90401e...63cb31 )
by Roeland
20:41 queued 20s
created

Manager::countUsers()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 8
nop 1
dl 0
loc 23
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 Joas Schilling <[email protected]>
7
 * @author Jörn Friedrich Dreyer <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Michael U <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author Thomas Müller <[email protected]>
14
 * @author Vincent Chan <[email protected]>
15
 *
16
 * @license AGPL-3.0
17
 *
18
 * This code is free software: you can redistribute it and/or modify
19
 * it under the terms of the GNU Affero General Public License, version 3,
20
 * as published by the Free Software Foundation.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public License, version 3,
28
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
29
 *
30
 */
31
32
namespace OC\User;
33
34
use OC\Hooks\PublicEmitter;
35
use OCP\DB\QueryBuilder\IQueryBuilder;
36
use OCP\EventDispatcher\IEventDispatcher;
37
use OCP\IConfig;
38
use OCP\IGroup;
39
use OCP\IUser;
40
use OCP\IUserBackend;
41
use OCP\IUserManager;
42
use OCP\User\Backend\IGetRealUIDBackend;
43
use OCP\User\Events\CreateUserEvent;
44
use OCP\User\Events\UserCreatedEvent;
45
use OCP\UserInterface;
46
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
47
48
/**
49
 * Class Manager
50
 *
51
 * Hooks available in scope \OC\User:
52
 * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
53
 * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword)
54
 * - preDelete(\OC\User\User $user)
55
 * - postDelete(\OC\User\User $user)
56
 * - preCreateUser(string $uid, string $password)
57
 * - postCreateUser(\OC\User\User $user, string $password)
58
 * - change(\OC\User\User $user)
59
 * - assignedUserId(string $uid)
60
 * - preUnassignedUserId(string $uid)
61
 * - postUnassignedUserId(string $uid)
62
 *
63
 * @package OC\User
64
 */
65
class Manager extends PublicEmitter implements IUserManager {
66
	/**
67
	 * @var \OCP\UserInterface[] $backends
68
	 */
69
	private $backends = array();
70
71
	/**
72
	 * @var \OC\User\User[] $cachedUsers
73
	 */
74
	private $cachedUsers = array();
75
76
	/** @var IConfig */
77
	private $config;
78
79
	/** @var EventDispatcherInterface */
80
	private $dispatcher;
81
82
	/** @var IEventDispatcher */
83
	private $eventDispatcher;
84
85
	public function __construct(IConfig $config,
86
								EventDispatcherInterface $oldDispatcher,
87
								IEventDispatcher $eventDispatcher) {
88
		$this->config = $config;
89
		$this->dispatcher = $oldDispatcher;
90
		$cachedUsers = &$this->cachedUsers;
91
		$this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
92
			/** @var \OC\User\User $user */
93
			unset($cachedUsers[$user->getUID()]);
94
		});
95
		$this->eventDispatcher = $eventDispatcher;
96
	}
97
98
	/**
99
	 * Get the active backends
100
	 * @return \OCP\UserInterface[]
101
	 */
102
	public function getBackends() {
103
		return $this->backends;
104
	}
105
106
	/**
107
	 * register a user backend
108
	 *
109
	 * @param \OCP\UserInterface $backend
110
	 */
111
	public function registerBackend($backend) {
112
		$this->backends[] = $backend;
113
	}
114
115
	/**
116
	 * remove a user backend
117
	 *
118
	 * @param \OCP\UserInterface $backend
119
	 */
120
	public function removeBackend($backend) {
121
		$this->cachedUsers = array();
122
		if (($i = array_search($backend, $this->backends)) !== false) {
123
			unset($this->backends[$i]);
124
		}
125
	}
126
127
	/**
128
	 * remove all user backends
129
	 */
130
	public function clearBackends() {
131
		$this->cachedUsers = array();
132
		$this->backends = array();
133
	}
134
135
	/**
136
	 * get a user by user id
137
	 *
138
	 * @param string $uid
139
	 * @return \OC\User\User|null Either the user or null if the specified user does not exist
140
	 */
141
	public function get($uid) {
142
		if (is_null($uid) || $uid === '' || $uid === false) {
143
			return null;
144
		}
145
		if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
146
			return $this->cachedUsers[$uid];
147
		}
148
		foreach ($this->backends as $backend) {
149
			if ($backend->userExists($uid)) {
150
				return $this->getUserObject($uid, $backend);
151
			}
152
		}
153
		return null;
154
	}
155
156
	/**
157
	 * get or construct the user object
158
	 *
159
	 * @param string $uid
160
	 * @param \OCP\UserInterface $backend
161
	 * @param bool $cacheUser If false the newly created user object will not be cached
162
	 * @return \OC\User\User
163
	 */
164
	protected function getUserObject($uid, $backend, $cacheUser = true) {
165
		if ($backend instanceof IGetRealUIDBackend) {
166
			$uid = $backend->getRealUID($uid);
167
		}
168
169
		if (isset($this->cachedUsers[$uid])) {
170
			return $this->cachedUsers[$uid];
171
		}
172
173
		$user = new User($uid, $backend, $this->dispatcher, $this, $this->config);
174
		if ($cacheUser) {
175
			$this->cachedUsers[$uid] = $user;
176
		}
177
		return $user;
178
	}
179
180
	/**
181
	 * check if a user exists
182
	 *
183
	 * @param string $uid
184
	 * @return bool
185
	 */
186
	public function userExists($uid) {
187
		$user = $this->get($uid);
188
		return ($user !== null);
189
	}
190
191
	/**
192
	 * Check if the password is valid for the user
193
	 *
194
	 * @param string $loginName
195
	 * @param string $password
196
	 * @return mixed the User object on success, false otherwise
197
	 */
198
	public function checkPassword($loginName, $password) {
199
		$result = $this->checkPasswordNoLogging($loginName, $password);
200
201
		if ($result === false) {
0 ignored issues
show
introduced by
The condition $result === false is always false.
Loading history...
202
			\OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
203
		}
204
205
		return $result;
206
	}
207
208
	/**
209
	 * Check if the password is valid for the user
210
	 *
211
	 * @internal
212
	 * @param string $loginName
213
	 * @param string $password
214
	 * @return IUser|false the User object on success, false otherwise
215
	 */
216
	public function checkPasswordNoLogging($loginName, $password) {
217
		$loginName = str_replace("\0", '', $loginName);
218
		$password = str_replace("\0", '', $password);
219
220
		foreach ($this->backends as $backend) {
221
			if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\UserInterface::implementsActions() has been deprecated: 14.0.0 Switch to the interfaces from OCP\User\Backend ( Ignorable by Annotation )

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

221
			if (/** @scrutinizer ignore-deprecated */ $backend->implementsActions(Backend::CHECK_PASSWORD)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
222
				$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

222
				/** @scrutinizer ignore-call */ 
223
    $uid = $backend->checkPassword($loginName, $password);
Loading history...
223
				if ($uid !== false) {
224
					return $this->getUserObject($uid, $backend);
225
				}
226
			}
227
		}
228
229
		return false;
230
	}
231
232
	/**
233
	 * search by user id
234
	 *
235
	 * @param string $pattern
236
	 * @param int $limit
237
	 * @param int $offset
238
	 * @return \OC\User\User[]
239
	 */
240
	public function search($pattern, $limit = null, $offset = null) {
241
		$users = array();
242
		foreach ($this->backends as $backend) {
243
			$backendUsers = $backend->getUsers($pattern, $limit, $offset);
244
			if (is_array($backendUsers)) {
245
				foreach ($backendUsers as $uid) {
246
					$users[$uid] = $this->getUserObject($uid, $backend);
247
				}
248
			}
249
		}
250
251
		uasort($users, function ($a, $b) {
252
			/**
253
			 * @var \OC\User\User $a
254
			 * @var \OC\User\User $b
255
			 */
256
			return strcasecmp($a->getUID(), $b->getUID());
257
		});
258
		return $users;
259
	}
260
261
	/**
262
	 * search by displayName
263
	 *
264
	 * @param string $pattern
265
	 * @param int $limit
266
	 * @param int $offset
267
	 * @return \OC\User\User[]
268
	 */
269
	public function searchDisplayName($pattern, $limit = null, $offset = null) {
270
		$users = array();
271
		foreach ($this->backends as $backend) {
272
			$backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
273
			if (is_array($backendUsers)) {
274
				foreach ($backendUsers as $uid => $displayName) {
275
					$users[] = $this->getUserObject($uid, $backend);
276
				}
277
			}
278
		}
279
280
		usort($users, function ($a, $b) {
281
			/**
282
			 * @var \OC\User\User $a
283
			 * @var \OC\User\User $b
284
			 */
285
			return strcasecmp($a->getDisplayName(), $b->getDisplayName());
286
		});
287
		return $users;
288
	}
289
290
	/**
291
	 * @param string $uid
292
	 * @param string $password
293
	 * @throws \InvalidArgumentException
294
	 * @return bool|IUser the created user or false
295
	 */
296
	public function createUser($uid, $password) {
297
		$localBackends = [];
298
		foreach ($this->backends as $backend) {
299
			if ($backend instanceof Database) {
300
				// First check if there is another user backend
301
				$localBackends[] = $backend;
302
				continue;
303
			}
304
305
			if ($backend->implementsActions(Backend::CREATE_USER)) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\UserInterface::implementsActions() has been deprecated: 14.0.0 Switch to the interfaces from OCP\User\Backend ( Ignorable by Annotation )

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

305
			if (/** @scrutinizer ignore-deprecated */ $backend->implementsActions(Backend::CREATE_USER)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
306
				return $this->createUserFromBackend($uid, $password, $backend);
307
			}
308
		}
309
310
		foreach ($localBackends as $backend) {
311
			if ($backend->implementsActions(Backend::CREATE_USER)) {
312
				return $this->createUserFromBackend($uid, $password, $backend);
313
			}
314
		}
315
316
		return false;
317
	}
318
319
	/**
320
	 * @param string $uid
321
	 * @param string $password
322
	 * @param UserInterface $backend
323
	 * @return IUser|null
324
	 * @throws \InvalidArgumentException
325
	 */
326
	public function createUserFromBackend($uid, $password, UserInterface $backend) {
327
		$l = \OC::$server->getL10N('lib');
328
329
		// Check the name for bad characters
330
		// Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
331
		if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
332
			throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
333
				. ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
334
		}
335
336
		// No empty username
337
		if (trim($uid) === '') {
338
			throw new \InvalidArgumentException($l->t('A valid username must be provided'));
339
		}
340
341
		// No whitespace at the beginning or at the end
342
		if (trim($uid) !== $uid) {
343
			throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
344
		}
345
346
		// Username only consists of 1 or 2 dots (directory traversal)
347
		if ($uid === '.' || $uid === '..') {
348
			throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
349
		}
350
351
		if (!$this->verifyUid($uid)) {
352
			throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
353
		}
354
355
		// No empty password
356
		if (trim($password) === '') {
357
			throw new \InvalidArgumentException($l->t('A valid password must be provided'));
358
		}
359
360
		// Check if user already exists
361
		if ($this->userExists($uid)) {
362
			throw new \InvalidArgumentException($l->t('The username is already being used'));
363
		}
364
365
		$this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
366
		$this->eventDispatcher->dispatchTyped(new CreateUserEvent($uid, $password));
367
		$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

367
		/** @scrutinizer ignore-call */ 
368
  $state = $backend->createUser($uid, $password);
Loading history...
368
		if($state === false) {
369
			throw new \InvalidArgumentException($l->t('Could not create user'));
370
		}
371
		$user = $this->getUserObject($uid, $backend);
372
		if ($user instanceof IUser) {
0 ignored issues
show
introduced by
$user is always a sub-type of OCP\IUser.
Loading history...
373
			$this->emit('\OC\User', 'postCreateUser', [$user, $password]);
374
			$this->eventDispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
375
		}
376
		return $user;
377
	}
378
379
	/**
380
	 * returns how many users per backend exist (if supported by backend)
381
	 *
382
	 * @param boolean $hasLoggedIn when true only users that have a lastLogin
383
	 *                entry in the preferences table will be affected
384
	 * @return array|int an array of backend class as key and count number as value
385
	 *                if $hasLoggedIn is true only an int is returned
386
	 */
387
	public function countUsers($hasLoggedIn = false) {
388
		if ($hasLoggedIn) {
389
			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...
390
		}
391
		$userCountStatistics = [];
392
		foreach ($this->backends as $backend) {
393
			if ($backend->implementsActions(Backend::COUNT_USERS)) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\UserInterface::implementsActions() has been deprecated: 14.0.0 Switch to the interfaces from OCP\User\Backend ( Ignorable by Annotation )

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

393
			if (/** @scrutinizer ignore-deprecated */ $backend->implementsActions(Backend::COUNT_USERS)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
394
				$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

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

616
		/** @scrutinizer ignore-call */ 
617
  $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...
617
618
		$users = array_map(function($uid) {
619
			return $this->get($uid);
620
		}, $userIds);
621
622
		return array_values(array_filter($users, function($u) {
623
			return ($u instanceof IUser);
624
		}));
625
	}
626
627
	private function verifyUid(string $uid): bool {
628
		$appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
629
630
		if (\in_array($uid, [
631
			'.htaccess',
632
			'files_external',
633
			'.ocdata',
634
			'owncloud.log',
635
			'nextcloud.log',
636
			$appdata], true)) {
637
			return false;
638
		}
639
640
		$dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
641
642
		return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
643
	}
644
}
645