Skip to content

Commit 389e785

Browse files
committed
chore: refactor migration functions.
First look for legacy locations and then try to restore general, proxy and accounts settings. Signed-off-by: Camila Ayres <[email protected]>
1 parent 40aa676 commit 389e785

File tree

4 files changed

+132
-132
lines changed

4 files changed

+132
-132
lines changed

src/gui/accountmanager.cpp

Lines changed: 21 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,6 @@ constexpr auto webflowAuthPrefix = "webflow_";
7171

7272
constexpr auto networkProxyPasswordKeychainKeySuffixC = "_proxy_password";
7373

74-
constexpr auto legacyRelativeConfigLocationC = "/ownCloud/owncloud.cfg";
75-
constexpr auto legacyCfgFileNameC = "owncloud.cfg";
76-
77-
constexpr auto unbrandedRelativeConfigLocationC = "/Nextcloud/nextcloud.cfg";
78-
constexpr auto unbrandedCfgFileNameC = "nextcloud.cfg";
79-
8074
// The maximum versions that this client can read
8175
constexpr auto maxAccountsVersion = 13;
8276
constexpr auto maxAccountVersion = 13;
@@ -104,12 +98,15 @@ AccountManager *AccountManager::instance()
10498
return &instance;
10599
}
106100

107-
AccountManager::AccountsRestoreResult AccountManager::restore(const bool alsoRestoreLegacySettings)
101+
AccountManager::AccountsRestoreResult AccountManager::restore(const QString &legacyConfigFile, const bool alsoRestoreLegacySettings)
108102
{
109103
QStringList skipSettingsKeys;
110104
backwardMigrationSettingsKeys(&skipSettingsKeys, &skipSettingsKeys);
111105

112-
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
106+
const auto isLegacyMigration = !legacyConfigFile.isEmpty();
107+
auto settings = isLegacyMigration ? std::make_unique<QSettings>(legacyConfigFile, QSettings::IniFormat)
108+
: ConfigFile::settingsWithGroup(QLatin1String(accountsC));
109+
113110
if (settings->status() != QSettings::NoError || !settings->isWritable()) {
114111
qCWarning(lcAccountManager) << "Could not read settings from" << settings->fileName()
115112
<< settings->status();
@@ -122,13 +119,23 @@ AccountManager::AccountsRestoreResult AccountManager::restore(const bool alsoRes
122119
return AccountsRestoreSuccessWithSkipped;
123120
}
124121

125-
// If there are no accounts, check the old format.
126-
if (settings->childGroups().isEmpty() && !settings->contains(QLatin1String(versionC)) && alsoRestoreLegacySettings) {
127-
restoreFromLegacySettings();
128-
return AccountsRestoreSuccessFromLegacyVersion;
122+
qCWarning(lcAccountManager) << "Restoring settings" << settings->allKeys().join(", ") << "from" << (isLegacyMigration ? legacyConfigFile
123+
: ConfigFile().configFile());
124+
// migrate general and proxy settings
125+
if (isLegacyMigration && alsoRestoreLegacySettings) {
126+
ConfigFile configFile;
127+
configFile.setVfsEnabled(settings->value(QLatin1String(isVfsEnabledC)).toBool());
128+
configFile.setLaunchOnSystemStartup(settings->value(QLatin1String(launchOnSystemStartupC)).toBool());
129+
configFile.setOptionalServerNotifications(settings->value(QLatin1String(optionalServerNotificationsC)).toBool());
130+
configFile.setPromptDeleteFiles(settings->value(QLatin1String(promptDeleteC)).toBool());
131+
configFile.setShowCallNotifications(settings->value(QLatin1String(showCallNotificationsC)).toBool());
132+
configFile.setShowChatNotifications(settings->value(QLatin1String(showChatNotificationsC)).toBool());
133+
configFile.setShowInExplorerNavigationPane(settings->value(QLatin1String(showInExplorerNavigationPaneC)).toBool());
134+
ClientProxy().setupQtProxyFromSettings(*settings);
129135
}
130136

131-
auto result = AccountsRestoreSuccess;
137+
auto result = isLegacyMigration ? AccountsRestoreSuccess : AccountsRestoreSuccessFromLegacyVersion;
138+
settings->beginGroup(accountsC);
132139
const auto settingsChildGroups = settings->childGroups();
133140
for (const auto &accountId : settingsChildGroups) {
134141
settings->beginGroup(accountId);
@@ -150,6 +157,7 @@ AccountManager::AccountsRestoreResult AccountManager::restore(const bool alsoRes
150157
}
151158
settings->endGroup();
152159
}
160+
settings->endGroup();
153161

154162
return result;
155163
}
@@ -179,120 +187,6 @@ void AccountManager::backwardMigrationSettingsKeys(QStringList *deleteKeys, QStr
179187
}
180188
}
181189

182-
bool AccountManager::restoreFromLegacySettings()
183-
{
184-
qCInfo(lcAccountManager) << "Migrate: restoreFromLegacySettings, checking settings group"
185-
<< Theme::instance()->appName();
186-
187-
// try to open the correctly themed settings
188-
auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
189-
190-
auto wasLegacyImportDialogDisplayed = false;
191-
const auto displayLegacyImportDialog = Theme::instance()->displayLegacyImportDialog();
192-
193-
// if the settings file could not be opened, the childKeys list is empty
194-
// then try to load settings from a very old place
195-
if (settings->childKeys().isEmpty()) {
196-
// Legacy settings used QDesktopServices to get the location for the config folder in 2.4 and before
197-
const auto legacy2_4CfgSettingsLocation = QString(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/data"));
198-
const auto legacy2_4CfgFileParentFolder = legacy2_4CfgSettingsLocation.left(legacy2_4CfgSettingsLocation.lastIndexOf('/'));
199-
200-
// 2.5+ (rest of 2.x series)
201-
const auto legacy2_5CfgSettingsLocation = QStandardPaths::writableLocation(Utility::isWindows() ? QStandardPaths::AppDataLocation : QStandardPaths::AppConfigLocation);
202-
const auto legacy2_5CfgFileParentFolder = legacy2_5CfgSettingsLocation.left(legacy2_5CfgSettingsLocation.lastIndexOf('/'));
203-
204-
// Now try the locations we use today
205-
const auto fullLegacyCfgFile = QDir::fromNativeSeparators(settings->fileName());
206-
const auto legacyCfgFileParentFolder = fullLegacyCfgFile.left(fullLegacyCfgFile.lastIndexOf('/'));
207-
const auto legacyCfgFileGrandParentFolder = legacyCfgFileParentFolder.left(legacyCfgFileParentFolder.lastIndexOf('/'));
208-
209-
const auto legacyCfgFileNamePath = QString(QStringLiteral("/") + legacyCfgFileNameC);
210-
const auto legacyCfgFileRelativePath = QString(legacyRelativeConfigLocationC);
211-
212-
auto legacyLocations = QVector<QString>{legacy2_4CfgFileParentFolder + legacyCfgFileRelativePath,
213-
legacy2_5CfgFileParentFolder + legacyCfgFileRelativePath,
214-
legacyCfgFileParentFolder + legacyCfgFileNamePath,
215-
legacyCfgFileGrandParentFolder + legacyCfgFileRelativePath};
216-
217-
if (Theme::instance()->isBranded()) {
218-
const auto unbrandedCfgFileNamePath = QString(QStringLiteral("/") + unbrandedCfgFileNameC);
219-
const auto unbrandedCfgFileRelativePath = QString(unbrandedRelativeConfigLocationC);
220-
legacyLocations.append({legacyCfgFileParentFolder + unbrandedCfgFileNamePath, legacyCfgFileGrandParentFolder + unbrandedCfgFileRelativePath});
221-
}
222-
223-
for (const auto &configFile : legacyLocations) {
224-
auto oCSettings = std::make_unique<QSettings>(configFile, QSettings::IniFormat);
225-
if (oCSettings->status() != QSettings::Status::NoError) {
226-
qCInfo(lcAccountManager) << "Error reading legacy configuration file" << oCSettings->status();
227-
break;
228-
}
229-
230-
oCSettings->beginGroup(QLatin1String(accountsC));
231-
const auto accountsListSize = oCSettings->childGroups().size();
232-
oCSettings->endGroup();
233-
if (const QFileInfo configFileInfo(configFile);
234-
configFileInfo.exists() && configFileInfo.isReadable()) {
235-
qCInfo(lcAccountManager) << "Migrate: checking old config " << configFile;
236-
if (!forceLegacyImport() && accountsListSize > 0 && displayLegacyImportDialog) {
237-
wasLegacyImportDialogDisplayed = true;
238-
const auto importQuestion = accountsListSize > 1
239-
? tr("%1 accounts were detected from a legacy desktop client.\n"
240-
"Should the accounts be imported?").arg(QString::number(accountsListSize))
241-
: tr("1 account was detected from a legacy desktop client.\n"
242-
"Should the account be imported?");
243-
const auto importMessageBox = new QMessageBox(QMessageBox::Question, tr("Legacy import"), importQuestion);
244-
importMessageBox->addButton(tr("Import"), QMessageBox::AcceptRole);
245-
const auto skipButton = importMessageBox->addButton(tr("Skip"), QMessageBox::DestructiveRole);
246-
importMessageBox->exec();
247-
if (importMessageBox->clickedButton() == skipButton) {
248-
return false;
249-
}
250-
}
251-
252-
qCInfo(lcAccountManager) << "Copy settings" << oCSettings->allKeys().join(", ");
253-
settings = std::move(oCSettings);
254-
255-
ConfigFile::setDiscoveredLegacyConfigPath(configFileInfo.canonicalPath());
256-
break;
257-
} else {
258-
qCInfo(lcAccountManager) << "Migrate: could not read old config " << configFile;
259-
}
260-
}
261-
}
262-
263-
ConfigFile configFile;
264-
configFile.setVfsEnabled(settings->value(QLatin1String(isVfsEnabledC)).toBool());
265-
configFile.setLaunchOnSystemStartup(settings->value(QLatin1String(launchOnSystemStartupC)).toBool());
266-
configFile.setOptionalServerNotifications(settings->value(QLatin1String(optionalServerNotificationsC)).toBool());
267-
configFile.setPromptDeleteFiles(settings->value(QLatin1String(promptDeleteC)).toBool());
268-
configFile.setShowCallNotifications(settings->value(QLatin1String(showCallNotificationsC)).toBool());
269-
configFile.setShowChatNotifications(settings->value(QLatin1String(showChatNotificationsC)).toBool());
270-
configFile.setShowInExplorerNavigationPane(settings->value(QLatin1String(showInExplorerNavigationPaneC)).toBool());
271-
ClientProxy().setupQtProxyFromSettings(*settings);
272-
273-
// Try to load the single account.
274-
if (!settings->childKeys().isEmpty()) {
275-
settings->beginGroup(accountsC);
276-
const auto childGroups = settings->childGroups();
277-
for (const auto &accountId : childGroups) {
278-
settings->beginGroup(accountId);
279-
if (const auto acc = loadAccountHelper(*settings)) {
280-
addAccount(acc);
281-
}
282-
settings->endGroup();
283-
}
284-
return true;
285-
}
286-
287-
if (wasLegacyImportDialogDisplayed) {
288-
QMessageBox::information(nullptr,
289-
tr("Legacy import"),
290-
tr("Could not import accounts from legacy client configuration."));
291-
}
292-
293-
return false;
294-
}
295-
296190
void AccountManager::save(bool saveCredentials)
297191
{
298192
const auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));

src/gui/accountmanager.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include "account.h"
1818
#include "accountstate.h"
1919

20+
class QSettings;
21+
2022
namespace OCC {
2123

2224
/**
@@ -47,7 +49,7 @@ class AccountManager : public QObject
4749
* Returns false if there was an error reading the settings,
4850
* but note that settings not existing is not an error.
4951
*/
50-
AccountsRestoreResult restore(const bool alsoRestoreLegacySettings = true);
52+
AccountsRestoreResult restore(const QString &legacyConfigFile, const bool alsoRestoreLegacySettings = true);
5153

5254
/**
5355
* Add this account in the list of saved accounts.
@@ -121,8 +123,6 @@ public slots:
121123
void saveAccountHelper(Account *account, QSettings &settings, bool saveCredentials = true);
122124
AccountPtr loadAccountHelper(QSettings &settings);
123125

124-
bool restoreFromLegacySettings();
125-
126126
[[nodiscard]] bool isAccountIdAvailable(const QString &id) const;
127127
[[nodiscard]] QString generateFreeAccountId() const;
128128

src/gui/application.cpp

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@
7272

7373
class QSocket;
7474

75+
namespace {
76+
constexpr auto accountsC = "Accounts";
77+
constexpr auto legacyRelativeConfigLocationC = "/ownCloud/owncloud.cfg";
78+
constexpr auto legacyCfgFileNameC = "owncloud.cfg";
79+
constexpr auto unbrandedRelativeConfigLocationC = "/Nextcloud/nextcloud.cfg";
80+
constexpr auto unbrandedCfgFileNameC = "nextcloud.cfg";
81+
}
82+
7583
namespace OCC {
7684

7785
Q_LOGGING_CATEGORY(lcApplication, "nextcloud.gui.application", QtInfoMsg)
@@ -515,6 +523,95 @@ void Application::setupAccountsAndFolders()
515523
}
516524
}
517525

526+
QString Application::findLegacyConfigFile() const
527+
{
528+
qCInfo(lcApplication) << "Migrate: restoreFromLegacySettings, checking settings group"
529+
<< Theme::instance()->appName();
530+
531+
// try to open the correctly themed settings
532+
auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
533+
534+
auto wasLegacyImportDialogDisplayed = false;
535+
const auto displayLegacyImportDialog = Theme::instance()->displayLegacyImportDialog();
536+
537+
QString validLegacyConfigFile;
538+
// if the settings file could not be opened, the childKeys list is empty
539+
// then try to load settings from a very old place
540+
if (settings->childKeys().isEmpty()) {
541+
// Legacy settings used QDesktopServices to get the location for the config folder in 2.4 and before
542+
const auto legacy2_4CfgSettingsLocation = QString(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/data"));
543+
const auto legacy2_4CfgFileParentFolder = legacy2_4CfgSettingsLocation.left(legacy2_4CfgSettingsLocation.lastIndexOf('/'));
544+
545+
// 2.5+ (rest of 2.x series)
546+
const auto legacy2_5CfgSettingsLocation = QStandardPaths::writableLocation(Utility::isWindows() ? QStandardPaths::AppDataLocation : QStandardPaths::AppConfigLocation);
547+
const auto legacy2_5CfgFileParentFolder = legacy2_5CfgSettingsLocation.left(legacy2_5CfgSettingsLocation.lastIndexOf('/'));
548+
549+
// Now try the locations we use today
550+
const auto fullLegacyCfgFile = QDir::fromNativeSeparators(settings->fileName());
551+
const auto legacyCfgFileParentFolder = fullLegacyCfgFile.left(fullLegacyCfgFile.lastIndexOf('/'));
552+
const auto legacyCfgFileGrandParentFolder = legacyCfgFileParentFolder.left(legacyCfgFileParentFolder.lastIndexOf('/'));
553+
554+
const auto legacyCfgFileNamePath = QString(QStringLiteral("/") + legacyCfgFileNameC);
555+
const auto legacyCfgFileRelativePath = QString(legacyRelativeConfigLocationC);
556+
557+
auto legacyLocations = QVector<QString>{legacy2_4CfgFileParentFolder + legacyCfgFileRelativePath,
558+
legacy2_5CfgFileParentFolder + legacyCfgFileRelativePath,
559+
legacyCfgFileParentFolder + legacyCfgFileNamePath,
560+
legacyCfgFileGrandParentFolder + legacyCfgFileRelativePath};
561+
562+
if (Theme::instance()->isBranded()) {
563+
const auto unbrandedCfgFileNamePath = QString(QStringLiteral("/") + unbrandedCfgFileNameC);
564+
const auto unbrandedCfgFileRelativePath = QString(unbrandedRelativeConfigLocationC);
565+
legacyLocations.append({legacyCfgFileParentFolder + unbrandedCfgFileNamePath, legacyCfgFileGrandParentFolder + unbrandedCfgFileRelativePath});
566+
}
567+
568+
for (const auto &configFile : legacyLocations) {
569+
auto oCSettings = std::make_unique<QSettings>(configFile, QSettings::IniFormat);
570+
if (oCSettings->status() != QSettings::Status::NoError) {
571+
qCInfo(lcApplication) << "Error reading legacy configuration file" << oCSettings->status();
572+
break;
573+
}
574+
575+
oCSettings->beginGroup(QLatin1String(accountsC));
576+
const auto accountsListSize = oCSettings->childGroups().size();
577+
oCSettings->endGroup();
578+
if (const QFileInfo configFileInfo(configFile);
579+
configFileInfo.exists() && configFileInfo.isReadable()) {
580+
qCInfo(lcApplication) << "Migrate: checking old config " << configFile;
581+
if (!AccountManager::instance()->forceLegacyImport() && accountsListSize > 0 && displayLegacyImportDialog) {
582+
wasLegacyImportDialogDisplayed = true;
583+
const auto importQuestion = accountsListSize > 1
584+
? tr("%1 accounts were detected from a legacy desktop client.\n"
585+
"Should the accounts be imported?").arg(QString::number(accountsListSize))
586+
: tr("1 account was detected from a legacy desktop client.\n"
587+
"Should the account be imported?");
588+
const auto importMessageBox = new QMessageBox(QMessageBox::Question, tr("Legacy import"), importQuestion);
589+
importMessageBox->addButton(tr("Import"), QMessageBox::AcceptRole);
590+
const auto skipButton = importMessageBox->addButton(tr("Skip"), QMessageBox::DestructiveRole);
591+
importMessageBox->exec();
592+
if (importMessageBox->clickedButton() == skipButton) {
593+
return validLegacyConfigFile;
594+
}
595+
}
596+
597+
validLegacyConfigFile = configFile;
598+
ConfigFile::setDiscoveredLegacyConfigPath(configFileInfo.canonicalPath());
599+
break;
600+
} else {
601+
qCInfo(lcApplication) << "Migrate: could not read old config " << configFile;
602+
}
603+
}
604+
}
605+
606+
if (wasLegacyImportDialogDisplayed) {
607+
QMessageBox::information(nullptr,
608+
tr("Legacy import"),
609+
tr("Could not import accounts from legacy client configuration."));
610+
}
611+
612+
return validLegacyConfigFile;
613+
}
614+
518615
bool Application::setupConfigFolderFromLegacyLocation(const QString &legacyLocation) const
519616
{
520617
// Migrate from version <= 2.4
@@ -564,20 +661,22 @@ bool Application::setupConfigFolderFromLegacyLocation(const QString &legacyLocat
564661
return QFile::link(confDir, legacyDir);
565662
#endif
566663
}
664+
665+
return false;
567666
}
568667

569668
AccountManager::AccountsRestoreResult Application::restoreLegacyAccount()
570669
{
571670
ConfigFile cfg;
572671
const auto tryMigrate = cfg.overrideServerUrl().isEmpty();
573672
auto accountsRestoreResult = AccountManager::AccountsRestoreFailure;
574-
if (accountsRestoreResult = AccountManager::instance()->restore(tryMigrate);
673+
if (accountsRestoreResult = AccountManager::instance()->restore(findLegacyConfigFile(), tryMigrate);
575674
accountsRestoreResult == AccountManager::AccountsRestoreFailure) {
576675
// If there is an error reading the account settings, try again
577676
// after a couple of seconds, if that fails, give up.
578677
// (non-existence is not an error)
579678
Utility::sleep(5);
580-
if (accountsRestoreResult = AccountManager::instance()->restore(tryMigrate);
679+
if (accountsRestoreResult = AccountManager::instance()->restore(findLegacyConfigFile(), tryMigrate);
581680
accountsRestoreResult == AccountManager::AccountsRestoreFailure) {
582681
qCCritical(lcApplication) << "Could not read the account settings, quitting";
583682
QMessageBox::critical(

src/gui/application.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ protected slots:
115115
AccountManager::AccountsRestoreResult restoreLegacyAccount();
116116
bool setupConfigFolderFromLegacyLocation(const QString &legacyLocation) const;
117117
void setupAccountsAndFolders();
118+
/**
119+
* Looks for config files with different names from older client versions
120+
* in different locations
121+
*
122+
* Returns the found config file path found.
123+
*/
124+
[[nodiscard]] QString findLegacyConfigFile() const;
118125

119126
/**
120127
* Maybe a newer version of the client was used with this config file:

0 commit comments

Comments
 (0)