From 8b5f09305c82c55aad6908ef4ca0d7bf4970700f Mon Sep 17 00:00:00 2001 From: Michael Schuster Date: Mon, 23 Dec 2019 06:51:46 +0100 Subject: [PATCH] Flow2: Refactor UI into Flow2AuthWidget only and improve Flow2Auth - Flow2AuthCredsPage: - Remove .ui file and embed Flow2AuthWidget into layout - Flow2AuthWidget: - Make use generic for Flow2AuthCredsPage and WebFlowCredentialsDialog - Fix _errorLabel to render HTML tags instead of dumping them as plain text - Flow2Auth: - Explicitly start auth with startAuth(account) instead of using constructor - Take control of copying the auth link to clipboard - Request a new auth link on copying, to avoid expiry invalidation - Use signals statusChanged() and result() to be more verbose (status, errors) - Change timer invocation and add safety bool's to avoid weird behaviour when the user triggers multiple link-copy calls (fetchNewToken) Signed-off-by: Michael Schuster --- src/gui/CMakeLists.txt | 3 +- src/gui/creds/flow2auth.cpp | 130 ++++++++++++++++----- src/gui/creds/flow2auth.h | 28 +++-- src/gui/creds/webflowcredentialsdialog.cpp | 16 ++- src/gui/creds/webflowcredentialsdialog.h | 2 + src/gui/wizard/flow2authcredspage.cpp | 115 ++++-------------- src/gui/wizard/flow2authcredspage.h | 22 ++-- src/gui/wizard/flow2authcredspage.ui | 126 -------------------- src/gui/wizard/flow2authwidget.cpp | 79 ++++++++----- src/gui/wizard/flow2authwidget.h | 12 +- 10 files changed, 221 insertions(+), 312 deletions(-) delete mode 100644 src/gui/wizard/flow2authcredspage.ui diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 381a5d2d1..849d2cf28 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -35,12 +35,11 @@ set(client_UI_SRCS addcertificatedialog.ui proxyauthdialog.ui mnemonicdialog.ui + wizard/flow2authwidget.ui wizard/owncloudadvancedsetuppage.ui wizard/owncloudconnectionmethoddialog.ui wizard/owncloudhttpcredspage.ui wizard/owncloudoauthcredspage.ui - wizard/flow2authcredspage.ui - wizard/flow2authwidget.ui wizard/owncloudsetupnocredspage.ui wizard/owncloudwizardresultpage.ui wizard/webview.ui diff --git a/src/gui/creds/flow2auth.cpp b/src/gui/creds/flow2auth.cpp index f5e6423c5..e75a8c9bf 100644 --- a/src/gui/creds/flow2auth.cpp +++ b/src/gui/creds/flow2auth.cpp @@ -14,10 +14,12 @@ */ #include +#include +#include #include #include #include "account.h" -#include "creds/flow2auth.h" +#include "flow2auth.h" #include #include #include "theme.h" @@ -28,6 +30,17 @@ namespace OCC { Q_LOGGING_CATEGORY(lcFlow2auth, "nextcloud.sync.credentials.flow2auth", QtInfoMsg) + +Flow2Auth::Flow2Auth(Account *account, QObject *parent) + : QObject(parent) + , _account(account) + , _isBusy(false) + , _hasToken(false) +{ + _pollTimer.setInterval(1000); + QObject::connect(&_pollTimer, &QTimer::timeout, this, &Flow2Auth::slotPollTimerTimeout); +} + Flow2Auth::~Flow2Auth() { } @@ -47,7 +60,23 @@ QUrl Flow2Auth::authorisationLink() const void Flow2Auth::openBrowser() { - _pollTimer.stop(); + fetchNewToken(TokenAction::actionOpenBrowser); +} + +void Flow2Auth::copyLinkToClipboard() +{ + fetchNewToken(TokenAction::actionCopyLinkToClipboard); +} + +void Flow2Auth::fetchNewToken(const TokenAction action) +{ + if(_isBusy) + return; + + _isBusy = true; + _hasToken = false; + + emit statusChanged(PollStatus::statusFetchToken, 0); // Step 1: Initiate a login, do an anonymous POST request QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2")); @@ -59,14 +88,18 @@ void Flow2Auth::openBrowser() auto job = _account->sendRequest("POST", url, req); job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec())); - QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) { + QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this, action](QNetworkReply *reply) { auto jsonData = reply->readAll(); QJsonParseError jsonParseError; QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object(); + QString pollToken, pollEndpoint, loginUrl; - QString pollToken = json.value("poll").toObject().value("token").toString(); - QString pollEndpoint = json.value("poll").toObject().value("endpoint").toString(); - QUrl loginUrl = json["login"].toString(); + if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError + && !json.isEmpty()) { + pollToken = json.value("poll").toObject().value("token").toString(); + pollEndpoint = json.value("poll").toObject().value("endpoint").toString(); + loginUrl = json["login"].toString(); + } if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError || json.isEmpty() || pollToken.isEmpty() || pollEndpoint.isEmpty() || loginUrl.isEmpty()) { @@ -85,7 +118,9 @@ void Flow2Auth::openBrowser() errorReason = tr("The reply from the server did not contain all expected fields"); } qCWarning(lcFlow2auth) << "Error when getting the loginUrl" << json << errorReason; - emit result(Error); + emit result(Error, errorReason); + _pollTimer.stop(); + _isBusy = false; return; } @@ -99,34 +134,50 @@ void Flow2Auth::openBrowser() ConfigFile cfg; std::chrono::milliseconds polltime = cfg.remotePollInterval(); qCInfo(lcFlow2auth) << "setting remote poll timer interval to" << polltime.count() << "msec"; - _pollTimer.setInterval(1000); - QObject::connect(&_pollTimer, &QTimer::timeout, this, &Flow2Auth::slotPollTimerTimeout); _secondsInterval = (polltime.count() / 1000); _secondsLeft = _secondsInterval; - emit statusChanged(_secondsLeft); - _pollTimer.start(); + emit statusChanged(PollStatus::statusPollCountdown, _secondsLeft); + if(!_pollTimer.isActive()) { + _pollTimer.start(); + } - // Try to open Browser - if (!QDesktopServices::openUrl(authorisationLink())) { - // We cannot open the browser, then we claim we don't support Flow2Auth. - // Our UI callee should ask the user to copy and open the link. - emit result(NotSupported, QString()); + + switch(action) + { + case actionOpenBrowser: + // Try to open Browser + if (!QDesktopServices::openUrl(authorisationLink())) { + // We cannot open the browser, then we claim we don't support Flow2Auth. + // Our UI callee will ask the user to copy and open the link. + emit result(NotSupported); + } + break; + case actionCopyLinkToClipboard: + QApplication::clipboard()->setText(authorisationLink().toString(QUrl::FullyEncoded)); + emit statusChanged(PollStatus::statusCopyLinkToClipboard, 0); + break; } + + _isBusy = false; + _hasToken = true; }); } void Flow2Auth::slotPollTimerTimeout() { - _pollTimer.stop(); + if(_isBusy || !_hasToken) + return; - _secondsLeft--; - emit statusChanged(_secondsLeft); + _isBusy = true; + _secondsLeft--; if(_secondsLeft > 0) { - _pollTimer.start(); + emit statusChanged(PollStatus::statusPollCountdown, _secondsLeft); + _isBusy = false; return; } + emit statusChanged(PollStatus::statusPollNow, 0); // Step 2: Poll QNetworkRequest req; @@ -143,10 +194,15 @@ void Flow2Auth::slotPollTimerTimeout() auto jsonData = reply->readAll(); QJsonParseError jsonParseError; QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object(); - - QUrl serverUrl = json["server"].toString(); - QString loginName = json["loginName"].toString(); - QString appPassword = json["appPassword"].toString(); + QUrl serverUrl; + QString loginName, appPassword; + + if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError + && !json.isEmpty()) { + serverUrl = json["server"].toString(); + loginName = json["loginName"].toString(); + appPassword = json["appPassword"].toString(); + } if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError || json.isEmpty() || serverUrl.isEmpty() || loginName.isEmpty() || appPassword.isEmpty()) { @@ -166,36 +222,50 @@ void Flow2Auth::slotPollTimerTimeout() } qCDebug(lcFlow2auth) << "Error when polling for the appPassword" << json << errorReason; + // We get a 404 until authentication is done, so don't show this error in the GUI. + if(reply->error() != QNetworkReply::ContentNotFoundError) + emit result(Error, errorReason); + // Forget sensitive data appPassword.clear(); loginName.clear(); // Failed: poll again _secondsLeft = _secondsInterval; - _pollTimer.start(); + _isBusy = false; return; } + _pollTimer.stop(); + // Success qCInfo(lcFlow2auth) << "Success getting the appPassword for user: " << loginName << ", server: " << serverUrl.toString(); _account->setUrl(serverUrl); - emit result(LoggedIn, loginName, appPassword); + emit result(LoggedIn, QString(), loginName, appPassword); // Forget sensitive data appPassword.clear(); loginName.clear(); + + _loginUrl.clear(); + _pollToken.clear(); + _pollEndpoint.clear(); + + _isBusy = false; + _hasToken = false; }); } void Flow2Auth::slotPollNow() { // poll now if we're not already doing so - if(_pollTimer.isActive()) { - _secondsLeft = 1; - slotPollTimerTimeout(); - } + if(_isBusy || !_hasToken) + return; + + _secondsLeft = 1; + slotPollTimerTimeout(); } } // namespace OCC diff --git a/src/gui/creds/flow2auth.h b/src/gui/creds/flow2auth.h index b53c32e8a..e4deb203e 100644 --- a/src/gui/creds/flow2auth.h +++ b/src/gui/creds/flow2auth.h @@ -30,11 +30,18 @@ class Flow2Auth : public QObject { Q_OBJECT public: - Flow2Auth(Account *account, QObject *parent) - : QObject(parent) - , _account(account) - { - } + enum TokenAction { + actionOpenBrowser = 1, + actionCopyLinkToClipboard + }; + enum PollStatus { + statusPollCountdown = 1, + statusPollNow, + statusFetchToken, + statusCopyLinkToClipboard + }; + + Flow2Auth(Account *account, QObject *parent); ~Flow2Auth(); enum Result { NotSupported, @@ -43,6 +50,7 @@ public: Q_ENUM(Result); void start(); void openBrowser(); + void copyLinkToClipboard(); QUrl authorisationLink() const; signals: @@ -50,9 +58,10 @@ signals: * The state has changed. * when logged in, appPassword has the value of the app password. */ - void result(Flow2Auth::Result result, const QString &user = QString(), const QString &appPassword = QString()); + void result(Flow2Auth::Result result, const QString &errorString = QString(), + const QString &user = QString(), const QString &appPassword = QString()); - void statusChanged(int secondsLeft); + void statusChanged(const PollStatus status, int secondsLeft); public slots: void slotPollNow(); @@ -61,6 +70,8 @@ private slots: void slotPollTimerTimeout(); private: + void fetchNewToken(const TokenAction action); + Account *_account; QUrl _loginUrl; QString _pollToken; @@ -68,7 +79,8 @@ private: QTimer _pollTimer; int _secondsLeft; int _secondsInterval; + bool _isBusy; + bool _hasToken; }; - } // namespace OCC diff --git a/src/gui/creds/webflowcredentialsdialog.cpp b/src/gui/creds/webflowcredentialsdialog.cpp index 3e8d55a39..ea8d29e79 100644 --- a/src/gui/creds/webflowcredentialsdialog.cpp +++ b/src/gui/creds/webflowcredentialsdialog.cpp @@ -43,17 +43,18 @@ WebFlowCredentialsDialog::WebFlowCredentialsDialog(Account *account, bool useFlo _containerLayout->addWidget(_infoLabel); if (_useFlow2) { - _flow2AuthWidget = new Flow2AuthWidget(account); _flow2AuthWidget = new Flow2AuthWidget(); _containerLayout->addWidget(_flow2AuthWidget); - connect(_flow2AuthWidget, &Flow2AuthWidget::urlCatched, this, &WebFlowCredentialsDialog::urlCatched); + connect(_flow2AuthWidget, &Flow2AuthWidget::authResult, this, &WebFlowCredentialsDialog::slotFlow2AuthResult); // Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching) connect(this, &WebFlowCredentialsDialog::styleChanged, _flow2AuthWidget, &Flow2AuthWidget::slotStyleChanged); // allow Flow2 page to poll on window activation connect(this, &WebFlowCredentialsDialog::onActivate, _flow2AuthWidget, &Flow2AuthWidget::slotPollNow); + + _flow2AuthWidget->startAuth(account); } else { _webView = new WebView(); _containerLayout->addWidget(_webView); @@ -87,6 +88,7 @@ void WebFlowCredentialsDialog::closeEvent(QCloseEvent* e) { } if (_flow2AuthWidget) { + _flow2AuthWidget->resetAuth(); _flow2AuthWidget->deleteLater(); _flow2AuthWidget = nullptr; } @@ -155,4 +157,14 @@ void WebFlowCredentialsDialog::slotShowSettingsDialog() }); } +void WebFlowCredentialsDialog::slotFlow2AuthResult(Flow2Auth::Result r, const QString &errorString, const QString &user, const QString &appPassword) +{ + if(r == Flow2Auth::LoggedIn) { + emit urlCatched(user, appPassword, QString()); + } else { + // bring window to top + slotShowSettingsDialog(); + } +} + } // namespace OCC diff --git a/src/gui/creds/webflowcredentialsdialog.h b/src/gui/creds/webflowcredentialsdialog.h index 3dfdf744d..50ed7088d 100644 --- a/src/gui/creds/webflowcredentialsdialog.h +++ b/src/gui/creds/webflowcredentialsdialog.h @@ -5,6 +5,7 @@ #include #include "accountfwd.h" +#include "creds/flow2auth.h" class QLabel; class QVBoxLayout; @@ -34,6 +35,7 @@ protected: void changeEvent(QEvent *) override; public slots: + void slotFlow2AuthResult(Flow2Auth::Result, const QString &errorString, const QString &user, const QString &appPassword); void slotShowSettingsDialog(); signals: diff --git a/src/gui/wizard/flow2authcredspage.cpp b/src/gui/wizard/flow2authcredspage.cpp index 97df052ec..d04d9741e 100644 --- a/src/gui/wizard/flow2authcredspage.cpp +++ b/src/gui/wizard/flow2authcredspage.cpp @@ -14,49 +14,39 @@ */ #include -#include -#include +#include -#include "wizard/flow2authcredspage.h" +#include "flow2authcredspage.h" #include "theme.h" #include "account.h" #include "cookiejar.h" #include "wizard/owncloudwizardcommon.h" #include "wizard/owncloudwizard.h" +#include "wizard/flow2authwidget.h" #include "creds/credentialsfactory.h" #include "creds/webflowcredentials.h" -#include "QProgressIndicator.h" - namespace OCC { Flow2AuthCredsPage::Flow2AuthCredsPage() - : AbstractCredentialsWizardPage() - , _ui() - , _progressIndi(new QProgressIndicator(this)) + : AbstractCredentialsWizardPage(), + _flow2AuthWidget(nullptr) { - _ui.setupUi(this); - - Theme *theme = Theme::instance(); - _ui.topLabel->hide(); - _ui.bottomLabel->hide(); - QVariant variant = theme->customMedia(Theme::oCSetupTop); - WizardCommon::setupCustomMedia(variant, _ui.topLabel); - variant = theme->customMedia(Theme::oCSetupBottom); - WizardCommon::setupCustomMedia(variant, _ui.bottomLabel); - - WizardCommon::initErrorLabel(_ui.errorLabel); + _layout = new QVBoxLayout(this); setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(Theme::instance()->appNameGUI()))); setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Login in your browser (Login Flow v2)"))); - connect(_ui.openLinkButton, &QCommandLinkButton::clicked, this, &Flow2AuthCredsPage::slotOpenBrowser); - connect(_ui.copyLinkButton, &QCommandLinkButton::clicked, this, &Flow2AuthCredsPage::slotCopyLinkToClipboard); + _flow2AuthWidget = new Flow2AuthWidget(); + _layout->addWidget(_flow2AuthWidget); + + connect(_flow2AuthWidget, &Flow2AuthWidget::authResult, this, &Flow2AuthCredsPage::slotFlow2AuthResult); - _ui.horizontalLayout->addWidget(_progressIndi); - stopSpinner(false); + // Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching) + connect(this, &Flow2AuthCredsPage::styleChanged, _flow2AuthWidget, &Flow2AuthWidget::slotStyleChanged); - customizeStyle(); + // allow Flow2 page to poll on window activation + connect(this, &Flow2AuthCredsPage::pollNow, _flow2AuthWidget, &Flow2AuthWidget::slotPollNow); } void Flow2AuthCredsPage::initializePage() @@ -64,11 +54,9 @@ void Flow2AuthCredsPage::initializePage() OwncloudWizard *ocWizard = qobject_cast(wizard()); Q_ASSERT(ocWizard); ocWizard->account()->setCredentials(CredentialsFactory::create("http")); - _asyncAuth.reset(new Flow2Auth(ocWizard->account().data(), this)); - connect(_asyncAuth.data(), &Flow2Auth::result, this, &Flow2AuthCredsPage::asyncAuthResult, Qt::QueuedConnection); - connect(_asyncAuth.data(), &Flow2Auth::statusChanged, this, &Flow2AuthCredsPage::slotStatusChanged); - connect(this, &Flow2AuthCredsPage::pollNow, _asyncAuth.data(), &Flow2Auth::slotPollNow); - _asyncAuth->start(); + + if(_flow2AuthWidget) + _flow2AuthWidget->startAuth(ocWizard->account().data()); // Don't hide the wizard (avoid user confusion)! //wizard()->hide(); @@ -78,23 +66,20 @@ void OCC::Flow2AuthCredsPage::cleanupPage() { // The next or back button was activated, show the wizard again wizard()->show(); - _asyncAuth.reset(); + if(_flow2AuthWidget) + _flow2AuthWidget->resetAuth(); // Forget sensitive data _appPassword.clear(); _user.clear(); } -void Flow2AuthCredsPage::asyncAuthResult(Flow2Auth::Result r, const QString &user, - const QString &appPassword) +void Flow2AuthCredsPage::slotFlow2AuthResult(Flow2Auth::Result r, const QString &errorString, const QString &user, const QString &appPassword) { - stopSpinner(false); - switch (r) { case Flow2Auth::NotSupported: { /* Flow2Auth not supported (can't open browser) */ - _ui.errorLabel->setText(tr("Unable to open the Browser, please copy the link to your Browser.")); - _ui.errorLabel->show(); + wizard()->show(); /* Don't fallback to HTTP credentials */ /*OwncloudWizard *ocWizard = qobject_cast(wizard()); @@ -104,7 +89,6 @@ void Flow2AuthCredsPage::asyncAuthResult(Flow2Auth::Result r, const QString &use } case Flow2Auth::Error: /* Error while getting the access token. (Timeout, or the server did not accept our client credentials */ - _ui.errorLabel->show(); wizard()->show(); break; case Flow2Auth::LoggedIn: { @@ -151,69 +135,14 @@ bool Flow2AuthCredsPage::isComplete() const return false; /* We can never go forward manually */ } -void Flow2AuthCredsPage::slotOpenBrowser() -{ - if (_ui.errorLabel) - _ui.errorLabel->hide(); - - if (_asyncAuth) - _asyncAuth->openBrowser(); -} - -void Flow2AuthCredsPage::slotCopyLinkToClipboard() -{ - if (_asyncAuth) - QApplication::clipboard()->setText(_asyncAuth->authorisationLink().toString(QUrl::FullyEncoded)); -} - void Flow2AuthCredsPage::slotPollNow() { emit pollNow(); } -void Flow2AuthCredsPage::slotStatusChanged(int secondsLeft) -{ - const bool pollingNow = (secondsLeft == 0); - - _ui.statusLabel->setText(tr("Polling for authorization") + (pollingNow ? "" : QString(" " + tr("in %1 seconds").arg(secondsLeft))) + "..."); - - if(pollingNow) - startSpinner(); - else - stopSpinner(true); -} - -void Flow2AuthCredsPage::startSpinner() -{ - _ui.horizontalLayout->setEnabled(true); - _ui.statusLabel->setVisible(true); - _progressIndi->setVisible(true); - _progressIndi->startAnimation(); - - _ui.openLinkButton->setEnabled(false); - _ui.copyLinkButton->setEnabled(false); -} - -void Flow2AuthCredsPage::stopSpinner(bool showStatusLabel) -{ - _ui.horizontalLayout->setEnabled(false); - _ui.statusLabel->setVisible(showStatusLabel); - _progressIndi->setVisible(false); - _progressIndi->stopAnimation(); - - _ui.openLinkButton->setEnabled(true); - _ui.copyLinkButton->setEnabled(true); -} - void Flow2AuthCredsPage::slotStyleChanged() { - customizeStyle(); -} - -void Flow2AuthCredsPage::customizeStyle() -{ - if(_progressIndi) - _progressIndi->setColor(QGuiApplication::palette().color(QPalette::Text)); + emit styleChanged(); } } // namespace OCC diff --git a/src/gui/wizard/flow2authcredspage.h b/src/gui/wizard/flow2authcredspage.h index eac4a0c37..8a59605e0 100644 --- a/src/gui/wizard/flow2authcredspage.h +++ b/src/gui/wizard/flow2authcredspage.h @@ -25,12 +25,13 @@ #include "accountfwd.h" #include "creds/flow2auth.h" -#include "ui_flow2authcredspage.h" - +class QVBoxLayout; class QProgressIndicator; namespace OCC { +class Flow2AuthWidget; + class Flow2AuthCredsPage : public AbstractCredentialsWizardPage { Q_OBJECT @@ -46,31 +47,22 @@ public: bool isComplete() const override; public Q_SLOTS: - void asyncAuthResult(Flow2Auth::Result, const QString &user, const QString &appPassword); + void slotFlow2AuthResult(Flow2Auth::Result, const QString &errorString, const QString &user, const QString &appPassword); void slotPollNow(); - void slotStatusChanged(int secondsLeft); void slotStyleChanged(); signals: void connectToOCUrl(const QString &); void pollNow(); + void styleChanged(); public: QString _user; QString _appPassword; - QScopedPointer _asyncAuth; - Ui_Flow2AuthCredsPage _ui; - -protected slots: - void slotOpenBrowser(); - void slotCopyLinkToClipboard(); private: - void startSpinner(); - void stopSpinner(bool showStatusLabel); - void customizeStyle(); - - QProgressIndicator *_progressIndi; + Flow2AuthWidget *_flow2AuthWidget; + QVBoxLayout *_layout; }; } // namespace OCC diff --git a/src/gui/wizard/flow2authcredspage.ui b/src/gui/wizard/flow2authcredspage.ui deleted file mode 100644 index 7fe3587f3..000000000 --- a/src/gui/wizard/flow2authcredspage.ui +++ /dev/null @@ -1,126 +0,0 @@ - - - Flow2AuthCredsPage - - - - 0 - 0 - 424 - 373 - - - - Browser Authentication - - - - - - TextLabel - - - Qt::RichText - - - Qt::AlignCenter - - - true - - - - - - - Please switch to your browser to proceed. - - - true - - - - - - - An error occurred while connecting. Please try again. - - - Qt::PlainText - - - - - - - Re-open Browser - - - - - - - - 50 - false - - - - Copy link - - - - - - - Qt::Vertical - - - - 20 - 10 - - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - - - - Qt::Vertical - - - - 20 - 127 - - - - - - - - TextLabel - - - Qt::RichText - - - - - - - - diff --git a/src/gui/wizard/flow2authwidget.cpp b/src/gui/wizard/flow2authwidget.cpp index ee8d6c749..1ba91be33 100644 --- a/src/gui/wizard/flow2authwidget.cpp +++ b/src/gui/wizard/flow2authwidget.cpp @@ -14,15 +14,6 @@ #include "flow2authwidget.h" -#include -#include -#include -#include -#include - -#include -#include - #include "common/utility.h" #include "account.h" #include "wizard/owncloudwizardcommon.h" @@ -34,15 +25,16 @@ namespace OCC { Q_LOGGING_CATEGORY(lcFlow2AuthWidget, "gui.wizard.flow2authwidget", QtInfoMsg) -Flow2AuthWidget::Flow2AuthWidget(Account *account, QWidget *parent) +Flow2AuthWidget::Flow2AuthWidget(QWidget *parent) : QWidget(parent) - , _account(account) + , _account(nullptr) , _ui() , _progressIndi(new QProgressIndicator(this)) { _ui.setupUi(this); WizardCommon::initErrorLabel(_ui.errorLabel); + _ui.errorLabel->setTextFormat(Qt::RichText); connect(_ui.openLinkButton, &QCommandLinkButton::clicked, this, &Flow2AuthWidget::slotOpenBrowser); connect(_ui.copyLinkButton, &QCommandLinkButton::clicked, this, &Flow2AuthWidget::slotCopyLinkToClipboard); @@ -50,17 +42,32 @@ Flow2AuthWidget::Flow2AuthWidget(Account *account, QWidget *parent) _ui.horizontalLayout->addWidget(_progressIndi); stopSpinner(false); + customizeStyle(); +} + +void Flow2AuthWidget::startAuth(Account *account) +{ + Flow2Auth *oldAuth = _asyncAuth.take(); + if(oldAuth) + oldAuth->deleteLater(); + + if(account) { + _account = account; + _asyncAuth.reset(new Flow2Auth(_account, this)); - connect(_asyncAuth.data(), &Flow2Auth::result, this, &Flow2AuthWidget::asyncAuthResult, Qt::QueuedConnection); + connect(_asyncAuth.data(), &Flow2Auth::result, this, &Flow2AuthWidget::slotAuthResult, Qt::QueuedConnection); connect(_asyncAuth.data(), &Flow2Auth::statusChanged, this, &Flow2AuthWidget::slotStatusChanged); connect(this, &Flow2AuthWidget::pollNow, _asyncAuth.data(), &Flow2Auth::slotPollNow); _asyncAuth->start(); + } +} - customizeStyle(); +void Flow2AuthWidget::resetAuth(Account *account) +{ + startAuth(account); } -void Flow2AuthWidget::asyncAuthResult(Flow2Auth::Result r, const QString &user, - const QString &appPassword) +void Flow2AuthWidget::slotAuthResult(Flow2Auth::Result r, const QString &errorString, const QString &user, const QString &appPassword) { stopSpinner(false); @@ -72,15 +79,16 @@ void Flow2AuthWidget::asyncAuthResult(Flow2Auth::Result r, const QString &user, break; case Flow2Auth::Error: /* Error while getting the access token. (Timeout, or the server did not accept our client credentials */ + _ui.errorLabel->setText(errorString); _ui.errorLabel->show(); break; case Flow2Auth::LoggedIn: { - _user = user; - _appPassword = appPassword; - emit urlCatched(_user, _appPassword, QString()); + _ui.errorLabel->hide(); break; } } + + emit authResult(r, errorString, user, appPassword); } void Flow2AuthWidget::setError(const QString &error) { @@ -93,11 +101,8 @@ void Flow2AuthWidget::setError(const QString &error) { } Flow2AuthWidget::~Flow2AuthWidget() { - _asyncAuth.reset(); - // Forget sensitive data - _appPassword.clear(); - _user.clear(); + _asyncAuth.reset(); } void Flow2AuthWidget::slotOpenBrowser() @@ -111,8 +116,11 @@ void Flow2AuthWidget::slotOpenBrowser() void Flow2AuthWidget::slotCopyLinkToClipboard() { + if (_ui.errorLabel) + _ui.errorLabel->hide(); + if (_asyncAuth) - QApplication::clipboard()->setText(_asyncAuth->authorisationLink().toString(QUrl::FullyEncoded)); + _asyncAuth->copyLinkToClipboard(); } void Flow2AuthWidget::slotPollNow() @@ -120,16 +128,27 @@ void Flow2AuthWidget::slotPollNow() emit pollNow(); } -void Flow2AuthWidget::slotStatusChanged(int secondsLeft) +void Flow2AuthWidget::slotStatusChanged(Flow2Auth::PollStatus status, int secondsLeft) { - const bool pollingNow = (secondsLeft == 0); - - _ui.statusLabel->setText(tr("Polling for authorization") + (pollingNow ? "" : QString(" " + tr("in %1 seconds").arg(secondsLeft))) + "..."); - - if(pollingNow) + switch(status) +{ + case Flow2Auth::statusPollCountdown: + _ui.statusLabel->setText(tr("Waiting for authorization") + QString(" (%1)").arg(secondsLeft)); + stopSpinner(true); + break; + case Flow2Auth::statusPollNow: + _ui.statusLabel->setText(tr("Polling for authorization") + "..."); + startSpinner(); + break; + case Flow2Auth::statusFetchToken: + _ui.statusLabel->setText(tr("Starting authorization") + "..."); startSpinner(); - else + break; + case Flow2Auth::statusCopyLinkToClipboard: + _ui.statusLabel->setText(tr("Link copied to clipboard.")); stopSpinner(true); + break; + } } void Flow2AuthWidget::startSpinner() diff --git a/src/gui/wizard/flow2authwidget.h b/src/gui/wizard/flow2authwidget.h index 0912657a7..c10b84710 100644 --- a/src/gui/wizard/flow2authwidget.h +++ b/src/gui/wizard/flow2authwidget.h @@ -30,25 +30,25 @@ class Flow2AuthWidget : public QWidget { Q_OBJECT public: - Flow2AuthWidget(Account *account, QWidget *parent = nullptr); + Flow2AuthWidget(QWidget *parent = nullptr); virtual ~Flow2AuthWidget(); + void startAuth(Account *account); + void resetAuth(Account *account = nullptr); void setError(const QString &error); public Q_SLOTS: - void asyncAuthResult(Flow2Auth::Result, const QString &user, const QString &appPassword); + void slotAuthResult(Flow2Auth::Result, const QString &errorString, const QString &user, const QString &appPassword); void slotPollNow(); - void slotStatusChanged(int secondsLeft); + void slotStatusChanged(Flow2Auth::PollStatus status, int secondsLeft); void slotStyleChanged(); signals: - void urlCatched(const QString user, const QString pass, const QString host); + void authResult(Flow2Auth::Result, const QString &errorString, const QString &user, const QString &appPassword); void pollNow(); private: Account *_account; - QString _user; - QString _appPassword; QScopedPointer _asyncAuth; Ui_Flow2AuthWidget _ui; -- 2.30.2