Completed
Pull Request — master (#4522)
by Joas
158:20 queued 143:37
created
lib/private/User/Manager.php 1 patch
Indentation   +453 added lines, -453 removed lines patch added patch discarded remove patch
@@ -55,457 +55,457 @@
 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 \Exception
284
-	 * @return bool|\OC\User\User the created user or false
285
-	 */
286
-	public function createUser($uid, $password) {
287
-		$l = \OC::$server->getL10N('lib');
288
-		// Check the name for bad characters
289
-		// Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
290
-		if (preg_match('/[^a-zA-Z0-9 _\.@\-\']/', $uid)) {
291
-			throw new \Exception($l->t('Only the following characters are allowed in a username:'
292
-				. ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
293
-		}
294
-		// No empty username
295
-		if (trim($uid) == '') {
296
-			throw new \Exception($l->t('A valid username must be provided'));
297
-		}
298
-		// No whitespace at the beginning or at the end
299
-		if (trim($uid) !== $uid) {
300
-			throw new \Exception($l->t('Username contains whitespace at the beginning or at the end'));
301
-		}
302
-		// Username only consists of 1 or 2 dots (directory traversal)
303
-		if ($uid === '.' || $uid === '..') {
304
-			throw new \Exception($l->t('Username must not consist of dots only'));
305
-		}
306
-		// No empty password
307
-		if (trim($password) == '') {
308
-			throw new \Exception($l->t('A valid password must be provided'));
309
-		}
310
-
311
-		// Check if user already exists
312
-		if ($this->userExists($uid)) {
313
-			throw new \Exception($l->t('The username is already being used'));
314
-		}
315
-
316
-		$this->emit('\OC\User', 'preCreateUser', array($uid, $password));
317
-		foreach ($this->backends as $backend) {
318
-			if ($backend->implementsActions(Backend::CREATE_USER)) {
319
-				$backend->createUser($uid, $password);
320
-				$user = $this->getUserObject($uid, $backend);
321
-				$this->emit('\OC\User', 'postCreateUser', array($user, $password));
322
-				return $user;
323
-			}
324
-		}
325
-
326
-		return false;
327
-	}
328
-
329
-	/**
330
-	 * @param string $uid
331
-	 * @param string $password
332
-	 * @param UserInterface $backend
333
-	 * @return IUser|null
334
-	 */
335
-	public function createUserFromBackend($uid, $password, UserInterface $backend) {
336
-		$this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
337
-		$backend->createUser($uid, $password);
338
-		$user = $this->getUserObject($uid, $backend);
339
-		if ($user instanceof IUser) {
340
-			$this->emit('\OC\User', 'postCreateUser', [$user, $password]);
341
-		}
342
-		return $user;
343
-	}
344
-
345
-	/**
346
-	 * returns how many users per backend exist (if supported by backend)
347
-	 *
348
-	 * @param boolean $hasLoggedIn when true only users that have a lastLogin
349
-	 *                entry in the preferences table will be affected
350
-	 * @return array|int an array of backend class as key and count number as value
351
-	 *                if $hasLoggedIn is true only an int is returned
352
-	 */
353
-	public function countUsers($hasLoggedIn = false) {
354
-		if ($hasLoggedIn) {
355
-			return $this->countSeenUsers();
356
-		}
357
-		$userCountStatistics = [];
358
-		foreach ($this->backends as $backend) {
359
-			if ($backend->implementsActions(Backend::COUNT_USERS)) {
360
-				$backendUsers = $backend->countUsers();
361
-				if($backendUsers !== false) {
362
-					if($backend instanceof IUserBackend) {
363
-						$name = $backend->getBackendName();
364
-					} else {
365
-						$name = get_class($backend);
366
-					}
367
-					if(isset($userCountStatistics[$name])) {
368
-						$userCountStatistics[$name] += $backendUsers;
369
-					} else {
370
-						$userCountStatistics[$name] = $backendUsers;
371
-					}
372
-				}
373
-			}
374
-		}
375
-		return $userCountStatistics;
376
-	}
377
-
378
-	/**
379
-	 * The callback is executed for each user on each backend.
380
-	 * If the callback returns false no further users will be retrieved.
381
-	 *
382
-	 * @param \Closure $callback
383
-	 * @param string $search
384
-	 * @param boolean $onlySeen when true only users that have a lastLogin entry
385
-	 *                in the preferences table will be affected
386
-	 * @since 9.0.0
387
-	 */
388
-	public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
389
-		if ($onlySeen) {
390
-			$this->callForSeenUsers($callback);
391
-		} else {
392
-			foreach ($this->getBackends() as $backend) {
393
-				$limit = 500;
394
-				$offset = 0;
395
-				do {
396
-					$users = $backend->getUsers($search, $limit, $offset);
397
-					foreach ($users as $uid) {
398
-						if (!$backend->userExists($uid)) {
399
-							continue;
400
-						}
401
-						$user = $this->getUserObject($uid, $backend, false);
402
-						$return = $callback($user);
403
-						if ($return === false) {
404
-							break;
405
-						}
406
-					}
407
-					$offset += $limit;
408
-				} while (count($users) >= $limit);
409
-			}
410
-		}
411
-	}
412
-
413
-	/**
414
-	 * returns how many users have logged in once
415
-	 *
416
-	 * @return int
417
-	 * @since 11.0.0
418
-	 */
419
-	public function countSeenUsers() {
420
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
421
-		$queryBuilder->select($queryBuilder->createFunction('COUNT(*)'))
422
-			->from('preferences')
423
-			->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
424
-			->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
425
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
426
-
427
-		$query = $queryBuilder->execute();
428
-
429
-		$result = (int)$query->fetchColumn();
430
-		$query->closeCursor();
431
-
432
-		return $result;
433
-	}
434
-
435
-	/**
436
-	 * @param \Closure $callback
437
-	 * @since 11.0.0
438
-	 */
439
-	public function callForSeenUsers(\Closure $callback) {
440
-		$limit = 1000;
441
-		$offset = 0;
442
-		do {
443
-			$userIds = $this->getSeenUserIds($limit, $offset);
444
-			$offset += $limit;
445
-			foreach ($userIds as $userId) {
446
-				foreach ($this->backends as $backend) {
447
-					if ($backend->userExists($userId)) {
448
-						$user = $this->getUserObject($userId, $backend, false);
449
-						$return = $callback($user);
450
-						if ($return === false) {
451
-							return;
452
-						}
453
-					}
454
-				}
455
-			}
456
-		} while (count($userIds) >= $limit);
457
-	}
458
-
459
-	/**
460
-	 * Getting all userIds that have a listLogin value requires checking the
461
-	 * value in php because on oracle you cannot use a clob in a where clause,
462
-	 * preventing us from doing a not null or length(value) > 0 check.
463
-	 * 
464
-	 * @param int $limit
465
-	 * @param int $offset
466
-	 * @return string[] with user ids
467
-	 */
468
-	private function getSeenUserIds($limit = null, $offset = null) {
469
-		$queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
470
-		$queryBuilder->select(['userid'])
471
-			->from('preferences')
472
-			->where($queryBuilder->expr()->eq(
473
-				'appid', $queryBuilder->createNamedParameter('login'))
474
-			)
475
-			->andWhere($queryBuilder->expr()->eq(
476
-				'configkey', $queryBuilder->createNamedParameter('lastLogin'))
477
-			)
478
-			->andWhere($queryBuilder->expr()->isNotNull('configvalue')
479
-			);
480
-
481
-		if ($limit !== null) {
482
-			$queryBuilder->setMaxResults($limit);
483
-		}
484
-		if ($offset !== null) {
485
-			$queryBuilder->setFirstResult($offset);
486
-		}
487
-		$query = $queryBuilder->execute();
488
-		$result = [];
489
-
490
-		while ($row = $query->fetch()) {
491
-			$result[] = $row['userid'];
492
-		}
493
-
494
-		$query->closeCursor();
495
-
496
-		return $result;
497
-	}
498
-
499
-	/**
500
-	 * @param string $email
501
-	 * @return IUser[]
502
-	 * @since 9.1.0
503
-	 */
504
-	public function getByEmail($email) {
505
-		$userIds = $this->config->getUsersForUserValue('settings', 'email', $email);
506
-
507
-		return array_map(function($uid) {
508
-			return $this->get($uid);
509
-		}, $userIds);
510
-	}
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 \Exception
284
+     * @return bool|\OC\User\User the created user or false
285
+     */
286
+    public function createUser($uid, $password) {
287
+        $l = \OC::$server->getL10N('lib');
288
+        // Check the name for bad characters
289
+        // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
290
+        if (preg_match('/[^a-zA-Z0-9 _\.@\-\']/', $uid)) {
291
+            throw new \Exception($l->t('Only the following characters are allowed in a username:'
292
+                . ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
293
+        }
294
+        // No empty username
295
+        if (trim($uid) == '') {
296
+            throw new \Exception($l->t('A valid username must be provided'));
297
+        }
298
+        // No whitespace at the beginning or at the end
299
+        if (trim($uid) !== $uid) {
300
+            throw new \Exception($l->t('Username contains whitespace at the beginning or at the end'));
301
+        }
302
+        // Username only consists of 1 or 2 dots (directory traversal)
303
+        if ($uid === '.' || $uid === '..') {
304
+            throw new \Exception($l->t('Username must not consist of dots only'));
305
+        }
306
+        // No empty password
307
+        if (trim($password) == '') {
308
+            throw new \Exception($l->t('A valid password must be provided'));
309
+        }
310
+
311
+        // Check if user already exists
312
+        if ($this->userExists($uid)) {
313
+            throw new \Exception($l->t('The username is already being used'));
314
+        }
315
+
316
+        $this->emit('\OC\User', 'preCreateUser', array($uid, $password));
317
+        foreach ($this->backends as $backend) {
318
+            if ($backend->implementsActions(Backend::CREATE_USER)) {
319
+                $backend->createUser($uid, $password);
320
+                $user = $this->getUserObject($uid, $backend);
321
+                $this->emit('\OC\User', 'postCreateUser', array($user, $password));
322
+                return $user;
323
+            }
324
+        }
325
+
326
+        return false;
327
+    }
328
+
329
+    /**
330
+     * @param string $uid
331
+     * @param string $password
332
+     * @param UserInterface $backend
333
+     * @return IUser|null
334
+     */
335
+    public function createUserFromBackend($uid, $password, UserInterface $backend) {
336
+        $this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
337
+        $backend->createUser($uid, $password);
338
+        $user = $this->getUserObject($uid, $backend);
339
+        if ($user instanceof IUser) {
340
+            $this->emit('\OC\User', 'postCreateUser', [$user, $password]);
341
+        }
342
+        return $user;
343
+    }
344
+
345
+    /**
346
+     * returns how many users per backend exist (if supported by backend)
347
+     *
348
+     * @param boolean $hasLoggedIn when true only users that have a lastLogin
349
+     *                entry in the preferences table will be affected
350
+     * @return array|int an array of backend class as key and count number as value
351
+     *                if $hasLoggedIn is true only an int is returned
352
+     */
353
+    public function countUsers($hasLoggedIn = false) {
354
+        if ($hasLoggedIn) {
355
+            return $this->countSeenUsers();
356
+        }
357
+        $userCountStatistics = [];
358
+        foreach ($this->backends as $backend) {
359
+            if ($backend->implementsActions(Backend::COUNT_USERS)) {
360
+                $backendUsers = $backend->countUsers();
361
+                if($backendUsers !== false) {
362
+                    if($backend instanceof IUserBackend) {
363
+                        $name = $backend->getBackendName();
364
+                    } else {
365
+                        $name = get_class($backend);
366
+                    }
367
+                    if(isset($userCountStatistics[$name])) {
368
+                        $userCountStatistics[$name] += $backendUsers;
369
+                    } else {
370
+                        $userCountStatistics[$name] = $backendUsers;
371
+                    }
372
+                }
373
+            }
374
+        }
375
+        return $userCountStatistics;
376
+    }
377
+
378
+    /**
379
+     * The callback is executed for each user on each backend.
380
+     * If the callback returns false no further users will be retrieved.
381
+     *
382
+     * @param \Closure $callback
383
+     * @param string $search
384
+     * @param boolean $onlySeen when true only users that have a lastLogin entry
385
+     *                in the preferences table will be affected
386
+     * @since 9.0.0
387
+     */
388
+    public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) {
389
+        if ($onlySeen) {
390
+            $this->callForSeenUsers($callback);
391
+        } else {
392
+            foreach ($this->getBackends() as $backend) {
393
+                $limit = 500;
394
+                $offset = 0;
395
+                do {
396
+                    $users = $backend->getUsers($search, $limit, $offset);
397
+                    foreach ($users as $uid) {
398
+                        if (!$backend->userExists($uid)) {
399
+                            continue;
400
+                        }
401
+                        $user = $this->getUserObject($uid, $backend, false);
402
+                        $return = $callback($user);
403
+                        if ($return === false) {
404
+                            break;
405
+                        }
406
+                    }
407
+                    $offset += $limit;
408
+                } while (count($users) >= $limit);
409
+            }
410
+        }
411
+    }
412
+
413
+    /**
414
+     * returns how many users have logged in once
415
+     *
416
+     * @return int
417
+     * @since 11.0.0
418
+     */
419
+    public function countSeenUsers() {
420
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
421
+        $queryBuilder->select($queryBuilder->createFunction('COUNT(*)'))
422
+            ->from('preferences')
423
+            ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login')))
424
+            ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin')))
425
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue'));
426
+
427
+        $query = $queryBuilder->execute();
428
+
429
+        $result = (int)$query->fetchColumn();
430
+        $query->closeCursor();
431
+
432
+        return $result;
433
+    }
434
+
435
+    /**
436
+     * @param \Closure $callback
437
+     * @since 11.0.0
438
+     */
439
+    public function callForSeenUsers(\Closure $callback) {
440
+        $limit = 1000;
441
+        $offset = 0;
442
+        do {
443
+            $userIds = $this->getSeenUserIds($limit, $offset);
444
+            $offset += $limit;
445
+            foreach ($userIds as $userId) {
446
+                foreach ($this->backends as $backend) {
447
+                    if ($backend->userExists($userId)) {
448
+                        $user = $this->getUserObject($userId, $backend, false);
449
+                        $return = $callback($user);
450
+                        if ($return === false) {
451
+                            return;
452
+                        }
453
+                    }
454
+                }
455
+            }
456
+        } while (count($userIds) >= $limit);
457
+    }
458
+
459
+    /**
460
+     * Getting all userIds that have a listLogin value requires checking the
461
+     * value in php because on oracle you cannot use a clob in a where clause,
462
+     * preventing us from doing a not null or length(value) > 0 check.
463
+     * 
464
+     * @param int $limit
465
+     * @param int $offset
466
+     * @return string[] with user ids
467
+     */
468
+    private function getSeenUserIds($limit = null, $offset = null) {
469
+        $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
470
+        $queryBuilder->select(['userid'])
471
+            ->from('preferences')
472
+            ->where($queryBuilder->expr()->eq(
473
+                'appid', $queryBuilder->createNamedParameter('login'))
474
+            )
475
+            ->andWhere($queryBuilder->expr()->eq(
476
+                'configkey', $queryBuilder->createNamedParameter('lastLogin'))
477
+            )
478
+            ->andWhere($queryBuilder->expr()->isNotNull('configvalue')
479
+            );
480
+
481
+        if ($limit !== null) {
482
+            $queryBuilder->setMaxResults($limit);
483
+        }
484
+        if ($offset !== null) {
485
+            $queryBuilder->setFirstResult($offset);
486
+        }
487
+        $query = $queryBuilder->execute();
488
+        $result = [];
489
+
490
+        while ($row = $query->fetch()) {
491
+            $result[] = $row['userid'];
492
+        }
493
+
494
+        $query->closeCursor();
495
+
496
+        return $result;
497
+    }
498
+
499
+    /**
500
+     * @param string $email
501
+     * @return IUser[]
502
+     * @since 9.1.0
503
+     */
504
+    public function getByEmail($email) {
505
+        $userIds = $this->config->getUsersForUserValue('settings', 'email', $email);
506
+
507
+        return array_map(function($uid) {
508
+            return $this->get($uid);
509
+        }, $userIds);
510
+    }
511 511
 }
Please login to merge, or discard this patch.
lib/public/IUserManager.php 1 patch
Indentation   +132 added lines, -132 removed lines patch added patch discarded remove patch
@@ -41,136 +41,136 @@
 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 \Exception
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
-	 * @since 12.0.0
138
-	 */
139
-	public function createUserFromBackend($uid, $password, UserInterface $backend);
140
-
141
-	/**
142
-	 * returns how many users per backend exist (if supported by backend)
143
-	 *
144
-	 * @return array an array of backend class as key and count number as value
145
-	 * @since 8.0.0
146
-	 */
147
-	public function countUsers();
148
-
149
-	/**
150
-	 * @param \Closure $callback
151
-	 * @param string $search
152
-	 * @since 9.0.0
153
-	 */
154
-	public function callForAllUsers(\Closure $callback, $search = '');
155
-
156
-	/**
157
-	 * returns how many users have logged in once
158
-	 *
159
-	 * @return int
160
-	 * @since 11.0.0
161
-	 */
162
-	public function countSeenUsers();
163
-
164
-	/**
165
-	 * @param \Closure $callback
166
-	 * @since 11.0.0
167
-	 */
168
-	public function callForSeenUsers(\Closure $callback);
169
-
170
-	/**
171
-	 * @param string $email
172
-	 * @return IUser[]
173
-	 * @since 9.1.0
174
-	 */
175
-	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 \Exception
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
+     * @since 12.0.0
138
+     */
139
+    public function createUserFromBackend($uid, $password, UserInterface $backend);
140
+
141
+    /**
142
+     * returns how many users per backend exist (if supported by backend)
143
+     *
144
+     * @return array an array of backend class as key and count number as value
145
+     * @since 8.0.0
146
+     */
147
+    public function countUsers();
148
+
149
+    /**
150
+     * @param \Closure $callback
151
+     * @param string $search
152
+     * @since 9.0.0
153
+     */
154
+    public function callForAllUsers(\Closure $callback, $search = '');
155
+
156
+    /**
157
+     * returns how many users have logged in once
158
+     *
159
+     * @return int
160
+     * @since 11.0.0
161
+     */
162
+    public function countSeenUsers();
163
+
164
+    /**
165
+     * @param \Closure $callback
166
+     * @since 11.0.0
167
+     */
168
+    public function callForSeenUsers(\Closure $callback);
169
+
170
+    /**
171
+     * @param string $email
172
+     * @return IUser[]
173
+     * @since 9.1.0
174
+     */
175
+    public function getByEmail($email);
176 176
 }
Please login to merge, or discard this patch.