diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/Repair/NC11/MoveAvatarBackgroundJob.php | 46 | ||||
-rw-r--r-- | lib/private/Repair/RemoveRootShares.php | 21 | ||||
-rw-r--r-- | lib/private/Repair/RepairUnmergedShares.php | 19 | ||||
-rw-r--r-- | lib/private/User/Manager.php | 136 | ||||
-rw-r--r-- | lib/public/IUserManager.php | 16 |
5 files changed, 157 insertions, 81 deletions
diff --git a/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php index 993235146c9..f8c0d9b3abf 100644 --- a/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php +++ b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php @@ -64,35 +64,33 @@ class MoveAvatarsBackgroundJob extends QueuedJob { private function moveAvatars() { $counter = 0; - $this->userManager->callForAllUsers(function (IUser $user) use ($counter) { - if ($user->getLastLogin() !== 0) { - $uid = $user->getUID(); + $this->userManager->callForSeenUsers(function (IUser $user) use ($counter) { + $uid = $user->getUID(); - \OC\Files\Filesystem::initMountPoints($uid); - /** @var Folder $userFolder */ - $userFolder = $this->rootFolder->get($uid); + \OC\Files\Filesystem::initMountPoints($uid); + /** @var Folder $userFolder */ + $userFolder = $this->rootFolder->get($uid); - try { - $userData = $this->appData->getFolder($uid); - } catch (NotFoundException $e) { - $userData = $this->appData->newFolder($uid); - } + try { + $userData = $this->appData->getFolder($uid); + } catch (NotFoundException $e) { + $userData = $this->appData->newFolder($uid); + } - $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/'; - $avatars = $userFolder->getDirectoryListing(); + $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/'; + $avatars = $userFolder->getDirectoryListing(); - foreach ($avatars as $avatar) { - /** @var File $avatar */ - if (preg_match($regex, $avatar->getName())) { - /* - * This is not the most effective but it is the most abstract way - * to handle this. Avatars should be small anyways. - */ - $newAvatar = $userData->newFile($avatar->getName()); - $newAvatar->putContent($avatar->getContent()); - $avatar->delete(); - } + foreach ($avatars as $avatar) { + /** @var File $avatar */ + if (preg_match($regex, $avatar->getName())) { + /* + * This is not the most effective but it is the most abstract way + * to handle this. Avatars should be small anyways. + */ + $newAvatar = $userData->newFile($avatar->getName()); + $newAvatar->putContent($avatar->getContent()); + $avatar->delete(); } } $counter++; diff --git a/lib/private/Repair/RemoveRootShares.php b/lib/private/Repair/RemoveRootShares.php index 1fd7d8d7dae..69fcb1b4492 100644 --- a/lib/private/Repair/RemoveRootShares.php +++ b/lib/private/Repair/RemoveRootShares.php @@ -96,31 +96,14 @@ class RemoveRootShares implements IRepairStep { $output->advance(); }; - $userCount = $this->countUsers(); - $output->startProgress($userCount); + $output->startProgress($this->userManager->countSeenUsers()); - $this->userManager->callForAllUsers($function); + $this->userManager->callForSeenUsers($function); $output->finishProgress(); } /** - * Count all the users - * - * @return int - */ - private function countUsers() { - $allCount = $this->userManager->countUsers(); - - $totalCount = 0; - foreach ($allCount as $backend => $count) { - $totalCount += $count; - } - - return $totalCount; - } - - /** * Verify if this repair steps is required * It *should* not be necessary in most cases and it can be very * costly. diff --git a/lib/private/Repair/RepairUnmergedShares.php b/lib/private/Repair/RepairUnmergedShares.php index d57bc3779f8..56d935c74f5 100644 --- a/lib/private/Repair/RepairUnmergedShares.php +++ b/lib/private/Repair/RepairUnmergedShares.php @@ -335,22 +335,6 @@ class RepairUnmergedShares implements IRepairStep { } } - /** - * Count all the users - * - * @return int - */ - private function countUsers() { - $allCount = $this->userManager->countUsers(); - - $totalCount = 0; - foreach ($allCount as $backend => $count) { - $totalCount += $count; - } - - return $totalCount; - } - public function run(IOutput $output) { $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0'); if (version_compare($ocVersionFromBeforeUpdate, '9.1.0.16', '<')) { @@ -363,8 +347,7 @@ class RepairUnmergedShares implements IRepairStep { $this->buildPreparedQueries(); - $userCount = $this->countUsers(); - $output->startProgress($userCount); + $output->startProgress($this->userManager->countUsers()); $this->userManager->callForAllUsers($function); diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 7d8c6d48b2c..c3fb8737420 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -72,7 +72,7 @@ class Manager extends PublicEmitter implements IUserManager { /** * @param \OCP\IConfig $config */ - public function __construct(IConfig $config = null) { + public function __construct(IConfig $config) { $this->config = $config; $cachedUsers = &$this->cachedUsers; $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) { @@ -314,10 +314,16 @@ class Manager extends PublicEmitter implements IUserManager { /** * returns how many users per backend exist (if supported by backend) * - * @return array an array of backend class as key and count number as value + * @param boolean $hasLoggedIn when true only users that have a lastLogin + * entry in the preferences table will be affected + * @return array|int an array of backend class as key and count number as value + * if $hasLoggedIn is true only an int is returned */ - public function countUsers() { - $userCountStatistics = array(); + public function countUsers($hasLoggedIn = false) { + if ($hasLoggedIn) { + return $this->countSeenUsers(); + } + $userCountStatistics = []; foreach ($this->backends as $backend) { if ($backend->implementsActions(Backend::COUNT_USERS)) { $backendUsers = $backend->countUsers(); @@ -344,27 +350,119 @@ class Manager extends PublicEmitter implements IUserManager { * * @param \Closure $callback * @param string $search + * @param boolean $onlySeen when true only users that have a lastLogin entry + * in the preferences table will be affected * @since 9.0.0 */ - public function callForAllUsers(\Closure $callback, $search = '') { - foreach($this->getBackends() as $backend) { - $limit = 500; - $offset = 0; - do { - $users = $backend->getUsers($search, $limit, $offset); - foreach ($users as $uid) { - if (!$backend->userExists($uid)) { - continue; + public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) { + if ($onlySeen) { + $this->callForSeenUsers($callback); + } else { + foreach ($this->getBackends() as $backend) { + $limit = 500; + $offset = 0; + do { + $users = $backend->getUsers($search, $limit, $offset); + foreach ($users as $uid) { + if (!$backend->userExists($uid)) { + continue; + } + $user = $this->getUserObject($uid, $backend, false); + $return = $callback($user); + if ($return === false) { + break; + } } - $user = $this->getUserObject($uid, $backend, false); - $return = $callback($user); - if ($return === false) { - break; + $offset += $limit; + } while (count($users) >= $limit); + } + } + } + + /** + * returns how many users have logged in once + * + * @return int + * @since 9.2.0 + */ + public function countSeenUsers() { + $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); + $queryBuilder->select($queryBuilder->createFunction('COUNT(*)')) + ->from('preferences') + ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login'))) + ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin'))) + ->andWhere($queryBuilder->expr()->isNotNull('configvalue')); + + $query = $queryBuilder->execute(); + + $result = (int)$query->fetchColumn(); + $query->closeCursor(); + + return $result; + } + + /** + * @param \Closure $callback + * @since 9.2.0 + */ + public function callForSeenUsers(\Closure $callback) { + $limit = 1000; + $offset = 0; + do { + $userIds = $this->getSeenUserIds($limit, $offset); + $offset += $limit; + foreach ($userIds as $userId) { + foreach ($this->backends as $backend) { + if ($backend->userExists($userId)) { + $user = $this->getUserObject($userId, $backend, false); + $return = $callback($user); + if ($return === false) { + return; + } } } - $offset += $limit; - } while (count($users) >= $limit); + } + } while (count($userIds) >= $limit); + } + + /** + * Getting all userIds that have a listLogin value requires checking the + * value in php because on oracle you cannot use a clob in a where clause, + * preventing us from doing a not null or length(value) > 0 check. + * + * @param int $limit + * @param int $offset + * @return string[] with user ids + */ + private function getSeenUserIds($limit = null, $offset = null) { + $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); + $queryBuilder->select(['userid']) + ->from('preferences') + ->where($queryBuilder->expr()->eq( + 'appid', $queryBuilder->createNamedParameter('login')) + ) + ->andWhere($queryBuilder->expr()->eq( + 'configkey', $queryBuilder->createNamedParameter('lastLogin')) + ) + ->andWhere($queryBuilder->expr()->isNotNull('configvalue') + ); + + if ($limit !== null) { + $queryBuilder->setMaxResults($limit); } + if ($offset !== null) { + $queryBuilder->setFirstResult($offset); + } + $query = $queryBuilder->execute(); + $result = []; + + while ($row = $query->fetch()) { + $result[] = $row['userid']; + } + + $query->closeCursor(); + + return $result; } /** diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php index 1e0c298edcf..5220a0c65c7 100644 --- a/lib/public/IUserManager.php +++ b/lib/public/IUserManager.php @@ -142,7 +142,21 @@ interface IUserManager { * @param string $search * @since 9.0.0 */ - public function callForAllUsers (\Closure $callback, $search = ''); + public function callForAllUsers(\Closure $callback, $search = ''); + + /** + * returns how many users have logged in once + * + * @return int + * @since 9.2.0 + */ + public function countSeenUsers(); + + /** + * @param \Closure $callback + * @since 9.2.0 + */ + public function callForSeenUsers(\Closure $callback); /** * @param string $email |