From 5716676e083bde4a6f2ddb57a683df85b96c2d04 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 26 May 2019 08:14:21 -0400 Subject: fixes for /permissive-: - no implicit conversions for enum classes - can't bind rvalue to non-const ref - string literals are const --- src/settingsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/settingsdialog.cpp') diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 74091469..7f53a9bb 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -88,7 +88,7 @@ QString SettingsDialog::getColoredButtonStyleSheet() const "}"); } -void SettingsDialog::setButtonColor(QPushButton *button, QColor &color) +void SettingsDialog::setButtonColor(QPushButton *button, const QColor &color) { button->setStyleSheet( QString("QPushButton {" -- cgit v1.3.1 From 933f460ee61a89ff71038c478de92d6c3760cc9a Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 3 Jun 2019 17:20:31 -0400 Subject: added new dialog to enter api key manually added button in nexus settings to open the dialog added a force flag to apiCheck() to do a check with the new key even if the login was successful before --- src/nexusmanualkey.ui | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ src/nxmaccessmanager.cpp | 6 +++- src/nxmaccessmanager.h | 2 +- src/settingsdialog.cpp | 43 +++++++++++++++++++++++ src/settingsdialog.h | 2 ++ src/settingsdialog.ui | 16 +++++++++ 6 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/nexusmanualkey.ui (limited to 'src/settingsdialog.cpp') diff --git a/src/nexusmanualkey.ui b/src/nexusmanualkey.ui new file mode 100644 index 00000000..191ca218 --- /dev/null +++ b/src/nexusmanualkey.ui @@ -0,0 +1,89 @@ + + + NexusManualKeyDialog + + + + 0 + 0 + 452 + 302 + + + + Dialog + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Enter API key here + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + NexusManualKeyDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NexusManualKeyDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 00bb2a91..684a53fa 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -176,12 +176,16 @@ bool NXMAccessManager::validateWaiting() const } -void NXMAccessManager::apiCheck(const QString &apiKey) +void NXMAccessManager::apiCheck(const QString &apiKey, bool force) { if (m_ValidateReply != nullptr) { return; } + if (force) { + m_ValidateState = VALIDATE_NOT_CHECKED; + } + if (m_ValidateState == VALIDATE_VALID) { emit validateSuccessful(false); return; diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 54ae14fb..e3608f8d 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -46,7 +46,7 @@ public: bool validateAttempted() const; bool validateWaiting() const; - void apiCheck(const QString &apiKey); + void apiCheck(const QString &apiKey, bool force=false); void showCookies() const; diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 7f53a9bb..44d7fde5 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see . #include "settingsdialog.h" #include "ui_settingsdialog.h" +#include "ui_nexusmanualkey.h" #include "categoriesdialog.h" #include "helper.h" #include "noeditdelegate.h" @@ -27,6 +28,7 @@ along with Mod Organizer. If not, see . #include "settings.h" #include "instancemanager.h" #include "nexusinterface.h" +#include "nxmaccessmanager.h" #include "plugincontainer.h" #include @@ -47,6 +49,33 @@ along with Mod Organizer. If not, see . using namespace MOBase; + +class NexusManualKeyDialog : public QDialog +{ +public: + NexusManualKeyDialog(QWidget* parent) + : QDialog(parent), ui(new Ui::NexusManualKeyDialog) + { + ui->setupUi(this); + } + + void accept() override + { + m_key = ui->key->toPlainText(); + QDialog::accept(); + } + + const QString& key() const + { + return m_key; + } + +private: + std::unique_ptr ui; + QString m_key; +}; + + SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, QWidget *parent) : TutorableDialog("SettingsDialog", parent) , ui(new Ui::SettingsDialog) @@ -344,6 +373,20 @@ void SettingsDialog::on_nexusConnect_clicked() m_nexusLogin->open(url); } +void SettingsDialog::on_nexusManualKey_clicked() +{ + NexusManualKeyDialog dialog(this); + + if (dialog.exec() != QDialog::Accepted) { + return; + } + + const auto key = dialog.key(); + emit processApiKey(key); + ui->nexusConnect->setText("Nexus API Key Stored"); + NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(key, true); +} + void SettingsDialog::dispatchLogin() { m_KeyReceived = false; diff --git a/src/settingsdialog.h b/src/settingsdialog.h index afe988bd..a844b391 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -156,6 +156,8 @@ private slots: void on_nexusConnect_clicked(); + void on_nexusManualKey_clicked(); + void dispatchLogin(); void loginPing(); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index fa8893b9..088b7a0d 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -494,6 +494,22 @@ p, li { white-space: pre-wrap; } + + + + + 0 + 0 + + + + Manually enter the API key and try to login + + + Enter API Key Manually + + + -- cgit v1.3.1 From 2db29cffda538c6a9be24dff705e1d032bd42008 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 4 Jun 2019 20:58:30 -0400 Subject: renamed "revoke nexus authorization" to "disconnect from nexus" because "revoking" is ambiguous reworked manual key dialog to look more like MO1 moved all the UI stuff from callbacks in Settings back to SettingsDialog in a central updateNexusButtons(), which also enables/disables buttons as needed --- src/nexusmanualkey.ui | 156 ++++++++++++++++++++++++++++++++++++++++++++++--- src/settings.cpp | 78 +++++++++---------------- src/settings.h | 30 ++++++---- src/settingsdialog.cpp | 129 ++++++++++++++++++++++++++++++++++------ src/settingsdialog.h | 101 +++++++++++--------------------- src/settingsdialog.ui | 4 +- 6 files changed, 341 insertions(+), 157 deletions(-) (limited to 'src/settingsdialog.cpp') diff --git a/src/nexusmanualkey.ui b/src/nexusmanualkey.ui index 191ca218..1a842dc3 100644 --- a/src/nexusmanualkey.ui +++ b/src/nexusmanualkey.ui @@ -7,16 +7,16 @@ 0 0 452 - 302 + 236 Dialog - + - + 0 @@ -30,10 +30,152 @@ 0 - - - Enter API key here - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1. Get your personal API key + + + + + + + Open Browser + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 2. Enter your personal API key + + + + + + + Qt::Horizontal + + + + 115 + 20 + + + + + + + + Paste + + + + + + + Clear + + + + + + + + + + + 0 + 0 + + + + + 1 + 1 + + + + Enter API key here + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + <b>Sharing this key with anyone could get your Nexus account banned. You can always revoke this key from your account on the Nexus website.</b> + + + true + + + + diff --git a/src/settings.cpp b/src/settings.cpp index a844fdc9..53dd32dc 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -363,6 +363,32 @@ bool Settings::getNexusApiKey(QString &apiKey) const return true; } +bool Settings::setNexusApiKey(const QString& apiKey) +{ + if (!obfuscate("APIKEY", apiKey)) { + wchar_t buffer[256]; + + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buffer, (sizeof(buffer) / sizeof(wchar_t)), NULL); + + qCritical() << "Storing API key failed:" << buffer; + return false; + } + + return true; +} + +bool Settings::clearNexusApiKey() +{ + return setNexusApiKey(""); +} + +bool Settings::hasNexusApiKey() const +{ + return !deObfuscate("APIKEY").isEmpty(); +} + bool Settings::getSteamLogin(QString &username, QString &password) const { if (m_Settings.contains("Settings/steam_username")) { @@ -452,17 +478,6 @@ QString Settings::executablesBlacklist() const ).toString(); } -void Settings::setNexusApiKey(QString apiKey) -{ - if (!obfuscate("APIKEY", apiKey)) { - wchar_t buffer[256]; - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buffer, (sizeof(buffer) / sizeof(wchar_t)), NULL); - qCritical() << "Storing API key failed:" << buffer; - } -} - void Settings::setSteamLogin(QString username, QString password) { if (username == "") { @@ -706,43 +721,10 @@ void Settings::resetDialogs() QuestionBoxMemory::resetDialogs(); } -void Settings::processApiKey(const QString &apiKey) -{ - if (!obfuscate("APIKEY", apiKey)) { - wchar_t buffer[256]; - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buffer, (sizeof(buffer) / sizeof(wchar_t)), NULL); - qCritical() << "Storing or deleting API key failed:" << buffer; - } -} - -void Settings::clearApiKey(QPushButton *nexusButton) -{ - obfuscate("APIKEY", ""); - nexusButton->setEnabled(true); - nexusButton->setText("Connect to Nexus"); -} - -void Settings::checkApiKey(QPushButton *nexusButton) -{ - if (deObfuscate("APIKEY").isEmpty()) { - nexusButton->setEnabled(true); - nexusButton->setText("Connect to Nexus"); - 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.")); - } -} - void Settings::query(PluginContainer *pluginContainer, QWidget *parent) { - SettingsDialog dialog(pluginContainer, parent); - + SettingsDialog dialog(pluginContainer, this, parent); connect(&dialog, SIGNAL(resetDialogs()), this, SLOT(resetDialogs())); - connect(&dialog, SIGNAL(processApiKey(const QString &)), this, SLOT(processApiKey(const QString &))); - connect(&dialog, SIGNAL(closeApiConnection(QPushButton *)), this, SLOT(checkApiKey(QPushButton *))); - connect(&dialog, SIGNAL(revokeApiKey(QPushButton *)), this, SLOT(clearApiKey(QPushButton *))); std::vector> tabs; @@ -1043,7 +1025,6 @@ void Settings::DiagnosticsTab::update() Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog) : Settings::SettingsTab(parent, dialog) - , m_nexusConnect(dialog.findChild("nexusConnect")) , m_offlineBox(dialog.findChild("offlineBox")) , m_proxyBox(dialog.findChild("proxyBox")) , m_knownServersList(dialog.findChild("knownServersList")) @@ -1052,11 +1033,6 @@ Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog) , m_endorsementBox(dialog.findChild("endorsementBox")) , m_hideAPICounterBox(dialog.findChild("hideAPICounterBox")) { - if (!deObfuscate("APIKEY").isEmpty()) { - m_nexusConnect->setText("Nexus API Key Stored"); - m_nexusConnect->setDisabled(true); - } - m_offlineBox->setChecked(parent->offlineMode()); m_proxyBox->setChecked(parent->useProxy()); m_endorsementBox->setChecked(parent->endorsementIntegration()); diff --git a/src/settings.h b/src/settings.h index 04a0646e..bccd1e81 100644 --- a/src/settings.h +++ b/src/settings.h @@ -187,6 +187,24 @@ public: **/ bool getNexusApiKey(QString &apiKey) const; + /** + * @brief set the nexus login information + * + * @param username username + * @param password password + */ + bool setNexusApiKey(const QString& apiKey); + + /** + * @brief clears the nexus login information + */ + bool clearNexusApiKey(); + + /** + * @brief returns whether an API key is currently stored + */ + bool hasNexusApiKey() const; + /** * @brief retrieve the login information for steam * @@ -240,14 +258,6 @@ public: QString executablesBlacklist() const; - /** - * @brief set the nexus login information - * - * @param username username - * @param password password - */ - void setNexusApiKey(QString apiKey); - /** * @brief set the steam login information * @@ -481,7 +491,6 @@ private: void update(); private: - QPushButton *m_nexusConnect; QCheckBox *m_offlineBox; QCheckBox *m_proxyBox; QListWidget *m_knownServersList; @@ -538,9 +547,6 @@ private: private slots: void resetDialogs(); - void processApiKey(const QString &); - void clearApiKey(QPushButton *nexusButton); - void checkApiKey(QPushButton *nexusButton); signals: diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 44d7fde5..0373cef6 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -57,6 +57,10 @@ public: : QDialog(parent), ui(new Ui::NexusManualKeyDialog) { ui->setupUi(this); + + connect(ui->openBrowser, &QPushButton::clicked, [&]{ openBrowser(); }); + connect(ui->paste, &QPushButton::clicked, [&]{ paste(); }); + connect(ui->clear, &QPushButton::clicked, [&]{ clear(); }); } void accept() override @@ -70,15 +74,34 @@ public: return m_key; } + void openBrowser() + { + shell::OpenLink(QUrl("https://www.nexusmods.com/users/myaccount?tab=api")); + } + + void paste() + { + const auto text = QApplication::clipboard()->text(); + if (!text.isEmpty()) { + ui->key->setPlainText(text); + } + } + + void clear() + { + ui->key->clear(); + } + private: std::unique_ptr ui; QString m_key; }; -SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, QWidget *parent) +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) @@ -95,8 +118,9 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, QWidget *parent 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())); - connect(this, SIGNAL(retryApiConnection()), this, SLOT(on_nexusConnect_clicked())); m_loginTimer.callOnTimeout(this, &SettingsDialog::loginPing); + + updateNexusButtons(); } SettingsDialog::~SettingsDialog() @@ -367,10 +391,7 @@ void SettingsDialog::on_resetDialogsButton_clicked() void SettingsDialog::on_nexusConnect_clicked() { - ui->nexusConnect->setText("Connecting the API. Please login within the browser and accept the request. This will time out after 30 minutes."); - ui->nexusConnect->setDisabled(true); - QUrl url = QUrl("wss://sso.nexusmods.com"); - m_nexusLogin->open(url); + fetchNexusApiKey(); } void SettingsDialog::on_nexusManualKey_clicked() @@ -382,9 +403,21 @@ void SettingsDialog::on_nexusManualKey_clicked() } const auto key = dialog.key(); - emit processApiKey(key); - ui->nexusConnect->setText("Nexus API Key Stored"); - NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(key, true); + + if (key.isEmpty()) { + clearKey(); + } else { + if (setKey(key)) { + testApiKey(); + } + } +} + +void SettingsDialog::fetchNexusApiKey() +{ + QUrl url = QUrl("wss://sso.nexusmods.com"); + m_nexusLogin->open(url); + updateNexusButtons(); } void SettingsDialog::dispatchLogin() @@ -434,12 +467,17 @@ void SettingsDialog::receiveApiKey(const QString &response) if (data.contains("connection_token")) { m_AuthToken = data["connection_token"].toString(); } else { - m_KeyReceived = true; - emit processApiKey(data["api_key"].toString()); + const auto key = data["api_key"].toString(); + m_nexusLogin->close(); - ui->nexusConnect->setText("Nexus API Key Stored"); m_loginTimer.stop(); m_totalPings = 0; + + if (key.isEmpty()) { + clearKey(); + } else { + setKey(key); + } } } else { QString error("There was a problem with SSO initialization: %1"); @@ -450,10 +488,64 @@ void SettingsDialog::receiveApiKey(const QString &response) void SettingsDialog::completeApiConnection() { - if (m_KeyReceived == true || !m_loginTimer.isActive()) - emit closeApiConnection(ui->nexusConnect); - else - emit retryApiConnection(); + 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.")); + + // try again + fetchNexusApiKey(); + } +} + +bool SettingsDialog::setKey(const QString& key) +{ + m_KeyReceived = true; + const bool ret = m_settings->setNexusApiKey(key); + updateNexusButtons(); + return ret; +} + +bool SettingsDialog::clearKey() +{ + m_KeyCleared = true; + const auto ret = m_settings->clearNexusApiKey(); + updateNexusButtons(); + return ret; +} + +void SettingsDialog::testApiKey() +{ + QString key; + if (!m_settings->getNexusApiKey(key)) { + qWarning().nospace() << "can't test API key, nothing stored"; + return; + } + + auto* am = NexusInterface::instance(m_PluginContainer)->getAccessManager(); + am->apiCheck(key, true); +} + +void SettingsDialog::updateNexusButtons() +{ + if (m_nexusLogin->state() != QAbstractSocket::UnconnectedState) { + // 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); + } + else if (m_settings->hasNexusApiKey()) { + // api key is present + ui->nexusConnect->setText("Nexus API Key Stored"); + 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->setEnabled(true); + ui->nexusDisconnect->setEnabled(false); + ui->nexusManualKey->setEnabled(true); + } } void SettingsDialog::storeSettings(QListWidgetItem *pluginItem) @@ -523,10 +615,9 @@ void SettingsDialog::on_clearCacheButton_clicked() NexusInterface::instance(m_PluginContainer)->clearCache(); } -void SettingsDialog::on_revokeNexusAuthButton_clicked() +void SettingsDialog::on_nexusDisconnect_clicked() { - emit revokeApiKey(ui->nexusConnect); - m_KeyCleared = true; + clearKey(); } void SettingsDialog::normalizePath(QLineEdit *lineEdit) diff --git a/src/settingsdialog.h b/src/settingsdialog.h index a844b391..858a36d4 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -29,6 +29,7 @@ along with Mod Organizer. If not, see . #include class PluginContainer; +class Settings; namespace Ui { class SettingsDialog; @@ -44,7 +45,9 @@ class SettingsDialog : public MOBase::TutorableDialog Q_OBJECT public: - explicit SettingsDialog(PluginContainer *pluginContainer, QWidget *parent = 0); + explicit SettingsDialog( + PluginContainer *pluginContainer, Settings* settings, QWidget *parent = 0); + ~SettingsDialog(); /** @@ -62,9 +65,6 @@ public slots: signals: void resetDialogs(); - void processApiKey(const QString &); - void closeApiConnection(QPushButton *); - void revokeApiKey(QPushButton *); void retryApiConnection(); private: @@ -94,105 +94,74 @@ public: private slots: - //void on_loginCheckBox_toggled(bool checked); - void on_categoriesBtn_clicked(); - void on_execBlacklistBtn_clicked(); - void on_bsaDateBtn_clicked(); - void on_browseDownloadDirBtn_clicked(); - void on_browseModDirBtn_clicked(); - void on_browseCacheDirBtn_clicked(); - void on_resetDialogsButton_clicked(); - void on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); - - void deleteBlacklistItem(); - void on_associateButton_clicked(); - void on_clearCacheButton_clicked(); - - void on_revokeNexusAuthButton_clicked(); - + void on_nexusDisconnect_clicked(); void on_browseBaseDirBtn_clicked(); - void on_browseOverwriteDirBtn_clicked(); - void on_browseProfilesDirBtn_clicked(); - void on_browseGameDirBtn_clicked(); - void on_overwritingBtn_clicked(); - void on_overwrittenBtn_clicked(); - void on_overwritingArchiveBtn_clicked(); - void on_overwrittenArchiveBtn_clicked(); - void on_containsBtn_clicked(); - void on_containedBtn_clicked(); - void on_resetColorsBtn_clicked(); - void on_baseDirEdit_editingFinished(); - void on_downloadDirEdit_editingFinished(); - void on_modDirEdit_editingFinished(); - void on_cacheDirEdit_editingFinished(); - void on_profilesDirEdit_editingFinished(); - void on_overwriteDirEdit_editingFinished(); - void on_nexusConnect_clicked(); - void on_nexusManualKey_clicked(); + void on_resetGeometryBtn_clicked(); + void deleteBlacklistItem(); void dispatchLogin(); - void loginPing(); - void authError(QAbstractSocket::SocketError error); - void receiveApiKey(const QString &apiKey); - void completeApiConnection(); - void on_resetGeometryBtn_clicked(); - private: - Ui::SettingsDialog *ui; - PluginContainer *m_PluginContainer; - - QColor m_OverwritingColor; - QColor m_OverwrittenColor; - QColor m_OverwritingArchiveColor; - QColor m_OverwrittenArchiveColor; - QColor m_ContainsColor; - QColor m_ContainedColor; - - bool m_KeyReceived; - bool m_KeyCleared; - bool m_GeometriesReset; - QString m_UUID; - QString m_AuthToken; - - QString m_ExecutableBlacklist; - QWebSocket *m_nexusLogin; - QTimer m_loginTimer; - int m_totalPings = 0; + Ui::SettingsDialog *ui; + Settings* m_settings; + PluginContainer *m_PluginContainer; + + QColor m_OverwritingColor; + QColor m_OverwrittenColor; + QColor m_OverwritingArchiveColor; + QColor m_OverwrittenArchiveColor; + QColor m_ContainsColor; + QColor m_ContainedColor; + + bool m_KeyReceived; + bool m_KeyCleared; + bool m_GeometriesReset; + QString m_UUID; + QString m_AuthToken; + + QString m_ExecutableBlacklist; + QWebSocket *m_nexusLogin; + QTimer m_loginTimer; + int m_totalPings = 0; + + bool setKey(const QString& key); + bool clearKey(); + void updateNexusButtons(); + + void fetchNexusApiKey(); + void testApiKey(); }; - - #endif // SETTINGSDIALOG_H diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 088b7a0d..08c8d9f2 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -511,12 +511,12 @@ p, li { white-space: pre-wrap; } - + Clear the stored Nexus API key and force reauthorization. - Revoke Nexus Authorization + Disconnect from Nexus -- cgit v1.3.1 From c31303c6af77a47e61efd94022302f860ed5ebfc Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 4 Jun 2019 21:15:54 -0400 Subject: fixed title on the manual key dialog disabled disconnect and manual key buttons while fetching the api key --- src/nexusmanualkey.ui | 2 +- src/settingsdialog.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/settingsdialog.cpp') diff --git a/src/nexusmanualkey.ui b/src/nexusmanualkey.ui index 1a842dc3..847bdd61 100644 --- a/src/nexusmanualkey.ui +++ b/src/nexusmanualkey.ui @@ -11,7 +11,7 @@ - Dialog + Manual Nexus API Key diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 0373cef6..b3e8c8a7 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -532,6 +532,8 @@ void SettingsDialog::updateNexusButtons() // 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->nexusDisconnect->setEnabled(false); + ui->nexusManualKey->setEnabled(false); } else if (m_settings->hasNexusApiKey()) { // api key is present -- cgit v1.3.1 From 616925ebbb8e916119f8dbee0c1f0cb97b14a68b Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 14 Jun 2019 01:38:07 -0400 Subject: moved api user account classes to their own files api label in status bar: - now shows when not logged in - changed some of the colour thresholds to correspond to real throttling numbers make sure the api key is also cleared from the access manager when clearing from the settings removed unused bool m_ValidateAttempted in NXMAccessManager update the window title and status bar api label with correct values on startup, which fixes incorrect values when "restarting" MO after changing nexus settings --- src/CMakeLists.txt | 3 ++ src/apiuseraccount.cpp | 67 ++++++++++++++++++++++++ src/apiuseraccount.h | 129 ++++++++++++++++++++++++++++++++++++++++++++++ src/mainwindow.cpp | 13 +++-- src/nexusinterface.cpp | 78 ++++------------------------ src/nexusinterface.h | 131 ++--------------------------------------------- src/nxmaccessmanager.cpp | 17 ++++-- src/nxmaccessmanager.h | 7 +-- src/settingsdialog.cpp | 6 ++- src/statusbar.cpp | 34 +++++++----- 10 files changed, 263 insertions(+), 222 deletions(-) create mode 100644 src/apiuseraccount.cpp create mode 100644 src/apiuseraccount.h (limited to 'src/settingsdialog.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 71f87a8a..5623a851 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,6 +117,7 @@ SET(organizer_SRCS forcedloaddialogwidget.cpp filterwidget.cpp statusbar.cpp + apiuseraccount.cpp shared/windows_error.cpp shared/error_report.cpp @@ -215,6 +216,7 @@ SET(organizer_HDRS forcedloaddialogwidget.h filterwidget.h statusbar.h + apiuseraccount.h shared/windows_error.h shared/error_report.h @@ -299,6 +301,7 @@ set(core nxmaccessmanager organizercore organizerproxy + apiuseraccount ) set(dialogs diff --git a/src/apiuseraccount.cpp b/src/apiuseraccount.cpp new file mode 100644 index 00000000..b901e41a --- /dev/null +++ b/src/apiuseraccount.cpp @@ -0,0 +1,67 @@ +#include "apiuseraccount.h" + +APIUserAccount::APIUserAccount() + : m_type(APIUserAccountTypes::None) +{ +} + +const QString& APIUserAccount::id() const +{ + return m_id; +} + +const QString& APIUserAccount::name() const +{ + return m_name; +} + +APIUserAccountTypes APIUserAccount::type() const +{ + return m_type; +} + +const APILimits& APIUserAccount::limits() const +{ + return m_limits; +} + +APIUserAccount& APIUserAccount::id(const QString& id) +{ + m_id = id; + return *this; +} + +APIUserAccount& APIUserAccount::name(const QString& name) +{ + m_name = name; + return *this; +} + +APIUserAccount& APIUserAccount::type(APIUserAccountTypes type) +{ + m_type = type; + return *this; +} + +APIUserAccount& APIUserAccount::limits(const APILimits& limits) +{ + m_limits = limits; + return *this; +} + +int APIUserAccount::remainingRequests() const +{ + return std::max( + m_limits.remainingDailyRequests, + m_limits.remainingHourlyRequests); +} + +bool APIUserAccount::shouldThrottle() const +{ + return (remainingRequests() < ThrottleThreshold); +} + +bool APIUserAccount::exhausted() const +{ + return (remainingRequests() <= 0); +} diff --git a/src/apiuseraccount.h b/src/apiuseraccount.h new file mode 100644 index 00000000..8a238d71 --- /dev/null +++ b/src/apiuseraccount.h @@ -0,0 +1,129 @@ +#ifndef APIUSERACCOUNT_H +#define APIUSERACCOUNT_H + +#include + +/** +* represents user account types on a mod provider website such as nexus +*/ +enum class APIUserAccountTypes +{ + // not logged in + None = 0, + + // regular account + Regular, + + // premium account + Premium +}; + + +/** +* current limits imposed on the user account +**/ +struct APILimits +{ + // maximum number of requests per day + int maxDailyRequests = 0; + + // remaining number of requests today + int remainingDailyRequests = 0; + + // maximum number of requests per hour + int maxHourlyRequests = 0; + + // remaining number of requests this hour + int remainingHourlyRequests = 0; +}; + + +/** +* API statistics +*/ +struct APIStats +{ + // number of API requests currently queued + int requestsQueued = 0; +}; + + +/** +* represents a user account on the mod provier website +*/ +class APIUserAccount +{ +public: + // when the number of remanining requests is under this number, further + // requests will be throttled by avoiding non-critical ones + static const int ThrottleThreshold = 200; + + APIUserAccount(); + + /** + * user id + */ + const QString& id() const; + + /** + * user name + */ + const QString& name() const; + + /** + * account type + */ + APIUserAccountTypes type() const; + + /** + * current API limits + */ + const APILimits& limits() const; + + + /** + * sets the user id + */ + APIUserAccount& id(const QString& id); + + /** + * sets the user name + **/ + APIUserAccount& name(const QString& name); + + /** + * sets the acount type + */ + APIUserAccount& type(APIUserAccountTypes type); + + /** + * sets the current limits + */ + APIUserAccount& limits(const APILimits& limits); + + + /** + * returns the number of remaining requests + */ + int remainingRequests() const; + + /** + * whether the number of remaining requests is low enough that further + * requests should be throttled + */ + bool shouldThrottle() const; + + /** + * true if all the remaining requests have been used and the API will refuse + * further requests + */ + bool exhausted() const; + +private: + QString m_id, m_name; + APIUserAccountTypes m_type; + APILimits m_limits; + APIStats m_stats; +}; + +#endif // APIUSERACCOUNT_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c255759b..5018479d 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -225,8 +225,17 @@ MainWindow::MainWindow(QSettings &initSettings QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800); QWebEngineProfile::defaultProfile()->setCachePath(m_OrganizerCore.settings().getCacheDirectory()); QWebEngineProfile::defaultProfile()->setPersistentStoragePath(m_OrganizerCore.settings().getCacheDirectory()); + ui->setupUi(this); - updateWindowTitle({}); + + { + auto* ni = NexusInterface::instance(&m_PluginContainer); + + updateWindowTitle(ni->getAPIUserAccount()); + + m_statusBar.reset(new StatusBar(statusBar(), ui)); + m_statusBar->setAPI(ni->getAPIStats(), ni->getAPIUserAccount()); + } languageChange(m_OrganizerCore.settings().language()); @@ -244,8 +253,6 @@ MainWindow::MainWindow(QSettings &initSettings connect(ui->logList->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), ui->logList, SLOT(scrollToBottom())); - m_statusBar.reset(new StatusBar(statusBar(), ui)); - updateProblemsButton(); setupToolbar(); diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 8362143a..ee9acf2c 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -49,71 +49,6 @@ void throttledWarning(const APIUserAccount& user) } -APIUserAccount::APIUserAccount() - : m_type(APIUserAccountTypes::None) -{ -} - -const QString& APIUserAccount::id() const -{ - return m_id; -} - -const QString& APIUserAccount::name() const -{ - return m_name; -} - -APIUserAccountTypes APIUserAccount::type() const -{ - return m_type; -} - -const APILimits& APIUserAccount::limits() const -{ - return m_limits; -} - -APIUserAccount& APIUserAccount::id(const QString& id) -{ - m_id = id; - return *this; -} - -APIUserAccount& APIUserAccount::name(const QString& name) -{ - m_name = name; - return *this; -} - -APIUserAccount& APIUserAccount::type(APIUserAccountTypes type) -{ - m_type = type; - return *this; -} - -APIUserAccount& APIUserAccount::limits(const APILimits& limits) -{ - m_limits = limits; - return *this; -} - -int APIUserAccount::remainingRequests() const -{ - return m_limits.remainingDailyRequests + m_limits.remainingHourlyRequests; -} - -bool APIUserAccount::shouldThrottle() const -{ - return (remainingRequests() < ThrottleThreshold); -} - -bool APIUserAccount::exhausted() const -{ - return (remainingRequests() <= 0); -} - - NexusBridge::NexusBridge(PluginContainer *pluginContainer, const QString &subModule) : m_Interface(NexusInterface::instance(pluginContainer)) , m_SubModule(subModule) @@ -325,7 +260,7 @@ void NexusInterface::loginCompleted() void NexusInterface::setUserAccount(const APIUserAccount& user) { m_User = user; - emit requestsChanged(stats(), m_User); + emit requestsChanged(getAPIStats(), m_User); } void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query) @@ -884,7 +819,7 @@ void NexusInterface::requestFinished(std::list::iterator iter) qWarning("All API requests have been consumed and are now being denied."); } - emit requestsChanged(stats(), m_User); + emit requestsChanged(getAPIStats(), m_User); qWarning("Error: %s", reply->errorString().toUtf8().constData()); } else { qWarning("request failed: %s", reply->errorString().toUtf8().constData()); @@ -960,7 +895,7 @@ void NexusInterface::requestFinished(std::list::iterator iter) } m_User.limits(parseLimits(reply)); - emit requestsChanged(stats(), m_User); + emit requestsChanged(getAPIStats(), m_User); } else { emit nxmRequestFailed(iter->m_GameName, iter->m_ModID, iter->m_FileID, iter->m_UserData, iter->m_ID, reply->error(), tr("invalid response")); } @@ -1017,7 +952,12 @@ void NexusInterface::requestTimeout() } } -APIStats NexusInterface::stats() const +APIUserAccount NexusInterface::getAPIUserAccount() const +{ + return m_User; +} + +APIStats NexusInterface::getAPIStats() const { APIStats stats; stats.requestsQueued = m_RequestQueue.size(); diff --git a/src/nexusinterface.h b/src/nexusinterface.h index 6c4e8d11..6e768149 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -20,6 +20,8 @@ along with Mod Organizer. If not, see . #ifndef NEXUSINTERFACE_H #define NEXUSINTERFACE_H +#include "apiuseraccount.h" + #include #include #include @@ -40,130 +42,6 @@ class NexusInterface; class NXMAccessManager; -/** - * represents user account types on a mod provider website such as nexus - */ -enum class APIUserAccountTypes -{ - // not logged in - None = 0, - - // regular account - Regular, - - // premium account - Premium -}; - - -/** - * current limits imposed on the user account - **/ -struct APILimits -{ - // maximum number of requests per day - int maxDailyRequests = 0; - - // remaining number of requests today - int remainingDailyRequests = 0; - - // maximum number of requests per hour - int maxHourlyRequests = 0; - - // remaining number of requests this hour - int remainingHourlyRequests = 0; -}; - - -/** - * API statistics - */ -struct APIStats -{ - // number of API requests currently queued - int requestsQueued = 0; -}; - - -/** - * represents a user account on the mod provier website - */ -class APIUserAccount -{ -public: - // when the number of remanining requests is under this number, further - // requests will be throttled by avoiding non-critical ones - static const int ThrottleThreshold = 300; - - APIUserAccount(); - - /** - * user id - */ - const QString& id() const; - - /** - * user name - */ - const QString& name() const; - - /** - * account type - */ - APIUserAccountTypes type() const; - - /** - * current API limits - */ - const APILimits& limits() const; - - - /** - * sets the user id - */ - APIUserAccount& id(const QString& id); - - /** - * sets the user name - **/ - APIUserAccount& name(const QString& name); - - /** - * sets the acount type - */ - APIUserAccount& type(APIUserAccountTypes type); - - /** - * sets the current limits - */ - APIUserAccount& limits(const APILimits& limits); - - - /** - * returns the number of remaining requests - */ - int remainingRequests() const; - - /** - * whether the number of remaining requests is low enough that further - * requests should be throttled - */ - bool shouldThrottle() const; - - /** - * true if all the remaining requests have been used and the API will refuse - * further requests - */ - bool exhausted() const; - -private: - QString m_id, m_name; - APIUserAccountTypes m_type; - APILimits m_limits; - APIStats m_stats; -}; - - /** * @brief convenience class to make nxm requests easier * usually, all objects that started a nxm request will be signaled if one finished. @@ -521,6 +399,9 @@ public: std::vector> getGameChoices(const MOBase::IPluginGame *game); + APIUserAccount getAPIUserAccount() const; + APIStats getAPIStats() const; + public: /** @@ -667,8 +548,6 @@ private: MOBase::VersionInfo m_MOVersion; PluginContainer *m_PluginContainer; APIUserAccount m_User; - - APIStats stats() const; }; #endif // NEXUSINTERFACE_H diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 5886d3ee..ee6c03f1 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -190,6 +190,7 @@ void NXMAccessManager::apiCheck(const QString &apiKey, bool force) emit validateSuccessful(false); return; } + m_ApiKey = apiKey; startValidationCheck(); } @@ -218,6 +219,13 @@ QString NXMAccessManager::apiKey() const return m_ApiKey; } +void NXMAccessManager::clearApiKey() +{ + m_ApiKey = ""; + m_ValidateState = VALIDATE_NOT_VALID; + + emit credentialsReceived(APIUserAccount()); +} void NXMAccessManager::validateTimeout() { @@ -233,7 +241,6 @@ void NXMAccessManager::validateTimeout() if (m_ValidateReply != nullptr) { m_ValidateReply->deleteLater(); m_ValidateReply = nullptr; - m_ValidateAttempted = false; // this usually means we might have success later } emit validateFailed(tr("There was a timeout during the request")); @@ -280,17 +287,21 @@ void NXMAccessManager::validateFinished() QString name = credentialsData.value("name").toString(); bool premium = credentialsData.value("is_premium").toBool(); - emit credentialsReceived(APIUserAccount() + const auto user = APIUserAccount() .id(QString("%1").arg(id)) .name(name) .type(premium ? APIUserAccountTypes::Premium : APIUserAccountTypes::Regular) - .limits(NexusInterface::parseLimits(m_ValidateReply))); + .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; diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 1d23faf9..1bdeae40 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see . #ifndef NXMACCESSMANAGER_H #define NXMACCESSMANAGER_H +#include "apiuseraccount.h" #include #include #include @@ -28,8 +29,6 @@ along with Mod Organizer. If not, see . namespace MOBase { class IPluginGame; } -class APIUserAccount; - /** * @brief access manager extended to handle nxm links **/ @@ -56,6 +55,7 @@ public: QString userAgent(const QString &subModule = QString()) const; QString apiKey() const; + void clearApiKey(); void startValidationCheck(); @@ -94,7 +94,6 @@ protected: QIODevice *device); private: - QTimer m_ValidateTimeout; QNetworkReply *m_ValidateReply; QProgressDialog *m_ProgressDialog { nullptr }; @@ -103,7 +102,6 @@ private: QString m_ApiKey; - bool m_ValidateAttempted; enum { VALIDATE_NOT_CHECKED, VALIDATE_CHECKING, @@ -112,7 +110,6 @@ private: VALIDATE_REFUSED, VALIDATE_VALID } m_ValidateState = VALIDATE_NOT_CHECKED; - }; #endif // NXMACCESSMANAGER_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index b3e8c8a7..95e4ceb0 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -511,6 +511,9 @@ bool SettingsDialog::clearKey() m_KeyCleared = true; const auto ret = m_settings->clearNexusApiKey(); updateNexusButtons(); + + NexusInterface::instance(m_PluginContainer)->getAccessManager()->clearApiKey(); + return ret; } @@ -522,8 +525,7 @@ void SettingsDialog::testApiKey() return; } - auto* am = NexusInterface::instance(m_PluginContainer)->getAccessManager(); - am->apiCheck(key, true); + NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(key, true); } void SettingsDialog::updateNexusButtons() diff --git a/src/statusbar.cpp b/src/statusbar.cpp index 4effa6a3..712eb005 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -48,28 +48,34 @@ void StatusBar::setNotifications(bool hasNotifications) void StatusBar::setAPI(const APIStats& stats, const APIUserAccount& user) { - m_api->setText( - QString("API: Q: %1 | D: %2 | H: %3") - .arg(stats.requestsQueued) - .arg(user.limits().remainingDailyRequests) - .arg(user.limits().remainingHourlyRequests)); - + QString text; QString textColor; QString backgroundColor; if (user.type() == APIUserAccountTypes::None) { - backgroundColor = "transparent"; - } else if (user.remainingRequests() > 300) { - textColor = "white"; - backgroundColor = "darkgreen"; - } else if (user.remainingRequests() < 150) { + text = "API: not logged in"; textColor = "white"; - backgroundColor = "darkred"; + backgroundColor = "transparent"; } else { - textColor = "black"; - backgroundColor = "rgb(226, 192, 0)"; // yellow + text = QString("API: Queued: %1 | Daily: %2 | Hourly: %3") + .arg(stats.requestsQueued) + .arg(user.limits().remainingDailyRequests) + .arg(user.limits().remainingHourlyRequests); + + if (user.remainingRequests() > 500) { + textColor = "white"; + backgroundColor = "darkgreen"; + } else if (user.remainingRequests() > 200) { + textColor = "black"; + backgroundColor = "rgb(226, 192, 0)"; // yellow + } else { + textColor = "white"; + backgroundColor = "darkred"; + } } + m_api->setText(text); + m_api->setStyleSheet(QString(R"( QLabel { -- cgit v1.3.1