From 724945ab33864c1fd8d3162bdd85ca66f8bb311d Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 7 Jul 2019 16:29:11 -0400 Subject: removed useless validationFailed() callback in MainWindow moved the log that was in it to organizer core --- src/organizercore.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 81ec7f43..65c8eb81 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -2484,6 +2484,8 @@ void OrganizerCore::loginSuccessfulUpdate(bool necessary) void OrganizerCore::loginFailed(const QString &message) { + qDebug("Nexus API validation failed: %s", qUtf8Printable(message)); + if (QMessageBox::question(qApp->activeWindow(), tr("Login failed"), tr("Login failed, try again?")) == QMessageBox::Yes) { -- cgit v1.3.1 From c0a52bc1ca3bcde8107f7cd2b8924c1dda487b1c Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Thu, 11 Jul 2019 05:06:42 -0400 Subject: extracted api key validator from NXMAccessManager api key now part of ApiUserAccount --- src/apiuseraccount.cpp | 11 ++ src/apiuseraccount.h | 13 +- src/nexusinterface.cpp | 25 ++- src/nexusinterface.h | 1 + src/nxmaccessmanager.cpp | 441 +++++++++++++++++++++++++++++++---------------- src/nxmaccessmanager.h | 86 ++++++--- src/organizercore.cpp | 3 +- 7 files changed, 403 insertions(+), 177 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/apiuseraccount.cpp b/src/apiuseraccount.cpp index b901e41a..596f8aa7 100644 --- a/src/apiuseraccount.cpp +++ b/src/apiuseraccount.cpp @@ -5,6 +5,11 @@ APIUserAccount::APIUserAccount() { } +const QString& APIUserAccount::apiKey() const +{ + return m_key; +} + const QString& APIUserAccount::id() const { return m_id; @@ -25,6 +30,12 @@ const APILimits& APIUserAccount::limits() const return m_limits; } +APIUserAccount& APIUserAccount::apiKey(const QString& key) +{ + m_key = key; + return *this; +} + APIUserAccount& APIUserAccount::id(const QString& id) { m_id = id; diff --git a/src/apiuseraccount.h b/src/apiuseraccount.h index 8a238d71..7dd16128 100644 --- a/src/apiuseraccount.h +++ b/src/apiuseraccount.h @@ -60,6 +60,12 @@ public: APIUserAccount(); + + /** + * api key + */ + const QString& apiKey() const; + /** * user id */ @@ -81,6 +87,11 @@ public: const APILimits& limits() const; + /** + * sets the api key + */ + APIUserAccount& apiKey(const QString& key); + /** * sets the user id */ @@ -120,7 +131,7 @@ public: bool exhausted() const; private: - QString m_id, m_name; + QString m_key, m_id, m_name; APIUserAccountTypes m_type; APILimits m_limits; APIStats m_stats; diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index ee9acf2c..2bcd72f3 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -207,13 +207,28 @@ APILimits NexusInterface::defaultAPILimits() } APILimits NexusInterface::parseLimits(const QNetworkReply* reply) +{ + return parseLimits(reply->rawHeaderPairs()); +} + +APILimits NexusInterface::parseLimits( + const QList& headers) { APILimits limits; - limits.maxDailyRequests = reply->rawHeader("x-rl-daily-limit").toInt(); - limits.remainingDailyRequests = reply->rawHeader("x-rl-daily-remaining").toInt(); - limits.maxHourlyRequests = reply->rawHeader("x-rl-hourly-limit").toInt(); - limits.remainingHourlyRequests = reply->rawHeader("x-rl-hourly-remaining").toInt(); + for (const auto& pair : headers) { + const auto name = QString(pair.first).toLower(); + + if (name == "x-rl-daily-limit") { + limits.maxDailyRequests = pair.second.toInt(); + } else if (name == "x-rl-daily-remaining") { + limits.remainingDailyRequests = pair.second.toInt(); + } else if (name == "x-rl-hourly-limit") { + limits.maxHourlyRequests = pair.second.toInt(); + } else if (name == "x-rl-hourly-remaining") { + limits.remainingHourlyRequests = pair.second.toInt(); + } + } return limits; } @@ -765,7 +780,7 @@ void NexusInterface::nextRequest() QNetworkRequest request(url); request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - request.setRawHeader("APIKEY", m_AccessManager->apiKey().toUtf8()); + request.setRawHeader("APIKEY", m_User.apiKey().toUtf8()); request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m_AccessManager->userAgent(info.m_SubModule)); request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); request.setRawHeader("Protocol-Version", "1.0.0"); diff --git a/src/nexusinterface.h b/src/nexusinterface.h index 6e768149..0b1763c4 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -151,6 +151,7 @@ public: public: static APILimits defaultAPILimits(); static APILimits parseLimits(const QNetworkReply* reply); + static APILimits parseLimits(const QList& headers); ~NexusInterface(); diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index a274261d..c0a6c227 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -127,6 +127,9 @@ void ValidationProgressDialog::onTimer() NexusSSOLogin::NexusSSOLogin() : m_keyReceived(false), m_active(false) { + m_timeout.setInterval(NXMAccessManager::ValidationTimeout); + m_timeout.setSingleShot(true); + QObject::connect( &m_socket, &QWebSocket::connected, [&]{ onConnected(); }); @@ -135,6 +138,10 @@ NexusSSOLogin::NexusSSOLogin() &m_socket, qOverload(&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); }); @@ -150,21 +157,25 @@ void NexusSSOLogin::start() { m_active = true; setState(ConnectingToSSO); - m_timeout.start(NXMAccessManager::ValidationTimeout); + m_timeout.start(); m_socket.open(NexusSSO); } void NexusSSOLogin::cancel() { - abort(); - setState(Cancelled); + if (m_active) { + abort(); + setState(Cancelled); + } } void NexusSSOLogin::close() { - m_active = false; - m_timeout.stop(); - m_socket.close(); + if (m_active) { + m_active = false; + m_timeout.stop(); + m_socket.close(); + } } void NexusSSOLogin::abort() @@ -261,6 +272,16 @@ void NexusSSOLogin::onError(QAbstractSocket::SocketError e) { if (m_active) { setState(Error, m_socket.errorString()); + close(); + } +} + +void NexusSSOLogin::onSslErrors(const QList& errors) +{ + if (m_active) { + for (const auto& e : errors) { + setState(Error, e.errorString()); + } } } @@ -271,18 +292,207 @@ void NexusSSOLogin::onTimeout() } +NexusKeyValidator::NexusKeyValidator(NXMAccessManager& am) + : m_manager(am), m_reply(nullptr), m_active(false) +{ + m_timeout.setInterval(NXMAccessManager::ValidationTimeout); + m_timeout.setSingleShot(true); + + QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); +} + +NexusKeyValidator::~NexusKeyValidator() +{ + abort(); +} + +void NexusKeyValidator::start(const QString& key) +{ + if (m_reply) { + abort(); + return; + } + + qDebug("Checking Nexus API Key..."); + setState(Connecting); + + const QString requestUrl(NexusBaseUrl + "/users/validate"); + QNetworkRequest request(requestUrl); + + request.setRawHeader("APIKEY", key.toUtf8()); + request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, m_manager.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_manager.MOVersion().toUtf8()); + + m_reply = m_manager.get(request); + if (!m_reply) { + setState(Error, QObject::tr("Failed to request %1").arg(requestUrl)); + return; + } + + m_active = true; + m_timeout.start(NXMAccessManager::ValidationTimeout); + + QObject::connect( + m_reply, &QNetworkReply::finished, + [&]{ onFinished(); }); + + QObject::connect( + m_reply, &QNetworkReply::sslErrors, + [&](auto&& errors){ onSslErrors(errors); }); +} + +void NexusKeyValidator::cancel() +{ + if (m_active) { + abort(); + setState(Cancelled); + } +} + +bool NexusKeyValidator::isActive() const +{ + return m_active; +} + +void NexusKeyValidator::close() +{ + m_active = false; + m_timeout.stop(); + + if (m_reply) { + m_reply->disconnect(); + m_reply->deleteLater(); + m_reply = nullptr; + } +} + +void NexusKeyValidator::abort() +{ + m_active = false; + m_timeout.stop(); + + if (m_reply) { + m_reply->disconnect(); + m_reply->abort(); + m_reply->deleteLater(); + m_reply = nullptr; + } +} + +void NexusKeyValidator::setState(States s, const QString& error) +{ + if (stateChanged) { + stateChanged(s, error); + } +} + +void NexusKeyValidator::onFinished() +{ + if (!m_reply) { + // shouldn't happen + return; + } + + m_timeout.stop(); + + const auto code = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + const auto doc = QJsonDocument::fromJson(m_reply->readAll()); + const auto headers = m_reply->rawHeaderPairs(); + const auto error = m_reply->errorString(); + + close(); + + const QJsonObject data = doc.object(); + + if (code != 200) { + handleError(code, data.value("message").toString(), error); + return; + } + + if (doc.isNull()) { + setState(InvalidJson); + return; + } + + if (!data.contains("user_id")) { + setState(BadResponse); + 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(); + + const auto user = APIUserAccount() + .apiKey(key) + .id(QString("%1").arg(id)) + .name(name) + .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular) + .limits(NexusInterface::parseLimits(headers)); + + if (finished) { + setState(Finished); + finished(user); + } +} + +void NexusKeyValidator::onSslErrors(const QList& errors) +{ + if (m_active) { + for (const auto& e : errors) { + setState(Error, e.errorString()); + } + } +} + +void NexusKeyValidator::onTimeout() +{ + abort(); + setState(Timeout); +} + +void NexusKeyValidator::handleError( + int code, const QString& nexusMessage, const QString& httpError) +{ + QString s = httpError; + + if (!nexusMessage.isEmpty()) { + if (!s.isEmpty()) { + s += ", "; + } + + s += nexusMessage; + } + + if (code != 0) { + if (s.isEmpty()) { + s = QString("HTTP code %1").arg(code); + } else { + s += QString(" (%1)").arg(code); + } + } + + setState(Error, s); +} + + + NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) : QNetworkAccessManager(parent) - , m_ValidateReply(nullptr) , m_ProgressDialog(new ValidationProgressDialog(ValidationTimeout)) , m_MOVersion(moVersion) + , m_validator(*this) + , m_validationState(NotChecked) { - m_ValidateTimeout.setSingleShot(true); - m_ValidateTimeout.setInterval(ValidationTimeout); + m_validator.stateChanged = [&](auto&& s, auto&& e){ onValidatorState(s, e); }; + m_validator.finished = [&](auto&& user){ onValidatorFinished(user); }; - connect(&m_ValidateTimeout, SIGNAL(timeout()), this, SLOT(validateTimeout())); - setCookieJar(new PersistentCookieJar( - QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/nexus_cookies.dat"))); + setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( + Settings::instance().getCacheDirectory() + "/nexus_cookies.dat"))); if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) { // why is this necessary all of a sudden? @@ -290,14 +500,6 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) } } -NXMAccessManager::~NXMAccessManager() -{ - if (m_ValidateReply != nullptr) { - m_ValidateReply->deleteLater(); - m_ValidateReply = nullptr; - } -} - void NXMAccessManager::setTopLevelWidget(QWidget* w) { m_ProgressDialog->setParentWidget(w); @@ -323,7 +525,6 @@ QNetworkReply *NXMAccessManager::createRequest( } } - void NXMAccessManager::showCookies() const { QUrl url(NexusBaseUrl + "/"); @@ -344,80 +545,122 @@ void NXMAccessManager::clearCookies() } } -void NXMAccessManager::startValidationCheck(bool showProgress) +void NXMAccessManager::startValidationCheck(const QString& key, bool showProgress) { - qDebug("Checking Nexus API Key..."); - QString requestString = NexusBaseUrl + "/users/validate"; - - 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()); + m_validationState = NotChecked; + m_validator.start(key); if (showProgress) { m_ProgressDialog->start(); } +} + +void NXMAccessManager::onValidatorState( + NexusKeyValidator::States s, const QString& e) +{ + switch (s) + { + case NexusKeyValidator::Connecting: // fall-through + case NexusKeyValidator::Finished: + { + // no-op, success is handled in onValidatorFinished() + break; + } + + case NexusKeyValidator::InvalidJson: + { + onValidatorError(tr("Invalid JSON")); + break; + } + + case NexusKeyValidator::BadResponse: + { + onValidatorError(tr("Bad response")); + break; + } + + case NexusKeyValidator::Timeout: + { + onValidatorError(tr("There was a timeout during the request")); + break; + } + + case NexusKeyValidator::Cancelled: + { + onValidatorError(tr("Cancelled")); + break; + } + + case NexusKeyValidator::Error: + { + onValidatorError(e); + break; + } + } +} - 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(const APIUserAccount& user) +{ + m_ProgressDialog->stop(); - 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))); + m_validationState = Valid; + emit credentialsReceived(user); + emit validateSuccessful(true); } +void NXMAccessManager::onValidatorError(const QString& e) +{ + m_ProgressDialog->stop(); + m_validationState = Invalid; + emit validateFailed(e); +} bool NXMAccessManager::validated() const { - if (m_ValidateState == VALIDATE_CHECKING) { + if (m_validator.isActive()) { m_ProgressDialog->show(); } - return m_ValidateState == VALIDATE_VALID; + return (m_validationState == Valid); } - 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, ApiCheckFlags flags) { - if (m_ValidateReply != nullptr) { + if (m_validator.isActive()) { return; } if (flags & 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((flags & HideProgress) == 0); + startValidationCheck(apiKey, (flags & HideProgress) == 0); } +const QString& NXMAccessManager::MOVersion() const +{ + return m_MOVersion; +} QString NXMAccessManager::userAgent(const QString &subModule) const { @@ -436,100 +679,8 @@ 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() -{ - m_ValidateTimeout.stop(); - m_ProgressDialog->stop(); - - 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(); - m_ProgressDialog->stop(); - - 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")); - } -} - - -void NXMAccessManager::validateFinished() -{ - m_ValidateTimeout.stop(); - m_ProgressDialog->stop(); - - 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.")); - } -} diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 08a799f9..11370d65 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see . #include namespace MOBase { class IPluginGame; } +class NXMAccessManager; class ValidationProgressDialog : private QDialog { @@ -103,10 +104,56 @@ private: void onMessage(const QString& s); void onDisconnected(); void onError(QAbstractSocket::SocketError e); + void onSslErrors(const QList& errors); void onTimeout(); }; +class NexusKeyValidator +{ +public: + enum States + { + Connecting, + Finished, + InvalidJson, + BadResponse, + Timeout, + Cancelled, + Error + }; + + std::function finished; + std::function stateChanged; + + NexusKeyValidator(NXMAccessManager& am); + ~NexusKeyValidator(); + + void start(const QString& key); + void cancel(); + + bool isActive() const; + +private: + NXMAccessManager& m_manager; + QNetworkReply* m_reply; + QTimer m_timeout; + bool m_active; + + void setState(States s, const QString& error={}); + + void close(); + void abort(); + + void onFinished(); + void onSslErrors(const QList& errors); + void onTimeout(); + + void handleError( + int code, const QString& nexusMessage, const QString& httpError); +}; + + /** * @brief access manager extended to handle nxm links **/ @@ -127,7 +174,6 @@ public: explicit NXMAccessManager(QObject *parent, const QString &moVersion); - ~NXMAccessManager(); void setTopLevelWidget(QWidget* w); @@ -143,8 +189,8 @@ public: void clearCookies(); QString userAgent(const QString &subModule = QString()) const; + const QString& MOVersion() const; - QString apiKey() const; void clearApiKey(); void refuseValidation(); @@ -164,17 +210,9 @@ signals: * @param necessary true if a login was necessary and succeeded, false if the user is still logged in **/ void validateSuccessful(bool necessary); - void validateFailed(const QString &message); - void credentialsReceived(const APIUserAccount& user); -private slots: - - void validateFinished(); - void validateError(QNetworkReply::NetworkError errorCode); - void validateTimeout(); - protected: virtual QNetworkReply *createRequest( @@ -182,25 +220,23 @@ protected: QIODevice *device); private: + enum States + { + NotChecked, + Valid, + Invalid + }; + QWidget* m_TopLevel; - QTimer m_ValidateTimeout; - QNetworkReply *m_ValidateReply; mutable ValidationProgressDialog* m_ProgressDialog; - QString m_MOVersion; + NexusKeyValidator m_validator; + States m_validationState; - QString m_ApiKey; - - enum { - VALIDATE_NOT_CHECKED, - VALIDATE_CHECKING, - VALIDATE_NOT_VALID, - VALIDATE_ATTEMPT_FAILED, - VALIDATE_REFUSED, - VALIDATE_VALID - } m_ValidateState = VALIDATE_NOT_CHECKED; - - void startValidationCheck(bool showProgress); + void startValidationCheck(const QString& key, bool showProgress); + void onValidatorState(NexusKeyValidator::States s, const QString& e); + void onValidatorFinished(const APIUserAccount& user); + void onValidatorError(const QString& e); }; Q_DECLARE_OPERATORS_FOR_FLAGS(NXMAccessManager::ApiCheckFlags); diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 65c8eb81..87668f4b 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -2484,7 +2484,8 @@ void OrganizerCore::loginSuccessfulUpdate(bool necessary) void OrganizerCore::loginFailed(const QString &message) { - qDebug("Nexus API validation failed: %s", qUtf8Printable(message)); + qDebug().nospace().noquote() + << "Nexus API validation failed: " << message; if (QMessageBox::question(qApp->activeWindow(), tr("Login failed"), tr("Login failed, try again?")) -- cgit v1.3.1 From 45f0a9e78ac876a2a956bc538c6d34358703e338 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 12 Jul 2019 02:46:31 -0400 Subject: nexus info and stats in settings cleaned up double logging for github reset validation progress dialog parent just before the main window dies removed unused APIStats from APIUserAccount, added isValid() --- src/apiuseraccount.cpp | 22 +++++ src/apiuseraccount.h | 8 +- src/main.cpp | 8 +- src/nxmaccessmanager.cpp | 2 +- src/organizercore.cpp | 2 +- src/selfupdater.cpp | 2 +- src/settingsdialog.cpp | 98 ++++++++++++++++----- src/settingsdialog.h | 6 ++ src/settingsdialog.ui | 218 +++++++++++++++++++++++------------------------ 9 files changed, 226 insertions(+), 140 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/apiuseraccount.cpp b/src/apiuseraccount.cpp index 596f8aa7..35a868d5 100644 --- a/src/apiuseraccount.cpp +++ b/src/apiuseraccount.cpp @@ -1,10 +1,32 @@ #include "apiuseraccount.h" +QString localizedUserAccountType(APIUserAccountTypes t) +{ + switch (t) + { + case APIUserAccountTypes::Regular: + return QObject::tr("Regular"); + + case APIUserAccountTypes::Premium: + return QObject::tr("Premium"); + + case APIUserAccountTypes::None: // fall-through + default: + return QObject::tr("None"); + } +} + + APIUserAccount::APIUserAccount() : m_type(APIUserAccountTypes::None) { } +bool APIUserAccount::isValid() const +{ + return !m_key.isEmpty(); +} + const QString& APIUserAccount::apiKey() const { return m_key; diff --git a/src/apiuseraccount.h b/src/apiuseraccount.h index 7dd16128..ea4e8685 100644 --- a/src/apiuseraccount.h +++ b/src/apiuseraccount.h @@ -18,6 +18,8 @@ enum class APIUserAccountTypes Premium }; +QString localizedUserAccountType(APIUserAccountTypes t); + /** * current limits imposed on the user account @@ -61,6 +63,11 @@ public: APIUserAccount(); + /** + * whether the user is logged in + */ + bool isValid() const; + /** * api key */ @@ -134,7 +141,6 @@ private: QString m_key, m_id, m_name; APIUserAccountTypes m_type; APILimits m_limits; - APIStats m_stats; }; #endif // APIUSERACCOUNT_H diff --git a/src/main.cpp b/src/main.cpp index 0b078f03..4359c645 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -713,7 +713,13 @@ int runApplication(MOApplication &application, SingleInstance &instance, mainWindow.activateWindow(); splash.finish(&mainWindow); - return application.exec(); + + const auto ret = application.exec(); + + NexusInterface::instance(&pluginContainer) + ->getAccessManager()->setTopLevelWidget(nullptr); + + return ret; } } catch (const std::exception &e) { reportError(e.what()); diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index a331b2e8..196368fd 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -167,7 +167,7 @@ QString NexusSSOLogin::stateToString(States s, const QString& e) return QObject::tr("Opened browser, waiting for user..."); case Finished: - return QObject::tr("Connected."); + return QObject::tr("Finished."); case Timeout: return QObject::tr( diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 87668f4b..eeb69e61 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -2484,7 +2484,7 @@ void OrganizerCore::loginSuccessfulUpdate(bool necessary) void OrganizerCore::loginFailed(const QString &message) { - qDebug().nospace().noquote() + qCritical().nospace().noquote() << "Nexus API validation failed: " << message; if (QMessageBox::question(qApp->activeWindow(), tr("Login failed"), diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 271c621b..e967b27c 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -130,7 +130,7 @@ void SelfUpdater::testForUpdate() m_GitHub.releases(GitHub::Repository("Modorganizer2", "modorganizer"), [this](const QJsonArray &releases) { if (releases.isEmpty()) { - qDebug("Unable to connect to github.com to check version"); + // error message already logged return; } diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index df957f87..0dae31ac 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -55,6 +55,7 @@ public: : QDialog(parent), ui(new Ui::NexusManualKeyDialog) { ui->setupUi(this); + ui->key->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); connect(ui->openBrowser, &QPushButton::clicked, [&]{ openBrowser(); }); connect(ui->paste, &QPushButton::clicked, [&]{ paste(); }); @@ -111,7 +112,7 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* setti QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem())); - updateNexusButtons(); + updateNexusState(); } SettingsDialog::~SettingsDialog() @@ -399,7 +400,7 @@ void SettingsDialog::on_nexusConnect_clicked() ui->nexusLog->clear(); m_nexusLogin->start(); - updateNexusButtons(); + updateNexusState(); } void SettingsDialog::on_nexusManualKey_clicked() @@ -421,8 +422,18 @@ void SettingsDialog::on_nexusManualKey_clicked() } ui->nexusLog->clear(); - ui->nexusLog->addItem(tr("Checking API key...")); + validateKey(key); +} + +void SettingsDialog::on_nexusDisconnect_clicked() +{ + clearKey(); + ui->nexusLog->clear(); + addNexusLog(tr("Disconnected.")); +} +void SettingsDialog::validateKey(const QString& key) +{ if (!m_nexusValidator) { m_nexusValidator.reset(new NexusKeyValidator( *NexusInterface::instance(m_PluginContainer)->getAccessManager())); @@ -436,6 +447,7 @@ void SettingsDialog::on_nexusManualKey_clicked() }; } + addNexusLog(tr("Checking API key...")); m_nexusValidator->start(key); } @@ -444,45 +456,62 @@ void SettingsDialog::onSSOKeyChanged(const QString& key) if (key.isEmpty()) { clearKey(); } else { - setKey(key); + addNexusLog(tr("Received API key.")); + validateKey(key); } } void SettingsDialog::onSSOStateChanged(NexusSSOLogin::States s, const QString& e) { - const auto log = NexusSSOLogin::stateToString(s, e); + if (s != NexusSSOLogin::Finished) { + // finished state is handled in onSSOKeyChanged() + const auto log = NexusSSOLogin::stateToString(s, e); - for (auto&& line : log.split("\n")) { - ui->nexusLog->addItem(line); + for (auto&& line : log.split("\n")) { + addNexusLog(line); + } } - updateNexusButtons(); + updateNexusState(); } void SettingsDialog::onValidatorStateChanged( NexusKeyValidator::States s, const QString& e) { - const auto log = NexusKeyValidator::stateToString(s, e); + if (s != NexusKeyValidator::Finished) { + // finished state is handled in onValidatorFinished() + const auto log = NexusKeyValidator::stateToString(s, e); - for (auto&& line : log.split("\n")) { - ui->nexusLog->addItem(line); + for (auto&& line : log.split("\n")) { + addNexusLog(line); + } } - updateNexusButtons(); + updateNexusState(); } void SettingsDialog::onValidatorFinished(const APIUserAccount& user) { + NexusInterface::instance(m_PluginContainer)->setUserAccount(user); + if (!user.apiKey().isEmpty()) { - setKey(user.apiKey()); + if (setKey(user.apiKey())) { + addNexusLog(tr("Linked with Nexus successfully.")); + } } } +void SettingsDialog::addNexusLog(const QString& s) +{ + ui->nexusLog->addItem(s); + ui->nexusLog->scrollToBottom(); +} + bool SettingsDialog::setKey(const QString& key) { m_keyChanged = true; const bool ret = m_settings->setNexusApiKey(key); - updateNexusButtons(); + updateNexusState(); return ret; } @@ -490,13 +519,19 @@ bool SettingsDialog::clearKey() { m_keyChanged = true; const auto ret = m_settings->clearNexusApiKey(); - updateNexusButtons(); NexusInterface::instance(m_PluginContainer)->getAccessManager()->clearApiKey(); + updateNexusState(); return ret; } +void SettingsDialog::updateNexusState() +{ + updateNexusButtons(); + updateNexusData(); +} + void SettingsDialog::updateNexusButtons() { if (m_nexusLogin && m_nexusLogin->isActive()) { @@ -532,6 +567,32 @@ void SettingsDialog::updateNexusButtons() } } +void SettingsDialog::updateNexusData() +{ + const auto user = NexusInterface::instance(m_PluginContainer) + ->getAPIUserAccount(); + + if (user.isValid()) { + ui->nexusUserID->setText(user.id()); + ui->nexusName->setText(user.name()); + ui->nexusAccount->setText(localizedUserAccountType(user.type())); + + ui->nexusDailyRequests->setText(QString("%1/%2") + .arg(user.limits().remainingDailyRequests) + .arg(user.limits().maxDailyRequests)); + + ui->nexusHourlyRequests->setText(QString("%1/%2") + .arg(user.limits().remainingHourlyRequests) + .arg(user.limits().maxHourlyRequests)); + } else { + ui->nexusUserID->setText(tr("N/A")); + ui->nexusName->setText(tr("N/A")); + ui->nexusAccount->setText(tr("N/A")); + ui->nexusDailyRequests->setText(tr("N/A")); + ui->nexusHourlyRequests->setText(tr("N/A")); + } +} + void SettingsDialog::storeSettings(QListWidgetItem *pluginItem) { if (pluginItem != nullptr) { @@ -599,13 +660,6 @@ void SettingsDialog::on_clearCacheButton_clicked() NexusInterface::instance(m_PluginContainer)->clearCache(); } -void SettingsDialog::on_nexusDisconnect_clicked() -{ - clearKey(); - ui->nexusLog->clear(); - ui->nexusLog->addItem(tr("Disconnected.")); -} - void SettingsDialog::normalizePath(QLineEdit *lineEdit) { QString text = lineEdit->text(); diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 1741fc13..c5f487fd 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -145,15 +145,21 @@ private: std::unique_ptr m_nexusLogin; std::unique_ptr m_nexusValidator; + void validateKey(const QString& key); bool setKey(const QString& key); bool clearKey(); + + void updateNexusState(); void updateNexusButtons(); + void updateNexusData(); void onSSOKeyChanged(const QString& key); void onSSOStateChanged(NexusSSOLogin::States s, const QString& e); void onValidatorStateChanged(NexusKeyValidator::States s, const QString& e); void onValidatorFinished(const APIUserAccount& user); + + void addNexusLog(const QString& s); }; #endif // SETTINGSDIALOG_H diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index dfbde943..fccc8be0 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -451,103 +451,7 @@ If you use pre-releases, never contact me directly by e-mail or via private mess Nexus - - - - - Nexus Connection - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Connect to Nexus - - - - - - - Manually enter the API key and try to login - - - Enter API Key Manually - - - - - - - Clear the stored Nexus API key and force reauthorization. - - - Disconnect from Nexus - - - - :/MO/gui/edit_clear:/MO/gui/edit_clear - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractScrollArea::AdjustToContents - - - - - - - - - + @@ -569,10 +473,13 @@ If you use pre-releases, never contact me directly by e-mail or via private mess Nexus Account + + 10 + - User ID + User ID: Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse @@ -589,21 +496,21 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - Username + Name: - + - username + name - Account + Account: @@ -623,17 +530,27 @@ If you use pre-releases, never contact me directly by e-mail or via private mess Statistics + + 10 + - Daily requests + Daily requests: + + + + + + + daily requests - Hourly requests + Hourly requests: @@ -644,24 +561,99 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - - + + + + + + + + + + Nexus Connection + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + - Requests queued + Connect to Nexus - - + + + + Manually enter the API key and try to login + - queued + Enter API Key Manually - - + + + + Clear the stored Nexus API key and force reauthorization. + - daily requests + Disconnect from Nexus + + + + :/MO/gui/edit_clear:/MO/gui/edit_clear + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractScrollArea::AdjustToContents -- cgit v1.3.1