mirror of
https://github.com/nextcloud/desktop.git
synced 2024-10-26 06:15:48 +03:00
Config: Add version flags to accounts and folders
Also, if there is too-new configuration, backup the file, show a warning message asking the user whether it's ok to discard the configuration from the future. See #6504
This commit is contained in:
parent
aa6f5f59c4
commit
87ba4e6b9c
10 changed files with 160 additions and 2 deletions
|
@ -36,6 +36,10 @@ static const char caCertsKeyC[] = "CaCertificates";
|
|||
static const char accountsC[] = "Accounts";
|
||||
static const char versionC[] = "version";
|
||||
static const char serverVersionC[] = "serverVersion";
|
||||
|
||||
// The maximum versions that this client can read
|
||||
static const int maxAccountsVersion = 2;
|
||||
static const int maxAccountVersion = 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,6 +83,27 @@ bool AccountManager::restore()
|
|||
return true;
|
||||
}
|
||||
|
||||
QStringList AccountManager::backwardMigrationKeys()
|
||||
{
|
||||
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
||||
QStringList badKeys;
|
||||
|
||||
const int accountsVersion = settings->value(QLatin1String(versionC)).toInt();
|
||||
if (accountsVersion <= maxAccountsVersion) {
|
||||
foreach (const auto &accountId, settings->childGroups()) {
|
||||
settings->beginGroup(accountId);
|
||||
const int accountVersion = settings->value(QLatin1String(versionC), 1).toInt();
|
||||
if (accountVersion > maxAccountVersion) {
|
||||
badKeys.append(settings->group());
|
||||
}
|
||||
settings->endGroup();
|
||||
}
|
||||
} else {
|
||||
badKeys.append(settings->group());
|
||||
}
|
||||
return badKeys;
|
||||
}
|
||||
|
||||
bool AccountManager::restoreFromLegacySettings()
|
||||
{
|
||||
qCInfo(lcAccountManager) << "Migrate: restoreFromLegacySettings, checking settings group"
|
||||
|
@ -139,7 +164,7 @@ bool AccountManager::restoreFromLegacySettings()
|
|||
void AccountManager::save(bool saveCredentials)
|
||||
{
|
||||
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
||||
settings->setValue(QLatin1String(versionC), 2);
|
||||
settings->setValue(QLatin1String(versionC), maxAccountsVersion);
|
||||
for (const auto &acc : qAsConst(_accounts)) {
|
||||
settings->beginGroup(acc->account()->id());
|
||||
saveAccountHelper(acc->account().data(), *settings, saveCredentials);
|
||||
|
@ -177,6 +202,7 @@ void AccountManager::saveAccountState(AccountState *a)
|
|||
|
||||
void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool saveCredentials)
|
||||
{
|
||||
settings.setValue(QLatin1String(versionC), maxAccountVersion);
|
||||
settings.setValue(QLatin1String(urlC), acc->_url.toString());
|
||||
settings.setValue(QLatin1String(serverVersionC), acc->_serverVersion);
|
||||
if (acc->_credentials) {
|
||||
|
|
|
@ -76,6 +76,12 @@ public:
|
|||
*/
|
||||
static AccountPtr createAccount();
|
||||
|
||||
/**
|
||||
* Returns the list of settings keys that can't be read because
|
||||
* they are from the future.
|
||||
*/
|
||||
static QStringList backwardMigrationKeys();
|
||||
|
||||
private:
|
||||
// saving and loading Account to settings
|
||||
void saveAccountHelper(Account *account, QSettings &settings, bool saveCredentials = true);
|
||||
|
|
|
@ -102,6 +102,50 @@ namespace {
|
|||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
bool Application::configBackwardMigration()
|
||||
{
|
||||
auto accountKeys = AccountManager::backwardMigrationKeys();
|
||||
auto folderKeys = FolderMan::backwardMigrationKeys();
|
||||
|
||||
bool containsFutureData = !accountKeys.isEmpty() || !folderKeys.isEmpty();
|
||||
|
||||
// Deal with unreadable accounts
|
||||
if (!containsFutureData)
|
||||
return true;
|
||||
|
||||
const auto backupFile = ConfigFile().backup();
|
||||
|
||||
QMessageBox box(
|
||||
QMessageBox::Warning,
|
||||
APPLICATION_SHORTNAME,
|
||||
tr("Some settings were configured in newer versions of this client and "
|
||||
"use features that are not available in this version.<br>"
|
||||
"<br>"
|
||||
"<b>Continuing will mean losing these settings.</b><br>"
|
||||
"<br>"
|
||||
"The current configuration file was already backed up to <i>%1</i>.")
|
||||
.arg(backupFile));
|
||||
box.addButton(tr("Quit"), QMessageBox::AcceptRole);
|
||||
auto continueBtn = box.addButton(tr("Continue"), QMessageBox::DestructiveRole);
|
||||
|
||||
box.exec();
|
||||
if (box.clickedButton() != continueBtn) {
|
||||
QTimer::singleShot(0, qApp, SLOT(quit()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto settings = ConfigFile::settingsWithGroup("foo");
|
||||
settings->endGroup();
|
||||
|
||||
// Wipe the keys from the future
|
||||
for (const auto &badKey : accountKeys)
|
||||
settings->remove(badKey);
|
||||
for (const auto &badKey : folderKeys)
|
||||
settings->remove(badKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Application::Application(int &argc, char **argv)
|
||||
: SharedTools::QtSingleApplication(Theme::instance()->appName(), argc, argv)
|
||||
, _gui(nullptr)
|
||||
|
@ -187,8 +231,12 @@ Application::Application(int &argc, char **argv)
|
|||
setupLogging();
|
||||
setupTranslations();
|
||||
|
||||
// The timeout is initialized with an environment variable, if not, override with the value from the config
|
||||
if (!configBackwardMigration()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigFile cfg;
|
||||
// The timeout is initialized with an environment variable, if not, override with the value from the config
|
||||
if (!AbstractNetworkJob::httpTimeout)
|
||||
AbstractNetworkJob::httpTimeout = cfg.timeout();
|
||||
|
||||
|
|
|
@ -103,6 +103,12 @@ protected slots:
|
|||
private:
|
||||
void setHelp();
|
||||
|
||||
/**
|
||||
* Maybe a newer version of the client was used with this config file:
|
||||
* if so, backup, confirm with user and remove the config that can't be read.
|
||||
*/
|
||||
bool configBackwardMigration();
|
||||
|
||||
QPointer<ownCloudGui> _gui;
|
||||
|
||||
Theme *_theme;
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
static const char versionC[] = "version";
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFolder, "nextcloud.gui.folder", QtInfoMsg)
|
||||
|
@ -571,6 +573,8 @@ void Folder::saveToSettings() const
|
|||
}
|
||||
|
||||
settings->beginGroup(settingsGroup);
|
||||
// Note: Each of these groups might have a "version" tag, but that's
|
||||
// currently unused.
|
||||
FolderDefinition::save(*settings, _definition);
|
||||
|
||||
settings->sync();
|
||||
|
@ -1127,6 +1131,7 @@ void FolderDefinition::save(QSettings &settings, const FolderDefinition &folder)
|
|||
settings.setValue(QLatin1String("paused"), folder.paused);
|
||||
settings.setValue(QLatin1String("ignoreHiddenFiles"), folder.ignoreHiddenFiles);
|
||||
settings.setValue(QLatin1String("usePlaceholders"), folder.useVirtualFiles);
|
||||
settings.setValue(QLatin1String(versionC), maxSettingsVersion());
|
||||
|
||||
// Happens only on Windows when the explorer integration is enabled.
|
||||
if (!folder.navigationPaneClsid.isNull())
|
||||
|
|
|
@ -72,6 +72,9 @@ public:
|
|||
static bool load(QSettings &settings, const QString &alias,
|
||||
FolderDefinition *folder);
|
||||
|
||||
/// The highest version in the settings that load() can read
|
||||
static int maxSettingsVersion() { return 1; }
|
||||
|
||||
/// Ensure / as separator and trailing /.
|
||||
static QString prepareLocalPath(const QString &path);
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#include <QSet>
|
||||
#include <QNetworkProxy>
|
||||
|
||||
static const char versionC[] = "version";
|
||||
static const int maxFoldersVersion = 1;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFolderMan, "nextcloud.gui.folder.manager", QtInfoMsg)
|
||||
|
@ -303,6 +306,39 @@ int FolderMan::setupFoldersMigration()
|
|||
return _folderMap.size();
|
||||
}
|
||||
|
||||
QStringList FolderMan::backwardMigrationKeys()
|
||||
{
|
||||
QStringList badKeys;
|
||||
auto settings = ConfigFile::settingsWithGroup(QLatin1String("Accounts"));
|
||||
|
||||
auto processSubgroup = [&](const QString &name) {
|
||||
settings->beginGroup(name);
|
||||
const int foldersVersion = settings->value(QLatin1String(versionC), 1).toInt();
|
||||
if (foldersVersion <= maxFoldersVersion) {
|
||||
foreach (const auto &folderAlias, settings->childGroups()) {
|
||||
settings->beginGroup(folderAlias);
|
||||
const int folderVersion = settings->value(QLatin1String(versionC), 1).toInt();
|
||||
if (folderVersion > FolderDefinition::maxSettingsVersion()) {
|
||||
badKeys.append(settings->group());
|
||||
}
|
||||
settings->endGroup();
|
||||
}
|
||||
} else {
|
||||
badKeys.append(settings->group());
|
||||
}
|
||||
settings->endGroup();
|
||||
};
|
||||
|
||||
for (const auto &accountId : settings->childGroups()) {
|
||||
settings->beginGroup(accountId);
|
||||
processSubgroup("Folders");
|
||||
processSubgroup("Multifolders");
|
||||
processSubgroup("FoldersWithPlaceholders");
|
||||
settings->endGroup();
|
||||
}
|
||||
return badKeys;
|
||||
}
|
||||
|
||||
bool FolderMan::ensureJournalGone(const QString &journalDbFile)
|
||||
{
|
||||
// remove the old journal file
|
||||
|
|
|
@ -68,6 +68,12 @@ public:
|
|||
int setupFolders();
|
||||
int setupFoldersMigration();
|
||||
|
||||
/**
|
||||
* Returns a list of keys that can't be read because they are from
|
||||
* future versions.
|
||||
*/
|
||||
static QStringList backwardMigrationKeys();
|
||||
|
||||
OCC::Folder::Map map();
|
||||
|
||||
/** Adds a folder for an account, ensures the journal is gone and saves it in the settings.
|
||||
|
|
|
@ -411,6 +411,21 @@ QString ConfigFile::excludeFileFromSystem()
|
|||
return fi.absoluteFilePath();
|
||||
}
|
||||
|
||||
QString ConfigFile::backup() const
|
||||
{
|
||||
QString baseFile = configFile();
|
||||
QString backupFile = QString("%1.backup_%2").arg(baseFile, QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"));
|
||||
|
||||
// If this exact file already exists it's most likely that a backup was
|
||||
// already done. (two backup calls directly after each other, potentially
|
||||
// even with source alterations in between!)
|
||||
if (!QFile::exists(backupFile)) {
|
||||
QFile f(baseFile);
|
||||
f.copy(backupFile);
|
||||
}
|
||||
return backupFile;
|
||||
}
|
||||
|
||||
QString ConfigFile::configFile() const
|
||||
{
|
||||
return configPath() + Theme::instance()->configFileName();
|
||||
|
|
|
@ -48,6 +48,13 @@ public:
|
|||
QString excludeFile(Scope scope) const;
|
||||
static QString excludeFileFromSystem(); // doesn't access config dir
|
||||
|
||||
/**
|
||||
* Creates a backup of the file
|
||||
*
|
||||
* Returns the path of the new backup.
|
||||
*/
|
||||
QString backup() const;
|
||||
|
||||
bool exists();
|
||||
|
||||
QString defaultConnection() const;
|
||||
|
|
Loading…
Reference in a new issue