From 995daee56ff04e67f47904fb5f2522b575914aee Mon Sep 17 00:00:00 2001 From: Lidiya Gelemeev <l_gele02@uni-muenster.de> Date: Tue, 4 Feb 2025 20:25:44 +0100 Subject: [PATCH 1/6] Changing the DB requests --- ...eferencesMapper.php => AccountsMapper.php} | 99 ++++++--------- lib/Db/OC/FilecacheMapper.php | 4 +- lib/SessionStatistics.php | 74 +++++++++++ lib/ShareStatistics.php | 82 ++++++++++++ lib/Stats/Collector/UsersCountCollector.php | 4 +- lib/Stats/Collector/UsersQuotaCollector.php | 4 +- lib/Stats/Collector/UsersStorageCollector.php | 4 +- lib/StorageStatistic.php | 117 ++++++++++++++++++ 8 files changed, 317 insertions(+), 71 deletions(-) rename lib/Db/OC/{PreferencesMapper.php => AccountsMapper.php} (58%) create mode 100644 lib/SessionStatistics.php create mode 100644 lib/ShareStatistics.php create mode 100644 lib/StorageStatistic.php diff --git a/lib/Db/OC/PreferencesMapper.php b/lib/Db/OC/AccountsMapper.php similarity index 58% rename from lib/Db/OC/PreferencesMapper.php rename to lib/Db/OC/AccountsMapper.php index 1c0588a..20933aa 100644 --- a/lib/Db/OC/PreferencesMapper.php +++ b/lib/Db/OC/AccountsMapper.php @@ -5,81 +5,54 @@ namespace OCA\SccuotNC\Db\OC; use OCA\SccuotNC\Db\ExtMapper; use OCA\SccuotNC\Util\FileSize; +use OCP\DB\Exception; +use OCP\IConfig; use OCP\IDBConnection; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCA\SccuotNC\Service\ConfigService; - -class PreferencesMapper extends ExtMapper { +class AccountsMapper extends ExtMapper { const PREFERENCES_TABLE = 'preferences'; + private ConfigService $configService; - public function __construct(IDBConnection $db, int $chunkSize = 10) { - parent::__construct($db, self::PREFERENCES_TABLE, 10); + public function __construct(IDBConnection $db, int $chunkSize, ConfigService $configService ) { + parent::__construct($db, self::PREFERENCES_TABLE, $chunkSize); + $this->configService = $configService; } - public function queryTotalCount(string $state) { - $data = [ - 'state' => $state, - 'count' => 0 - ]; - $this->chunkedQuery('userid', array($this, 'queryTotalCountCallback'), $data, true); - return $data['count']; - } - - protected function queryTotalCountCallback(IQueryBuilder $query, $offset, &$data): string { - $state = $data['state']; - - $qb = $this->getQueryBuilder(); - $qb->selectDistinct('userid') - ->from(self::PREFERENCES_TABLE) - ->where($qb->expr()->eq('configkey', $qb->expr()->literal('enabled'))) - ->andWhere($qb->expr()->eq('configvalue', $qb->expr()->literal('false'))); - - if ($state == 'true') { - $query - ->selectAlias($query->createFunction('COUNT(DISTINCT userid)'), 'c') - ->selectAlias($query->createFunction('MAX(userid)'), 'm') - ->from(self::PREFERENCES_TABLE) - ->where($query->expr()->notIn('userid', $query->createFunction($qb->getSQL()))); - } else { - $query->selectAlias($query->createFunction('COUNT(DISTINCT userid)'), 'c') - ->selectAlias($query->createFunction('MAX(userid)'), 'm') - ->from(self::PREFERENCES_TABLE) - ->where($query->expr()->in('userid', $query->createFunction($qb->getSQL()))); + public function queryTotalCount(string $state): int { + $users = $this->configService->config()->getUsersForUserValue('core', 'enabled', 'false'); + if ($state === 'false'){ + return count($users); } - - $this->addAlphabeticalChunkCondition($query,'userid', $offset); - - // Query values and add up count - $values = $this->queryValues($query, ['c', 'm']); - $data['count'] += $values['c']; - return $values['m'] == NULL ? '' : $values['m']; - } - - public function queryActiveCount(int $since): int { - $data = [ - 'since' => $since, - 'count' => 0 - ]; - $this->chunkedQuery('userid', array($this, 'queryActiveCountCallback'), $data, true); - return $data['count']; + + $qb = $this->db->getQueryBuilder(); + $qb->selectAlias($qb->createFunction('COUNT(DISTINCT uid)'), 'c') + ->from('accounts'); + $stmt = $qb->execute(); + $result = $stmt->fetch(); + $stmt->closeCursor(); + + $count = (int)$result['c'] - count($users); + return $count; } - protected function queryActiveCountCallback(IQueryBuilder $query, $offset, &$data): string { - $since = $data['since']; + /** + * @throws Exception + */ + public function queryActiveCount(int $since): int { + $qb = $this->db->getQueryBuilder(); - $query->selectAlias($query->createFunction('COUNT(*)'), 'c') - ->selectAlias($query->createFunction('MAX(userid)'), 'm') - ->from(self::PREFERENCES_TABLE) - ->where($query->expr()->eq('configkey', $query->createPositionalParameter('lastLogin'))) - ->andWhere($query->expr()->gte('configvalue',$query->createPositionalParameter($since))); - $this->addAlphabeticalChunkCondition($query,'userid', $offset); + $qb->selectAlias($qb->createFunction('COUNT(DISTINCT uid)'), 'c') + ->from('authtoken') + ->where($qb->expr()->gte('last_activity', $qb->createPositionalParameter($since))); - // Query values and add up count - $values = $this->queryValues($query, ['c', 'm']); - $data['count'] += $values['c']; + $stmt = $qb->execute(); + $result = $stmt->fetch(); + $stmt->closeCursor(); - return $values['m'] == NULL ? '' : $values['m']; - } + return (int) $result['c']; + } public function queryUserStorages(): array { $data = [ @@ -109,7 +82,7 @@ class PreferencesMapper extends ExtMapper { $this->addAlphabeticalChunkCondition($query,'p.userid', $offset); // Add storages and get highest ID - $highestID = 'A'; + $highestID = '0'; foreach ($this->queryRows($query) as $row) { $storages[] = intval($row['s']); $highestID = max($row['i'], $highestID); diff --git a/lib/Db/OC/FilecacheMapper.php b/lib/Db/OC/FilecacheMapper.php index f143689..f816bbc 100644 --- a/lib/Db/OC/FilecacheMapper.php +++ b/lib/Db/OC/FilecacheMapper.php @@ -130,7 +130,7 @@ class FilecacheMapper extends ExtMapper { private function joinUserAccounts(IQueryBuilder $query) { if ($this->accountsState != '') { $query->join('fc', StoragesMapper::STORAGES_TABLE, 's', 's.numeric_id = fc.storage') - ->join('s', PreferencesMapper::PREFERENCES_TABLE, 'p', "CONCAT('home::', p.userid) = s.id"); + ->join('s', AccountsMapper::PREFERENCES_TABLE, 'p', "CONCAT('home::', p.userid) = s.id"); } } @@ -139,7 +139,7 @@ class FilecacheMapper extends ExtMapper { $qb = $this->getQueryBuilder(); $qb->selectDistinct('userid') - ->from(PreferencesMapper::PREFERENCES_TABLE) + ->from(AccountsMapper::PREFERENCES_TABLE) ->where($qb->expr()->eq('configkey', $qb->expr()->literal('enabled'))) ->andWhere($qb->expr()->eq('configvalue', $qb->expr()->literal('false'))); diff --git a/lib/SessionStatistics.php b/lib/SessionStatistics.php new file mode 100644 index 0000000..f1bf3eb --- /dev/null +++ b/lib/SessionStatistics.php @@ -0,0 +1,74 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\SccuotNC; + +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\IDBConnection; + +/** + * Class SessionStatistics + * + * get active users + * + * @group DB + * @package OCA\ServerInfo + */ +class SessionStatistics { + private const OFFSET_5MIN = 300; + private const OFFSET_1HOUR = 3600; + private const OFFSET_1DAY = 86400; + private const OFFSET_7DAYS = 604800; + private const OFFSET_1MONTH = 2592000; + private const OFFSET_3MONTHS = 7776000; + private const OFFSET_6MONTHS = 15552000; + private const OFFSET_1YEAR = 31536000; + + private IDBConnection $connection; + private ITimeFactory $timeFactory; + + public function __construct(IDBConnection $connection, ITimeFactory $timeFactory) { + $this->connection = $connection; + $this->timeFactory = $timeFactory; + } + + public function getSessionStatistics(): array { + return [ + 'last5minutes' => $this->getNumberOfActiveUsers(self::OFFSET_5MIN), + 'last1hour' => $this->getNumberOfActiveUsers(self::OFFSET_1HOUR), + 'last24hours' => $this->getNumberOfActiveUsers(self::OFFSET_1DAY), + 'last7days' => $this->getNumberOfActiveUsers(self::OFFSET_7DAYS), + 'last1month' => $this->getNumberOfActiveUsers(self::OFFSET_1MONTH), + 'last3months' => $this->getNumberOfActiveUsers(self::OFFSET_3MONTHS), + 'last6months' => $this->getNumberOfActiveUsers(self::OFFSET_6MONTHS), + 'lastyear' => $this->getNumberOfActiveUsers(self::OFFSET_1YEAR), + ]; + } + + /** + * get number of active user in a given time span + * + * @param int $offset seconds + */ + private function getNumberOfActiveUsers(int $offset): int { + $query = $this->connection->getQueryBuilder(); + $query->select('uid') + ->from('authtoken') + ->where($query->expr()->gte( + 'last_activity', + $query->createNamedParameter($this->timeFactory->getTime() - $offset) + ))->groupBy('uid'); + + $result = $query->executeQuery(); + $activeUsers = $result->fetchAll(); + $result->closeCursor(); + + return count($activeUsers); + } +} diff --git a/lib/ShareStatistics.php b/lib/ShareStatistics.php new file mode 100644 index 0000000..4ffe3e1 --- /dev/null +++ b/lib/ShareStatistics.php @@ -0,0 +1,82 @@ +<?php +declare(strict_types=1); +namespace OCA\SccuotNC; + +use OCP\IDBConnection; +use OCP\Share\IShare; + +class ShareStatistics { + protected IDBConnection $connection; + + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + } + + /** + * @return array (string => string|int) + */ + public function getShareStatistics(): array { + $query = $this->connection->getQueryBuilder(); + $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') + ->addSelect(['permissions', 'share_type']) + ->from('share') + ->addGroupBy('permissions') + ->addGroupBy('share_type'); + $result = $query->executeQuery(); + + $data = [ + 'num_shares' => $this->countEntries('share'), + 'num_shares_user' => $this->countShares(IShare::TYPE_USER), + 'num_shares_groups' => $this->countShares(IShare::TYPE_GROUP), + 'num_shares_link' => $this->countShares(IShare::TYPE_LINK), + 'num_shares_mail' => $this->countShares(IShare::TYPE_EMAIL), + 'num_shares_room' => $this->countShares(IShare::TYPE_ROOM), + 'num_shares_link_no_password' => $this->countShares(IShare::TYPE_LINK, true), + 'num_fed_shares_sent' => $this->countShares(IShare::TYPE_REMOTE), + 'num_fed_shares_received' => $this->countEntries('share_external'), + ]; + while ($row = $result->fetch()) { + $data['permissions_' . $row['share_type'] . '_' . $row['permissions']] = $row['num_entries']; + } + $result->closeCursor(); + + return $data; + } + + /** + * @param string $tableName + * @return int + */ + protected function countEntries(string $tableName): int { + $query = $this->connection->getQueryBuilder(); + $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') + ->from($tableName); + $result = $query->executeQuery(); + $row = $result->fetch(); + $result->closeCursor(); + + return (int)$row['num_entries']; + } + + /** + * @param int $type + * @param bool $noPassword + * @return int + */ + protected function countShares(int $type, bool $noPassword = false): int { + $query = $this->connection->getQueryBuilder(); + $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') + ->from('share') + ->where($query->expr()->eq('share_type', $query->createNamedParameter($type))); + + if ($noPassword) { + $query->andWhere($query->expr()->isNull('password')); + } + + $result = $query->executeQuery(); + $row = $result->fetch(); + $result->closeCursor(); + + return (int)$row['num_entries']; + } +} diff --git a/lib/Stats/Collector/UsersCountCollector.php b/lib/Stats/Collector/UsersCountCollector.php index c0b8728..15f9aa5 100644 --- a/lib/Stats/Collector/UsersCountCollector.php +++ b/lib/Stats/Collector/UsersCountCollector.php @@ -2,7 +2,7 @@ namespace OCA\SccuotNC\Stats\Collector; -use OCA\SccuotNC\Db\OC\PreferencesMapper; +use OCA\SccuotNC\Db\OC\AccountsMapper; use OCA\SccuotNC\Misc\TimePeriods; use OCA\SccuotNC\Service\ConfigService; use OCA\SccuotNC\Stats\Value\UsersCountValue; @@ -11,7 +11,7 @@ use OCP\IDBConnection; class UsersCountCollector extends BaseCollector { protected function collectData(IDBConnection $db, int $timestamp, int $chunkSize, ConfigService $config): array { - $mapper = new PreferencesMapper($db, $chunkSize); + $mapper = new AccountsMapper($db, $chunkSize, $config); $activeUsers = $mapper->queryTotalCount(self::STATE_ENABLED); $closedUsers = $mapper->queryTotalCount(self::STATE_DISABLED); $values = [UsersCountValue::TOTAL_COUNT => $activeUsers + $closedUsers, UsersCountValue::CLOSED_COUNT => $closedUsers]; diff --git a/lib/Stats/Collector/UsersQuotaCollector.php b/lib/Stats/Collector/UsersQuotaCollector.php index b67fa53..b44dbc0 100644 --- a/lib/Stats/Collector/UsersQuotaCollector.php +++ b/lib/Stats/Collector/UsersQuotaCollector.php @@ -2,7 +2,7 @@ namespace OCA\SccuotNC\Stats\Collector; -use OCA\SccuotNC\Db\OC\PreferencesMapper; +use OCA\SccuotNC\Db\OC\AccountsMapper; use OCA\SccuotNC\Db\OC\StoragesMapper; use OCA\SccuotNC\Service\ConfigService; use OCA\SccuotNC\Util\FileSize; @@ -11,7 +11,7 @@ use OCP\IDBConnection; class UsersQuotaCollector extends BaseCollector { protected function collectData(IDBConnection $db, int $timestamp, int $chunkSize, ConfigService $config) { - $accMapper = new PreferencesMapper($db, $chunkSize); + $accMapper = new AccountsMapper($db, $chunkSize, $config); $storeMapper = new StoragesMapper($db, $chunkSize); $userQuotas = $accMapper->queryUserQuotas($this->getDefaultQuotas($config)); $quotaUsages = []; diff --git a/lib/Stats/Collector/UsersStorageCollector.php b/lib/Stats/Collector/UsersStorageCollector.php index cf81af8..837ba18 100644 --- a/lib/Stats/Collector/UsersStorageCollector.php +++ b/lib/Stats/Collector/UsersStorageCollector.php @@ -2,14 +2,14 @@ namespace OCA\SccuotNC\Stats\Collector; -use OCA\SccuotNC\Db\OC\PreferencesMapper; +use OCA\SccuotNC\Db\OC\AccountsMapper; use OCA\SccuotNC\Service\ConfigService; use OCP\IDBConnection; class UsersStorageCollector extends BaseCollector { protected function collectData(IDBConnection $db, int $timestamp, int $chunkSize, ConfigService $config) { - $mapper = new PreferencesMapper($db, $chunkSize); + $mapper = new AccountsMapper($db, $chunkSize, $config); $filesSizes = $mapper->queryUserStorages(); sort($filesSizes); return $filesSizes; diff --git a/lib/StorageStatistic.php b/lib/StorageStatistic.php new file mode 100644 index 0000000..95b67a5 --- /dev/null +++ b/lib/StorageStatistic.php @@ -0,0 +1,117 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + + +namespace OCA\SccuotNC\Db\OC; + +use OCP\Files\IRootFolder; +use OCP\IAppConfig; +use OCP\IDBConnection; + +class StorageStatistics { + + public function __construct( + private IDBConnection $connection, + private IRootFolder $rootFolder, + private IAppConfig $appConfig, + ) { + } + + public function getStorageStatistics(): array { + return [ + 'num_users' => $this->countUserEntries(), + 'num_files' => $this->getCountOf('filecache'), + 'num_storages' => $this->getCountOf('storages'), + 'num_storages_local' => $this->countStorages('local'), + 'num_storages_home' => $this->countStorages('home'), + 'num_storages_other' => $this->countStorages('other'), + 'size_appdata_storage' => $this->appConfig->getValueFloat('serverinfo', 'size_appdata_storage'), + 'num_files_appdata' => $this->getCountOf('appdata_files'), + ]; + } + + /** + * count number of users + */ + protected function countUserEntries(): int { + $query = $this->connection->getQueryBuilder(); + $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') + ->from('preferences') + ->where($query->expr()->eq('configkey', $query->createNamedParameter('lastLogin'))); + $result = $query->executeQuery(); + $row = $result->fetch(); + $result->closeCursor(); + return (int)$row['num_entries']; + } + + protected function getCountOf(string $table): int { + return $this->appConfig->getValueInt('serverinfo', 'cached_count_' . $table); + } + + public function updateStorageCounts(): void { + $storageCount = 0; + $fileCount = 0; + + $fileQuery = $this->connection->getQueryBuilder(); + $fileQuery->select($fileQuery->func()->count()) + ->from('filecache') + ->where($fileQuery->expr()->eq('storage', $fileQuery->createParameter('storageId'))); + + $storageQuery = $this->connection->getQueryBuilder(); + $storageQuery->selectAlias('numeric_id', 'id') + ->from('storages'); + $storageResult = $storageQuery->executeQuery(); + while ($storageRow = $storageResult->fetch()) { + $storageCount++; + $fileQuery->setParameter('storageId', $storageRow['id']); + $fileResult = $fileQuery->executeQuery(); + $fileCount += (int)$fileResult->fetchOne(); + $fileResult->closeCursor(); + } + $storageResult->closeCursor(); + + $this->updateAppDataStorageStats(); + + $this->appConfig->setValueInt('serverinfo', 'cached_count_filecache', $fileCount); + $this->appConfig->setValueInt('serverinfo', 'cached_count_storages', $storageCount); + } + + protected function countStorages(string $type): int { + $query = $this->connection->getQueryBuilder(); + $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') + ->from('storages'); + if ($type === 'home') { + $query->where($query->expr()->like('id', $query->createNamedParameter('home::%'))); + } elseif ($type === 'local') { + $query->where($query->expr()->like('id', $query->createNamedParameter('local::%'))); + } elseif ($type === 'other') { + $query->where($query->expr()->notLike('id', $query->createNamedParameter('home::%'))); + $query->andWhere($query->expr()->notLike('id', $query->createNamedParameter('local::%'))); + } + $result = $query->executeQuery(); + $row = $result->fetch(); + $result->closeCursor(); + return (int)$row['num_entries']; + } + + public function updateAppDataStorageStats(): void { + $appDataPath = $this->rootFolder->getAppDataDirectoryName(); + $appDataFolder = $this->rootFolder->get($appDataPath); + $this->appConfig->setValueFloat('serverinfo', 'size_appdata_storage', $appDataFolder->getSize()); + + $query = $this->connection->getQueryBuilder(); + $query->select($query->func()->count()) + ->from('filecache') + ->where($query->expr()->like('path', $query->createNamedParameter($appDataPath . '%'))); + $fileResult = $query->executeQuery(); + $fileCount = (int)$fileResult->fetchOne(); + $fileResult->closeCursor(); + $this->appConfig->setValueInt('serverinfo', 'cached_count_appdata_files', $fileCount); + } +} -- GitLab From afcf6fac0eb4c6b2a17d5826463f9bafffc00559 Mon Sep 17 00:00:00 2001 From: Lidiya Gelemeev <l_gele02@uni-muenster.de> Date: Thu, 6 Feb 2025 15:13:59 +0100 Subject: [PATCH 2/6] Controller modification --- lib/Db/ExtMapper.php | 54 ++++++++------------ lib/Db/OC/AccountsMapper.php | 98 ++++++++++++++++++++---------------- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/lib/Db/ExtMapper.php b/lib/Db/ExtMapper.php index f25b9b9..e5ee27d 100644 --- a/lib/Db/ExtMapper.php +++ b/lib/Db/ExtMapper.php @@ -34,19 +34,33 @@ abstract class ExtMapper extends QBMapper { return $this->queryValue($query, $field); } - protected function chunkedQuery(string $idField, callable $callback, &$data, $alphabetic = false) { - $alphabetic ? $offset = 'A' : $offset = 0; + protected function chunkedQuery(string $idField, callable $callback, &$data) { + $offset = 0; $highestEntityID = $this->getHighestEntityID($idField); while ($offset < $highestEntityID) { $query = $this->getQueryBuilder(); // The provided callback performs the actual query; afterwards, advance the offset $maxEntityID = call_user_func_array($callback, array($query, $offset, &$data)); - if (!$alphabetic) { - $offset = max($maxEntityID, $this->advanceOffset($offset)); - } else { - $offset = max($maxEntityID, $this->advanceAlphabeticOffset($offset)); + $offset = max($maxEntityID, $this->advanceOffset($offset)); + } + } + + protected function chunkedQueryArray(callable $callback, &$data, $activeUsers): void { + + $offset = 0; + $totalUsers = count($activeUsers); // Total number of users + + while ($offset < $totalUsers) { + $query = $this->getQueryBuilder(); + + $userChunk = array_slice($activeUsers, $offset, $this->chunkSize); + if (empty($userChunk)) { + break; } + $callback($query, $userChunk, $data); + + $offset += $this->chunkSize; } } @@ -64,23 +78,6 @@ abstract class ExtMapper extends QBMapper { } } - protected function addAlphabeticalChunkCondition(IQueryBuilder $query, string $field, string $offset, bool $firstWhereClause = false): void { - //Changed chunkSize to a string that can define the size of a chunk - if ($this->chunkSize > 0) { - $endOffset = $this->advanceAlphabeticOffset($offset); - - $expr = $query->expr()->gt($field, $query->createPositionalParameter($offset)); - if ($firstWhereClause) { - $query->where($expr); - } else { - $query->andWhere($expr); - } - $expr = $query->expr()->lte($field, $query->createPositionalParameter($endOffset)); - $query->andWhere($expr); - $query->orderBy($field, 'ASC'); - } - } - protected function getQueryBuilder() : IQueryBuilder { return $this->db->getQueryBuilder(); } @@ -115,6 +112,7 @@ abstract class ExtMapper extends QBMapper { $stmt = $query->execute(); $rows = []; while ($row = $stmt->fetch()) { + echo "Row fetched: " . json_encode($row) . PHP_EOL; $rows[] = $row; } $stmt->closeCursor(); @@ -160,14 +158,4 @@ abstract class ExtMapper extends QBMapper { } return $offset; } - - private function advanceAlphabeticOffset(string $offset): string { - if ($this->chunkSize > 0) { - $offset = chr(ord($offset) + $this->chunkSize); - } else { - $offset = '{'; - } - return $offset; - } - } diff --git a/lib/Db/OC/AccountsMapper.php b/lib/Db/OC/AccountsMapper.php index 20933aa..028b095 100644 --- a/lib/Db/OC/AccountsMapper.php +++ b/lib/Db/OC/AccountsMapper.php @@ -6,14 +6,15 @@ use OCA\SccuotNC\Db\ExtMapper; use OCA\SccuotNC\Util\FileSize; use OCP\DB\Exception; -use OCP\IConfig; use OCP\IDBConnection; use OCP\DB\QueryBuilder\IQueryBuilder; use OCA\SccuotNC\Service\ConfigService; +use PDO; class AccountsMapper extends ExtMapper { const PREFERENCES_TABLE = 'preferences'; private ConfigService $configService; + private string $activeUsersFile = '/tmp/active_users.txt'; public function __construct(IDBConnection $db, int $chunkSize, ConfigService $configService ) { parent::__construct($db, self::PREFERENCES_TABLE, $chunkSize); @@ -21,20 +22,23 @@ class AccountsMapper extends ExtMapper { } public function queryTotalCount(string $state): int { - $users = $this->configService->config()->getUsersForUserValue('core', 'enabled', 'false'); + $deactivatedUsers = array_map('strval', $this->configService->config()->getUsersForUserValue('core', 'enabled', 'false')); if ($state === 'false'){ - return count($users); + return count($deactivatedUsers); } - $qb = $this->db->getQueryBuilder(); - $qb->selectAlias($qb->createFunction('COUNT(DISTINCT uid)'), 'c') + $qb->select('uid') ->from('accounts'); $stmt = $qb->execute(); - $result = $stmt->fetch(); + $result = $stmt->fetchAll(PDO::FETCH_COLUMN); $stmt->closeCursor(); + $result = array_map('strval', $result); - $count = (int)$result['c'] - count($users); - return $count; + $activerUsers = array_diff($result, $deactivatedUsers); + $fileContent = implode(PHP_EOL, $activerUsers); + file_put_contents($this->activeUsersFile, $fileContent); + + return count($result) - count($deactivatedUsers); } /** @@ -54,79 +58,74 @@ class AccountsMapper extends ExtMapper { return (int) $result['c']; } + /** + * @throws \Exception + */ public function queryUserStorages(): array { + $activeUsers = $this->getActiveUsersFromFile($this->activeUsersFile); $data = [ 'storages' => [] ]; - $this->chunkedQuery('userid', array($this, 'queryUserStoragesCallback'), $data, true); + $this->chunkedQueryArray(function ($query, $userChunk, &$data) use ($activeUsers) { + return $this->queryUserStoragesCallback($query, $userChunk, $data); + }, $data, $activeUsers); + return $data['storages']; } - protected function queryUserStoragesCallback(IQueryBuilder $query, $offset, &$data): string { + protected function queryUserStoragesCallback(IQueryBuilder $query, array $userChunk, &$data): string { $storages = &$data['storages']; - - $qb = $this->getQueryBuilder(); - $qb->selectDistinct('userid') - ->from(self::PREFERENCES_TABLE) - ->where($qb->expr()->eq('configkey', $qb->expr()->literal('enabled'))) - ->andWhere($qb->expr()->eq('configvalue', $qb->expr()->literal('false'))); - + if (empty($userChunk)) { + return '0'; + } $query->selectAlias('fc.size', 's') - ->selectAlias('p.userid', 'i') - ->from(self::PREFERENCES_TABLE, 'p') - ->join('p', StoragesMapper::STORAGES_TABLE, 's', "s.id = CONCAT('home::', p.userid)") + ->selectAlias('a.uid', 'i') + ->from('accounts', 'a') + ->join('a', StoragesMapper::STORAGES_TABLE, 's', "s.id = CONCAT('home::', a.uid)") ->join('s', FilecacheMapper::FILECACHE_TABLE, 'fc', 'fc.storage = s.numeric_id') - ->where($query->expr()->notIn('p.userid', $query->createFunction($qb->getSQL()))) - ->where($query->expr()->eq('p.configkey', $query->createPositionalParameter('quota'))) - ->andWhere($query->expr()->eq('fc.path', $query->createPositionalParameter('files'))); - $this->addAlphabeticalChunkCondition($query,'p.userid', $offset); + ->where($query->expr()->eq('fc.path', $query->createPositionalParameter('files'))) + ->andWhere($query->expr()->in('a.uid', $query->createPositionalParameter($userChunk, IQueryBuilder::PARAM_STR_ARRAY))); - // Add storages and get highest ID - $highestID = '0'; foreach ($this->queryRows($query) as $row) { $storages[] = intval($row['s']); - $highestID = max($row['i'], $highestID); } - return $highestID; + return ''; } public function queryUserQuotas($defaultQuotas) { + $activeUsers = $this->getActiveUsersFromFile($this->activeUsersFile); $data = [ 'defaultQuotas' => $defaultQuotas, 'quotas' => [] ]; - $this->chunkedQuery('userid', array($this, 'queryUserQuotasCallback'), $data, true); + $this->chunkedQueryArray(function ($query, $userChunk, &$data) use ($activeUsers) { + + return $this->queryUserQuotasCallback($query, $userChunk, $data); + }, $data, $activeUsers); return $data['quotas']; } - protected function queryUserQuotasCallback(IQueryBuilder $query, $offset, &$data): string { + protected function queryUserQuotasCallback(IQueryBuilder $query, $userChunk, &$data): string { $defaultQuotas = $data['defaultQuotas']; $quotas = &$data['quotas']; - - $qb = $this->getQueryBuilder(); - $qb->selectDistinct('userid') - ->from(self::PREFERENCES_TABLE) - ->where($qb->expr()->eq('configkey', $qb->expr()->literal('enabled'))) - ->andWhere($qb->expr()->eq('configvalue', $qb->expr()->literal('false'))); + if (empty($userChunk)) { + return '0'; + } $query->selectDistinct('p.userid') ->selectAlias('p1.configvalue', 'quota') ->from(self::PREFERENCES_TABLE, 'p') ->join('p', self::PREFERENCES_TABLE, 'p1', 'p1.userid = p.userid') - ->where($query->expr()->notIn('p.userid', $query->createFunction($qb->getSQL()))) - ->andWhere($query->expr()->eq('p1.configkey', $query->createPositionalParameter('quota'))); - $this->addAlphabeticalChunkCondition($query,'p.userid', $offset); + ->andWhere($query->expr()->eq('p1.configkey', $query->createPositionalParameter('quota'))) + ->andWhere($query->expr()->in('p.userid', $query->createPositionalParameter($userChunk, IQueryBuilder::PARAM_STR_ARRAY))); - // Add quotas and get highest ID - $highestID = ''; foreach ($this->queryRows($query) as $row) { $defaultQuota = $this->findDefaultQuota($defaultQuotas, $row['quota']); if (($quota = FileSize::ParseQuotaString($row['quota'], $defaultQuota)) !== false) { $quotas[$row['userid']] = $quota; } - $highestID = max($row['userid'], $highestID); } - return $highestID; + return ''; } private function findDefaultQuota($defaultQuotas, $backend) { @@ -138,4 +137,17 @@ class AccountsMapper extends ExtMapper { } return false; } + + /** + * @throws \Exception + */ + protected function getActiveUsersFromFile(string $filePath): array { + if (!file_exists($filePath)) { + throw new \Exception("Active users file not found at: {$filePath}"); + } + + $activeUsers = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + + return array_map('trim', $activeUsers); // Ensure no extra whitespace + } } -- GitLab From c396c8f8dd70ed2457c8f9d48acc64565a546f20 Mon Sep 17 00:00:00 2001 From: Lidiya Gelemeev <l_gele02@uni-muenster.de> Date: Mon, 10 Feb 2025 13:17:38 +0100 Subject: [PATCH 3/6] Adjust the user fetching --- lib/Db/ExtMapper.php | 7 +++---- lib/Db/OC/AccountsMapper.php | 37 ++++------------------------------- lib/Db/OC/FilecacheMapper.php | 9 +-------- 3 files changed, 8 insertions(+), 45 deletions(-) diff --git a/lib/Db/ExtMapper.php b/lib/Db/ExtMapper.php index e5ee27d..2086674 100644 --- a/lib/Db/ExtMapper.php +++ b/lib/Db/ExtMapper.php @@ -46,15 +46,15 @@ abstract class ExtMapper extends QBMapper { } } - protected function chunkedQueryArray(callable $callback, &$data, $activeUsers): void { + protected function chunkedQueryArray(callable $callback, &$data, $users): void { $offset = 0; - $totalUsers = count($activeUsers); // Total number of users + $totalUsers = count($users); // Total number of users while ($offset < $totalUsers) { $query = $this->getQueryBuilder(); - $userChunk = array_slice($activeUsers, $offset, $this->chunkSize); + $userChunk = array_slice($users, $offset, $this->chunkSize); if (empty($userChunk)) { break; } @@ -112,7 +112,6 @@ abstract class ExtMapper extends QBMapper { $stmt = $query->execute(); $rows = []; while ($row = $stmt->fetch()) { - echo "Row fetched: " . json_encode($row) . PHP_EOL; $rows[] = $row; } $stmt->closeCursor(); diff --git a/lib/Db/OC/AccountsMapper.php b/lib/Db/OC/AccountsMapper.php index 028b095..2383f42 100644 --- a/lib/Db/OC/AccountsMapper.php +++ b/lib/Db/OC/AccountsMapper.php @@ -9,12 +9,10 @@ use OCP\DB\Exception; use OCP\IDBConnection; use OCP\DB\QueryBuilder\IQueryBuilder; use OCA\SccuotNC\Service\ConfigService; -use PDO; class AccountsMapper extends ExtMapper { const PREFERENCES_TABLE = 'preferences'; private ConfigService $configService; - private string $activeUsersFile = '/tmp/active_users.txt'; public function __construct(IDBConnection $db, int $chunkSize, ConfigService $configService ) { parent::__construct($db, self::PREFERENCES_TABLE, $chunkSize); @@ -22,23 +20,8 @@ class AccountsMapper extends ExtMapper { } public function queryTotalCount(string $state): int { - $deactivatedUsers = array_map('strval', $this->configService->config()->getUsersForUserValue('core', 'enabled', 'false')); - if ($state === 'false'){ - return count($deactivatedUsers); - } - $qb = $this->db->getQueryBuilder(); - $qb->select('uid') - ->from('accounts'); - $stmt = $qb->execute(); - $result = $stmt->fetchAll(PDO::FETCH_COLUMN); - $stmt->closeCursor(); - $result = array_map('strval', $result); - - $activerUsers = array_diff($result, $deactivatedUsers); - $fileContent = implode(PHP_EOL, $activerUsers); - file_put_contents($this->activeUsersFile, $fileContent); - - return count($result) - count($deactivatedUsers); + $users = $this->configService->config()->getUsersForUserValue('core', 'enabled', $state); + return count($users); } /** @@ -62,7 +45,7 @@ class AccountsMapper extends ExtMapper { * @throws \Exception */ public function queryUserStorages(): array { - $activeUsers = $this->getActiveUsersFromFile($this->activeUsersFile); + $activeUsers = $this->configService->config()->getUsersForUserValue('core', 'enabled', 'true'); $data = [ 'storages' => [] ]; @@ -93,7 +76,7 @@ class AccountsMapper extends ExtMapper { } public function queryUserQuotas($defaultQuotas) { - $activeUsers = $this->getActiveUsersFromFile($this->activeUsersFile); + $activeUsers = $this->configService->config()->getUsersForUserValue('core', 'enabled', 'true'); $data = [ 'defaultQuotas' => $defaultQuotas, 'quotas' => [] @@ -138,16 +121,4 @@ class AccountsMapper extends ExtMapper { return false; } - /** - * @throws \Exception - */ - protected function getActiveUsersFromFile(string $filePath): array { - if (!file_exists($filePath)) { - throw new \Exception("Active users file not found at: {$filePath}"); - } - - $activeUsers = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - - return array_map('trim', $activeUsers); // Ensure no extra whitespace - } } diff --git a/lib/Db/OC/FilecacheMapper.php b/lib/Db/OC/FilecacheMapper.php index f816bbc..a7d9080 100644 --- a/lib/Db/OC/FilecacheMapper.php +++ b/lib/Db/OC/FilecacheMapper.php @@ -141,14 +141,7 @@ class FilecacheMapper extends ExtMapper { $qb->selectDistinct('userid') ->from(AccountsMapper::PREFERENCES_TABLE) ->where($qb->expr()->eq('configkey', $qb->expr()->literal('enabled'))) - ->andWhere($qb->expr()->eq('configvalue', $qb->expr()->literal('false'))); - - $query->andWhere($query->expr()->like('configkey', $query->expr()->literal('%quota%'))); - if ($this->accountsState == 'true') { - $query->andWhere($query->expr()->notIn('p.userid', $query->createFunction($qb->getSQL()))); - } else { - $query->andWhere($query->expr()->in('p.userid', $query->createFunction($qb->getSQL()))); - } + ->andWhere($qb->expr()->eq('configvalue', $qb->expr()->literal($this->accountsState))); } } -- GitLab From 169f3f54bfeb70ab3e7d439df9d7791f51e62bfd Mon Sep 17 00:00:00 2001 From: Lidiya Gelemeev <l_gele02@uni-muenster.de> Date: Mon, 10 Feb 2025 13:42:10 +0100 Subject: [PATCH 4/6] Remove the callback by simple count --- lib/Db/OC/ExternalSharesMapper.php | 30 ++++------- lib/Db/OC/SharesMapper.php | 82 ++++++++---------------------- 2 files changed, 32 insertions(+), 80 deletions(-) diff --git a/lib/Db/OC/ExternalSharesMapper.php b/lib/Db/OC/ExternalSharesMapper.php index d683bfd..011edce 100644 --- a/lib/Db/OC/ExternalSharesMapper.php +++ b/lib/Db/OC/ExternalSharesMapper.php @@ -15,23 +15,15 @@ class ExternalSharesMapper extends ExtMapper { } public function queryTotalCount() { - $data = [ - 'count' => 0 - ]; - $this->chunkedQuery('id', array($this, 'queryTotalCountCallback'), $data); - return $data['count']; - } - - protected function queryTotalCountCallback(IQueryBuilder $query, $offset, &$data): int { - $query->selectAlias($query->createFunction('COUNT(*)'), 'c') - ->selectAlias($query->createFunction('MAX(id)'), 'm') - ->from(self::EXTERNAL_SHARES_TABLE); - $this->addChunkCondition($query,'id', $offset, true); - - // Query values and add up count - $values = $this->queryValues($query, ['c', 'm']); - $data['count'] += $values['c']; - - return $values['m'] == NULL ? 0 : $values['m']; - } + $query = $this->db->getQueryBuilder(); + + // Create a query to count all rows in the EXTERNAL_SHARES_TABLE + $query->selectAlias($query->createFunction('COUNT(*)'), 'count') + ->from(self::EXTERNAL_SHARES_TABLE); + + // Execute the query and fetch the result + $result = $query->execute()->fetch(); + + // Return the total count as an integer + return (int) $result['count']; } diff --git a/lib/Db/OC/SharesMapper.php b/lib/Db/OC/SharesMapper.php index 039db00..219c1aa 100644 --- a/lib/Db/OC/SharesMapper.php +++ b/lib/Db/OC/SharesMapper.php @@ -17,89 +17,49 @@ class SharesMapper extends ExtMapper { } public function queryTotalCount(): int { - $data = [ - 'count' => 0 - ]; - $this->chunkedQuery('id', array($this, 'queryTotalCountCallback'), $data); - return $data['count']; - } + $query = $this->db->getQueryBuilder(); - protected function queryTotalCountCallback(IQueryBuilder $query, $offset, &$data): int { - $query->selectAlias($query->createFunction('COUNT(*)'), 'c') - ->selectAlias($query->createFunction('MAX(id)'), 'm') - ->from(self::SHARES_TABLE); - $this->addChunkCondition($query,'id', $offset, true); + $query->selectAlias($query->createFunction('COUNT(*)'), 'count') + ->from(self::SHARES_TABLE); - // Query values and add up count - $values = $this->queryValues($query, ['c', 'm']); - $data['count'] += $values['c']; + $result = $query->execute()->fetch(); - return $values['m'] == NULL ? 0 : $values['m']; + return (int) $result['count']; } public function queryFilesCount(): int { - $data = [ - 'count' => 0 - ]; - $this->chunkedQuery('id', array($this, 'queryFilesCountCallback'), $data); - return $data['count']; - } + $query = $this->db->getQueryBuilder(); - protected function queryFilesCountCallback(IQueryBuilder $query, $offset, &$data): int { - $query->selectAlias($query->createFunction('COUNT(*)'), 'c') - ->selectAlias($query->createFunction('MAX(id)'), 'm') - ->from(self::SHARES_TABLE) - ->where($query->expr()->like('item_type', $query->createPositionalParameter('file'))); - $this->addChunkCondition($query,'id', $offset); + $query->selectAlias($query->createFunction('COUNT(*)'), 'count') + ->from(self::SHARES_TABLE) + ->where($query->expr()->like('item_type', $query->createPositionalParameter('file'))); - // Query values and add up count - $values = $this->queryValues($query, ['c', 'm']); - $data['count'] += $values['c']; + $result = $query->execute()->fetch(); - return $values['m'] == NULL ? 0 : $values['m']; + return (int) $result['count']; } public function queryFoldersCount(): int { - $data = [ - 'count' => 0 - ]; - $this->chunkedQuery('id', array($this, 'queryFoldersCountCallback'), $data); - return $data['count']; - } + $query = $this->db->getQueryBuilder(); - protected function queryFoldersCountCallback(IQueryBuilder $query, $offset, &$data): int { - $query->selectAlias($query->createFunction('COUNT(*)'), 'c') - ->selectAlias($query->createFunction('MAX(id)'), 'm') - ->from(self::SHARES_TABLE) - ->where($query->expr()->like('item_type', $query->createPositionalParameter('folder'))); - $this->addChunkCondition($query,'id', $offset); + $query->selectAlias($query->createFunction('COUNT(*)'), 'count') + ->from(self::SHARES_TABLE) + ->where($query->expr()->like('item_type', $query->createPositionalParameter('folder'))); - // Query values and add up count - $values = $this->queryValues($query, ['c', 'm']); - $data['count'] += $values['c']; + $result = $query->execute()->fetch(); - return $values['m'] == NULL ? 0 : $values['m']; + return (int) $result['count']; } public function queryPublicLinksCount(): int { - $data = [ - 'count' => 0 - ]; - $this->chunkedQuery('id', array($this, 'queryPublicLinksCountCallback'), $data); - return $data['count']; - } + $query = $this->db->getQueryBuilder(); - protected function queryPublicLinksCountCallback(IQueryBuilder $query, $offset, &$data): int { - $query->selectAlias($query->createFunction('COUNT(*)'), 'c') - ->selectAlias($query->createFunction('MAX(id)'), 'm') + $query->selectAlias($query->createFunction('COUNT(*)'), 'count') ->from(self::SHARES_TABLE) ->where($query->expr()->eq('share_type', $query->createPositionalParameter(IShare::TYPE_LINK, IQueryBuilder::PARAM_INT))); - $this->addChunkCondition($query,'id', $offset); - // Query values and add up count - $values = $this->queryValues($query, ['c', 'm']); - $data['count'] += $values['c']; + $result = $query->execute()->fetch(); - return $values['m'] == NULL ? 0 : $values['m']; + return (int) $result['count']; } } -- GitLab From d9e1383a6d5842f268c1c3c950149bfc130e70ad Mon Sep 17 00:00:00 2001 From: Lidiya Gelemeev <l_gele02@uni-muenster.de> Date: Mon, 10 Feb 2025 13:42:39 +0100 Subject: [PATCH 5/6] fix --- lib/Db/OC/ExternalSharesMapper.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Db/OC/ExternalSharesMapper.php b/lib/Db/OC/ExternalSharesMapper.php index 011edce..a1d7377 100644 --- a/lib/Db/OC/ExternalSharesMapper.php +++ b/lib/Db/OC/ExternalSharesMapper.php @@ -8,11 +8,11 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; class ExternalSharesMapper extends ExtMapper { - const EXTERNAL_SHARES_TABLE = 'share_external'; + const EXTERNAL_SHARES_TABLE = 'share_external'; - public function __construct(IDBConnection $db, int $chunkSize) { - parent::__construct($db, self::EXTERNAL_SHARES_TABLE, $chunkSize); - } + public function __construct(IDBConnection $db, int $chunkSize) { + parent::__construct($db, self::EXTERNAL_SHARES_TABLE, $chunkSize); + } public function queryTotalCount() { $query = $this->db->getQueryBuilder(); @@ -25,5 +25,6 @@ class ExternalSharesMapper extends ExtMapper { $result = $query->execute()->fetch(); // Return the total count as an integer - return (int) $result['count']; + return (int)$result['count']; + } } -- GitLab From de281b1ff4ba8bdeba492acd51a217ed5ad26404 Mon Sep 17 00:00:00 2001 From: Lidiya Gelemeev <l_gele02@uni-muenster.de> Date: Mon, 10 Feb 2025 14:36:02 +0100 Subject: [PATCH 6/6] fix --- lib/SessionStatistics.php | 74 ------------------------ lib/ShareStatistics.php | 82 -------------------------- lib/StorageStatistic.php | 117 -------------------------------------- 3 files changed, 273 deletions(-) delete mode 100644 lib/SessionStatistics.php delete mode 100644 lib/ShareStatistics.php delete mode 100644 lib/StorageStatistic.php diff --git a/lib/SessionStatistics.php b/lib/SessionStatistics.php deleted file mode 100644 index f1bf3eb..0000000 --- a/lib/SessionStatistics.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace OCA\SccuotNC; - -use OCP\AppFramework\Utility\ITimeFactory; -use OCP\IDBConnection; - -/** - * Class SessionStatistics - * - * get active users - * - * @group DB - * @package OCA\ServerInfo - */ -class SessionStatistics { - private const OFFSET_5MIN = 300; - private const OFFSET_1HOUR = 3600; - private const OFFSET_1DAY = 86400; - private const OFFSET_7DAYS = 604800; - private const OFFSET_1MONTH = 2592000; - private const OFFSET_3MONTHS = 7776000; - private const OFFSET_6MONTHS = 15552000; - private const OFFSET_1YEAR = 31536000; - - private IDBConnection $connection; - private ITimeFactory $timeFactory; - - public function __construct(IDBConnection $connection, ITimeFactory $timeFactory) { - $this->connection = $connection; - $this->timeFactory = $timeFactory; - } - - public function getSessionStatistics(): array { - return [ - 'last5minutes' => $this->getNumberOfActiveUsers(self::OFFSET_5MIN), - 'last1hour' => $this->getNumberOfActiveUsers(self::OFFSET_1HOUR), - 'last24hours' => $this->getNumberOfActiveUsers(self::OFFSET_1DAY), - 'last7days' => $this->getNumberOfActiveUsers(self::OFFSET_7DAYS), - 'last1month' => $this->getNumberOfActiveUsers(self::OFFSET_1MONTH), - 'last3months' => $this->getNumberOfActiveUsers(self::OFFSET_3MONTHS), - 'last6months' => $this->getNumberOfActiveUsers(self::OFFSET_6MONTHS), - 'lastyear' => $this->getNumberOfActiveUsers(self::OFFSET_1YEAR), - ]; - } - - /** - * get number of active user in a given time span - * - * @param int $offset seconds - */ - private function getNumberOfActiveUsers(int $offset): int { - $query = $this->connection->getQueryBuilder(); - $query->select('uid') - ->from('authtoken') - ->where($query->expr()->gte( - 'last_activity', - $query->createNamedParameter($this->timeFactory->getTime() - $offset) - ))->groupBy('uid'); - - $result = $query->executeQuery(); - $activeUsers = $result->fetchAll(); - $result->closeCursor(); - - return count($activeUsers); - } -} diff --git a/lib/ShareStatistics.php b/lib/ShareStatistics.php deleted file mode 100644 index 4ffe3e1..0000000 --- a/lib/ShareStatistics.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php -declare(strict_types=1); -namespace OCA\SccuotNC; - -use OCP\IDBConnection; -use OCP\Share\IShare; - -class ShareStatistics { - protected IDBConnection $connection; - - public function __construct(IDBConnection $connection) { - $this->connection = $connection; - } - - /** - * @return array (string => string|int) - */ - public function getShareStatistics(): array { - $query = $this->connection->getQueryBuilder(); - $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') - ->addSelect(['permissions', 'share_type']) - ->from('share') - ->addGroupBy('permissions') - ->addGroupBy('share_type'); - $result = $query->executeQuery(); - - $data = [ - 'num_shares' => $this->countEntries('share'), - 'num_shares_user' => $this->countShares(IShare::TYPE_USER), - 'num_shares_groups' => $this->countShares(IShare::TYPE_GROUP), - 'num_shares_link' => $this->countShares(IShare::TYPE_LINK), - 'num_shares_mail' => $this->countShares(IShare::TYPE_EMAIL), - 'num_shares_room' => $this->countShares(IShare::TYPE_ROOM), - 'num_shares_link_no_password' => $this->countShares(IShare::TYPE_LINK, true), - 'num_fed_shares_sent' => $this->countShares(IShare::TYPE_REMOTE), - 'num_fed_shares_received' => $this->countEntries('share_external'), - ]; - while ($row = $result->fetch()) { - $data['permissions_' . $row['share_type'] . '_' . $row['permissions']] = $row['num_entries']; - } - $result->closeCursor(); - - return $data; - } - - /** - * @param string $tableName - * @return int - */ - protected function countEntries(string $tableName): int { - $query = $this->connection->getQueryBuilder(); - $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') - ->from($tableName); - $result = $query->executeQuery(); - $row = $result->fetch(); - $result->closeCursor(); - - return (int)$row['num_entries']; - } - - /** - * @param int $type - * @param bool $noPassword - * @return int - */ - protected function countShares(int $type, bool $noPassword = false): int { - $query = $this->connection->getQueryBuilder(); - $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') - ->from('share') - ->where($query->expr()->eq('share_type', $query->createNamedParameter($type))); - - if ($noPassword) { - $query->andWhere($query->expr()->isNull('password')); - } - - $result = $query->executeQuery(); - $row = $result->fetch(); - $result->closeCursor(); - - return (int)$row['num_entries']; - } -} diff --git a/lib/StorageStatistic.php b/lib/StorageStatistic.php deleted file mode 100644 index 95b67a5..0000000 --- a/lib/StorageStatistic.php +++ /dev/null @@ -1,117 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - - -namespace OCA\SccuotNC\Db\OC; - -use OCP\Files\IRootFolder; -use OCP\IAppConfig; -use OCP\IDBConnection; - -class StorageStatistics { - - public function __construct( - private IDBConnection $connection, - private IRootFolder $rootFolder, - private IAppConfig $appConfig, - ) { - } - - public function getStorageStatistics(): array { - return [ - 'num_users' => $this->countUserEntries(), - 'num_files' => $this->getCountOf('filecache'), - 'num_storages' => $this->getCountOf('storages'), - 'num_storages_local' => $this->countStorages('local'), - 'num_storages_home' => $this->countStorages('home'), - 'num_storages_other' => $this->countStorages('other'), - 'size_appdata_storage' => $this->appConfig->getValueFloat('serverinfo', 'size_appdata_storage'), - 'num_files_appdata' => $this->getCountOf('appdata_files'), - ]; - } - - /** - * count number of users - */ - protected function countUserEntries(): int { - $query = $this->connection->getQueryBuilder(); - $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') - ->from('preferences') - ->where($query->expr()->eq('configkey', $query->createNamedParameter('lastLogin'))); - $result = $query->executeQuery(); - $row = $result->fetch(); - $result->closeCursor(); - return (int)$row['num_entries']; - } - - protected function getCountOf(string $table): int { - return $this->appConfig->getValueInt('serverinfo', 'cached_count_' . $table); - } - - public function updateStorageCounts(): void { - $storageCount = 0; - $fileCount = 0; - - $fileQuery = $this->connection->getQueryBuilder(); - $fileQuery->select($fileQuery->func()->count()) - ->from('filecache') - ->where($fileQuery->expr()->eq('storage', $fileQuery->createParameter('storageId'))); - - $storageQuery = $this->connection->getQueryBuilder(); - $storageQuery->selectAlias('numeric_id', 'id') - ->from('storages'); - $storageResult = $storageQuery->executeQuery(); - while ($storageRow = $storageResult->fetch()) { - $storageCount++; - $fileQuery->setParameter('storageId', $storageRow['id']); - $fileResult = $fileQuery->executeQuery(); - $fileCount += (int)$fileResult->fetchOne(); - $fileResult->closeCursor(); - } - $storageResult->closeCursor(); - - $this->updateAppDataStorageStats(); - - $this->appConfig->setValueInt('serverinfo', 'cached_count_filecache', $fileCount); - $this->appConfig->setValueInt('serverinfo', 'cached_count_storages', $storageCount); - } - - protected function countStorages(string $type): int { - $query = $this->connection->getQueryBuilder(); - $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') - ->from('storages'); - if ($type === 'home') { - $query->where($query->expr()->like('id', $query->createNamedParameter('home::%'))); - } elseif ($type === 'local') { - $query->where($query->expr()->like('id', $query->createNamedParameter('local::%'))); - } elseif ($type === 'other') { - $query->where($query->expr()->notLike('id', $query->createNamedParameter('home::%'))); - $query->andWhere($query->expr()->notLike('id', $query->createNamedParameter('local::%'))); - } - $result = $query->executeQuery(); - $row = $result->fetch(); - $result->closeCursor(); - return (int)$row['num_entries']; - } - - public function updateAppDataStorageStats(): void { - $appDataPath = $this->rootFolder->getAppDataDirectoryName(); - $appDataFolder = $this->rootFolder->get($appDataPath); - $this->appConfig->setValueFloat('serverinfo', 'size_appdata_storage', $appDataFolder->getSize()); - - $query = $this->connection->getQueryBuilder(); - $query->select($query->func()->count()) - ->from('filecache') - ->where($query->expr()->like('path', $query->createNamedParameter($appDataPath . '%'))); - $fileResult = $query->executeQuery(); - $fileCount = (int)$fileResult->fetchOne(); - $fileResult->closeCursor(); - $this->appConfig->setValueInt('serverinfo', 'cached_count_appdata_files', $fileCount); - } -} -- GitLab