mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-23 21:46:03 +03:00
Fix review comments from Claudio. Refactoring.
Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
parent
94df6769dc
commit
e53d08fedb
5 changed files with 418 additions and 230 deletions
|
@ -65,6 +65,8 @@ set(client_SRCS
|
||||||
accountmanager.cpp
|
accountmanager.cpp
|
||||||
accountsettings.h
|
accountsettings.h
|
||||||
accountsettings.cpp
|
accountsettings.cpp
|
||||||
|
accountsetupcommandlinemanager.h
|
||||||
|
accountsetupcommandlinemanager.cpp
|
||||||
application.h
|
application.h
|
||||||
application.cpp
|
application.cpp
|
||||||
invalidfilenamedialog.h
|
invalidfilenamedialog.h
|
||||||
|
|
311
src/gui/accountsetupcommandlinemanager.cpp
Normal file
311
src/gui/accountsetupcommandlinemanager.cpp
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "accountsetupcommandlinemanager.h"
|
||||||
|
|
||||||
|
#include "accountmanager.h"
|
||||||
|
#include "creds/webflowcredentials.h"
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "folder.h"
|
||||||
|
#include "folderman.h"
|
||||||
|
#include "networkjobs.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
namespace OCC
|
||||||
|
{
|
||||||
|
Q_LOGGING_CATEGORY(lcAccountSetupCommandLineManager, "nextcloud.gui.accountsetupcommandlinemanager", QtInfoMsg)
|
||||||
|
|
||||||
|
AccountSetupFromCommandLineJob::AccountSetupFromCommandLineJob(QString appPassword,
|
||||||
|
QString userId,
|
||||||
|
QUrl serverUrl,
|
||||||
|
QString localDirPath,
|
||||||
|
bool nonVfsMode,
|
||||||
|
QString remoteDirPath,
|
||||||
|
QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, _appPassword(appPassword)
|
||||||
|
, _userId(userId)
|
||||||
|
, _serverUrl(serverUrl)
|
||||||
|
, _localDirPath(localDirPath)
|
||||||
|
, _nonVfsMode(nonVfsMode)
|
||||||
|
, _remoteDirPath(remoteDirPath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSetupFromCommandLineJob::handleAccountSetupFromCommandLine()
|
||||||
|
{
|
||||||
|
if (AccountManager::instance()->accountFromUserId(QStringLiteral("%1@%2").arg(_userId).arg(_serverUrl.host()))) {
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Account %1 already exists!").arg(QDir::toNativeSeparators(_userId)), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_localDirPath.isEmpty()) {
|
||||||
|
QDir dir(_localDirPath);
|
||||||
|
if (dir.exists() && !dir.isEmpty()) {
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(
|
||||||
|
QStringLiteral("Local folder %1 already exists and is non-empty!").arg(QDir::toNativeSeparators(_localDirPath)),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << "Creating folder" << _localDirPath;
|
||||||
|
if (!dir.exists() && !dir.mkpath(".")) {
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(
|
||||||
|
QStringLiteral("Folder creation failed. Could not create local folder %1").arg(QDir::toNativeSeparators(_localDirPath)),
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystem::setFolderMinimumPermissions(_localDirPath);
|
||||||
|
Utility::setupFavLink(_localDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto credentials = new WebFlowCredentials(_userId, _appPassword);
|
||||||
|
_account = AccountManager::createAccount();
|
||||||
|
_account->setCredentials(credentials);
|
||||||
|
_account->setUrl(_serverUrl);
|
||||||
|
|
||||||
|
fetchUserName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSetupFromCommandLineJob::checkLastModifiedWithPropfind()
|
||||||
|
{
|
||||||
|
const auto job = new PropfindJob(_account, "/", this);
|
||||||
|
job->setIgnoreCredentialFailure(true);
|
||||||
|
// There is custom redirect handling in the error handler,
|
||||||
|
// so don't automatically follow redirects.
|
||||||
|
job->setFollowRedirects(false);
|
||||||
|
job->setProperties(QList<QByteArray>() << QByteArrayLiteral("getlastmodified"));
|
||||||
|
connect(job, &PropfindJob::result, this, &AccountSetupFromCommandLineJob::accountSetupFromCommandLinePropfindHandleSuccess);
|
||||||
|
connect(job, &PropfindJob::finishedWithError, this, &AccountSetupFromCommandLineJob::accountSetupFromCommandLinePropfindHandleFailure);
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSetupFromCommandLineJob::accountSetupFromCommandLinePropfindHandleSuccess()
|
||||||
|
{
|
||||||
|
const auto accountManager = AccountManager::instance();
|
||||||
|
const auto accountState = accountManager->addAccount(_account);
|
||||||
|
accountManager->save();
|
||||||
|
|
||||||
|
if (!_localDirPath.isEmpty()) {
|
||||||
|
FolderDefinition definition;
|
||||||
|
definition.localPath = _localDirPath;
|
||||||
|
definition.targetPath = FolderDefinition::prepareTargetPath(!_remoteDirPath.isEmpty() ? _remoteDirPath : QStringLiteral("/"));
|
||||||
|
definition.virtualFilesMode = _nonVfsMode ? Vfs::Off : bestAvailableVfsMode();
|
||||||
|
|
||||||
|
const auto folderMan = FolderMan::instance();
|
||||||
|
|
||||||
|
definition.ignoreHiddenFiles = folderMan->ignoreHiddenFiles();
|
||||||
|
definition.alias = folderMan->map().size() > 0 ? QString::number(folderMan->map().size()) : QString::number(0);
|
||||||
|
|
||||||
|
if (folderMan->navigationPaneHelper().showInExplorerNavigationPane()) {
|
||||||
|
definition.navigationPaneClsid = QUuid::createUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
folderMan->setSyncEnabled(false);
|
||||||
|
|
||||||
|
if (const auto folder = folderMan->addFolder(accountState, definition)) {
|
||||||
|
if (definition.virtualFilesMode != Vfs::Off) {
|
||||||
|
folder->setRootPinState(PinState::OnlineOnly);
|
||||||
|
}
|
||||||
|
folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, QStringList() << QLatin1String("/"));
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << QStringLiteral("Folder %1 setup from command line success.").arg(definition.localPath);
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Account %1 setup from command line success.").arg(_account->displayName()), false);
|
||||||
|
} else {
|
||||||
|
accountManager->deleteAccount(accountState);
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(
|
||||||
|
QStringLiteral("Account %1 setup from command line failed, due to folder creation failure.").arg(_account->displayName()),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << QStringLiteral("Set up a new account without a folder.");
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Account %1 setup from command line success.").arg(_account->displayName()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSetupFromCommandLineJob::accountSetupFromCommandLinePropfindHandleFailure()
|
||||||
|
{
|
||||||
|
const auto job = qobject_cast<PropfindJob *>(sender());
|
||||||
|
if (!job) {
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Cannot check for authed redirects. This slot should be invoked from PropfindJob!"), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto reply = job->reply();
|
||||||
|
|
||||||
|
QString errorMsg;
|
||||||
|
|
||||||
|
// If there were redirects on the *authed* requests, also store
|
||||||
|
// the updated server URL, similar to redirects on status.php.
|
||||||
|
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||||
|
if (!redirectUrl.isEmpty()) {
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << "Authed request was redirected to" << redirectUrl.toString();
|
||||||
|
|
||||||
|
// strip the expected path
|
||||||
|
auto path = redirectUrl.path();
|
||||||
|
static QString expectedPath = "/" + _account->davPath();
|
||||||
|
if (path.endsWith(expectedPath)) {
|
||||||
|
path.chop(expectedPath.size());
|
||||||
|
redirectUrl.setPath(path);
|
||||||
|
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << "Setting account url to" << redirectUrl.toString();
|
||||||
|
_account->setUrl(redirectUrl);
|
||||||
|
checkLastModifiedWithPropfind();
|
||||||
|
}
|
||||||
|
errorMsg = tr("The authenticated request to the server was redirected to "
|
||||||
|
"\"%1\". The URL is bad, the server is misconfigured.")
|
||||||
|
.arg(Utility::escape(redirectUrl.toString()));
|
||||||
|
|
||||||
|
// A 404 is actually a success: we were authorized to know that the folder does
|
||||||
|
// not exist. It will be created later...
|
||||||
|
} else if (reply->error() == QNetworkReply::ContentNotFoundError) {
|
||||||
|
accountSetupFromCommandLinePropfindHandleSuccess();
|
||||||
|
} else if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
if (!_account->credentials()->stillValid(reply)) {
|
||||||
|
errorMsg = tr("Access forbidden by server. To verify that you have proper access, "
|
||||||
|
"<a href=\"%1\">click here</a> to access the service with your browser.")
|
||||||
|
.arg(Utility::escape(_account->url().toString()));
|
||||||
|
} else {
|
||||||
|
errorMsg = job->errorStringParsingBody();
|
||||||
|
}
|
||||||
|
// Something else went wrong, maybe the response was 200 but with invalid data.
|
||||||
|
} else {
|
||||||
|
errorMsg = tr("There was an invalid response to an authenticated WebDAV request");
|
||||||
|
}
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit(
|
||||||
|
QStringLiteral("Account %1 setup from command line failed with error: %2.").arg(_account->displayName()).arg(errorMsg),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSetupFromCommandLineJob::printAccountSetupFromCommandLineStatusAndExit(const QString &status, bool isFailure)
|
||||||
|
{
|
||||||
|
if (isFailure) {
|
||||||
|
qCWarning(lcAccountSetupCommandLineManager) << status;
|
||||||
|
} else {
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << status;
|
||||||
|
}
|
||||||
|
QTimer::singleShot(0, this, [this, isFailure]() {
|
||||||
|
this->deleteLater();
|
||||||
|
if (!isFailure) {
|
||||||
|
qApp->quit();
|
||||||
|
} else {
|
||||||
|
qApp->exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSetupFromCommandLineJob::fetchUserName()
|
||||||
|
{
|
||||||
|
const auto fetchUserNameJob = new JsonApiJob(_account, QStringLiteral("/ocs/v1.php/cloud/user"));
|
||||||
|
connect(fetchUserNameJob, &JsonApiJob::jsonReceived, this, [this](const QJsonDocument &json, int statusCode) {
|
||||||
|
sender()->deleteLater();
|
||||||
|
|
||||||
|
if (statusCode != 100) {
|
||||||
|
printAccountSetupFromCommandLineStatusAndExit("Could not fetch username.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto objData = json.object().value("ocs").toObject().value("data").toObject();
|
||||||
|
const auto userId = objData.value("id").toString("");
|
||||||
|
const auto displayName = objData.value("display-name").toString("");
|
||||||
|
_account->setDavUser(userId);
|
||||||
|
_account->setDavDisplayName(displayName);
|
||||||
|
|
||||||
|
checkLastModifiedWithPropfind();
|
||||||
|
});
|
||||||
|
fetchUserNameJob->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AccountSetupCommandLineManager::parseCommandlineOption(const QString &option, QStringListIterator &optionsIterator, QString &errorMessage)
|
||||||
|
{
|
||||||
|
if (option == QStringLiteral("--apppassword")) {
|
||||||
|
if (optionsIterator.hasNext() && !optionsIterator.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_appPassword = optionsIterator.next();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
errorMessage = QStringLiteral("apppassword not specified");
|
||||||
|
}
|
||||||
|
} else if (option == QStringLiteral("--localdirpath")) {
|
||||||
|
if (optionsIterator.hasNext() && !optionsIterator.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_localDirPath = optionsIterator.next();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
errorMessage = QStringLiteral("basedir not specified");
|
||||||
|
}
|
||||||
|
} else if (option == QStringLiteral("--remotedirpath")) {
|
||||||
|
if (optionsIterator.hasNext() && !optionsIterator.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_remoteDirPath = optionsIterator.next();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
errorMessage = QStringLiteral("remotedir not specified");
|
||||||
|
}
|
||||||
|
} else if (option == QStringLiteral("--serverurl")) {
|
||||||
|
if (optionsIterator.hasNext() && !optionsIterator.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_serverUrl = optionsIterator.next();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
errorMessage = QStringLiteral("serverurl not specified");
|
||||||
|
}
|
||||||
|
} else if (option == QStringLiteral("--userid")) {
|
||||||
|
if (optionsIterator.hasNext() && !optionsIterator.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_userId = optionsIterator.next();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
errorMessage = QStringLiteral("userid not specified");
|
||||||
|
}
|
||||||
|
} else if (option == QLatin1String("--nonvfsmode")) {
|
||||||
|
if (optionsIterator.hasNext() && !optionsIterator.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_nonVfsMode = optionsIterator.next().toInt() != 0;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
errorMessage = QStringLiteral("nonVfsMode not specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AccountSetupCommandLineManager::isCommandLineParsed()
|
||||||
|
{
|
||||||
|
return !_appPassword.isEmpty() && !_userId.isEmpty() && _serverUrl.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountSetupCommandLineManager::setupAccountFromCommandLine(QObject *parent)
|
||||||
|
{
|
||||||
|
if (isCommandLineParsed()) {
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << QStringLiteral("Command line has been parsed and account setup parameters have been found. Attempting setup a new account %1...").arg(_userId);
|
||||||
|
const auto accountSetupJob = new AccountSetupFromCommandLineJob(_appPassword, _userId, _serverUrl, _localDirPath, _nonVfsMode, _remoteDirPath, parent);
|
||||||
|
accountSetupJob->handleAccountSetupFromCommandLine();
|
||||||
|
} else {
|
||||||
|
qCInfo(lcAccountSetupCommandLineManager) << QStringLiteral("No account setup parameters have been found, or they are invalid. Proceed with normal startup...");
|
||||||
|
}
|
||||||
|
_appPassword.clear();
|
||||||
|
_userId.clear();
|
||||||
|
_serverUrl.clear();
|
||||||
|
_remoteDirPath.clear();
|
||||||
|
_localDirPath.clear();
|
||||||
|
_nonVfsMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AccountSetupCommandLineManager::_appPassword;
|
||||||
|
QString AccountSetupCommandLineManager::_userId;
|
||||||
|
QUrl AccountSetupCommandLineManager::_serverUrl;
|
||||||
|
QString AccountSetupCommandLineManager::_remoteDirPath;
|
||||||
|
QString AccountSetupCommandLineManager::_localDirPath;
|
||||||
|
bool AccountSetupCommandLineManager::_nonVfsMode = false;
|
||||||
|
}
|
82
src/gui/accountsetupcommandlinemanager.h
Normal file
82
src/gui/accountsetupcommandlinemanager.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "account.h"
|
||||||
|
#include "accountstate.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
|
||||||
|
class AccountSetupFromCommandLineJob : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AccountSetupFromCommandLineJob(QString appPassword,
|
||||||
|
QString userId,
|
||||||
|
QUrl serverUrl,
|
||||||
|
QString localDirPath = {},
|
||||||
|
bool nonVfsMode = false,
|
||||||
|
QString remoteDirPath = QStringLiteral("/"),
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void handleAccountSetupFromCommandLine();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void checkLastModifiedWithPropfind();
|
||||||
|
|
||||||
|
void accountSetupFromCommandLinePropfindHandleSuccess();
|
||||||
|
|
||||||
|
void accountSetupFromCommandLinePropfindHandleFailure();
|
||||||
|
|
||||||
|
void printAccountSetupFromCommandLineStatusAndExit(const QString &status, bool isFailure);
|
||||||
|
|
||||||
|
void fetchUserName();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _appPassword;
|
||||||
|
QString _userId;
|
||||||
|
QUrl _serverUrl;
|
||||||
|
QString _localDirPath;
|
||||||
|
bool _nonVfsMode = false;
|
||||||
|
QString _remoteDirPath;
|
||||||
|
|
||||||
|
AccountPtr _account;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AccountSetupCommandLineManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]] static bool parseCommandlineOption(const QString &option, QStringListIterator &optionsIterator, QString &errorMessage);
|
||||||
|
|
||||||
|
[[nodiscard]] static bool isCommandLineParsed();
|
||||||
|
|
||||||
|
static void setupAccountFromCommandLine(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit AccountSetupCommandLineManager() = delete;
|
||||||
|
|
||||||
|
static QString _appPassword;
|
||||||
|
static QString _userId;
|
||||||
|
static QUrl _serverUrl;
|
||||||
|
static QString _remoteDirPath;
|
||||||
|
static QString _localDirPath;
|
||||||
|
static bool _nonVfsMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -21,10 +21,10 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
|
#include "accountsetupcommandlinemanager.h"
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include "editlocallymanager.h"
|
#include "editlocallymanager.h"
|
||||||
#include "connectionvalidator.h"
|
#include "connectionvalidator.h"
|
||||||
#include "filesystem.h"
|
|
||||||
#include "folder.h"
|
#include "folder.h"
|
||||||
#include "folderman.h"
|
#include "folderman.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
@ -35,7 +35,6 @@
|
||||||
#include "clientproxy.h"
|
#include "clientproxy.h"
|
||||||
#include "accountmanager.h"
|
#include "accountmanager.h"
|
||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
#include "creds/webflowcredentials.h"
|
|
||||||
#include "pushnotifications.h"
|
#include "pushnotifications.h"
|
||||||
#include "shellextensionsserver.h"
|
#include "shellextensionsserver.h"
|
||||||
|
|
||||||
|
@ -87,7 +86,13 @@ namespace {
|
||||||
" --logflush : flush the log file after every write.\n"
|
" --logflush : flush the log file after every write.\n"
|
||||||
" --logdebug : also output debug-level messages in the log.\n"
|
" --logdebug : also output debug-level messages in the log.\n"
|
||||||
" --confdir <dirname> : Use the given configuration folder.\n"
|
" --confdir <dirname> : Use the given configuration folder.\n"
|
||||||
" --background : launch the application in the background.\n";
|
" --background : launch the application in the background.\n"
|
||||||
|
" --userid : userId (username as on the server) to pass when creating an account via command-line.\n"
|
||||||
|
" --apppassword : appPassword to pass when creating an account via command-line.\n"
|
||||||
|
" --localdirpath : (optional) path where to create a local sync folder when creating an account via command-line.\n"
|
||||||
|
" --nonvfsmode : whether to set up a non-VFS folder (1 for 'yes' or 0 for 'no') when creating an account via command-line.\n"
|
||||||
|
" --remotedirpath : (optional) path to a remote subfolder when creating an account via command-line.\n"
|
||||||
|
" --serverurl : a server URL to use when creating an account via command-line.\n";
|
||||||
|
|
||||||
QString applicationTrPath()
|
QString applicationTrPath()
|
||||||
{
|
{
|
||||||
|
@ -414,8 +419,8 @@ Application::Application(int &argc, char **argv)
|
||||||
|
|
||||||
handleEditLocallyFromOptions();
|
handleEditLocallyFromOptions();
|
||||||
|
|
||||||
if (!_appPassword.isEmpty() && !_userId.isEmpty() && !_baseDir.isEmpty() && _serverUrl.isValid()) {
|
if (AccountSetupCommandLineManager::isCommandLineParsed()) {
|
||||||
handleAccountSetupFromCommandLine();
|
AccountSetupCommandLineManager::setupAccountFromCommandLine(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,6 +590,10 @@ void Application::slotParseMessage(const QString &msg, QObject *)
|
||||||
|
|
||||||
handleEditLocallyFromOptions();
|
handleEditLocallyFromOptions();
|
||||||
|
|
||||||
|
if (AccountSetupCommandLineManager::isCommandLineParsed()) {
|
||||||
|
AccountSetupCommandLineManager::setupAccountFromCommandLine(this);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (msg.startsWith(QLatin1String("MSG_SHOWMAINDIALOG"))) {
|
} else if (msg.startsWith(QLatin1String("MSG_SHOWMAINDIALOG"))) {
|
||||||
qCInfo(lcApplication) << "Running for" << _startedAt.elapsed() / 1000.0 << "sec";
|
qCInfo(lcApplication) << "Running for" << _startedAt.elapsed() / 1000.0 << "sec";
|
||||||
if (_startedAt.elapsed() < 10 * 1000) {
|
if (_startedAt.elapsed() < 10 * 1000) {
|
||||||
|
@ -669,41 +678,18 @@ void Application::parseOptions(const QStringList &options)
|
||||||
qCInfo(lcApplication) << errorParsingLocalFileEditingUrl;
|
qCInfo(lcApplication) << errorParsingLocalFileEditingUrl;
|
||||||
showHint(errorParsingLocalFileEditingUrl.toStdString());
|
showHint(errorParsingLocalFileEditingUrl.toStdString());
|
||||||
}
|
}
|
||||||
} else if (option == QLatin1String("--apppassword")) {
|
|
||||||
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
|
||||||
_appPassword = it.next();
|
|
||||||
} else {
|
|
||||||
showHint("apppassword not specified");
|
|
||||||
}
|
|
||||||
} else if (option == QLatin1String("--userid")) {
|
|
||||||
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
|
||||||
_userId = it.next();
|
|
||||||
} else {
|
|
||||||
showHint("userid not specified");
|
|
||||||
}
|
|
||||||
} else if (option == QLatin1String("--basedir")) {
|
|
||||||
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
|
||||||
_baseDir = it.next();
|
|
||||||
} else {
|
|
||||||
showHint("basedir not specified");
|
|
||||||
}
|
|
||||||
} else if (option == QLatin1String("--remotedir")) {
|
|
||||||
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
|
||||||
_remoteDir = it.next();
|
|
||||||
} else {
|
|
||||||
showHint("remotedir not specified");
|
|
||||||
}
|
|
||||||
} else if (option == QLatin1String("--serverurl")) {
|
|
||||||
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
|
||||||
_serverUrl = it.next();
|
|
||||||
} else {
|
|
||||||
showHint("serverurl not specified");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
QString errorMessage;
|
||||||
|
if (!AccountSetupCommandLineManager::parseCommandlineOption(option, it, errorMessage)) {
|
||||||
|
if (!errorMessage.isEmpty()) {
|
||||||
|
showHint(errorMessage.toStdString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
showHint("Unrecognized option '" + option.toStdString() + "'");
|
showHint("Unrecognized option '" + option.toStdString() + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers for displaying messages. Note that there is no console on Windows.
|
// Helpers for displaying messages. Note that there is no console on Windows.
|
||||||
|
@ -885,184 +871,6 @@ void Application::slotGuiIsShowingSettings()
|
||||||
emit isShowingSettingsDialog();
|
emit isShowingSettingsDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::handleAccountSetupFromCommandLine()
|
|
||||||
{
|
|
||||||
if (AccountManager::instance()->accountFromUserId(QStringLiteral("%1@%2").arg(_userId).arg(_serverUrl.host()))) {
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Account %1 already exists!").arg(QDir::toNativeSeparators(_userId)), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir dir(_baseDir);
|
|
||||||
if (dir.exists() && !dir.isEmpty()) {
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Local folder %1 already exists and is non-empty!").arg(QDir::toNativeSeparators(_baseDir)), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qInfo() << "Creating folder" << _baseDir;
|
|
||||||
if (!dir.exists() && !dir.mkpath(".")) {
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Folder creation failed. Could not create local folder %1").arg(QDir::toNativeSeparators(_baseDir)), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSystem::setFolderMinimumPermissions(_baseDir);
|
|
||||||
Utility::setupFavLink(_baseDir);
|
|
||||||
|
|
||||||
const auto credentials = new WebFlowCredentials(_userId, _appPassword);
|
|
||||||
_account = AccountManager::createAccount();
|
|
||||||
_account->setCredentials(credentials);
|
|
||||||
_account->setUrl(_serverUrl);
|
|
||||||
|
|
||||||
_userId.clear();
|
|
||||||
_appPassword.clear();
|
|
||||||
_serverUrl.clear();
|
|
||||||
|
|
||||||
fetchUserName();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::checkLastModifiedWithPropfind()
|
|
||||||
{
|
|
||||||
const auto job = new PropfindJob(_account, "/", this);
|
|
||||||
job->setIgnoreCredentialFailure(true);
|
|
||||||
// There is custom redirect handling in the error handler,
|
|
||||||
// so don't automatically follow redirects.
|
|
||||||
job->setFollowRedirects(false);
|
|
||||||
job->setProperties(QList<QByteArray>() << "getlastmodified");
|
|
||||||
connect(job, &PropfindJob::result, this, &Application::accountSetupFromCommandLinePropfindHandleSuccess);
|
|
||||||
connect(job, &PropfindJob::finishedWithError, this, &Application::accountSetupFromCommandLinePropfindHandleFailure);
|
|
||||||
job->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::accountSetupFromCommandLinePropfindHandleSuccess()
|
|
||||||
{
|
|
||||||
const auto accountManager = AccountManager::instance();
|
|
||||||
const auto accountState = accountManager->addAccount(_account);
|
|
||||||
accountManager->save();
|
|
||||||
|
|
||||||
FolderDefinition definition;
|
|
||||||
definition.localPath = _baseDir;
|
|
||||||
definition.targetPath = FolderDefinition::prepareTargetPath(!_remoteDir.isEmpty() ? _remoteDir : QStringLiteral("/"));
|
|
||||||
definition.virtualFilesMode = bestAvailableVfsMode();
|
|
||||||
|
|
||||||
const auto folderMan = FolderMan::instance();
|
|
||||||
|
|
||||||
definition.ignoreHiddenFiles = folderMan->ignoreHiddenFiles();
|
|
||||||
definition.alias = folderMan->map().size() > 0 ? QString::number(folderMan->map().size()) : QString::number(0);
|
|
||||||
|
|
||||||
if (folderMan->navigationPaneHelper().showInExplorerNavigationPane()) {
|
|
||||||
definition.navigationPaneClsid = QUuid::createUuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
folderMan->setSyncEnabled(false);
|
|
||||||
|
|
||||||
if (const auto folder = folderMan->addFolder(accountState, definition)) {
|
|
||||||
if (definition.virtualFilesMode != Vfs::Off) {
|
|
||||||
folder->setRootPinState(PinState::OnlineOnly);
|
|
||||||
}
|
|
||||||
folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, QStringList() << QLatin1String("/"));
|
|
||||||
qInfo() << QStringLiteral("Folder %1 setup from command line success.").arg(definition.localPath);
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Account %1 setup from command line success.").arg(_account->displayName()), false);
|
|
||||||
} else {
|
|
||||||
accountManager->deleteAccount(accountState);
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Account %1 setup from command line failed, due to folder creation failure.").arg(_account->displayName()), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::accountSetupFromCommandLinePropfindHandleFailure()
|
|
||||||
{
|
|
||||||
const auto job = qobject_cast<PropfindJob *>(sender());
|
|
||||||
if (!job) {
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit(QStringLiteral("Cannot check for authed redirects. This slot should be invoked from PropfindJob!"), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto reply = job->reply();
|
|
||||||
|
|
||||||
QString errorMsg;
|
|
||||||
|
|
||||||
// If there were redirects on the *authed* requests, also store
|
|
||||||
// the updated server URL, similar to redirects on status.php.
|
|
||||||
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
|
||||||
if (!redirectUrl.isEmpty()) {
|
|
||||||
qInfo() << "Authed request was redirected to" << redirectUrl.toString();
|
|
||||||
|
|
||||||
// strip the expected path
|
|
||||||
auto path = redirectUrl.path();
|
|
||||||
static QString expectedPath = "/" + _account->davPath();
|
|
||||||
if (path.endsWith(expectedPath)) {
|
|
||||||
path.chop(expectedPath.size());
|
|
||||||
redirectUrl.setPath(path);
|
|
||||||
|
|
||||||
qInfo() << "Setting account url to" << redirectUrl.toString();
|
|
||||||
_account->setUrl(redirectUrl);
|
|
||||||
checkLastModifiedWithPropfind();
|
|
||||||
}
|
|
||||||
errorMsg = tr("The authenticated request to the server was redirected to "
|
|
||||||
"\"%1\". The URL is bad, the server is misconfigured.")
|
|
||||||
.arg(Utility::escape(redirectUrl.toString()));
|
|
||||||
|
|
||||||
// A 404 is actually a success: we were authorized to know that the folder does
|
|
||||||
// not exist. It will be created later...
|
|
||||||
} else if (reply->error() == QNetworkReply::ContentNotFoundError) {
|
|
||||||
accountSetupFromCommandLinePropfindHandleSuccess();
|
|
||||||
} else if (reply->error() != QNetworkReply::NoError) {
|
|
||||||
if (!_account->credentials()->stillValid(reply)) {
|
|
||||||
errorMsg = tr("Access forbidden by server. To verify that you have proper access, "
|
|
||||||
"<a href=\"%1\">click here</a> to access the service with your browser.")
|
|
||||||
.arg(Utility::escape(_account->url().toString()));
|
|
||||||
} else {
|
|
||||||
errorMsg = job->errorStringParsingBody();
|
|
||||||
}
|
|
||||||
// Something else went wrong, maybe the response was 200 but with invalid data.
|
|
||||||
} else {
|
|
||||||
errorMsg = tr("There was an invalid response to an authenticated WebDAV request");
|
|
||||||
}
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit( QStringLiteral("Account %1 setup from command line failed with error: %2.").arg(_account->displayName()).arg(errorMsg), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::printAccountSetupFromCommandLineStatusAndExit(const QString &status, bool isFailure)
|
|
||||||
{
|
|
||||||
if (isFailure) {
|
|
||||||
qWarning() << status;
|
|
||||||
} else {
|
|
||||||
qInfo() << status;
|
|
||||||
}
|
|
||||||
_userId.clear();
|
|
||||||
_appPassword.clear();
|
|
||||||
_serverUrl.clear();
|
|
||||||
_baseDir.clear();
|
|
||||||
_remoteDir.clear();
|
|
||||||
_account.clear();
|
|
||||||
QTimer::singleShot(0, this, [isFailure]() {
|
|
||||||
if (isFailure) {
|
|
||||||
qApp->exit(1);
|
|
||||||
} else {
|
|
||||||
// we might need another wait to quit such that we won't end up with syncjournal being locked and lock not lifted
|
|
||||||
qApp->quit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::fetchUserName()
|
|
||||||
{
|
|
||||||
const auto fetchUserNameJob = new JsonApiJob(_account, QStringLiteral("/ocs/v1.php/cloud/user"));
|
|
||||||
connect(fetchUserNameJob, &JsonApiJob::jsonReceived, this, [this](const QJsonDocument &json, int statusCode) {
|
|
||||||
sender()->deleteLater();
|
|
||||||
|
|
||||||
if (statusCode != 100) {
|
|
||||||
printAccountSetupFromCommandLineStatusAndExit("Could not fetch username.", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto objData = json.object().value("ocs").toObject().value("data").toObject();
|
|
||||||
const auto userId = objData.value("id").toString("");
|
|
||||||
const auto displayName = objData.value("display-name").toString("");
|
|
||||||
_account->setDavUser(userId);
|
|
||||||
_account->setDavDisplayName(displayName);
|
|
||||||
|
|
||||||
checkLastModifiedWithPropfind();
|
|
||||||
});
|
|
||||||
fetchUserNameJob->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::openVirtualFile(const QString &filename)
|
void Application::openVirtualFile(const QString &filename)
|
||||||
{
|
{
|
||||||
QString virtualFileExt = QStringLiteral(APPLICATION_DOTVIRTUALFILE_SUFFIX);
|
QString virtualFileExt = QStringLiteral(APPLICATION_DOTVIRTUALFILE_SUFFIX);
|
||||||
|
|
|
@ -107,14 +107,6 @@ protected slots:
|
||||||
void slotSystemOnlineConfigurationChanged(QNetworkConfiguration);
|
void slotSystemOnlineConfigurationChanged(QNetworkConfiguration);
|
||||||
void slotGuiIsShowingSettings();
|
void slotGuiIsShowingSettings();
|
||||||
|
|
||||||
private slots:
|
|
||||||
void handleAccountSetupFromCommandLine();
|
|
||||||
void fetchUserName();
|
|
||||||
void checkLastModifiedWithPropfind();
|
|
||||||
void accountSetupFromCommandLinePropfindHandleSuccess();
|
|
||||||
void accountSetupFromCommandLinePropfindHandleFailure();
|
|
||||||
void printAccountSetupFromCommandLineStatusAndExit(const QString &status, bool isFailure);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setHelp();
|
void setHelp();
|
||||||
|
|
||||||
|
@ -140,11 +132,6 @@ private:
|
||||||
bool _quitInstance = false;
|
bool _quitInstance = false;
|
||||||
QString _logFile;
|
QString _logFile;
|
||||||
QString _logDir;
|
QString _logDir;
|
||||||
QString _appPassword;
|
|
||||||
QString _userId;
|
|
||||||
QString _baseDir;
|
|
||||||
QString _remoteDir;
|
|
||||||
QUrl _serverUrl;
|
|
||||||
int _logExpire;
|
int _logExpire;
|
||||||
bool _logFlush;
|
bool _logFlush;
|
||||||
bool _logDebug;
|
bool _logDebug;
|
||||||
|
@ -158,8 +145,6 @@ private:
|
||||||
QNetworkConfigurationManager _networkConfigurationManager;
|
QNetworkConfigurationManager _networkConfigurationManager;
|
||||||
QTimer _checkConnectionTimer;
|
QTimer _checkConnectionTimer;
|
||||||
|
|
||||||
AccountPtr _account;
|
|
||||||
|
|
||||||
#if defined(WITH_CRASHREPORTER)
|
#if defined(WITH_CRASHREPORTER)
|
||||||
QScopedPointer<CrashReporter::Handler> _crashHandler;
|
QScopedPointer<CrashReporter::Handler> _crashHandler;
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue