From 5e5681709ab878f3aa6cf1344af44e8ae9544987 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Thu, 11 Jul 2019 01:55:31 -0400 Subject: reworked the nexus connection panel moved most of the stuff into a new NexusSSOLogin class --- src/settingsdialog.cpp | 321 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 237 insertions(+), 84 deletions(-) (limited to 'src/settingsdialog.cpp') diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 95e4ceb0..d1ace6a5 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -49,6 +49,8 @@ along with Mod Organizer. If not, see . using namespace MOBase; +const QString NexusSSO("wss://sso.nexusmods.com"); +const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); class NexusManualKeyDialog : public QDialog { @@ -98,35 +100,177 @@ private: }; + +NexusSSOLogin::NexusSSOLogin() + : m_keyReceived(false), m_active(false) +{ + QObject::connect( + &m_socket, &QWebSocket::connected, + [&]{ onConnected(); }); + + QObject::connect( + &m_socket, qOverload(&QWebSocket::error), + [&](auto&& e){ onError(e); }); + + QObject::connect( + &m_socket, &QWebSocket::textMessageReceived, + [&](auto&& s){ onMessage(s); }); + + QObject::connect( + &m_socket, &QWebSocket::disconnected, + [&]{ onDisconnected(); }); + + QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); +} + +void NexusSSOLogin::start() +{ + m_active = true; + setState(ConnectingToSSO); + m_timeout.start(NXMAccessManager::ValidationTimeout); + m_socket.open(NexusSSO); +} + +void NexusSSOLogin::cancel() +{ + abort(); + setState(Cancelled); +} + +void NexusSSOLogin::close() +{ + 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; + + //if (m_guid.isEmpty()) { + 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("token"), QJsonValue(m_token)); + 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 + m_token = data["connection_token"].toString(); + + // open browser + const auto url = NexusSSOPage.arg(m_guid); + shell::OpenLink(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) { + m_active = false; + + if (!m_keyReceived) { + setState(ClosedByRemote); + } + } +} + +void NexusSSOLogin::onError(QAbstractSocket::SocketError e) +{ + if (m_active) { + setState(Error, m_socket.errorString()); + } +} + +void NexusSSOLogin::onTimeout() +{ + abort(); + setState(Timeout); +} + + SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* settings, QWidget *parent) : TutorableDialog("SettingsDialog", parent) , ui(new Ui::SettingsDialog) , m_settings(settings) , m_PluginContainer(pluginContainer) - , m_nexusLogin(new QWebSocket) - , m_KeyReceived(false) - , m_KeyCleared(false) + , m_keyChanged(false) , m_GeometriesReset(false) { + m_nexusLogin.keyChanged = [&](auto&& s){ onKeyChanged(s); }; + m_nexusLogin.stateChanged = [&](auto&& s, auto&& e){ onStateChanged(s, e); }; + ui->setupUi(this); ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}"); QShortcut *delShortcut = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem())); - connect(m_nexusLogin, SIGNAL(connected()), this, SLOT(dispatchLogin())); - connect(m_nexusLogin, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(authError(QAbstractSocket::SocketError))); - connect(m_nexusLogin, SIGNAL(textMessageReceived(const QString &)), this, SLOT(receiveApiKey(const QString &))); - connect(m_nexusLogin, SIGNAL(disconnected()), this, SLOT(completeApiConnection())); - m_loginTimer.callOnTimeout(this, &SettingsDialog::loginPing); updateNexusButtons(); } SettingsDialog::~SettingsDialog() { - m_loginTimer.stop(); - m_nexusLogin->close(); disconnect(this); delete ui; } @@ -188,7 +332,7 @@ bool SettingsDialog::getResetGeometries() bool SettingsDialog::getApiKeyChanged() { - return m_KeyReceived || m_KeyCleared; + return m_keyChanged; } void SettingsDialog::on_categoriesBtn_clicked() @@ -391,7 +535,11 @@ void SettingsDialog::on_resetDialogsButton_clicked() void SettingsDialog::on_nexusConnect_clicked() { - fetchNexusApiKey(); + if (m_nexusLogin.isActive()) { + m_nexusLogin.cancel(); + } else { + fetchNexusApiKey(); + } } void SettingsDialog::on_nexusManualKey_clicked() @@ -415,92 +563,95 @@ void SettingsDialog::on_nexusManualKey_clicked() void SettingsDialog::fetchNexusApiKey() { - QUrl url = QUrl("wss://sso.nexusmods.com"); - m_nexusLogin->open(url); + ui->nexusLog->clear(); + m_nexusLogin.start(); updateNexusButtons(); } -void SettingsDialog::dispatchLogin() +void SettingsDialog::onKeyChanged(const QString& key) { - m_KeyReceived = false; - QJsonObject login; - if (m_UUID.isEmpty()) { - boost::uuids::random_generator generator; - boost::uuids::uuid sessionId = generator(); - m_UUID = boost::uuids::to_string(sessionId).c_str(); + if (key.isEmpty()) { + clearKey(); + } else { + setKey(key); } - login.insert(QString("id"), QJsonValue(m_UUID)); - login.insert(QString("token"), QJsonValue(m_AuthToken)); - login.insert(QString("protocol"), 2); - QJsonDocument loginDoc(login); - QString finalMessage(loginDoc.toJson()); - m_nexusLogin->sendTextMessage(finalMessage); - QDesktopServices::openUrl(QUrl(QString("https://www.nexusmods.com/sso?id=%1&application=%2").arg(m_UUID).arg("modorganizer2"))); - m_loginTimer.start(30000); } -void SettingsDialog::loginPing() +void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e) { - if (m_nexusLogin->isValid()) { - m_nexusLogin->ping(); - m_totalPings++; - } - if (m_totalPings >= 60) { - m_loginTimer.stop(); - m_totalPings = 0; - m_nexusLogin->close(QWebSocketProtocol::CloseCodeGoingAway, "Timeout: No response received after thirty minutes. Cancelling request."); - } -} + QString log; -void SettingsDialog::authError(QAbstractSocket::SocketError error) -{ - auto errorInfo = m_nexusLogin->errorString(); - qCritical() << "An error occurred: " << errorInfo; -} + switch (s) + { + case NexusSSOLogin::Idle: + { + break; + } -void SettingsDialog::receiveApiKey(const QString &response) -{ - QJsonDocument responseDoc = QJsonDocument::fromJson(response.toUtf8()); - QVariantMap responseData = responseDoc.object().toVariantMap(); - if (responseData["success"].toBool()) { - QVariantMap data = responseData["data"].toMap(); - if (data.contains("connection_token")) { - m_AuthToken = data["connection_token"].toString(); - } else { - const auto key = data["api_key"].toString(); + case NexusSSOLogin::ConnectingToSSO: + { + log = tr("Connecting to Nexus..."); + break; + } + + case NexusSSOLogin::WaitingForToken: + { + log = tr("Waiting for Nexus..."); + break; + } - m_nexusLogin->close(); - m_loginTimer.stop(); - m_totalPings = 0; + case NexusSSOLogin::WaitingForBrowser: + { + log = tr("Opened browser, waiting for user..."); + break; + } - if (key.isEmpty()) { - clearKey(); - } else { - setKey(key); - } + case NexusSSOLogin::Finished: + { + log = tr("Connected."); + break; } - } else { - QString error("There was a problem with SSO initialization: %1"); - qCritical() << error.arg(responseData["error"].toString()); - m_nexusLogin->close(); - } -} -void SettingsDialog::completeApiConnection() -{ - if (!m_KeyReceived && !m_loginTimer.isActive()) { - QMessageBox::warning(qApp->activeWindow(), tr("Error"), - tr("Failed to retrieve a Nexus API key! Please try again. " - "A browser window should open asking you to authorize.")); + case NexusSSOLogin::Timeout: + { + log = QObject::tr( + "No answer from Nexus.\n" + "A firewall might be blocking Mod Organizer."); - // try again - fetchNexusApiKey(); + break; + } + + case NexusSSOLogin::ClosedByRemote: + { + log = QObject::tr("Nexus closed the connection."); + break; + } + + case NexusSSOLogin::Cancelled: + { + log = QObject::tr("Cancelled."); + break; + } + + case NexusSSOLogin::Error: + { + log = tr("Error: %1.").arg(e); + break; + } } + + if (!log.isEmpty()) { + for (auto&& line : log.split("\n")) { + ui->nexusLog->addItem(line); + } + } + + updateNexusButtons(); } bool SettingsDialog::setKey(const QString& key) { - m_KeyReceived = true; + m_keyChanged = true; const bool ret = m_settings->setNexusApiKey(key); updateNexusButtons(); return ret; @@ -508,7 +659,7 @@ bool SettingsDialog::setKey(const QString& key) bool SettingsDialog::clearKey() { - m_KeyCleared = true; + m_keyChanged = true; const auto ret = m_settings->clearNexusApiKey(); updateNexusButtons(); @@ -530,22 +681,22 @@ void SettingsDialog::testApiKey() void SettingsDialog::updateNexusButtons() { - if (m_nexusLogin->state() != QAbstractSocket::UnconnectedState) { + if (m_nexusLogin.isActive()) { // api key is in the process of being retrieved - ui->nexusConnect->setText("Connecting the API. Please login within the browser and accept the request. This will time out after 30 minutes."); - ui->nexusConnect->setEnabled(false); + ui->nexusConnect->setText(tr("Cancel")); + ui->nexusConnect->setEnabled(true); ui->nexusDisconnect->setEnabled(false); ui->nexusManualKey->setEnabled(false); } else if (m_settings->hasNexusApiKey()) { // api key is present - ui->nexusConnect->setText("Nexus API Key Stored"); + ui->nexusConnect->setText(tr("Connect to Nexus")); ui->nexusConnect->setEnabled(false); ui->nexusDisconnect->setEnabled(true); ui->nexusManualKey->setEnabled(false); } else { // api key not present - ui->nexusConnect->setText("Connect to Nexus"); + ui->nexusConnect->setText(tr("Connect to Nexus")); ui->nexusConnect->setEnabled(true); ui->nexusDisconnect->setEnabled(false); ui->nexusManualKey->setEnabled(true); @@ -622,6 +773,8 @@ void SettingsDialog::on_clearCacheButton_clicked() void SettingsDialog::on_nexusDisconnect_clicked() { clearKey(); + ui->nexusLog->clear(); + ui->nexusLog->addItem(tr("Disconnected.")); } void SettingsDialog::normalizePath(QLineEdit *lineEdit) -- cgit v1.3.1 From ad29525e982f83343dbd70e17b914e0a30adb662 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Thu, 11 Jul 2019 02:31:59 -0400 Subject: moved NexusSSOLogin to nxmaccessmanager added logs for manual key validation, will need to rewrite a few things --- src/nxmaccessmanager.cpp | 166 +++++++++++++++++++++++++++++++++++++-- src/nxmaccessmanager.h | 64 ++++++++++++++- src/settingsdialog.cpp | 198 +++++++---------------------------------------- src/settingsdialog.h | 52 +------------ 4 files changed, 250 insertions(+), 230 deletions(-) (limited to 'src/settingsdialog.cpp') diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 8bbfd536..a274261d 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -44,6 +44,8 @@ using namespace std::chrono_literals; const QString NexusBaseUrl("https://api.nexusmods.com/v1"); const std::chrono::seconds NXMAccessManager::ValidationTimeout = 10s; +const QString NexusSSO("wss://sso.nexusmods.com"); +const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t) @@ -94,7 +96,10 @@ void ValidationProgressDialog::start() void ValidationProgressDialog::stop() { - m_timer->stop(); + if (m_timer) { + m_timer->stop(); + } + hide(); } @@ -119,6 +124,153 @@ void ValidationProgressDialog::onTimer() } +NexusSSOLogin::NexusSSOLogin() + : m_keyReceived(false), m_active(false) +{ + QObject::connect( + &m_socket, &QWebSocket::connected, + [&]{ onConnected(); }); + + QObject::connect( + &m_socket, qOverload(&QWebSocket::error), + [&](auto&& e){ onError(e); }); + + QObject::connect( + &m_socket, &QWebSocket::textMessageReceived, + [&](auto&& s){ onMessage(s); }); + + QObject::connect( + &m_socket, &QWebSocket::disconnected, + [&]{ onDisconnected(); }); + + QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); +} + +void NexusSSOLogin::start() +{ + m_active = true; + setState(ConnectingToSSO); + m_timeout.start(NXMAccessManager::ValidationTimeout); + m_socket.open(NexusSSO); +} + +void NexusSSOLogin::cancel() +{ + abort(); + setState(Cancelled); +} + +void NexusSSOLogin::close() +{ + 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; + + //if (m_guid.isEmpty()) { + 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("token"), QJsonValue(m_token)); + 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 + m_token = data["connection_token"].toString(); + + // open browser + const auto url = NexusSSOPage.arg(m_guid); + shell::OpenLink(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) { + m_active = false; + + if (!m_keyReceived) { + setState(ClosedByRemote); + } + } +} + +void NexusSSOLogin::onError(QAbstractSocket::SocketError e) +{ + if (m_active) { + setState(Error, m_socket.errorString()); + } +} + +void NexusSSOLogin::onTimeout() +{ + abort(); + setState(Timeout); +} + + NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) : QNetworkAccessManager(parent) , m_ValidateReply(nullptr) @@ -192,7 +344,7 @@ void NXMAccessManager::clearCookies() } } -void NXMAccessManager::startValidationCheck() +void NXMAccessManager::startValidationCheck(bool showProgress) { qDebug("Checking Nexus API Key..."); QString requestString = NexusBaseUrl + "/users/validate"; @@ -205,7 +357,9 @@ void NXMAccessManager::startValidationCheck() request.setRawHeader("Application-Name", "MO2"); request.setRawHeader("Application-Version", m_MOVersion.toUtf8()); - m_ProgressDialog->start(); + if (showProgress) { + m_ProgressDialog->start(); + } QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback @@ -245,13 +399,13 @@ bool NXMAccessManager::validateWaiting() const } -void NXMAccessManager::apiCheck(const QString &apiKey, bool force) +void NXMAccessManager::apiCheck(const QString &apiKey, ApiCheckFlags flags) { if (m_ValidateReply != nullptr) { return; } - if (force) { + if (flags & Force) { m_ValidateState = VALIDATE_NOT_CHECKED; } @@ -261,7 +415,7 @@ void NXMAccessManager::apiCheck(const QString &apiKey, bool force) } m_ApiKey = apiKey; - startValidationCheck(); + startValidationCheck((flags & HideProgress) == 0); } diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index cbec0530..08a799f9 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include namespace MOBase { class IPluginGame; } @@ -60,6 +61,52 @@ private: }; +class NexusSSOLogin +{ +public: + enum States + { + ConnectingToSSO, + WaitingForToken, + WaitingForBrowser, + Finished, + Timeout, + ClosedByRemote, + Cancelled, + Error + }; + + std::function keyChanged; + std::function stateChanged; + + NexusSSOLogin(); + + void start(); + void cancel(); + + bool isActive() const; + +private: + QWebSocket m_socket; + QString m_guid; + bool m_keyReceived; + QString m_token; + bool m_active; + QTimer m_timeout; + + void setState(States s, const QString& error={}); + + void close(); + void abort(); + + void onConnected(); + void onMessage(const QString& s); + void onDisconnected(); + void onError(QAbstractSocket::SocketError e); + void onTimeout(); +}; + + /** * @brief access manager extended to handle nxm links **/ @@ -67,6 +114,15 @@ class NXMAccessManager : public QNetworkAccessManager { Q_OBJECT public: + enum ApiCheckFlagsEnum + { + NoFlags = 0, + Force, + HideProgress + }; + + Q_DECLARE_FLAGS(ApiCheckFlags, ApiCheckFlagsEnum) + static const std::chrono::seconds ValidationTimeout; explicit NXMAccessManager(QObject *parent, const QString &moVersion); @@ -80,7 +136,7 @@ public: bool validateAttempted() const; bool validateWaiting() const; - void apiCheck(const QString &apiKey, bool force=false); + void apiCheck(const QString &apiKey, ApiCheckFlags flags=NoFlags); void showCookies() const; @@ -91,8 +147,6 @@ public: QString apiKey() const; void clearApiKey(); - void startValidationCheck(); - void refuseValidation(); signals: @@ -145,6 +199,10 @@ private: VALIDATE_REFUSED, VALIDATE_VALID } m_ValidateState = VALIDATE_NOT_CHECKED; + + void startValidationCheck(bool showProgress); }; +Q_DECLARE_OPERATORS_FOR_FLAGS(NXMAccessManager::ApiCheckFlags); + #endif // NXMACCESSMANAGER_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index d1ace6a5..0131d20b 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -28,7 +28,6 @@ along with Mod Organizer. If not, see . #include "settings.h" #include "instancemanager.h" #include "nexusinterface.h" -#include "nxmaccessmanager.h" #include "plugincontainer.h" #include @@ -49,9 +48,6 @@ along with Mod Organizer. If not, see . using namespace MOBase; -const QString NexusSSO("wss://sso.nexusmods.com"); -const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); - class NexusManualKeyDialog : public QDialog { public: @@ -100,154 +96,6 @@ private: }; - -NexusSSOLogin::NexusSSOLogin() - : m_keyReceived(false), m_active(false) -{ - QObject::connect( - &m_socket, &QWebSocket::connected, - [&]{ onConnected(); }); - - QObject::connect( - &m_socket, qOverload(&QWebSocket::error), - [&](auto&& e){ onError(e); }); - - QObject::connect( - &m_socket, &QWebSocket::textMessageReceived, - [&](auto&& s){ onMessage(s); }); - - QObject::connect( - &m_socket, &QWebSocket::disconnected, - [&]{ onDisconnected(); }); - - QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); }); -} - -void NexusSSOLogin::start() -{ - m_active = true; - setState(ConnectingToSSO); - m_timeout.start(NXMAccessManager::ValidationTimeout); - m_socket.open(NexusSSO); -} - -void NexusSSOLogin::cancel() -{ - abort(); - setState(Cancelled); -} - -void NexusSSOLogin::close() -{ - 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; - - //if (m_guid.isEmpty()) { - 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("token"), QJsonValue(m_token)); - 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 - m_token = data["connection_token"].toString(); - - // open browser - const auto url = NexusSSOPage.arg(m_guid); - shell::OpenLink(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) { - m_active = false; - - if (!m_keyReceived) { - setState(ClosedByRemote); - } - } -} - -void NexusSSOLogin::onError(QAbstractSocket::SocketError e) -{ - if (m_active) { - setState(Error, m_socket.errorString()); - } -} - -void NexusSSOLogin::onTimeout() -{ - abort(); - setState(Timeout); -} - - SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* settings, QWidget *parent) : TutorableDialog("SettingsDialog", parent) , ui(new Ui::SettingsDialog) @@ -259,11 +107,22 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* setti m_nexusLogin.keyChanged = [&](auto&& s){ onKeyChanged(s); }; m_nexusLogin.stateChanged = [&](auto&& s, auto&& e){ onStateChanged(s, e); }; + connect( + NexusInterface::instance(m_PluginContainer)->getAccessManager(), + &NXMAccessManager::validateSuccessful, + [&]{ onManualKeyValidation(true, ""); }); + + connect( + NexusInterface::instance(m_PluginContainer)->getAccessManager(), + &NXMAccessManager::validateFailed, + [&](auto&& e){ onManualKeyValidation(false, e); }); + + ui->setupUi(this); ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}"); - QShortcut *delShortcut - = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); + QShortcut *delShortcut = new QShortcut( + QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem())); updateNexusButtons(); @@ -556,7 +415,11 @@ void SettingsDialog::on_nexusManualKey_clicked() clearKey(); } else { if (setKey(key)) { - testApiKey(); + ui->nexusLog->clear(); + ui->nexusLog->addItem(tr("Checking API key...")); + + NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck( + key, NXMAccessManager::Force | NXMAccessManager::HideProgress); } } } @@ -583,11 +446,6 @@ void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e) switch (s) { - case NexusSSOLogin::Idle: - { - break; - } - case NexusSSOLogin::ConnectingToSSO: { log = tr("Connecting to Nexus..."); @@ -649,6 +507,15 @@ void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e) updateNexusButtons(); } +void SettingsDialog::onManualKeyValidation(bool success, const QString& e) +{ + if (success) { + ui->nexusLog->addItem("Connected."); + } else { + ui->nexusLog->addItem("Error: " + e); + } +} + bool SettingsDialog::setKey(const QString& key) { m_keyChanged = true; @@ -668,17 +535,6 @@ bool SettingsDialog::clearKey() return ret; } -void SettingsDialog::testApiKey() -{ - QString key; - if (!m_settings->getNexusApiKey(key)) { - qWarning().nospace() << "can't test API key, nothing stored"; - return; - } - - NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(key, true); -} - void SettingsDialog::updateNexusButtons() { if (m_nexusLogin.isActive()) { diff --git a/src/settingsdialog.h b/src/settingsdialog.h index aee447d7..507214dd 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -21,12 +21,9 @@ along with Mod Organizer. If not, see . #define SETTINGSDIALOG_H #include "tutorabledialog.h" +#include "nxmaccessmanager.h" #include -#include -#include -#include #include -#include class PluginContainer; class Settings; @@ -35,51 +32,6 @@ namespace Ui { class SettingsDialog; } -class NexusSSOLogin -{ -public: - enum States - { - Idle, - ConnectingToSSO, - WaitingForToken, - WaitingForBrowser, - Finished, - Timeout, - ClosedByRemote, - Cancelled, - Error - }; - - std::function keyChanged; - std::function stateChanged; - - NexusSSOLogin(); - - void start(); - void cancel(); - - bool isActive() const; - -private: - QWebSocket m_socket; - QString m_guid; - bool m_keyReceived; - QString m_token; - bool m_active; - QTimer m_timeout; - - void setState(States s, const QString& error={}); - - void close(); - void abort(); - - void onConnected(); - void onMessage(const QString& s); - void onDisconnected(); - void onError(QAbstractSocket::SocketError e); - void onTimeout(); -}; /** * dialog used to change settings for Mod Organizer. On top of the @@ -197,9 +149,9 @@ private: void updateNexusButtons(); void fetchNexusApiKey(); - void testApiKey(); void onKeyChanged(const QString& key); void onStateChanged(NexusSSOLogin::States s, const QString& e); + void onManualKeyValidation(bool success, const QString& e); }; #endif // SETTINGSDIALOG_H -- cgit v1.3.1 From 226372dba2f8a06ef2349a331da91010d97e72bf Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Thu, 11 Jul 2019 05:33:35 -0400 Subject: api key validator in settings --- src/nxmaccessmanager.cpp | 4 +- src/settingsdialog.cpp | 161 +++++++++++++++++++++++++++++++++++------------ src/settingsdialog.h | 12 ++-- 3 files changed, 129 insertions(+), 48 deletions(-) (limited to 'src/settingsdialog.cpp') diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index c0a6c227..40ab19b9 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -313,7 +313,7 @@ void NexusKeyValidator::start(const QString& key) return; } - qDebug("Checking Nexus API Key..."); + m_active = true; setState(Connecting); const QString requestUrl(NexusBaseUrl + "/users/validate"); @@ -328,11 +328,11 @@ void NexusKeyValidator::start(const QString& key) m_reply = m_manager.get(request); if (!m_reply) { + close(); setState(Error, QObject::tr("Failed to request %1").arg(requestUrl)); return; } - m_active = true; m_timeout.start(NXMAccessManager::ValidationTimeout); QObject::connect( diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 0131d20b..12dbc482 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -104,20 +104,6 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* setti , m_keyChanged(false) , m_GeometriesReset(false) { - m_nexusLogin.keyChanged = [&](auto&& s){ onKeyChanged(s); }; - m_nexusLogin.stateChanged = [&](auto&& s, auto&& e){ onStateChanged(s, e); }; - - connect( - NexusInterface::instance(m_PluginContainer)->getAccessManager(), - &NXMAccessManager::validateSuccessful, - [&]{ onManualKeyValidation(true, ""); }); - - connect( - NexusInterface::instance(m_PluginContainer)->getAccessManager(), - &NXMAccessManager::validateFailed, - [&](auto&& e){ onManualKeyValidation(false, e); }); - - ui->setupUi(this); ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}"); @@ -394,44 +380,66 @@ void SettingsDialog::on_resetDialogsButton_clicked() void SettingsDialog::on_nexusConnect_clicked() { - if (m_nexusLogin.isActive()) { - m_nexusLogin.cancel(); - } else { - fetchNexusApiKey(); + if (m_nexusLogin && m_nexusLogin->isActive()) { + m_nexusLogin->cancel(); + return; } + + if (!m_nexusLogin) { + m_nexusLogin.reset(new NexusSSOLogin); + + m_nexusLogin->keyChanged = [&](auto&& s){ + onSSOKeyChanged(s); + }; + + m_nexusLogin->stateChanged = [&](auto&& s, auto&& e){ + onSSOStateChanged(s, e); + }; + } + + ui->nexusLog->clear(); + m_nexusLogin->start(); + updateNexusButtons(); } void SettingsDialog::on_nexusManualKey_clicked() { - NexusManualKeyDialog dialog(this); + if (m_nexusValidator && m_nexusValidator->isActive()) { + m_nexusValidator->cancel(); + return; + } + NexusManualKeyDialog dialog(this); if (dialog.exec() != QDialog::Accepted) { return; } const auto key = dialog.key(); - if (key.isEmpty()) { clearKey(); - } else { - if (setKey(key)) { - ui->nexusLog->clear(); - ui->nexusLog->addItem(tr("Checking API key...")); - - NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck( - key, NXMAccessManager::Force | NXMAccessManager::HideProgress); - } + return; } -} -void SettingsDialog::fetchNexusApiKey() -{ ui->nexusLog->clear(); - m_nexusLogin.start(); - updateNexusButtons(); + ui->nexusLog->addItem(tr("Checking API key...")); + + if (!m_nexusValidator) { + m_nexusValidator.reset(new NexusKeyValidator( + *NexusInterface::instance(m_PluginContainer)->getAccessManager())); + + m_nexusValidator->stateChanged = [&](auto&& s, auto&& e){ + onValidatorStateChanged(s, e); + }; + + m_nexusValidator->finished = [&](auto&& user) { + onValidatorFinished(user); + }; + } + + m_nexusValidator->start(key); } -void SettingsDialog::onKeyChanged(const QString& key) +void SettingsDialog::onSSOKeyChanged(const QString& key) { if (key.isEmpty()) { clearKey(); @@ -440,7 +448,7 @@ void SettingsDialog::onKeyChanged(const QString& key) } } -void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e) +void SettingsDialog::onSSOStateChanged(NexusSSOLogin::States s, const QString& e) { QString log; @@ -507,12 +515,72 @@ void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e) updateNexusButtons(); } -void SettingsDialog::onManualKeyValidation(bool success, const QString& e) +void SettingsDialog::onValidatorStateChanged( + NexusKeyValidator::States s, const QString& e) { - if (success) { - ui->nexusLog->addItem("Connected."); - } else { - ui->nexusLog->addItem("Error: " + e); + QString log; + + switch (s) + { + case NexusKeyValidator::Connecting: + { + log = tr("Connecting to Nexus..."); + break; + } + + case NexusKeyValidator::Finished: + { + log = tr("Connected."); + break; + } + + case NexusKeyValidator::InvalidJson: + { + log = tr("Invalid JSON"); + break; + } + + case NexusKeyValidator::BadResponse: + { + log = tr("Bad response"); + break; + } + + case NexusKeyValidator::Timeout: + { + log = QObject::tr( + "No answer from Nexus.\n" + "A firewall might be blocking Mod Organizer."); + + break; + } + + case NexusKeyValidator::Cancelled: + { + log = QObject::tr("Cancelled."); + break; + } + + case NexusKeyValidator::Error: + { + log = tr("Error: %1.").arg(e); + break; + } + } + + if (!log.isEmpty()) { + for (auto&& line : log.split("\n")) { + ui->nexusLog->addItem(line); + } + } + + updateNexusButtons(); +} + +void SettingsDialog::onValidatorFinished(const APIUserAccount& user) +{ + if (!user.apiKey().isEmpty()) { + setKey(user.apiKey()); } } @@ -537,24 +605,35 @@ bool SettingsDialog::clearKey() void SettingsDialog::updateNexusButtons() { - if (m_nexusLogin.isActive()) { + if (m_nexusLogin && m_nexusLogin->isActive()) { // api key is in the process of being retrieved ui->nexusConnect->setText(tr("Cancel")); ui->nexusConnect->setEnabled(true); ui->nexusDisconnect->setEnabled(false); + ui->nexusManualKey->setText(tr("Enter API Key Manually")); ui->nexusManualKey->setEnabled(false); } + else if (m_nexusValidator && m_nexusValidator->isActive()) { + // api key is in the process of being tested + ui->nexusConnect->setText(tr("Connect to Nexus")); + ui->nexusConnect->setEnabled(false); + ui->nexusDisconnect->setEnabled(false); + ui->nexusManualKey->setText(tr("Cancel")); + ui->nexusManualKey->setEnabled(true); + } else if (m_settings->hasNexusApiKey()) { // api key is present ui->nexusConnect->setText(tr("Connect to Nexus")); ui->nexusConnect->setEnabled(false); ui->nexusDisconnect->setEnabled(true); + ui->nexusManualKey->setText(tr("Enter API Key Manually")); ui->nexusManualKey->setEnabled(false); } else { // api key not present ui->nexusConnect->setText(tr("Connect to Nexus")); ui->nexusConnect->setEnabled(true); ui->nexusDisconnect->setEnabled(false); + ui->nexusManualKey->setText(tr("Enter API Key Manually")); ui->nexusManualKey->setEnabled(true); } } diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 507214dd..1741fc13 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -142,16 +142,18 @@ private: bool m_keyChanged; QString m_ExecutableBlacklist; - NexusSSOLogin m_nexusLogin; + std::unique_ptr m_nexusLogin; + std::unique_ptr m_nexusValidator; bool setKey(const QString& key); bool clearKey(); void updateNexusButtons(); - void fetchNexusApiKey(); - void onKeyChanged(const QString& key); - void onStateChanged(NexusSSOLogin::States s, const QString& e); - void onManualKeyValidation(bool success, const QString& e); + 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); }; #endif // SETTINGSDIALOG_H -- cgit v1.3.1 From be1ee2a97c867a80c07c4b865c306977d96249dc Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Thu, 11 Jul 2019 05:49:12 -0400 Subject: refactored state messages --- src/nxmaccessmanager.cpp | 125 ++++++++++++++++++++++++++++++----------------- src/nxmaccessmanager.h | 5 +- src/settingsdialog.cpp | 118 +++----------------------------------------- 3 files changed, 90 insertions(+), 158 deletions(-) (limited to 'src/settingsdialog.cpp') diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 40ab19b9..a331b2e8 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -153,6 +153,45 @@ NexusSSOLogin::NexusSSOLogin() 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 browser, waiting for user..."); + + case Finished: + return QObject::tr("Connected."); + + case Timeout: + return QObject::tr( + "No answer from Nexus.\n" + "A firewall might be blocking Mod Organizer."); + + case ClosedByRemote: + return QObject::tr("Nexus closed the connection."); + + 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; @@ -306,6 +345,40 @@ NexusKeyValidator::~NexusKeyValidator() abort(); } +QString NexusKeyValidator::stateToString(States s, const QString& e) +{ + switch (s) + { + case NexusKeyValidator::Connecting: + return QObject::tr("Connecting to Nexus..."); + + case NexusKeyValidator::Finished: + return QObject::tr("Finished."); + + case NexusKeyValidator::InvalidJson: + return QObject::tr("Invalid JSON"); + + case NexusKeyValidator::BadResponse: + return QObject::tr("Bad response"); + + case NexusKeyValidator::Timeout: + return QObject::tr("There was a timeout during the request"); + + case NexusKeyValidator::Cancelled: + return QObject::tr("Cancelled"); + + case NexusKeyValidator::Error: // fall-through + default: + { + if (e.isEmpty()) { + return QString("%1").arg(s); + } else { + return e; + } + } + } +} + void NexusKeyValidator::start(const QString& key) { if (m_reply) { @@ -558,45 +631,14 @@ void NXMAccessManager::startValidationCheck(const QString& key, bool showProgres 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; - } + if (s == NexusKeyValidator::Connecting || s == NexusKeyValidator::Finished) { + // no-op, success is handled in onValidatorFinished() + return; } + + m_ProgressDialog->stop(); + m_validationState = Invalid; + emit validateFailed(NexusKeyValidator::stateToString(s, e)); } void NXMAccessManager::onValidatorFinished(const APIUserAccount& user) @@ -608,13 +650,6 @@ void NXMAccessManager::onValidatorFinished(const APIUserAccount& 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_validator.isActive()) { diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 11370d65..c633ae3b 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -80,6 +80,8 @@ public: std::function keyChanged; std::function stateChanged; + static QString stateToString(States s, const QString& e); + NexusSSOLogin(); void start(); @@ -126,6 +128,8 @@ public: std::function finished; std::function stateChanged; + static QString stateToString(States s, const QString& e); + NexusKeyValidator(NXMAccessManager& am); ~NexusKeyValidator(); @@ -236,7 +240,6 @@ private: 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/settingsdialog.cpp b/src/settingsdialog.cpp index 12dbc482..df957f87 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -450,66 +450,10 @@ void SettingsDialog::onSSOKeyChanged(const QString& key) void SettingsDialog::onSSOStateChanged(NexusSSOLogin::States s, const QString& e) { - QString log; + const auto log = NexusSSOLogin::stateToString(s, e); - switch (s) - { - case NexusSSOLogin::ConnectingToSSO: - { - log = tr("Connecting to Nexus..."); - break; - } - - case NexusSSOLogin::WaitingForToken: - { - log = tr("Waiting for Nexus..."); - break; - } - - case NexusSSOLogin::WaitingForBrowser: - { - log = tr("Opened browser, waiting for user..."); - break; - } - - case NexusSSOLogin::Finished: - { - log = tr("Connected."); - break; - } - - case NexusSSOLogin::Timeout: - { - log = QObject::tr( - "No answer from Nexus.\n" - "A firewall might be blocking Mod Organizer."); - - break; - } - - case NexusSSOLogin::ClosedByRemote: - { - log = QObject::tr("Nexus closed the connection."); - break; - } - - case NexusSSOLogin::Cancelled: - { - log = QObject::tr("Cancelled."); - break; - } - - case NexusSSOLogin::Error: - { - log = tr("Error: %1.").arg(e); - break; - } - } - - if (!log.isEmpty()) { - for (auto&& line : log.split("\n")) { - ui->nexusLog->addItem(line); - } + for (auto&& line : log.split("\n")) { + ui->nexusLog->addItem(line); } updateNexusButtons(); @@ -518,60 +462,10 @@ void SettingsDialog::onSSOStateChanged(NexusSSOLogin::States s, const QString& e void SettingsDialog::onValidatorStateChanged( NexusKeyValidator::States s, const QString& e) { - QString log; - - switch (s) - { - case NexusKeyValidator::Connecting: - { - log = tr("Connecting to Nexus..."); - break; - } - - case NexusKeyValidator::Finished: - { - log = tr("Connected."); - break; - } - - case NexusKeyValidator::InvalidJson: - { - log = tr("Invalid JSON"); - break; - } - - case NexusKeyValidator::BadResponse: - { - log = tr("Bad response"); - break; - } - - case NexusKeyValidator::Timeout: - { - log = QObject::tr( - "No answer from Nexus.\n" - "A firewall might be blocking Mod Organizer."); + const auto log = NexusKeyValidator::stateToString(s, e); - break; - } - - case NexusKeyValidator::Cancelled: - { - log = QObject::tr("Cancelled."); - break; - } - - case NexusKeyValidator::Error: - { - log = tr("Error: %1.").arg(e); - break; - } - } - - if (!log.isEmpty()) { - for (auto&& line : log.split("\n")) { - ui->nexusLog->addItem(line); - } + for (auto&& line : log.split("\n")) { + ui->nexusLog->addItem(line); } updateNexusButtons(); -- 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/settingsdialog.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