Completed
Pull Request — master (#4522)
by Joas
20:04
created
lib/private/User/Manager.php 1 patch
Indentation   +451 added lines, -451 removed lines patch added patch discarded remove patch
@@ -55,455 +55,455 @@
 block discarded – undo
55 55
  * @package OC\User
56 56
  */
57 57
 class Manager extends PublicEmitter implements IUserManager {
58
-	/**
59
-	 * @var \OCP\UserInterface[] $backends
60
-	 */
61
-	private $backends = array();
62
-
63
-	/**
64
-	 * @var \OC\User\User[] $cachedUsers
65
-	 */
66
-	private $cachedUsers = array();
67
-
68
-	/**
69
-	 * @var \OCP\IConfig $config
70
-	 */
71
-	private $config;
72
-
73
-	/**
74
-	 * @param \OCP\IConfig $config
75
-	 */
76
-	public function __construct(IConfig $config) {
77
-		$this->config = $config;
78
-		$cachedUsers = &$this->cachedUsers;
79
-		$this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
80
-			/** @var \OC\User\User $user */
81
-			unset($cachedUsers[$user->getUID()]);
82
-		});
83
-	}
84
-
85
-	/**
86
-	 * Get the active backends
87
-	 * @return \OCP\UserInterface[]
88
-	 */
89
-	public function getBackends() {
90
-		return $this->backends;
91
-	}
92
-
93
-	/**
94
-	 * register a user backend
95
-	 *
96
-	 * @param \OCP\UserInterface $backend
97
-	 */
98
-	public function registerBackend($backend) {
99
-		$this->backends[] = $backend;
100
-	}
101
-
102
-	/**
103
-	 * remove a user backend
104
-	 *
105
-	 * @param \OCP\UserInterface $backend
106
-	 */
107
-	public function removeBackend($backend) {
108
-		$this->cachedUsers = array();
109
-		if (($i = array_search($backend, $this->backends)) !== false) {
110
-			unset($this->backends[$i]);
111
-		}
112
-	}
113
-
114
-	/**
115
-	 * remove all user backends
116
-	 */
117
-	public function clearBackends() {
118
-		$this->cachedUsers = array();
119
-		$this->backends = array();
120
-	}
121
-
122
-	/**
123
-	 * get a user by user id
124
-	 *
125
-	 * @param string $uid
126
-	 * @return \OC\User\User|null Either the user or null if the specified user does not exist
127
-	 */
128
-	public function get($uid) {
129
-		if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
130
-			return $this->cachedUsers[$uid];
131
-		}
132
-		foreach ($this->backends as $backend) {
133
-			if ($backend->userExists($uid)) {
134
-				return $this->getUserObject($uid, $backend);
135
-			}
136
-		}
137
-		return null;
138
-	}
139
-
140
-	/**
141
-	 * get or construct the user object
142
-	 *
143
-	 * @param string $uid
144
-	 * @param \OCP\UserInterface $backend
145
-	 * @param bool $cacheUser If false the newly created user object will not be cached
146
-	 * @return \OC\User\User
147
-	 */
148
-	protected function getUserObject($uid, $backend, $cacheUser = true) {
149
-		if (isset($this->cachedUsers[$uid])) {
150
-			return $this->cachedUsers[$uid];
151
-		}
152
-
153
-		if (method_exists($backend, 'loginName2UserName')) {
154
-			$loginName = $backend->loginName2UserName($uid);
155
-			if ($loginName !== false) {
156
-				$uid = $loginName;
157
-			}
158
-			if (isset($this->cachedUsers[$uid])) {
159
-				return $this->cachedUsers[$uid];
160
-			}
161
-		}
162
-
163
-		$user = new User($uid, $backend, $this, $this->config);
164
-		if ($cacheUser) {
165
-			$this->cachedUsers[$uid] = $user;
166
-		}
167
-		return $user;
168
-	}
169
-
170
-	/**
171
-	 * check if a user exists
172
-	 *
173
-	 * @param string $uid
174
-	 * @return bool
175
-	 */
176
-	public function userExists($uid) {
177
-		$user = $this->get($uid);
178
-		return ($user !== null);
179
-	}
180
-
181
-	/**
182
-	 * Check if the password is valid for the user
183
-	 *
184
-	 * @param string $loginName
185
-	 * @param string $password
186
-	 * @return mixed the User object on success, false otherwise
187
-	 */
188
-	public function checkPassword($loginName, $password) {
189
-		$result = $this->checkPasswordNoLogging($loginName, $password);
190
-
191
-		if ($result === false) {
192
-			\OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
193
-		}
194
-
195
-		return $result;
196
-	}
197
-
198
-	/**
199
-	 * Check if the password is valid for the user
200
-	 *
201
-	 * @internal
202
-	 * @param string $loginName
203
-	 * @param string $password
204
-	 * @return mixed the User object on success, false otherwise
205
-	 */
206
-	public function checkPasswordNoLogging($loginName, $password) {
207
-		$loginName = str_replace("\0", '', $loginName);
208
-		$password = str_replace("\0", '', $password);
209
-
210
-		foreach ($this->backends as $backend) {
211
-			if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
212
-				$uid = $backend->checkPassword($loginName, $password);
213
-				if ($uid !== false) {
214
-					return $this->getUserObject($uid, $backend);
215
-				}
216
-			}
217
-		}
218
-
219
-		return false;
220
-	}
221
-
222
-	/**
223
-	 * search by user id
224
-	 *
225
-	 * @param string $pattern
226
-	 * @param int $limit
227
-	 * @param int $offset
228
-	 * @return \OC\User\User[]
229
-	 */
230
-	public function search($pattern, $limit = null, $offset = null) {
231
-		$users = array();
232
-		foreach ($this->backends as $backend) {
233
-			$backendUsers = $backend->getUsers($pattern, $limit, $offset);
234
-			if (is_array($backendUsers)) {
235
-				foreach ($backendUsers as $uid) {
236
-					$users[$uid] = $this->getUserObject($uid, $backend);
237
-				}
238
-			}
239
-		}
240
-
241
-		uasort($users, function ($a, $b) {
242
-			/**
243
-			 * @var \OC\User\User $a
244
-			 * @var \OC\User\User $b
245
-			 */
246
-			return strcmp($a->getUID(), $b->getUID());
247
-		});
248
-		return $users;
249
-	}
250
-
251
-	/**
252
-	 * search by displayName
253
-	 *
254
-	 * @param string $pattern
255
-	 * @param int $limit
256
-	 * @param int $offset
257
-	 * @return \OC\User\User[]
258
-	 */
259
-	public function searchDisplayName($pattern, $limit = null, $offset = null) {
260
-		$users = array();
261
-		foreach ($this->backends as $backend) {
262
-			$backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
263
-			if (is_array($backendUsers)) {
264
-				foreach ($backendUsers as $uid => $displayName) {
265
-					$users[] = $this->getUserObject($uid, $backend);
266
-				}
267
-			}
268
-		}
269
-
270
-		usort($users, function ($a, $b) {
271
-			/**
272
-			 * @var \OC\User\User $a
273
-			 * @var \OC\User\User $b
274
-			 */
275
-			return strcmp(strtolower($a->getDisplayName()), strtolower($b->getDisplayName()));
276
-		});
277
-		return $users;
278
-	}
279
-
280
-	/**
281
-	 * @param string $uid
282
-	 * @param string $password
283
-	 * @throws \InvalidArgumentException
284
-	 * @return bool|IUser the created user or false
285
-	 */
286
-	public function createUser($uid, $password) {
287
-		foreach ($this->backends as $backend) {
288
-			if ($backend->implementsActions(Backend::CREATE_USER)) {
289
-				return $this->createUserFromBackend($uid, $password, $backend);
290
-			}
291
-		}
292
-
293
-		return false;
294
-	}
295
-
296
-	/**
297
-	 * @param string $uid
298
-	 * @param string $password
299
-	 * @param UserInterface $backend
300
-	 * @return IUser|null
301
-	 * @throws \InvalidArgumentException
302
-	 */
303
-	public function createUserFromBackend($uid, $password, UserInterface $backend) {
304
-		$l = \OC::$server->getL10N('lib');
305
-
306
-		// Check the name for bad characters
307
-		// Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
308
-		if (preg_match('/[^a-zA-Z0-9 _\.@\-\']/', $uid)) {
309
-			throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
310
-				. ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
311
-		}
312
-		// No empty username
313
-		if (trim($uid) === '') {
314
-			throw new \InvalidArgumentException($l->t('A valid username must be provided'));
315
-		}
316
-		// No whitespace at the beginning or at the end
317
-		if (trim($uid) !== $uid) {
318
-			throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
319
-		}
320
-		// Username only consists of 1 or 2 dots (directory traversal)
321
-		if ($uid === '.' || $uid === '..') {
322
-			throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
323
-		}
324
-		// No empty password
325
-		if (trim($password) === '') {
326
-			throw new \InvalidArgumentException($l->t('A valid password must be provided'));
327
-		}
328
-
329
-		// Check if user already exists
330
-		if ($this->userExists($uid)) {
331
-			throw new \InvalidArgumentException($l->t('The username is already being used'));
332
-		}
333
-
334
-		$this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
335
-		$backend->createUser($uid, $password);
336
-		$user = $this->getUserObject($uid, $backend);
337
-		if ($user instanceof IUser) {
338
-			$this->emit('\OC\User', 'postCreateUser', [$user, $password]);
339
-		}
340
-		return $user;
341
-	}
342
-
343
-	/**
344
-	 * returns how many users per backend exist (if supported by backend)
345
-	 *
346
-	 * @param boolean $hasLoggedIn when true only users that have a lastLogin
347
-	 *                entry in the preferences table will be affected
348
-	 * @return array|int an array of backend class as key and count number as value
349
-	 *                if $hasLoggedIn is true only an int is returned
350
-	 */
351
-	public function countUsers($hasLoggedIn = false) {
352
-		if ($hasLoggedIn) {
353
-			return $this->countSeenUsers();
354
-		}
355
-		$userCountStatistics = [];
356
-		foreach ($this->backends as $backend) {
357
-			if ($backend->implementsActions(Backend::COUNT_USERS)) {
358
-				$backendUsers = $backend->countUsers();
359
-				if($backendUsers !== false) {
360
-					if($backend instanceof IUserBackend) {
361
-						$name = $backend->getBackendName();
362
-					} else {
363
-						$name = get_class($backend);
364
-					}
365
-					if(isset($userCountStatistics[$name])) {
366
-						$userCountStatistics[$name] += $backendUsers;
367
-					} else {
368
-						$userCountStatistics[$name] = $backendUsers;
369
-					}
370
-				}
371
-			}
372
-		}
373
-		return $userCountStatistics;
374
-	}
375
-
376
-	/**
377
-	 * The callback is executed for each user on each backend.
378
-	 * If the callback returns false no further users will be retrieved.
379
-	 *
380
-	 * @param \Closure $callback
381
-	 * @param string $search
382
-	 * @param boolean $onlySeen when true only users that have a lastLogin entry
383
-	 *                in the preferences table will be affected
384
-	 * @since 9.0.0
385
-	 */
386
-	public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
387
-		if ($onlySeen) {
388
-			$this->callForSeenUsers($callback);
389
-		} else {
390
-			foreach ($this->getBackends() as $backend) {
391
-				$limit = 500;
392
-				$offset = 0;
393
-				do {
394
-					$users = $backend->getUsers($search, $limit, $offset);
395
-					foreach ($users as $uid) {
396
-						if (!$backend->userExists($uid)) {
397
-							continue;
398
-						}
399
-						$user = $this->getUserObject($uid, $backend, false);
400
-						$return = $callback($user);
401
-						if ($return === false) {
402
-							break;
403
-						}
404
-					}
405
-					$offset += $limit;
406
-				} while (count($users) >= $limit);
407
-			}
408
-		}
409
-	}
410
-
411
-	/**
412
-	 * returns how many users have logged in once
413
-	 *
414
-	 * @return int
415
-	 * @since 11.0.0
416
-	 */
417
-	public function countSeenUsers() {
418
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
419
-		$queryBuilder->select($queryBuilder->createFunction('COUNT(*)'))
420
-			->from('preferences')
421
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
422
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
423
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
424
-
425
-		$query = $queryBuilder->execute();
426
-
427
-		$result = (int)$query->fetchColumn();
428
-		$query->closeCursor();
429
-
430
-		return $result;
431
-	}
432
-
433
-	/**
434
-	 * @param \Closure $callback
435
-	 * @since 11.0.0
436
-	 */
437
-	public function callForSeenUsers(\Closure $callback) {
438
-		$limit = 1000;
439
-		$offset = 0;
440
-		do {
441
-			$userIds = $this->getSeenUserIds($limit, $offset);
442
-			$offset += $limit;
443
-			foreach ($userIds as $userId) {
444
-				foreach ($this->backends as $backend) {
445
-					if ($backend->userExists($userId)) {
446
-						$user = $this->getUserObject($userId, $backend, false);
447
-						$return = $callback($user);
448
-						if ($return === false) {
449
-							return;
450
-						}
451
-					}
452
-				}
453
-			}
454
-		} while (count($userIds) >= $limit);
455
-	}
456
-
457
-	/**
458
-	 * Getting all userIds that have a listLogin value requires checking the
459
-	 * value in php because on oracle you cannot use a clob in a where clause,
460
-	 * preventing us from doing a not null or length(value) > 0 check.
461
-	 * 
462
-	 * @param int $limit
463
-	 * @param int $offset
464
-	 * @return string[] with user ids
465
-	 */
466
-	private function getSeenUserIds($limit = null, $offset = null) {
467
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
468
-		$queryBuilder->select(['userid'])
469
-			->from('preferences')
470
-			->where($queryBuilder->expr()->eq(
471
-				'appid', $queryBuilder->createNamedParameter('login'))
472
-			)
473
-			->andWhere($queryBuilder->expr()->eq(
474
-				'configkey', $queryBuilder->createNamedParameter('lastLogin'))
475
-			)
476
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue')
477
-			);
478
-
479
-		if ($limit !== null) {
480
-			$queryBuilder->setMaxResults($limit);
481
-		}
482
-		if ($offset !== null) {
483
-			$queryBuilder->setFirstResult($offset);
484
-		}
485
-		$query = $queryBuilder->execute();
486
-		$result = [];
487
-
488
-		while ($row = $query->fetch()) {
489
-			$result[] = $row['userid'];
490
-		}
491
-
492
-		$query->closeCursor();
493
-
494
-		return $result;
495
-	}
496
-
497
-	/**
498
-	 * @param string $email
499
-	 * @return IUser[]
500
-	 * @since 9.1.0
501
-	 */
502
-	public function getByEmail($email) {
503
-		$userIds = $this->config->getUsersForUserValue('settings', 'email', $email);
504
-
505
-		return array_map(function($uid) {
506
-			return $this->get($uid);
507
-		}, $userIds);
508
-	}
58
+    /**
59
+     * @var \OCP\UserInterface[] $backends
60
+     */
61
+    private $backends = array();
62
+
63
+    /**
64
+     * @var \OC\User\User[] $cachedUsers
65
+     */
66
+    private $cachedUsers = array();
67
+
68
+    /**
69
+     * @var \OCP\IConfig $config
70
+     */
71
+    private $config;
72
+
73
+    /**
74
+     * @param \OCP\IConfig $config
75
+     */
76
+    public function __construct(IConfig $config) {
77
+        $this->config = $config;
78
+        $cachedUsers = &$this->cachedUsers;
79
+        $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) {
80
+            /** @var \OC\User\User $user */
81
+            unset($cachedUsers[$user->getUID()]);
82
+        });
83
+    }
84
+
85
+    /**
86
+     * Get the active backends
87
+     * @return \OCP\UserInterface[]
88
+     */
89
+    public function getBackends() {
90
+        return $this->backends;
91
+    }
92
+
93
+    /**
94
+     * register a user backend
95
+     *
96
+     * @param \OCP\UserInterface $backend
97
+     */
98
+    public function registerBackend($backend) {
99
+        $this->backends[] = $backend;
100
+    }
101
+
102
+    /**
103
+     * remove a user backend
104
+     *
105
+     * @param \OCP\UserInterface $backend
106
+     */
107
+    public function removeBackend($backend) {
108
+        $this->cachedUsers = array();
109
+        if (($i = array_search($backend, $this->backends)) !== false) {
110
+            unset($this->backends[$i]);
111
+        }
112
+    }
113
+
114
+    /**
115
+     * remove all user backends
116
+     */
117
+    public function clearBackends() {
118
+        $this->cachedUsers = array();
119
+        $this->backends = array();
120
+    }
121
+
122
+    /**
123
+     * get a user by user id
124
+     *
125
+     * @param string $uid
126
+     * @return \OC\User\User|null Either the user or null if the specified user does not exist
127
+     */
128
+    public function get($uid) {
129
+        if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends
130
+            return $this->cachedUsers[$uid];
131
+        }
132
+        foreach ($this->backends as $backend) {
133
+            if ($backend->userExists($uid)) {
134
+                return $this->getUserObject($uid, $backend);
135
+            }
136
+        }
137
+        return null;
138
+    }
139
+
140
+    /**
141
+     * get or construct the user object
142
+     *
143
+     * @param string $uid
144
+     * @param \OCP\UserInterface $backend
145
+     * @param bool $cacheUser If false the newly created user object will not be cached
146
+     * @return \OC\User\User
147
+     */
148
+    protected function getUserObject($uid, $backend, $cacheUser = true) {
149
+        if (isset($this->cachedUsers[$uid])) {
150
+            return $this->cachedUsers[$uid];
151
+        }
152
+
153
+        if (method_exists($backend, 'loginName2UserName')) {
154
+            $loginName = $backend->loginName2UserName($uid);
155
+            if ($loginName !== false) {
156
+                $uid = $loginName;
157
+            }
158
+            if (isset($this->cachedUsers[$uid])) {
159
+                return $this->cachedUsers[$uid];
160
+            }
161
+        }
162
+
163
+        $user = new User($uid, $backend, $this, $this->config);
164
+        if ($cacheUser) {
165
+            $this->cachedUsers[$uid] = $user;
166
+        }
167
+        return $user;
168
+    }
169
+
170
+    /**
171
+     * check if a user exists
172
+     *
173
+     * @param string $uid
174
+     * @return bool
175
+     */
176
+    public function userExists($uid) {
177
+        $user = $this->get($uid);
178
+        return ($user !== null);
179
+    }
180
+
181
+    /**
182
+     * Check if the password is valid for the user
183
+     *
184
+     * @param string $loginName
185
+     * @param string $password
186
+     * @return mixed the User object on success, false otherwise
187
+     */
188
+    public function checkPassword($loginName, $password) {
189
+        $result = $this->checkPasswordNoLogging($loginName, $password);
190
+
191
+        if ($result === false) {
192
+            \OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']);
193
+        }
194
+
195
+        return $result;
196
+    }
197
+
198
+    /**
199
+     * Check if the password is valid for the user
200
+     *
201
+     * @internal
202
+     * @param string $loginName
203
+     * @param string $password
204
+     * @return mixed the User object on success, false otherwise
205
+     */
206
+    public function checkPasswordNoLogging($loginName, $password) {
207
+        $loginName = str_replace("\0", '', $loginName);
208
+        $password = str_replace("\0", '', $password);
209
+
210
+        foreach ($this->backends as $backend) {
211
+            if ($backend->implementsActions(Backend::CHECK_PASSWORD)) {
212
+                $uid = $backend->checkPassword($loginName, $password);
213
+                if ($uid !== false) {
214
+                    return $this->getUserObject($uid, $backend);
215
+                }
216
+            }
217
+        }
218
+
219
+        return false;
220
+    }
221
+
222
+    /**
223
+     * search by user id
224
+     *
225
+     * @param string $pattern
226
+     * @param int $limit
227
+     * @param int $offset
228
+     * @return \OC\User\User[]
229
+     */
230
+    public function search($pattern, $limit = null, $offset = null) {
231
+        $users = array();
232
+        foreach ($this->backends as $backend) {
233
+            $backendUsers = $backend->getUsers($pattern, $limit, $offset);
234
+            if (is_array($backendUsers)) {
235
+                foreach ($backendUsers as $uid) {
236
+                    $users[$uid] = $this->getUserObject($uid, $backend);
237
+                }
238
+            }
239
+        }
240
+
241
+        uasort($users, function ($a, $b) {
242
+            /**
243
+             * @var \OC\User\User $a
244
+             * @var \OC\User\User $b
245
+             */
246
+            return strcmp($a->getUID(), $b->getUID());
247
+        });
248
+        return $users;
249
+    }
250
+
251
+    /**
252
+     * search by displayName
253
+     *
254
+     * @param string $pattern
255
+     * @param int $limit
256
+     * @param int $offset
257
+     * @return \OC\User\User[]
258
+     */
259
+    public function searchDisplayName($pattern, $limit = null, $offset = null) {
260
+        $users = array();
261
+        foreach ($this->backends as $backend) {
262
+            $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset);
263
+            if (is_array($backendUsers)) {
264
+                foreach ($backendUsers as $uid => $displayName) {
265
+                    $users[] = $this->getUserObject($uid, $backend);
266
+                }
267
+            }
268
+        }
269
+
270
+        usort($users, function ($a, $b) {
271
+            /**
272
+             * @var \OC\User\User $a
273
+             * @var \OC\User\User $b
274
+             */
275
+            return strcmp(strtolower($a->getDisplayName()), strtolower($b->getDisplayName()));
276
+        });
277
+        return $users;
278
+    }
279
+
280
+    /**
281
+     * @param string $uid
282
+     * @param string $password
283
+     * @throws \InvalidArgumentException
284
+     * @return bool|IUser the created user or false
285
+     */
286
+    public function createUser($uid, $password) {
287
+        foreach ($this->backends as $backend) {
288
+            if ($backend->implementsActions(Backend::CREATE_USER)) {
289
+                return $this->createUserFromBackend($uid, $password, $backend);
290
+            }
291
+        }
292
+
293
+        return false;
294
+    }
295
+
296
+    /**
297
+     * @param string $uid
298
+     * @param string $password
299
+     * @param UserInterface $backend
300
+     * @return IUser|null
301
+     * @throws \InvalidArgumentException
302
+     */
303
+    public function createUserFromBackend($uid, $password, UserInterface $backend) {
304
+        $l = \OC::$server->getL10N('lib');
305
+
306
+        // Check the name for bad characters
307
+        // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
308
+        if (preg_match('/[^a-zA-Z0-9 _\.@\-\']/', $uid)) {
309
+            throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
310
+                . ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
311
+        }
312
+        // No empty username
313
+        if (trim($uid) === '') {
314
+            throw new \InvalidArgumentException($l->t('A valid username must be provided'));
315
+        }
316
+        // No whitespace at the beginning or at the end
317
+        if (trim($uid) !== $uid) {
318
+            throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
319
+        }
320
+        // Username only consists of 1 or 2 dots (directory traversal)
321
+        if ($uid === '.' || $uid === '..') {
322
+            throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
323
+        }
324
+        // No empty password
325
+        if (trim($password) === '') {
326
+            throw new \InvalidArgumentException($l->t('A valid password must be provided'));
327
+        }
328
+
329
+        // Check if user already exists
330
+        if ($this->userExists($uid)) {
331
+            throw new \InvalidArgumentException($l->t('The username is already being used'));
332
+        }
333
+
334
+        $this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
335
+        $backend->createUser($uid, $password);
336
+        $user = $this->getUserObject($uid, $backend);
337
+        if ($user instanceof IUser) {
338
+            $this->emit('\OC\User', 'postCreateUser', [$user, $password]);
339
+        }
340
+        return $user;
341
+    }
342
+
343
+    /**
344
+     * returns how many users per backend exist (if supported by backend)
345
+     *
346
+     * @param boolean $hasLoggedIn when true only users that have a lastLogin
347
+     *                entry in the preferences table will be affected
348
+     * @return array|int an array of backend class as key and count number as value
349
+     *                if $hasLoggedIn is true only an int is returned
350
+     */
351
+    public function countUsers($hasLoggedIn = false) {
352
+        if ($hasLoggedIn) {
353
+            return $this->countSeenUsers();
354
+        }
355
+        $userCountStatistics = [];
356
+        foreach ($this->backends as $backend) {
357
+            if ($backend->implementsActions(Backend::COUNT_USERS)) {
358
+                $backendUsers = $backend->countUsers();
359
+                if($backendUsers !== false) {
360
+                    if($backend instanceof IUserBackend) {
361
+                        $name = $backend->getBackendName();
362
+                    } else {
363
+                        $name = get_class($backend);
364
+                    }
365
+                    if(isset($userCountStatistics[$name])) {
366
+                        $userCountStatistics[$name] += $backendUsers;
367
+                    } else {
368
+                        $userCountStatistics[$name] = $backendUsers;
369
+                    }
370
+                }
371
+            }
372
+        }
373
+        return $userCountStatistics;
374
+    }
375
+
376
+    /**
377
+     * The callback is executed for each user on each backend.
378
+     * If the callback returns false no further users will be retrieved.
379
+     *
380
+     * @param \Closure $callback
381
+     * @param string $search
382
+     * @param boolean $onlySeen when true only users that have a lastLogin entry
383
+     *                in the preferences table will be affected
384
+     * @since 9.0.0
385
+     */
386
+    public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
387
+        if ($onlySeen) {
388
+            $this->callForSeenUsers($callback);
389
+        } else {
390
+            foreach ($this->getBackends() as $backend) {
391
+                $limit = 500;
392
+                $offset = 0;
393
+                do {
394
+                    $users = $backend->getUsers($search, $limit, $offset);
395
+                    foreach ($users as $uid) {
396
+                        if (!$backend->userExists($uid)) {
397
+                            continue;
398
+                        }
399
+                        $user = $this->getUserObject($uid, $backend, false);
400
+                        $return = $callback($user);
401
+                        if ($return === false) {
402
+                            break;
403
+                        }
404
+                    }
405
+                    $offset += $limit;
406
+                } while (count($users) >= $limit);
407
+            }
408
+        }
409
+    }
410
+
411
+    /**
412
+     * returns how many users have logged in once
413
+     *
414
+     * @return int
415
+     * @since 11.0.0
416
+     */
417
+    public function countSeenUsers() {
418
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
419
+        $queryBuilder->select($queryBuilder->createFunction('COUNT(*)'))
420
+            ->from('preferences')
421
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
422
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
423
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
424
+
425
+        $query = $queryBuilder->execute();
426
+
427
+        $result = (int)$query->fetchColumn();
428
+        $query->closeCursor();
429
+
430
+        return $result;
431
+    }
432
+
433
+    /**
434
+     * @param \Closure $callback
435
+     * @since 11.0.0
436
+     */
437
+    public function callForSeenUsers(\Closure $callback) {
438
+        $limit = 1000;
439
+        $offset = 0;
440
+        do {
441
+            $userIds = $this->getSeenUserIds($limit, $offset);
442
+            $offset += $limit;
443
+            foreach ($userIds as $userId) {
444
+                foreach ($this->backends as $backend) {
445
+                    if ($backend->userExists($userId)) {
446
+                        $user = $this->getUserObject($userId, $backend, false);
447
+                        $return = $callback($user);
448
+                        if ($return === false) {
449
+                            return;
450
+                        }
451
+                    }
452
+                }
453
+            }
454
+        } while (count($userIds) >= $limit);
455
+    }
456
+
457
+    /**
458
+     * Getting all userIds that have a listLogin value requires checking the
459
+     * value in php because on oracle you cannot use a clob in a where clause,
460
+     * preventing us from doing a not null or length(value) > 0 check.
461
+     * 
462
+     * @param int $limit
463
+     * @param int $offset
464
+     * @return string[] with user ids
465
+     */
466
+    private function getSeenUserIds($limit = null, $offset = null) {
467
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
468
+        $queryBuilder->select(['userid'])
469
+            ->from('preferences')
470
+            ->where($queryBuilder->expr()->eq(
471
+                'appid', $queryBuilder->createNamedParameter('login'))
472
+            )
473
+            ->andWhere($queryBuilder->expr()->eq(
474
+                'configkey', $queryBuilder->createNamedParameter('lastLogin'))
475
+            )
476
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue')
477
+            );
478
+
479
+        if ($limit !== null) {
480
+            $queryBuilder->setMaxResults($limit);
481
+        }
482
+        if ($offset !== null) {
483
+            $queryBuilder->setFirstResult($offset);
484
+        }
485
+        $query = $queryBuilder->execute();
486
+        $result = [];
487
+
488
+        while ($row = $query->fetch()) {
489
+            $result[] = $row['userid'];
490
+        }
491
+
492
+        $query->closeCursor();
493
+
494
+        return $result;
495
+    }
496
+
497
+    /**
498
+     * @param string $email
499
+     * @return IUser[]
500
+     * @since 9.1.0
501
+     */
502
+    public function getByEmail($email) {
503
+        $userIds = $this->config->getUsersForUserValue('settings', 'email', $email);
504
+
505
+        return array_map(function($uid) {
506
+            return $this->get($uid);
507
+        }, $userIds);
508
+    }
509 509
 }
Please login to merge, or discard this patch.
lib/public/IUserManager.php 1 patch
Indentation   +133 added lines, -133 removed lines patch added patch discarded remove patch
@@ -41,137 +41,137 @@
 block discarded – undo
41 41
  * @since 8.0.0
42 42
  */
43 43
 interface IUserManager {
44
-		/**
45
-	 * register a user backend
46
-	 *
47
-	 * @param \OCP\UserInterface $backend
48
-	 * @since 8.0.0
49
-	 */
50
-	public function registerBackend($backend);
51
-
52
-	/**
53
-	 * Get the active backends
54
-	 * @return \OCP\UserInterface[]
55
-	 * @since 8.0.0
56
-	 */
57
-	public function getBackends();
58
-
59
-	/**
60
-	 * remove a user backend
61
-	 *
62
-	 * @param \OCP\UserInterface $backend
63
-	 * @since 8.0.0
64
-	 */
65
-	public function removeBackend($backend);
66
-
67
-	/**
68
-	 * remove all user backends
69
-	 * @since 8.0.0
70
-	 */
71
-	public function clearBackends() ;
72
-
73
-	/**
74
-	 * get a user by user id
75
-	 *
76
-	 * @param string $uid
77
-	 * @return \OCP\IUser|null Either the user or null if the specified user does not exist
78
-	 * @since 8.0.0
79
-	 */
80
-	public function get($uid);
81
-
82
-	/**
83
-	 * check if a user exists
84
-	 *
85
-	 * @param string $uid
86
-	 * @return bool
87
-	 * @since 8.0.0
88
-	 */
89
-	public function userExists($uid);
90
-
91
-	/**
92
-	 * Check if the password is valid for the user
93
-	 *
94
-	 * @param string $loginName
95
-	 * @param string $password
96
-	 * @return mixed the User object on success, false otherwise
97
-	 * @since 8.0.0
98
-	 */
99
-	public function checkPassword($loginName, $password);
100
-
101
-	/**
102
-	 * search by user id
103
-	 *
104
-	 * @param string $pattern
105
-	 * @param int $limit
106
-	 * @param int $offset
107
-	 * @return \OCP\IUser[]
108
-	 * @since 8.0.0
109
-	 */
110
-	public function search($pattern, $limit = null, $offset = null);
111
-
112
-	/**
113
-	 * search by displayName
114
-	 *
115
-	 * @param string $pattern
116
-	 * @param int $limit
117
-	 * @param int $offset
118
-	 * @return \OCP\IUser[]
119
-	 * @since 8.0.0
120
-	 */
121
-	public function searchDisplayName($pattern, $limit = null, $offset = null);
122
-
123
-	/**
124
-	 * @param string $uid
125
-	 * @param string $password
126
-	 * @throws \InvalidArgumentException
127
-	 * @return bool|\OCP\IUser the created user of false
128
-	 * @since 8.0.0
129
-	 */
130
-	public function createUser($uid, $password);
131
-
132
-	/**
133
-	 * @param string $uid
134
-	 * @param string $password
135
-	 * @param UserInterface $backend
136
-	 * @return IUser|null
137
-	 * @throws \InvalidArgumentException
138
-	 * @since 12.0.0
139
-	 */
140
-	public function createUserFromBackend($uid, $password, UserInterface $backend);
141
-
142
-	/**
143
-	 * returns how many users per backend exist (if supported by backend)
144
-	 *
145
-	 * @return array an array of backend class as key and count number as value
146
-	 * @since 8.0.0
147
-	 */
148
-	public function countUsers();
149
-
150
-	/**
151
-	 * @param \Closure $callback
152
-	 * @param string $search
153
-	 * @since 9.0.0
154
-	 */
155
-	public function callForAllUsers(\Closure $callback, $search = '');
156
-
157
-	/**
158
-	 * returns how many users have logged in once
159
-	 *
160
-	 * @return int
161
-	 * @since 11.0.0
162
-	 */
163
-	public function countSeenUsers();
164
-
165
-	/**
166
-	 * @param \Closure $callback
167
-	 * @since 11.0.0
168
-	 */
169
-	public function callForSeenUsers(\Closure $callback);
170
-
171
-	/**
172
-	 * @param string $email
173
-	 * @return IUser[]
174
-	 * @since 9.1.0
175
-	 */
176
-	public function getByEmail($email);
44
+        /**
45
+         * register a user backend
46
+         *
47
+         * @param \OCP\UserInterface $backend
48
+         * @since 8.0.0
49
+         */
50
+    public function registerBackend($backend);
51
+
52
+    /**
53
+     * Get the active backends
54
+     * @return \OCP\UserInterface[]
55
+     * @since 8.0.0
56
+     */
57
+    public function getBackends();
58
+
59
+    /**
60
+     * remove a user backend
61
+     *
62
+     * @param \OCP\UserInterface $backend
63
+     * @since 8.0.0
64
+     */
65
+    public function removeBackend($backend);
66
+
67
+    /**
68
+     * remove all user backends
69
+     * @since 8.0.0
70
+     */
71
+    public function clearBackends() ;
72
+
73
+    /**
74
+     * get a user by user id
75
+     *
76
+     * @param string $uid
77
+     * @return \OCP\IUser|null Either the user or null if the specified user does not exist
78
+     * @since 8.0.0
79
+     */
80
+    public function get($uid);
81
+
82
+    /**
83
+     * check if a user exists
84
+     *
85
+     * @param string $uid
86
+     * @return bool
87
+     * @since 8.0.0
88
+     */
89
+    public function userExists($uid);
90
+
91
+    /**
92
+     * Check if the password is valid for the user
93
+     *
94
+     * @param string $loginName
95
+     * @param string $password
96
+     * @return mixed the User object on success, false otherwise
97
+     * @since 8.0.0
98
+     */
99
+    public function checkPassword($loginName, $password);
100
+
101
+    /**
102
+     * search by user id
103
+     *
104
+     * @param string $pattern
105
+     * @param int $limit
106
+     * @param int $offset
107
+     * @return \OCP\IUser[]
108
+     * @since 8.0.0
109
+     */
110
+    public function search($pattern, $limit = null, $offset = null);
111
+
112
+    /**
113
+     * search by displayName
114
+     *
115
+     * @param string $pattern
116
+     * @param int $limit
117
+     * @param int $offset
118
+     * @return \OCP\IUser[]
119
+     * @since 8.0.0
120
+     */
121
+    public function searchDisplayName($pattern, $limit = null, $offset = null);
122
+
123
+    /**
124
+     * @param string $uid
125
+     * @param string $password
126
+     * @throws \InvalidArgumentException
127
+     * @return bool|\OCP\IUser the created user of false
128
+     * @since 8.0.0
129
+     */
130
+    public function createUser($uid, $password);
131
+
132
+    /**
133
+     * @param string $uid
134
+     * @param string $password
135
+     * @param UserInterface $backend
136
+     * @return IUser|null
137
+     * @throws \InvalidArgumentException
138
+     * @since 12.0.0
139
+     */
140
+    public function createUserFromBackend($uid, $password, UserInterface $backend);
141
+
142
+    /**
143
+     * returns how many users per backend exist (if supported by backend)
144
+     *
145
+     * @return array an array of backend class as key and count number as value
146
+     * @since 8.0.0
147
+     */
148
+    public function countUsers();
149
+
150
+    /**
151
+     * @param \Closure $callback
152
+     * @param string $search
153
+     * @since 9.0.0
154
+     */
155
+    public function callForAllUsers(\Closure $callback, $search = '');
156
+
157
+    /**
158
+     * returns how many users have logged in once
159
+     *
160
+     * @return int
161
+     * @since 11.0.0
162
+     */
163
+    public function countSeenUsers();
164
+
165
+    /**
166
+     * @param \Closure $callback
167
+     * @since 11.0.0
168
+     */
169
+    public function callForSeenUsers(\Closure $callback);
170
+
171
+    /**
172
+     * @param string $email
173
+     * @return IUser[]
174
+     * @since 9.1.0
175
+     */
176
+    public function getByEmail($email);
177 177
 }
Please login to merge, or discard this patch.