diff options
Diffstat (limited to 'src/nxmaccessmanager.cpp')
| -rw-r--r-- | src/nxmaccessmanager.cpp | 964 |
1 files changed, 809 insertions, 155 deletions
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index ee6c03f1..20540593 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -18,6 +18,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ #include "nxmaccessmanager.h" +#include "ui_validationprogressdialog.h" #include "iplugingame.h" #include "nexusinterface.h" #include "nxmurl.h" @@ -40,21 +41,734 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QJsonArray> using namespace MOBase; +using namespace std::chrono_literals; -namespace { - QString const nexusBaseUrl("https://api.nexusmods.com/v1"); +const QString NexusBaseUrl("https://api.nexusmods.com/v1"); +const QString NexusSSO("wss://sso.nexusmods.com"); +const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); + + +ValidationProgressDialog::ValidationProgressDialog(NexusKeyValidator& v) + : m_validator(v), m_updateTimer(nullptr), m_first(true) +{ + ui.reset(new Ui::ValidationProgressDialog); + ui->setupUi(this); + + connect(ui->hide, &QPushButton::clicked, [&]{ onHide(); }); + connect(ui->cancel, &QPushButton::clicked, [&]{ onCancel(); }); +} + +void ValidationProgressDialog::setParentWidget(QWidget* w) +{ + const auto wasVisible = isVisible(); + + hide(); + setParent(w, windowFlags() | Qt::Dialog); + setModal(false); + + if (w && wasVisible) { + setVisible(true); + raise(); + } +} + +void ValidationProgressDialog::start() +{ + if (!m_updateTimer) { + m_updateTimer = new QTimer(this); + connect(m_updateTimer, &QTimer::timeout, [&]{ onTimer(); }); + m_updateTimer->setInterval(100ms); + } + + updateProgress(); + m_updateTimer->start(); + + show(); +} + +void ValidationProgressDialog::stop() +{ + if (m_updateTimer) { + m_updateTimer->stop(); + } + + hide(); +} + +void ValidationProgressDialog::showEvent(QShowEvent* e) +{ + if (m_first) { + Settings::instance().geometry().centerOnMainWindowMonitor(this); + m_first = false; + } +} + +void ValidationProgressDialog::closeEvent(QCloseEvent* e) +{ + hide(); + e->ignore(); +} + +void ValidationProgressDialog::onHide() +{ + hide(); +} + +void ValidationProgressDialog::onCancel() +{ + m_validator.cancel(); +} + +void ValidationProgressDialog::onTimer() +{ + updateProgress(); +} + +void ValidationProgressDialog::updateProgress() +{ + const auto* current = m_validator.currentAttempt(); + + if (current) { + ui->progress->setRange(0, current->timeout().count()); + ui->progress->setValue(current->elapsed().elapsed() / 1000); + } else { + // indeterminate + ui->progress->setRange(0, 0); + } + + if (const auto* a=m_validator.lastAttempt()) { + ui->label->setText(a->message() + ". " + tr("Trying again...")); + } else if (current) { + ui->label->setText(tr("Connecting to Nexus...")); + } else { + ui->label->setText("?"); + } +} + + +NexusSSOLogin::NexusSSOLogin() + : m_keyReceived(false), m_active(false) +{ + m_timeout.setInterval(10s); + m_timeout.setSingleShot(true); + + QObject::connect( + &m_socket, &QWebSocket::connected, + [&]{ onConnected(); }); + + QObject::connect( + &m_socket, qOverload<QAbstractSocket::SocketError>(&QWebSocket::error), + [&](auto&& e){ onError(e); }); + + QObject::connect( + &m_socket, &QWebSocket::sslErrors, + [&](auto&& errors){ onSslErrors(errors); }); + + QObject::connect( + &m_socket, &QWebSocket::textMessageReceived, + [&](auto&& s){ onMessage(s); }); + + QObject::connect( + &m_socket, &QWebSocket::disconnected, + [&]{ onDisconnected(); }); + + QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); +} + +QString NexusSSOLogin::stateToString(States s, const QString& e) +{ + switch (s) + { + case ConnectingToSSO: + return QObject::tr("Connecting to Nexus..."); + + case WaitingForToken: + return QObject::tr("Waiting for Nexus..."); + + case WaitingForBrowser: + return + QObject::tr("Opened Nexus in browser.") + "\n" + + QObject::tr("Switch to your browser and accept the request."); + + case Finished: + return QObject::tr("Finished."); + + case Timeout: + return + QObject::tr("No answer from Nexus.") + "\n" + + QObject::tr("A firewall might be blocking Mod Organizer."); + + case ClosedByRemote: + return + QObject::tr("Nexus closed the connection.") + "\n" + + QObject::tr("A firewall might be blocking Mod Organizer."); + + case Cancelled: + return QObject::tr("Cancelled."); + + case Error: // fall-through + default: + { + if (e.isEmpty()) { + return QString("%1").arg(s); + } else { + return e; + } + } + } +} + +void NexusSSOLogin::start() +{ + m_active = true; + setState(ConnectingToSSO); + m_timeout.start(); + m_socket.open(NexusSSO); +} + +void NexusSSOLogin::cancel() +{ + if (m_active) { + abort(); + setState(Cancelled); + } +} + +void NexusSSOLogin::close() +{ + if (m_active) { + m_active = false; + m_timeout.stop(); + m_socket.close(); + } +} + +void NexusSSOLogin::abort() +{ + m_active = false; + m_timeout.stop(); + m_socket.abort(); +} + +bool NexusSSOLogin::isActive() const +{ + return m_active; +} + +void NexusSSOLogin::setState(States s, const QString& error) +{ + if (stateChanged) { + stateChanged(s, error); + } +} + +void NexusSSOLogin::onConnected() +{ + setState(WaitingForToken); + + m_keyReceived = false; + + boost::uuids::random_generator generator; + boost::uuids::uuid sessionId = generator(); + m_guid = boost::uuids::to_string(sessionId).c_str(); + + QJsonObject data; + data.insert(QString("id"), QJsonValue(m_guid)); + data.insert(QString("protocol"), 2); + + const QString message = QJsonDocument(data).toJson(); + m_socket.sendTextMessage(message); +} + +void NexusSSOLogin::onMessage(const QString& s) +{ + const QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8()); + const QVariantMap root = doc.object().toVariantMap(); + + if (!root["success"].toBool()) { + close(); + + setState(Error, QString("There was a problem with SSO initialization: %1") + .arg(root["error"].toString())); + + return; + } + + const QVariantMap data = root["data"].toMap(); + + if (data.contains("connection_token")) { + // first answer + + // open browser + const auto url = NexusSSOPage.arg(m_guid); + shell::Open(url); + + m_timeout.stop(); + setState(WaitingForBrowser); + } else { + // second answer + const auto key = data["api_key"].toString(); + close(); + + if (keyChanged) { + keyChanged(key); + } + + setState(Finished); + } +} + +void NexusSSOLogin::onDisconnected() +{ + if (m_active) { + if (!m_keyReceived) { + close(); + setState(ClosedByRemote); + } else { + m_active = false; + } + } +} + +void NexusSSOLogin::onError(QAbstractSocket::SocketError e) +{ + if (m_active) { + close(); + setState(Error, m_socket.errorString()); + } +} + +void NexusSSOLogin::onSslErrors(const QList<QSslError>& errors) +{ + if (m_active) { + for (const auto& e : errors) { + setState(Error, e.errorString()); + } + } +} + +void NexusSSOLogin::onTimeout() +{ + abort(); + setState(Timeout); +} + + +ValidationAttempt::ValidationAttempt(std::chrono::seconds timeout) + : m_reply(nullptr), m_result(None) +{ + m_timeout.setSingleShot(true); + m_timeout.setInterval(timeout); + + QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); +} + +void ValidationAttempt::start(NXMAccessManager& m, const QString& key) +{ + if (!sendRequest(m, key)) { + return; + } + + m_elapsed.start(); + m_timeout.start(); + + log::debug( + "validator: attempt started with timeout of {} seconds", timeout().count()); +} + +bool ValidationAttempt::sendRequest( + NXMAccessManager& m, const QString& key) +{ + const QString requestUrl(NexusBaseUrl + "/users/validate"); + QNetworkRequest request(requestUrl); + + request.setRawHeader("APIKEY", key.toUtf8()); + request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m.userAgent().toUtf8()); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); + request.setRawHeader("Protocol-Version", "1.0.0"); + request.setRawHeader("Application-Name", "MO2"); + request.setRawHeader("Application-Version", m.MOVersion().toUtf8()); + + m_reply = m.get(request); + + if (!m_reply) { + setFailure(SoftError, QObject::tr("Failed to request %1").arg(requestUrl)); + return false; + } + + QObject::connect( + m_reply, &QNetworkReply::finished, + [&]{ onFinished(); }); + + QObject::connect( + m_reply, &QNetworkReply::sslErrors, + [&](auto&& errors){ onSslErrors(errors); }); + + return true; +} + +void ValidationAttempt::cancel() +{ + if (!m_reply || m_result != None) { + // not running + return; + } + + setFailure(Cancelled, QObject::tr("Cancelled")); + + if (m_reply) { + m_reply->abort(); + } + + cleanup(); +} + +bool ValidationAttempt::done() const +{ + return (m_result != None); +} + +ValidationAttempt::Result ValidationAttempt::result() const +{ + return m_result; +} + +const QString& ValidationAttempt::message() const +{ + return m_message; +} + +std::chrono::seconds ValidationAttempt::timeout() const +{ + return std::chrono::duration_cast<std::chrono::seconds>( + m_timeout.intervalAsDuration()); +} + +QElapsedTimer ValidationAttempt::elapsed() const +{ + return m_elapsed; +} + +void ValidationAttempt::onFinished() +{ + if (m_result == Cancelled) { + return; + } + + log::debug("validator attempt: request has finished"); + + if (!m_reply) { + // shouldn't happen + log::error("validator attempt: reply is null"); + setFailure(HardError, QObject::tr("Internal error")); + return; + } + + const auto code = m_reply->attribute( + QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (code == 0) { + // request wasn't even sent + log::error("validator attempt: code is 0"); + setFailure(SoftError, m_reply->errorString()); + return; + } + + const auto doc = QJsonDocument::fromJson(m_reply->readAll()); + const auto headers = m_reply->rawHeaderPairs(); + const auto httpError = m_reply->errorString(); + + const QJsonObject data = doc.object(); + + if (code != 200) { + // http request failed + + QString s = m_reply->errorString(); + + const auto nexusMessage = data.value("message").toString(); + if (!nexusMessage.isEmpty()) { + if (!s.isEmpty()) { + s += ", "; + } + + s += nexusMessage; + } + + if (s.isEmpty()) { + s = QObject::tr("HTTP code %1").arg(code); + } else { + s += QString(" (%1)").arg(code); + } + + setFailure(SoftError, s); + return; + } + + if (doc.isNull()) { + setFailure(HardError, QObject::tr("Invalid JSON")); + return; + } + + if (!data.contains("user_id")) { + setFailure(HardError, QObject::tr("Bad response")); + return; + } + + const int id = data.value("user_id").toInt(); + const QString key = data.value("key").toString(); + const QString name = data.value("name").toString(); + const bool premium = data.value("is_premium").toBool(); + + if (key.isEmpty()) { + setFailure(HardError, QObject::tr("API key is empty")); + return; + } + + const auto user = APIUserAccount() + .apiKey(key) + .id(QString("%1").arg(id)) + .name(name) + .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular) + .limits(NexusInterface::parseLimits(headers)); + + setSuccess(user); +} + +void ValidationAttempt::onSslErrors(const QList<QSslError>& errors) +{ + log::error("validator attempt: ssl errors"); + + for (auto& e : errors) { + log::error(" . {}", e.errorString()); + } + + setFailure(HardError, QObject::tr("SSL error")); +} + +void ValidationAttempt::onTimeout() +{ + setFailure(SoftError, QObject::tr("Timed out")); +} + +void ValidationAttempt::setFailure(Result r, const QString& error) +{ + if (r != Cancelled) { + // don't spam the log + log::error("validator attempt: {}", error); + } + + cleanup(); + + m_result = r; + m_message = error; + + if (failure) { + failure(); + } +} + +void ValidationAttempt::setSuccess(const APIUserAccount& user) +{ + log::debug("validator attempt successful"); + cleanup(); + + m_result = Success; + m_message = ""; + + if (success) { + success(user); + } +} + +void ValidationAttempt::cleanup() +{ + m_timeout.stop(); + + if (m_reply) { + m_reply->disconnect(); + m_reply->deleteLater(); + m_reply = nullptr; + } +} + + +NexusKeyValidator::NexusKeyValidator(NXMAccessManager& am) + : m_manager(am) +{ +} + +NexusKeyValidator::~NexusKeyValidator() +{ + cancel(); +} + +void NexusKeyValidator::start(const QString& key, Behaviour b) +{ + if (isActive()) { + log::debug("validator: trying to start while ongoing; ignoring"); + return; + } + + m_key = key; + + switch (b) + { + case OneShot: + { + createAttempts({10s}); + break; + } + + case Retry: + { + createAttempts({5s, 5s, 10s}); + break; + } + } + + nextTry(); +} + +void NexusKeyValidator::createAttempts( + const std::vector<std::chrono::seconds>& timeouts) +{ + m_attempts.clear(); + + for (auto&& t : timeouts) { + m_attempts.push_back(std::make_unique<ValidationAttempt>(t)); + } +} + +void NexusKeyValidator::cancel() +{ + log::debug("validator: cancelled"); + + for (auto&& a : m_attempts) { + a->cancel(); + } +} + +bool NexusKeyValidator::isActive() const +{ + for (auto&& a : m_attempts) { + if (!a->done()) { + return true; + } + } + + return false; +} + +const ValidationAttempt* NexusKeyValidator::lastAttempt() const +{ + const ValidationAttempt* last = nullptr; + + for (auto&& a : m_attempts) { + if (a->done()) { + last = a.get(); + } else { + break; + } + } + + return last; +} + +const ValidationAttempt* NexusKeyValidator::currentAttempt() const +{ + for (auto&& a : m_attempts) { + if (!a->done()) { + return a.get(); + } + } + + return nullptr; } +bool NexusKeyValidator::nextTry() +{ + for (auto&& a : m_attempts) { + if (!a->done()) { + a->success = [&](auto&& user){ onAttemptSuccess(*a, user); }; + a->failure = [&]{ onAttemptFailure(*a); }; + + a->start(m_manager, m_key); + return true; + } + } + + // no more + return false; +} + +void NexusKeyValidator::onAttemptSuccess( + const ValidationAttempt& a, const APIUserAccount& u) +{ + if (attemptFinished) { + attemptFinished(a); + } + + setFinished(ValidationAttempt::Success, "", u); +} + +void NexusKeyValidator::onAttemptFailure(const ValidationAttempt& a) +{ + if (attemptFinished) { + attemptFinished(a); + } + + switch (a.result()) + { + case ValidationAttempt::SoftError: + { + if (!nextTry()) { + setFinished(a.result(), a.message(), {}); + } + + break; + } + + case ValidationAttempt::HardError: + { + cancel(); + setFinished(a.result(), a.message(), {}); + break; + } + + case ValidationAttempt::Cancelled: + { + setFinished(ValidationAttempt::Cancelled, QObject::tr("Cancelled"), {}); + break; + } + } +} + +void NexusKeyValidator::setFinished( + ValidationAttempt::Result r, const QString& message, + std::optional<APIUserAccount> user) +{ + if (finished) { + finished(r, message, user); + } +} + + NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) : QNetworkAccessManager(parent) - , m_ValidateReply(nullptr) , m_MOVersion(moVersion) + , m_validator(*this) + , m_validationState(NotChecked) { - m_ValidateTimeout.setSingleShot(true); - m_ValidateTimeout.setInterval(30000); - connect(&m_ValidateTimeout, SIGNAL(timeout()), this, SLOT(validateTimeout())); - setCookieJar(new PersistentCookieJar( - QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/nexus_cookies.dat"))); + m_validator.finished = [&](auto&& r, auto&& m, auto&& u) { + onValidatorFinished(r, m, u); + }; + + m_validator.attemptFinished = [&](auto&& a) { + onValidatorAttemptFinished(a); + }; + + setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( + Settings::instance().paths().cache() + "/nexus_cookies.dat"))); if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) { // why is this necessary all of a sudden? @@ -62,11 +776,15 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) } } -NXMAccessManager::~NXMAccessManager() +void NXMAccessManager::setTopLevelWidget(QWidget* w) { - if (m_ValidateReply != nullptr) { - m_ValidateReply->deleteLater(); - m_ValidateReply = nullptr; + if (w) { + if (m_ProgressDialog) { + m_ProgressDialog->setParentWidget(w); + } + } else { + m_ProgressDialog.reset(); + m_validator.cancel(); } } @@ -90,14 +808,13 @@ QNetworkReply *NXMAccessManager::createRequest( } } - void NXMAccessManager::showCookies() const { - QUrl url(nexusBaseUrl + "/"); + QUrl url(NexusBaseUrl + "/"); for (const QNetworkCookie &cookie : cookieJar()->cookiesForUrl(url)) { - qDebug("%s - %s (expires: %s)", + log::debug("{} - {} (expires: {})", cookie.name().constData(), cookie.value().constData(), - qUtf8Printable(cookie.expirationDate().toString())); + cookie.expirationDate().toString()); } } @@ -107,94 +824,116 @@ void NXMAccessManager::clearCookies() if (jar != nullptr) { jar->clear(); } else { - qWarning("failed to clear cookies, invalid cookie jar"); + log::warn("failed to clear cookies, invalid cookie jar"); } } -void NXMAccessManager::startValidationCheck() +void NXMAccessManager::startValidationCheck(const QString& key) { - qDebug("Checking Nexus API Key..."); - QString requestString = nexusBaseUrl + "/users/validate"; + m_validationState = NotChecked; + m_validator.start(key, NexusKeyValidator::Retry); - QNetworkRequest request(requestString); - request.setRawHeader("APIKEY", m_ApiKey.toUtf8()); - request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, userAgent().toUtf8()); - request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); - request.setRawHeader("Protocol-Version", "1.0.0"); - request.setRawHeader("Application-Name", "MO2"); - request.setRawHeader("Application-Version", m_MOVersion.toUtf8()); + if (m_ProgressDialog) { + // don't show the progress dialog on startup for the first attempt; the + // dialog will be shown in onValidatorAttemptFinished() if it failed + startProgress(); + } +} - m_ProgressDialog = new QProgressDialog(nullptr); - m_ProgressDialog->setLabelText(tr("Validating Nexus Connection")); - QList<QPushButton*> buttons = m_ProgressDialog->findChildren<QPushButton*>(); - buttons.at(0)->setEnabled(false); - m_ProgressDialog->show(); - QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback +void NXMAccessManager::onValidatorFinished( + ValidationAttempt::Result r, const QString& message, + std::optional<APIUserAccount> user) +{ + stopProgress(); - m_ValidateReply = get(request); - m_ValidateTimeout.start(); - m_ValidateState = VALIDATE_CHECKING; - connect(m_ValidateReply, SIGNAL(finished()), this, SLOT(validateFinished())); - connect(m_ValidateReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(validateError(QNetworkReply::NetworkError))); + if (user) { + m_validationState = Valid; + emit credentialsReceived(*user); + emit validateSuccessful(true); + } else { + if (r == ValidationAttempt::Cancelled) { + m_validationState = NotChecked; + } else { + m_validationState = Invalid; + emit validateFailed(message); + } + } } +void NXMAccessManager::onValidatorAttemptFinished(const ValidationAttempt& a) +{ + if (!m_ProgressDialog) { + switch (a.result()) + { + case ValidationAttempt::SoftError: + case ValidationAttempt::HardError: + { + startProgress(); + break; + } + + case ValidationAttempt::None: + case ValidationAttempt::Success: + case ValidationAttempt::Cancelled: + default: + { + // don't show the dialog + break; + } + } + } +} bool NXMAccessManager::validated() const { - if (m_ValidateState == VALIDATE_CHECKING) { - QProgressDialog progress; - progress.setLabelText(tr("Validating Nexus Connection")); - QList<QPushButton*> buttons = m_ProgressDialog->findChildren<QPushButton*>(); - buttons.at(0)->setEnabled(false); - progress.show(); - while (m_ValidateState == VALIDATE_CHECKING) { - QCoreApplication::processEvents(); - QThread::msleep(100); - } - progress.hide(); + if (m_validationState == Valid) { + return true; } - return m_ValidateState == VALIDATE_VALID; -} + if (m_validator.isActive()) { + const_cast<NXMAccessManager*>(this)->startProgress(); + } + return false; +} void NXMAccessManager::refuseValidation() { - m_ValidateState = VALIDATE_REFUSED; + m_validationState = Invalid; } - bool NXMAccessManager::validateAttempted() const { - return m_ValidateState != VALIDATE_NOT_CHECKED; + return (m_validationState != NotChecked); } - bool NXMAccessManager::validateWaiting() const { - return m_ValidateReply != nullptr; + return m_validator.isActive(); } - void NXMAccessManager::apiCheck(const QString &apiKey, bool force) { - if (m_ValidateReply != nullptr) { + if (m_validator.isActive()) { return; } if (force) { - m_ValidateState = VALIDATE_NOT_CHECKED; + m_validationState = NotChecked; } - if (m_ValidateState == VALIDATE_VALID) { + if (m_validationState == Valid) { emit validateSuccessful(false); return; } - m_ApiKey = apiKey; - startValidationCheck(); + startValidationCheck(apiKey); } +const QString& NXMAccessManager::MOVersion() const +{ + return m_MOVersion; +} QString NXMAccessManager::userAgent(const QString &subModule) const { @@ -213,109 +952,24 @@ QString NXMAccessManager::userAgent(const QString &subModule) const return QString("Mod Organizer/%1 (%2) Qt/%3").arg(m_MOVersion, comments.join("; "), qVersion()); } - -QString NXMAccessManager::apiKey() const -{ - return m_ApiKey; -} - void NXMAccessManager::clearApiKey() { - m_ApiKey = ""; - m_ValidateState = VALIDATE_NOT_VALID; - + m_validator.cancel(); emit credentialsReceived(APIUserAccount()); } -void NXMAccessManager::validateTimeout() +void NXMAccessManager::startProgress() { - m_ValidateTimeout.stop(); - if (m_ProgressDialog != nullptr) { - m_ProgressDialog->hide(); - m_ProgressDialog->deleteLater(); - m_ProgressDialog = nullptr; + if (!m_ProgressDialog) { + m_ProgressDialog.reset(new ValidationProgressDialog(m_validator)); } - m_ApiKey.clear(); - m_ValidateState = VALIDATE_NOT_VALID; - if (m_ValidateReply != nullptr) { - m_ValidateReply->deleteLater(); - m_ValidateReply = nullptr; - } - - emit validateFailed(tr("There was a timeout during the request")); -} - - -void NXMAccessManager::validateError(QNetworkReply::NetworkError) -{ - m_ValidateTimeout.stop(); - if (m_ProgressDialog != nullptr) { - m_ProgressDialog->hide(); - m_ProgressDialog->deleteLater(); - m_ProgressDialog = nullptr; - } - m_ApiKey.clear(); - m_ValidateState = VALIDATE_NOT_VALID; - - if (m_ValidateReply != nullptr) { - m_ValidateReply->disconnect(); - QString error = m_ValidateReply->errorString(); - m_ValidateReply->deleteLater(); - m_ValidateReply = nullptr; - emit validateFailed(error); - } else { - emit validateFailed(tr("Unknown error")); - } + m_ProgressDialog->start(); } - -void NXMAccessManager::validateFinished() +void NXMAccessManager::stopProgress() { - m_ValidateTimeout.stop(); - if (m_ProgressDialog != nullptr) { - m_ProgressDialog->deleteLater(); - m_ProgressDialog = nullptr; - } - - if (m_ValidateReply != nullptr) { - QJsonDocument jdoc = QJsonDocument::fromJson(m_ValidateReply->readAll()); - if (!jdoc.isNull()) { - QJsonObject credentialsData = jdoc.object(); - if (credentialsData.contains("user_id")) { - int id = credentialsData.value("user_id").toInt(); - QString name = credentialsData.value("name").toString(); - bool premium = credentialsData.value("is_premium").toBool(); - - const auto user = APIUserAccount() - .id(QString("%1").arg(id)) - .name(name) - .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular) - .limits(NexusInterface::parseLimits(m_ValidateReply)); - - - emit credentialsReceived(user); - - m_ValidateReply->deleteLater(); - m_ValidateReply = nullptr; - - m_ValidateState = VALIDATE_VALID; - emit validateSuccessful(true); - - } else { - m_ApiKey.clear(); - m_ValidateState = VALIDATE_NOT_VALID; - emit validateFailed(tr("Validation failed, please reauthenticate in the Settings -> Nexus tab: %1").arg(credentialsData.value("message").toString())); - } - } else { - m_ApiKey.clear(); - m_ValidateState = VALIDATE_NOT_CHECKED; - emit validateFailed(tr("Could not parse response. Invalid JSON.")); - } - } - else { - m_ApiKey.clear(); - m_ValidateState = VALIDATE_NOT_CHECKED; - emit validateFailed(tr("Unknown error.")); + if (m_ProgressDialog) { + m_ProgressDialog->stop(); } } |
