From b7903848dc13c4b757db5739dbe2b3845172710c Mon Sep 17 00:00:00 2001 From: Oleksandr Khryshchuk Date: Fri, 14 Nov 2025 18:47:32 +0100 Subject: [PATCH] Added accounts config version-based migration. - added forward migration possibility to Application::configVersionMigration(); - added version abstruction for accounts and each account settings; - added version 14 to account settings: - forcly removes buggy up/down network limits(#9037). Signed-off-by: Oleksandr Khryshchuk --- src/gui/accountmanager.cpp | 101 +++++++++++++++++++++++++++++++----- src/gui/accountmanager.h | 24 +++++++++ src/gui/application.cpp | 36 +++++++------ src/gui/networksettings.cpp | 28 +++++----- 4 files changed, 149 insertions(+), 40 deletions(-) diff --git a/src/gui/accountmanager.cpp b/src/gui/accountmanager.cpp index 4822d5f6212bd..e43d8ed21b8f6 100644 --- a/src/gui/accountmanager.cpp +++ b/src/gui/accountmanager.cpp @@ -72,10 +72,6 @@ constexpr auto legacyCfgFileNameC = "owncloud.cfg"; constexpr auto unbrandedRelativeConfigLocationC = "/Nextcloud/nextcloud.cfg"; constexpr auto unbrandedCfgFileNameC = "nextcloud.cfg"; -// The maximum versions that this client can read -constexpr auto maxAccountsVersion = 13; -constexpr auto maxAccountVersion = 13; - constexpr auto serverHasValidSubscriptionC = "serverHasValidSubscription"; constexpr auto generalC = "General"; @@ -84,6 +80,17 @@ constexpr auto generalC = "General"; namespace OCC { +namespace { + template + inline VersionType VersionFromSetting(QSettings *settings) { + return settings->value(QLatin1String(versionC), int(VersionType::Min)).value(); + } + template + inline void VersionToSetting(QSettings *settings, VersionType version) { + settings->setValue(QLatin1String(versionC), int(version)); + } +} + Q_LOGGING_CATEGORY(lcAccountManager, "nextcloud.gui.account.manager", QtInfoMsg) AccountManager *AccountManager::instance() @@ -149,7 +156,7 @@ AccountManager::AccountsRestoreResult AccountManager::restore(const bool alsoRes } ConfigFile().cleanupGlobalNetworkConfiguration(); - ClientProxy().cleanupGlobalNetworkConfiguration(); + ClientProxy().cleanupGlobalNetworkConfiguration(); return result; } @@ -157,27 +164,42 @@ AccountManager::AccountsRestoreResult AccountManager::restore(const bool alsoRes void AccountManager::backwardMigrationSettingsKeys(QStringList *deleteKeys, QStringList *ignoreKeys) { const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); - const auto accountsVersion = settings->value(QLatin1String(versionC)).toInt(); + const auto accountsVersion = VersionFromSetting(settings.get()); qCInfo(lcAccountManager) << "Checking for accounts versions."; qCInfo(lcAccountManager) << "Config accounts version:" << accountsVersion; - qCInfo(lcAccountManager) << "Max accounts Version is set to:" << maxAccountsVersion; - if (accountsVersion <= maxAccountsVersion) { + qCInfo(lcAccountManager) << "Max accounts Version is set to:" << AccountsVersion::Max; + if (accountsVersion <= AccountsVersion::Max) { const auto settingsChildGroups = settings->childGroups(); for (const auto &accountId : settingsChildGroups) { settings->beginGroup(accountId); - const auto accountVersion = settings->value(QLatin1String(versionC), 1).toInt(); + const auto accountVersion = VersionFromSetting(settings.get()); - if (accountVersion > maxAccountVersion) { + if (accountVersion > AccountVersion::Max) { ignoreKeys->append(settings->group()); qCInfo(lcAccountManager) << "Ignoring account" << accountId << "because of version" << accountVersion; } + settings->endGroup(); } } else { deleteKeys->append(settings->group()); } } + +void AccountManager::migrateToActualVersion() +{ + const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); + + migrateAccountsSettings(settings); + + for (const auto &accountId : settings->childGroups()) { + settings->beginGroup(accountId); + migrateAccountSettings(settings); + settings->endGroup(); + } +} + #if !DISABLE_ACCOUNT_MIGRATION bool AccountManager::restoreFromLegacySettings() { @@ -317,7 +339,7 @@ bool AccountManager::restoreFromLegacySettings() moveNetworkSettingsFromGlobalToAccount(acc); } configFile.cleanupGlobalNetworkConfiguration(); - ClientProxy().cleanupGlobalNetworkConfiguration(); + ClientProxy().cleanupGlobalNetworkConfiguration(); return true; } @@ -339,7 +361,9 @@ bool AccountManager::restoreFromLegacySettings() void AccountManager::save(bool saveCredentials) { const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC)); - settings->setValue(QLatin1String(versionC), maxAccountsVersion); + + VersionToSetting(settings.get(), AccountsVersion::Max); + for (const auto &acc : std::as_const(_accounts)) { settings->beginGroup(acc->account()->id()); saveAccountHelper(acc->account(), *settings, saveCredentials); @@ -376,7 +400,7 @@ void AccountManager::saveAccountState(AccountState *a) void AccountManager::saveAccountHelper(const AccountPtr &account, QSettings &settings, bool saveCredentials) { qCDebug(lcAccountManager) << "Saving settings to" << settings.fileName(); - settings.setValue(QLatin1String(versionC), maxAccountVersion); + VersionToSetting(&settings, AccountVersion::Max); if (account->isPublicShareLink()) { settings.setValue(QLatin1String(urlC), account->publicShareLinkUrl().toString()); } else { @@ -798,4 +822,55 @@ void AccountManager::setForceLegacyImport(const bool forceLegacyImport) _forceLegacyImport = forceLegacyImport; Q_EMIT forceLegacyImportChanged(); } + +void AccountManager::migrateAccountsSettings(const std::unique_ptr &settings) +{ + const auto accountsVersion = VersionFromSetting(settings.get()); + + switch (accountsVersion) { + // Nothing here for now + default: + VersionToSetting(settings.get(), AccountsVersion::Max); + break; + } +} + +void AccountManager::migrateAccountSettings(const std::unique_ptr &settings) +{ + const auto accountVersion = VersionFromSetting(settings.get()); + + switch (accountVersion) + { + // No previous statements + case AccountVersion::V13: { + // Related to issue #9037 + const auto networkLimitSettingFix = [&settings](const QString &key) { + using NetworkLimitSetting = Account::AccountNetworkTransferLimitSetting; + + const auto limitSetting = settings->value(key).value(); + + switch (limitSetting) { + case NetworkLimitSetting::LegacyGlobalLimit: + [[fallthrough]]; + case NetworkLimitSetting::AutoLimit: + settings->setValue(key, int(NetworkLimitSetting::NoLimit)); + break; + default: + break; + } + }; + + qCInfo(lcAccountManager) << "Migrating account" << settings->group() + << "settings from version" << accountVersion + << "to" << AccountVersion::V14; + + networkLimitSettingFix(networkDownloadLimitSettingC); + networkLimitSettingFix(networkUploadLimitSettingC); + } [[fallthrough]]; + // Tip: add new migration rules here + default: + VersionToSetting(settings.get(), AccountVersion::Max); + break; + } +} } diff --git a/src/gui/accountmanager.h b/src/gui/accountmanager.h index ea597594d08ad..c9f5c767edda8 100644 --- a/src/gui/accountmanager.h +++ b/src/gui/accountmanager.h @@ -31,6 +31,21 @@ class AccountManager : public QObject }; Q_ENUM (AccountsRestoreResult); + enum class AccountsVersion { + V13 = 13, + Min = V13, + Max = V13 + }; + Q_ENUM (AccountsVersion); + + enum class AccountVersion { + V13 = 13, + V14, + Min = V13, + Max = V14 + }; + Q_ENUM (AccountVersion); + static AccountManager *instance(); ~AccountManager() override = default; @@ -83,6 +98,12 @@ class AccountManager : public QObject */ static void backwardMigrationSettingsKeys(QStringList *deleteKeys, QStringList *ignoreKeys); + /** + * Checks the versions of account groups and each account individually + * then attempts a soft migration. + */ + static void migrateToActualVersion(); + public slots: /// Saves account data when adding user, when updating e.g. dav user, not including the credentials void saveAccount(const OCC::AccountPtr &newAccountData); @@ -110,6 +131,9 @@ public slots: void capabilitiesChanged(); private: + static void migrateAccountsSettings(const std::unique_ptr &settings); + static void migrateAccountSettings(const std::unique_ptr &settings); + // saving and loading Account to settings void saveAccountHelper(const AccountPtr &account, QSettings &settings, bool saveCredentials = true); AccountPtr loadAccountHelper(QSettings &settings); diff --git a/src/gui/application.cpp b/src/gui/application.cpp index b3637976d54a5..e41b6f3277619 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -141,14 +141,6 @@ bool Application::configVersionMigration() return true; } - // 'Launch on system startup' defaults to true > 3.11.x - const auto theme = Theme::instance(); - configFile.setLaunchOnSystemStartup(configFile.launchOnSystemStartup()); - Utility::setLaunchOnStartup(theme->appName(), theme->appNameGUI(), configFile.launchOnSystemStartup()); - - // default is now off to displaying dialog warning user of too many files deletion - configFile.setPromptDeleteFiles(false); - // back up all old config files QStringList backupFilesList; QDir configDir(configFile.configPath()); @@ -190,15 +182,27 @@ bool Application::configVersionMigration() } } - if (!deleteKeys.isEmpty()) { - auto settings = ConfigFile::settingsWithGroup("foo"); - settings->endGroup(); + if (downgrading) { + // 'Launch on system startup' defaults to true > 3.11.x + const auto theme = Theme::instance(); + configFile.setLaunchOnSystemStartup(configFile.launchOnSystemStartup()); + Utility::setLaunchOnStartup(theme->appName(), theme->appNameGUI(), configFile.launchOnSystemStartup()); + + // default is now off to displaying dialog warning user of too many files deletion + configFile.setPromptDeleteFiles(false); - // Wipe confusing keys from the future, ignore the others - for (const auto &badKey : std::as_const(deleteKeys)) { - settings->remove(badKey); - qCInfo(lcApplication) << "Migration: removed" << badKey << "key from settings."; + if (!deleteKeys.isEmpty()) { + auto settings = ConfigFile::settingsWithGroup("foo"); + settings->endGroup(); + + // Wipe confusing keys from the future, ignore the others + for (const auto &badKey : std::as_const(deleteKeys)) { + settings->remove(badKey); + qCInfo(lcApplication) << "Migration: removed" << badKey << "key from settings."; + } } + } else { // upgrading + AccountManager::migrateToActualVersion(); } configFile.setClientVersionString(MIRALL_VERSION_STRING); @@ -323,6 +327,8 @@ Application::Application(int &argc, char **argv) // only copy the settings and check what should be skipped if (!configVersionMigration()) { qCWarning(lcApplication) << "Config version migration was not possible."; + } else { + AccountManager::instance()->save(); } ConfigFile cfg; diff --git a/src/gui/networksettings.cpp b/src/gui/networksettings.cpp index eb73c7f4c3036..a9c521e2b24ef 100644 --- a/src/gui/networksettings.cpp +++ b/src/gui/networksettings.cpp @@ -198,36 +198,40 @@ void NetworkSettings::saveProxySettings() void NetworkSettings::saveBWLimitSettings() { + using NetworkTransferLimitSetting = Account::AccountNetworkTransferLimitSetting; + const auto downloadLimit = _ui->downloadSpinBox->value(); const auto uploadLimit = _ui->uploadSpinBox->value(); - auto useDownloadLimit = 0; - auto useUploadLimit = 0; + auto useDownloadLimit = NetworkTransferLimitSetting::NoLimit; + auto useUploadLimit = NetworkTransferLimitSetting::NoLimit; if (_ui->downloadLimitRadioButton->isChecked()) { - useDownloadLimit = 1; + useDownloadLimit = NetworkTransferLimitSetting::ManualLimit; } else if (_ui->noDownloadLimitRadioButton->isChecked()) { - useDownloadLimit = 0; + useDownloadLimit = NetworkTransferLimitSetting::NoLimit; } else if (_ui->autoDownloadLimitRadioButton->isChecked()) { - useDownloadLimit = -1; + useDownloadLimit = NetworkTransferLimitSetting::AutoLimit; } else if (_account) { - useDownloadLimit = -2; + // Legacy global. See Account::AccountNetworkTransferLimitSetting::LegacyGlobalLimit + useDownloadLimit = NetworkTransferLimitSetting::NoLimit; } if (_ui->uploadLimitRadioButton->isChecked()) { - useUploadLimit = 1; + useUploadLimit = NetworkTransferLimitSetting::ManualLimit; } else if (_ui->noUploadLimitRadioButton->isChecked()) { - useUploadLimit = 0; + useUploadLimit = NetworkTransferLimitSetting::NoLimit; } else if (_ui->autoUploadLimitRadioButton->isChecked()) { - useUploadLimit = -1; + useUploadLimit = NetworkTransferLimitSetting::AutoLimit; } else if (_account) { - useUploadLimit = -2; + // Legacy global. See Account::AccountNetworkTransferLimitSetting::LegacyGlobalLimit + useUploadLimit = NetworkTransferLimitSetting::NoLimit; } if (_account) { - _account->setDownloadLimitSetting(static_cast(useDownloadLimit)); + _account->setDownloadLimitSetting(useDownloadLimit); _account->setDownloadLimit(downloadLimit); - _account->setUploadLimitSetting(static_cast(useUploadLimit)); + _account->setUploadLimitSetting(useUploadLimit); _account->setUploadLimit(uploadLimit); AccountManager::instance()->saveAccount(_account); }