Merge branch 'master' of github.com:martinrotter/rssguard

This commit is contained in:
Martin Rotter 2021-01-15 10:59:28 +01:00
commit 3766af2774
24 changed files with 475 additions and 705 deletions

View File

@ -147,6 +147,7 @@ HEADERS += core/feeddownloader.h \
services/gmail/gmailserviceroot.h \
services/gmail/gui/emailrecipientcontrol.h \
services/gmail/gui/formeditgmailaccount.h \
services/gmail/gui/gmailaccountdetails.h \
services/gmail/network/gmailnetworkfactory.h \
services/inoreader/definitions.h \
services/inoreader/gui/formeditinoreaderaccount.h \
@ -304,6 +305,7 @@ SOURCES += core/feeddownloader.cpp \
services/gmail/gmailserviceroot.cpp \
services/gmail/gui/emailrecipientcontrol.cpp \
services/gmail/gui/formeditgmailaccount.cpp \
services/gmail/gui/gmailaccountdetails.cpp \
services/gmail/network/gmailnetworkfactory.cpp \
services/inoreader/gui/formeditinoreaderaccount.cpp \
services/inoreader/gui/inoreaderaccountdetails.cpp \
@ -375,9 +377,8 @@ FORMS += gui/dialogs/formabout.ui \
network-web/downloadmanager.ui \
services/abstract/gui/formaccountdetails.ui \
services/abstract/gui/formfeeddetails.ui \
services/gmail/gui/formeditgmailaccount.ui \
services/inoreader/gui/formeditinoreaderaccount.ui \
services/abstract/gui/authenticationdetails.ui \
services/gmail/gui/gmailaccountdetails.ui \
services/inoreader/gui/inoreaderaccountdetails.ui \
services/owncloud/gui/owncloudaccountdetails.ui \
services/standard/gui/formstandardcategorydetails.ui \

View File

@ -46,7 +46,7 @@ OAuth2Service::OAuth2Service(const QString& auth_url, const QString& token_url,
const QString& client_secret, const QString& scope, QObject* parent)
: QObject(parent),
m_id(QString::number(QRandomGenerator::global()->generate())), m_timerId(-1),
m_redirectionHandler(new OAuthHttpHandler(tr("You can close this window now. Go back to %1").arg(APP_NAME),
m_redirectionHandler(new OAuthHttpHandler(tr("You can close this window now. Go back to %1.").arg(APP_NAME),
this)) {
m_tokenGrantType = QSL("authorization_code");
m_tokenUrl = QUrl(token_url);

View File

@ -15,6 +15,9 @@ class FormAccountDetails : public QDialog {
public:
explicit FormAccountDetails(const QIcon& icon, QWidget* parent = nullptr);
template<class T>
T* addEditAccount(T* account_to_edit = nullptr);
template<class T>
T* account() const;
@ -43,6 +46,19 @@ class FormAccountDetails : public QDialog {
ServiceRoot* m_account;
};
template<class T>
inline T* FormAccountDetails::addEditAccount(T* account_to_edit) {
if (account_to_edit == nullptr) {
setWindowTitle(tr("Add new account"));
}
else {
setEditableAccount(static_cast<ServiceRoot*>(account_to_edit));
}
exec();
return account<T>();
}
template<class T>
inline T* FormAccountDetails::account() const {
return qobject_cast<T*>(m_account);

View File

@ -15,7 +15,7 @@
ServiceRoot* GmailEntryPoint::createNewRoot() const {
FormEditGmailAccount form_acc(qApp->mainFormWidget());
return form_acc.execForCreate();
return form_acc.addEditAccount<GmailServiceRoot>();
}
QList<ServiceRoot*> GmailEntryPoint::initializeSubtree() const {

View File

@ -168,7 +168,7 @@ bool GmailServiceRoot::canBeEdited() const {
bool GmailServiceRoot::editViaGui() {
FormEditGmailAccount form_pointer(qApp->mainFormWidget());
form_pointer.execForEdit(this);
form_pointer.addEditAccount(this);
return true;
}

View File

@ -9,184 +9,64 @@
#include "network-web/webfactory.h"
#include "services/gmail/definitions.h"
#include "services/gmail/gmailserviceroot.h"
#include "services/gmail/gui/gmailaccountdetails.h"
FormEditGmailAccount::FormEditGmailAccount(QWidget* parent)
: QDialog(parent), m_oauth(nullptr), m_editableRoot(nullptr) {
m_ui.setupUi(this);
: FormAccountDetails(qApp->icons()->miscIcon(QSL("gmail")), parent), m_details(new GmailAccountDetails(this)) {
insertCustomTab(m_details, tr("Server setup"), 0);
activateTab(0);
GuiUtilities::applyDialogProperties(*this, qApp->icons()->miscIcon(QSL("gmail")));
GuiUtilities::setLabelAsNotice(*m_ui.m_lblInfo, true);
m_ui.m_lblInfo->setText(tr("Specified redirect URL must start with \"http://localhost\" and "
"must be configured in your OAuth \"application\"."));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("Not tested yet."),
tr("Not tested yet."));
m_ui.m_lblTestResult->label()->setWordWrap(true);
m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("User-visible username"));
setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtAppId);
setTabOrder(m_ui.m_txtAppId, m_ui.m_txtAppKey);
setTabOrder(m_ui.m_txtAppKey, m_ui.m_txtRedirectUrl);
setTabOrder(m_ui.m_txtRedirectUrl, m_ui.m_spinLimitMessages);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_btnTestSetup);
setTabOrder(m_ui.m_btnTestSetup, m_ui.m_buttonBox);
connect(m_ui.m_txtAppId->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditGmailAccount::checkOAuthValue);
connect(m_ui.m_txtAppKey->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditGmailAccount::checkOAuthValue);
connect(m_ui.m_txtRedirectUrl->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditGmailAccount::checkOAuthValue);
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditGmailAccount::checkUsername);
connect(m_ui.m_btnTestSetup, &QPushButton::clicked, this, &FormEditGmailAccount::testSetup);
connect(m_ui.m_buttonBox, &QDialogButtonBox::accepted, this, &FormEditGmailAccount::onClickedOk);
connect(m_ui.m_buttonBox, &QDialogButtonBox::rejected, this, &FormEditGmailAccount::onClickedCancel);
connect(m_ui.m_btnRegisterApi, &QPushButton::clicked, this, &FormEditGmailAccount::registerApi);
m_ui.m_spinLimitMessages->setValue(GMAIL_DEFAULT_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMinimum(GMAIL_MIN_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMaximum(GMAIL_MAX_BATCH_SIZE);
checkUsername(m_ui.m_txtUsername->lineEdit()->text());
m_details->m_ui.m_txtUsername->setFocus();
}
FormEditGmailAccount::~FormEditGmailAccount() = default;
void FormEditGmailAccount::apply() {
FormAccountDetails::apply();
void FormEditGmailAccount::testSetup() {
if (m_oauth->clientId() != m_ui.m_txtAppId->lineEdit()->text() ||
m_oauth->clientSecret() != m_ui.m_txtAppKey->lineEdit()->text() ||
m_oauth->redirectUrl() != m_ui.m_txtRedirectUrl->lineEdit()->text()) {
// User changed some important settings. Log out.
m_oauth->logout();
}
m_oauth->setClientId(m_ui.m_txtAppId->lineEdit()->text());
m_oauth->setClientSecret(m_ui.m_txtAppKey->lineEdit()->text());
m_oauth->setRedirectUrl(m_ui.m_txtRedirectUrl->lineEdit()->text());
if (m_oauth->login()) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("You are already logged in."),
tr("Access granted."));
}
}
void FormEditGmailAccount::onClickedOk() {
bool editing_account = true;
if (m_editableRoot == nullptr) {
if (m_account == nullptr) {
// We want to confirm newly created account.
// So save new account into DB, setup its properties.
m_editableRoot = new GmailServiceRoot(nullptr);
m_account = new GmailServiceRoot(nullptr);
editing_account = false;
}
// We copy credentials from testing OAuth to live OAuth.
m_editableRoot->network()->oauth()->setAccessToken(m_oauth->accessToken());
m_editableRoot->network()->oauth()->setRefreshToken(m_oauth->refreshToken());
m_editableRoot->network()->oauth()->setTokensExpireIn(m_oauth->tokensExpireIn());
account<GmailServiceRoot>()->network()->oauth()->setAccessToken(m_details->m_oauth->accessToken());
account<GmailServiceRoot>()->network()->oauth()->setRefreshToken(m_details->m_oauth->refreshToken());
account<GmailServiceRoot>()->network()->oauth()->setTokensExpireIn(m_details->m_oauth->tokensExpireIn());
m_editableRoot->network()->oauth()->setClientId(m_ui.m_txtAppId->lineEdit()->text());
m_editableRoot->network()->oauth()->setClientSecret(m_ui.m_txtAppKey->lineEdit()->text());
m_editableRoot->network()->oauth()->setRedirectUrl(m_ui.m_txtRedirectUrl->lineEdit()->text());
account<GmailServiceRoot>()->network()->oauth()->setClientId(m_details->m_ui.m_txtAppId->lineEdit()->text());
account<GmailServiceRoot>()->network()->oauth()->setClientSecret(m_details->m_ui.m_txtAppKey->lineEdit()->text());
account<GmailServiceRoot>()->network()->oauth()->setRedirectUrl(m_details->m_ui.m_txtRedirectUrl->lineEdit()->text());
m_editableRoot->network()->setUsername(m_ui.m_txtUsername->lineEdit()->text());
m_editableRoot->network()->setBatchSize(m_ui.m_spinLimitMessages->value());
m_editableRoot->saveAccountDataToDatabase();
account<GmailServiceRoot>()->network()->setUsername(m_details->m_ui.m_txtUsername->lineEdit()->text());
account<GmailServiceRoot>()->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value());
account<GmailServiceRoot>()->saveAccountDataToDatabase();
accept();
if (editing_account) {
m_editableRoot->completelyRemoveAllData();
m_editableRoot->syncIn();
account<GmailServiceRoot>()->completelyRemoveAllData();
account<GmailServiceRoot>()->syncIn();
}
}
void FormEditGmailAccount::onClickedCancel() {
reject();
}
void FormEditGmailAccount::setEditableAccount(ServiceRoot* editable_account) {
FormAccountDetails::setEditableAccount(editable_account);
void FormEditGmailAccount::checkUsername(const QString& username) {
if (username.isEmpty()) {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("No username entered."));
if (m_details->m_oauth != nullptr) {
m_details->m_oauth->logout();
m_details->m_oauth->deleteLater();
}
else {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some username entered."));
}
}
void FormEditGmailAccount::onAuthFailed() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("You did not grant access."),
tr("There was error during testing."));
}
void FormEditGmailAccount::onAuthError(const QString& error, const QString& detailed_description) {
Q_UNUSED(error)
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("There is error. %1 ").arg(detailed_description),
tr("There was error during testing."));
}
void FormEditGmailAccount::onAuthGranted() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Tested successfully. You may be prompted to login once more."),
tr("Your access was approved."));
}
void FormEditGmailAccount::hookNetwork() {
connect(m_oauth, &OAuth2Service::tokensReceived, this, &FormEditGmailAccount::onAuthGranted);
connect(m_oauth, &OAuth2Service::tokensRetrieveError, this, &FormEditGmailAccount::onAuthError);
connect(m_oauth, &OAuth2Service::authFailed, this, &FormEditGmailAccount::onAuthFailed);
}
GmailServiceRoot* FormEditGmailAccount::execForCreate() {
setWindowTitle(tr("Add new Gmail account"));
m_oauth = new OAuth2Service(GMAIL_OAUTH_AUTH_URL, GMAIL_OAUTH_TOKEN_URL,
QString(), QString(), GMAIL_OAUTH_SCOPE, this);
hookNetwork();
m_ui.m_txtAppId->lineEdit()->clear();
m_ui.m_txtAppKey->lineEdit()->clear();
m_ui.m_txtRedirectUrl->lineEdit()->setText(m_oauth->redirectUrl());
exec();
return m_editableRoot;
}
void FormEditGmailAccount::execForEdit(GmailServiceRoot* existing_root) {
setWindowTitle(tr("Edit existing Gmail account"));
m_editableRoot = existing_root;
m_oauth = m_editableRoot->network()->oauth();
hookNetwork();
m_details->m_oauth = account<GmailServiceRoot>()->network()->oauth();
m_details->hookNetwork();
// Setup the GUI.
m_ui.m_txtAppId->lineEdit()->setText(m_oauth->clientId());
m_ui.m_txtAppKey->lineEdit()->setText(m_oauth->clientSecret());
m_ui.m_txtRedirectUrl->lineEdit()->setText(m_oauth->redirectUrl());
m_details->m_ui.m_txtAppId->lineEdit()->setText(m_details->m_oauth->clientId());
m_details->m_ui.m_txtAppKey->lineEdit()->setText(m_details->m_oauth->clientSecret());
m_details->m_ui.m_txtRedirectUrl->lineEdit()->setText(m_details->m_oauth->redirectUrl());
m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->username());
m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize());
exec();
}
void FormEditGmailAccount::registerApi() {
qApp->web()->openUrlInExternalBrowser(GMAIL_REG_API_URL);
}
void FormEditGmailAccount::checkOAuthValue(const QString& value) {
auto* line_edit = qobject_cast<LineEditWithStatus*>(sender()->parent());
if (line_edit != nullptr) {
if (value.isEmpty()) {
line_edit->setStatus(WidgetWithStatus::StatusType::Error, tr("Empty value is entered."));
}
else {
line_edit->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some value is entered."));
}
}
m_details->m_ui.m_txtUsername->lineEdit()->setText(account<GmailServiceRoot>()->network()->username());
m_details->m_ui.m_spinLimitMessages->setValue(account<GmailServiceRoot>()->network()->batchSize());
}

View File

@ -3,46 +3,27 @@
#ifndef FORMEDITINOREADERACCOUNT_H
#define FORMEDITINOREADERACCOUNT_H
#include <QDialog>
#include "ui_formeditgmailaccount.h"
#include "services/abstract/gui/formaccountdetails.h"
#include "services/gmail/network/gmailnetworkfactory.h"
namespace Ui {
class FormEditGmailAccount;
}
class GmailServiceRoot;
class GmailAccountDetails;
class FormEditGmailAccount : public QDialog {
class FormEditGmailAccount : public FormAccountDetails {
Q_OBJECT
public:
explicit FormEditGmailAccount(QWidget* parent = nullptr);
virtual ~FormEditGmailAccount();
GmailServiceRoot* execForCreate();
protected slots:
virtual void apply();
void execForEdit(GmailServiceRoot* existing_root);
private slots:
void registerApi();
void testSetup();
void onClickedOk();
void onClickedCancel();
void checkOAuthValue(const QString& value);
void checkUsername(const QString& username);
void onAuthFailed();
void onAuthError(const QString& error, const QString& detailed_description);
void onAuthGranted();
protected:
virtual void setEditableAccount(ServiceRoot* editable_account);
private:
void hookNetwork();
Ui::FormEditGmailAccount m_ui;
OAuth2Service* m_oauth;
GmailServiceRoot* m_editableRoot;
GmailAccountDetails* m_details;
};
#endif // FORMEDITINOREADERACCOUNT_H

View File

@ -0,0 +1,123 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/gmail/gui/gmailaccountdetails.h"
#include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "network-web/oauth2service.h"
#include "network-web/webfactory.h"
#include "services/gmail/definitions.h"
#include "services/gmail/network/gmailnetworkfactory.h"
GmailAccountDetails::GmailAccountDetails(QWidget* parent)
: QWidget(parent), m_oauth(new OAuth2Service(GMAIL_OAUTH_AUTH_URL, GMAIL_OAUTH_TOKEN_URL,
QString(), QString(), GMAIL_OAUTH_SCOPE, this)) {
m_ui.setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui.m_lblInfo, true);
m_ui.m_lblInfo->setText(tr("Specified redirect URL must start with \"http://localhost\" and "
"must be configured in your OAuth \"application\"."));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("Not tested yet."),
tr("Not tested yet."));
m_ui.m_lblTestResult->label()->setWordWrap(true);
m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("User-visible username"));
setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtAppId);
setTabOrder(m_ui.m_txtAppId, m_ui.m_txtAppKey);
setTabOrder(m_ui.m_txtAppKey, m_ui.m_txtRedirectUrl);
setTabOrder(m_ui.m_txtRedirectUrl, m_ui.m_spinLimitMessages);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_btnTestSetup);
connect(m_ui.m_txtAppId->lineEdit(), &BaseLineEdit::textChanged, this, &GmailAccountDetails::checkOAuthValue);
connect(m_ui.m_txtAppKey->lineEdit(), &BaseLineEdit::textChanged, this, &GmailAccountDetails::checkOAuthValue);
connect(m_ui.m_txtRedirectUrl->lineEdit(), &BaseLineEdit::textChanged, this, &GmailAccountDetails::checkOAuthValue);
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &GmailAccountDetails::checkUsername);
connect(m_ui.m_btnTestSetup, &QPushButton::clicked, this, &GmailAccountDetails::testSetup);
connect(m_ui.m_btnRegisterApi, &QPushButton::clicked, this, &GmailAccountDetails::registerApi);
m_ui.m_spinLimitMessages->setValue(GMAIL_DEFAULT_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMinimum(GMAIL_MIN_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMaximum(GMAIL_MAX_BATCH_SIZE);
checkUsername(m_ui.m_txtUsername->lineEdit()->text());
m_ui.m_txtAppId->lineEdit()->clear();
m_ui.m_txtAppKey->lineEdit()->clear();
m_ui.m_txtRedirectUrl->lineEdit()->setText(m_oauth->redirectUrl());
hookNetwork();
}
void GmailAccountDetails::testSetup() {
if (m_oauth->clientId() != m_ui.m_txtAppId->lineEdit()->text() ||
m_oauth->clientSecret() != m_ui.m_txtAppKey->lineEdit()->text() ||
m_oauth->redirectUrl() != m_ui.m_txtRedirectUrl->lineEdit()->text()) {
// User changed some important settings. Log out.
m_oauth->logout();
}
m_oauth->setClientId(m_ui.m_txtAppId->lineEdit()->text());
m_oauth->setClientSecret(m_ui.m_txtAppKey->lineEdit()->text());
m_oauth->setRedirectUrl(m_ui.m_txtRedirectUrl->lineEdit()->text());
if (m_oauth->login()) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("You are already logged in."),
tr("Access granted."));
}
}
void GmailAccountDetails::checkUsername(const QString& username) {
if (username.isEmpty()) {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("No username entered."));
}
else {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some username entered."));
}
}
void GmailAccountDetails::onAuthFailed() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("You did not grant access."),
tr("There was error during testing."));
}
void GmailAccountDetails::onAuthError(const QString& error, const QString& detailed_description) {
Q_UNUSED(error)
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("There is error. %1 ").arg(detailed_description),
tr("There was error during testing."));
}
void GmailAccountDetails::onAuthGranted() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Tested successfully. You may be prompted to login once more."),
tr("Your access was approved."));
}
void GmailAccountDetails::hookNetwork() {
connect(m_oauth, &OAuth2Service::tokensReceived, this, &GmailAccountDetails::onAuthGranted);
connect(m_oauth, &OAuth2Service::tokensRetrieveError, this, &GmailAccountDetails::onAuthError);
connect(m_oauth, &OAuth2Service::authFailed, this, &GmailAccountDetails::onAuthFailed);
}
void GmailAccountDetails::registerApi() {
qApp->web()->openUrlInExternalBrowser(GMAIL_REG_API_URL);
}
void GmailAccountDetails::checkOAuthValue(const QString& value) {
auto* line_edit = qobject_cast<LineEditWithStatus*>(sender()->parent());
if (line_edit != nullptr) {
if (value.isEmpty()) {
line_edit->setStatus(WidgetWithStatus::StatusType::Error, tr("Empty value is entered."));
}
else {
line_edit->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some value is entered."));
}
}
}

View File

@ -0,0 +1,37 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef GMAILACCOUNTDETAILS_H
#define GMAILACCOUNTDETAILS_H
#include <QWidget>
#include "ui_gmailaccountdetails.h"
class OAuth2Service;
class GmailAccountDetails : public QWidget {
Q_OBJECT
friend class FormEditGmailAccount;
public:
explicit GmailAccountDetails(QWidget* parent = nullptr);
private slots:
void registerApi();
void testSetup();
void checkOAuthValue(const QString& value);
void checkUsername(const QString& username);
void onAuthFailed();
void onAuthError(const QString& error, const QString& detailed_description);
void onAuthGranted();
private:
void hookNetwork();
private:
Ui::GmailAccountDetails m_ui;
OAuth2Service* m_oauth;
};
#endif // GMAILACCOUNTDETAILS_H

View File

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FormEditGmailAccount</class>
<widget class="QDialog" name="FormEditGmailAccount">
<class>GmailAccountDetails</class>
<widget class="QWidget" name="GmailAccountDetails">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>363</height>
<width>431</width>
<height>258</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="m_lblUsername">
<property name="text">
@ -23,14 +23,20 @@
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>OAuth 2.0 settings</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="m_lblUsername_2">
<property name="text">
<string>Application ID</string>
<string>Client ID</string>
</property>
<property name="buddy">
<cstring>m_txtAppId</cstring>
@ -43,7 +49,7 @@
<item row="1" column="0">
<widget class="QLabel" name="m_lblUsername_3">
<property name="text">
<string>Application key</string>
<string>Client secret</string>
</property>
<property name="buddy">
<cstring>m_txtAppKey</cstring>
@ -66,20 +72,46 @@
<item row="2" column="1">
<widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/>
</item>
<item row="4" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="m_btnRegisterApi">
<property name="text">
<string>Get my credentials</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="m_lblInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="m_btnRegisterApi">
<property name="text">
<string>Get my credentials</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -121,12 +153,6 @@
</item>
<item row="0" column="1">
<widget class="LabelWithStatus" name="m_lblTestResult" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
@ -134,16 +160,6 @@
</item>
</layout>
</item>
<item row="5" column="0" colspan="2">
<widget class="QDialogButtonBox" name="m_buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
@ -151,8 +167,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<width>410</width>
<height>0</height>
</size>
</property>
</spacer>
@ -173,44 +189,6 @@
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>m_btnRegisterApi</tabstop>
<tabstop>m_spinLimitMessages</tabstop>
<tabstop>m_btnTestSetup</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>m_buttonBox</sender>
<signal>accepted()</signal>
<receiver>FormEditGmailAccount</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_buttonBox</sender>
<signal>rejected()</signal>
<receiver>FormEditGmailAccount</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

View File

@ -8,185 +8,66 @@
#include "network-web/oauth2service.h"
#include "network-web/webfactory.h"
#include "services/inoreader/definitions.h"
#include "services/inoreader/gui/inoreaderaccountdetails.h"
#include "services/inoreader/inoreaderserviceroot.h"
#include "services/inoreader/network/inoreadernetworkfactory.h"
FormEditInoreaderAccount::FormEditInoreaderAccount(QWidget* parent)
: QDialog(parent), m_oauth(nullptr), m_editableRoot(nullptr) {
m_ui.setupUi(this);
: FormAccountDetails(qApp->icons()->miscIcon(QSL("inoreader")), parent), m_details(new InoreaderAccountDetails(this)) {
insertCustomTab(m_details, tr("Server setup"), 0);
activateTab(0);
GuiUtilities::applyDialogProperties(*this, qApp->icons()->miscIcon(QSL("inoreader")));
GuiUtilities::setLabelAsNotice(*m_ui.m_lblInfo, true);
m_ui.m_lblInfo->setText(tr("Specified redirect URL must start with \"http://localhost\" and "
"must be configured in your OAuth \"application\".\n\n"
"It is highly recommended to create your own \"Application ID\"."));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("Not tested yet."),
tr("Not tested yet."));
m_ui.m_lblTestResult->label()->setWordWrap(true);
m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("User-visible username"));
setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtAppId);
setTabOrder(m_ui.m_txtAppId, m_ui.m_txtAppKey);
setTabOrder(m_ui.m_txtAppKey, m_ui.m_txtRedirectUrl);
setTabOrder(m_ui.m_txtRedirectUrl, m_ui.m_spinLimitMessages);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_btnTestSetup);
setTabOrder(m_ui.m_btnTestSetup, m_ui.m_buttonBox);
connect(m_ui.m_txtAppId->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditInoreaderAccount::checkOAuthValue);
connect(m_ui.m_txtAppKey->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditInoreaderAccount::checkOAuthValue);
connect(m_ui.m_txtRedirectUrl->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditInoreaderAccount::checkOAuthValue);
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &FormEditInoreaderAccount::checkUsername);
connect(m_ui.m_btnTestSetup, &QPushButton::clicked, this, &FormEditInoreaderAccount::testSetup);
connect(m_ui.m_buttonBox, &QDialogButtonBox::accepted, this, &FormEditInoreaderAccount::onClickedOk);
connect(m_ui.m_buttonBox, &QDialogButtonBox::rejected, this, &FormEditInoreaderAccount::onClickedCancel);
connect(m_ui.m_btnRegisterApi, &QPushButton::clicked, this, &FormEditInoreaderAccount::registerApi);
m_ui.m_spinLimitMessages->setValue(INOREADER_DEFAULT_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMinimum(INOREADER_MIN_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMaximum(INOREADER_MAX_BATCH_SIZE);
checkUsername(m_ui.m_txtUsername->lineEdit()->text());
m_details->m_ui.m_txtUsername->setFocus();
}
FormEditInoreaderAccount::~FormEditInoreaderAccount() = default;
void FormEditInoreaderAccount::apply() {
FormAccountDetails::apply();
void FormEditInoreaderAccount::testSetup() {
if (m_oauth->clientId() != m_ui.m_txtAppId->lineEdit()->text() ||
m_oauth->clientSecret() != m_ui.m_txtAppKey->lineEdit()->text() ||
m_oauth->redirectUrl() != m_ui.m_txtRedirectUrl->lineEdit()->text()) {
// User changed some important settings. Log out.
m_oauth->logout();
}
m_oauth->setClientId(m_ui.m_txtAppId->lineEdit()->text());
m_oauth->setClientSecret(m_ui.m_txtAppKey->lineEdit()->text());
m_oauth->setRedirectUrl(m_ui.m_txtRedirectUrl->lineEdit()->text());
if (m_oauth->login()) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("You are already logged in."),
tr("Access granted."));
}
}
void FormEditInoreaderAccount::onClickedOk() {
bool editing_account = true;
if (m_editableRoot == nullptr) {
if (m_account == nullptr) {
// We want to confirm newly created account.
// So save new account into DB, setup its properties.
m_editableRoot = new InoreaderServiceRoot(nullptr);
m_account = new InoreaderServiceRoot(nullptr);
editing_account = false;
}
// We copy credentials from testing OAuth to live OAuth.
m_editableRoot->network()->oauth()->setAccessToken(m_oauth->accessToken());
m_editableRoot->network()->oauth()->setRefreshToken(m_oauth->refreshToken());
m_editableRoot->network()->oauth()->setTokensExpireIn(m_oauth->tokensExpireIn());
account<InoreaderServiceRoot>()->network()->oauth()->setAccessToken(m_details->m_oauth->accessToken());
account<InoreaderServiceRoot>()->network()->oauth()->setRefreshToken(m_details->m_oauth->refreshToken());
account<InoreaderServiceRoot>()->network()->oauth()->setTokensExpireIn(m_details->m_oauth->tokensExpireIn());
m_editableRoot->network()->oauth()->setClientId(m_ui.m_txtAppId->lineEdit()->text());
m_editableRoot->network()->oauth()->setClientSecret(m_ui.m_txtAppKey->lineEdit()->text());
m_editableRoot->network()->oauth()->setRedirectUrl(m_ui.m_txtRedirectUrl->lineEdit()->text());
account<InoreaderServiceRoot>()->network()->oauth()->setClientId(m_details->m_ui.m_txtAppId->lineEdit()->text());
account<InoreaderServiceRoot>()->network()->oauth()->setClientSecret(m_details->m_ui.m_txtAppKey->lineEdit()->text());
account<InoreaderServiceRoot>()->network()->oauth()->setRedirectUrl(m_details->m_ui.m_txtRedirectUrl->lineEdit()->text());
m_editableRoot->network()->setUsername(m_ui.m_txtUsername->lineEdit()->text());
m_editableRoot->network()->setBatchSize(m_ui.m_spinLimitMessages->value());
m_editableRoot->saveAccountDataToDatabase();
account<InoreaderServiceRoot>()->network()->setUsername(m_details->m_ui.m_txtUsername->lineEdit()->text());
account<InoreaderServiceRoot>()->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value());
account<InoreaderServiceRoot>()->saveAccountDataToDatabase();
accept();
if (editing_account) {
m_editableRoot->completelyRemoveAllData();
m_editableRoot->syncIn();
account<InoreaderServiceRoot>()->completelyRemoveAllData();
account<InoreaderServiceRoot>()->syncIn();
}
}
void FormEditInoreaderAccount::onClickedCancel() {
reject();
}
void FormEditInoreaderAccount::setEditableAccount(ServiceRoot* editable_account) {
FormAccountDetails::setEditableAccount(editable_account);
void FormEditInoreaderAccount::checkUsername(const QString& username) {
if (username.isEmpty()) {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("No username entered."));
if (m_details->m_oauth != nullptr) {
m_details->m_oauth->logout();
m_details->m_oauth->deleteLater();
}
else {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some username entered."));
}
}
void FormEditInoreaderAccount::onAuthFailed() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("You did not grant access."),
tr("There was error during testing."));
}
void FormEditInoreaderAccount::onAuthError(const QString& error, const QString& detailed_description) {
Q_UNUSED(error)
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("There is error. %1").arg(detailed_description),
tr("There was error during testing."));
}
void FormEditInoreaderAccount::onAuthGranted() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Tested successfully. You may be prompted to login once more."),
tr("Your access was approved."));
}
void FormEditInoreaderAccount::hookNetwork() {
connect(m_oauth, &OAuth2Service::tokensReceived, this, &FormEditInoreaderAccount::onAuthGranted);
connect(m_oauth, &OAuth2Service::tokensRetrieveError, this, &FormEditInoreaderAccount::onAuthError);
connect(m_oauth, &OAuth2Service::authFailed, this, &FormEditInoreaderAccount::onAuthFailed);
}
InoreaderServiceRoot* FormEditInoreaderAccount::execForCreate() {
setWindowTitle(tr("Add new Inoreader account"));
m_oauth = new OAuth2Service(INOREADER_OAUTH_AUTH_URL, INOREADER_OAUTH_TOKEN_URL,
INOREADER_OAUTH_CLI_ID, INOREADER_OAUTH_CLI_KEY, INOREADER_OAUTH_SCOPE, this);
hookNetwork();
m_ui.m_txtAppId->lineEdit()->setText(INOREADER_OAUTH_CLI_ID);
m_ui.m_txtAppKey->lineEdit()->setText(INOREADER_OAUTH_CLI_KEY);
m_ui.m_txtRedirectUrl->lineEdit()->setText(OAUTH_REDIRECT_URI);
exec();
return m_editableRoot;
}
void FormEditInoreaderAccount::execForEdit(InoreaderServiceRoot* existing_root) {
setWindowTitle(tr("Edit existing Inoreader account"));
m_editableRoot = existing_root;
m_oauth = m_editableRoot->network()->oauth();
hookNetwork();
m_details->m_oauth = account<InoreaderServiceRoot>()->network()->oauth();
m_details->hookNetwork();
// Setup the GUI.
m_ui.m_txtAppId->lineEdit()->setText(m_oauth->clientId());
m_ui.m_txtAppKey->lineEdit()->setText(m_oauth->clientSecret());
m_ui.m_txtRedirectUrl->lineEdit()->setText(m_oauth->redirectUrl());
m_details->m_ui.m_txtAppId->lineEdit()->setText(m_details->m_oauth->clientId());
m_details->m_ui.m_txtAppKey->lineEdit()->setText(m_details->m_oauth->clientSecret());
m_details->m_ui.m_txtRedirectUrl->lineEdit()->setText(m_details->m_oauth->redirectUrl());
m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->userName());
m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize());
exec();
}
void FormEditInoreaderAccount::registerApi() {
qApp->web()->openUrlInExternalBrowser(INOREADER_REG_API_URL);
}
void FormEditInoreaderAccount::checkOAuthValue(const QString& value) {
auto* line_edit = qobject_cast<LineEditWithStatus*>(sender()->parent());
if (line_edit != nullptr) {
if (value.isEmpty()) {
line_edit->setStatus(WidgetWithStatus::StatusType::Error, tr("Empty value is entered."));
}
else {
line_edit->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some value is entered."));
}
}
m_details->m_ui.m_txtUsername->lineEdit()->setText(account<InoreaderServiceRoot>()->network()->userName());
m_details->m_ui.m_spinLimitMessages->setValue(account<InoreaderServiceRoot>()->network()->batchSize());
}

View File

@ -3,46 +3,25 @@
#ifndef FORMEDITINOREADERACCOUNT_H
#define FORMEDITINOREADERACCOUNT_H
#include <QDialog>
#include "ui_formeditinoreaderaccount.h"
#include "services/inoreader/network/inoreadernetworkfactory.h"
namespace Ui {
class FormEditInoreaderAccount;
}
#include "services/abstract/gui/formaccountdetails.h"
class InoreaderServiceRoot;
class InoreaderAccountDetails;
class FormEditInoreaderAccount : public QDialog {
class FormEditInoreaderAccount : public FormAccountDetails {
Q_OBJECT
public:
explicit FormEditInoreaderAccount(QWidget* parent = nullptr);
virtual ~FormEditInoreaderAccount();
InoreaderServiceRoot* execForCreate();
protected slots:
virtual void apply();
void execForEdit(InoreaderServiceRoot* existing_root);
private slots:
void registerApi();
void testSetup();
void onClickedOk();
void onClickedCancel();
void checkOAuthValue(const QString& value);
void checkUsername(const QString& username);
void onAuthFailed();
void onAuthError(const QString& error, const QString& detailed_description);
void onAuthGranted();
protected:
virtual void setEditableAccount(ServiceRoot* editable_account);
private:
void hookNetwork();
Ui::FormEditInoreaderAccount m_ui;
OAuth2Service* m_oauth;
InoreaderServiceRoot* m_editableRoot;
InoreaderAccountDetails* m_details;
};
#endif // FORMEDITINOREADERACCOUNT_H

View File

@ -1,216 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FormEditInoreaderAccount</class>
<widget class="QDialog" name="FormEditInoreaderAccount">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>363</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="m_lblUsername">
<property name="text">
<string>Username</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LineEditWithStatus" name="m_txtUsername" native="true"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>OAuth 2.0 settings</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="m_lblUsername_2">
<property name="text">
<string>Application ID</string>
</property>
<property name="buddy">
<cstring>m_txtAppId</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LineEditWithStatus" name="m_txtAppId" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="m_lblUsername_3">
<property name="text">
<string>Application key</string>
</property>
<property name="buddy">
<cstring>m_txtAppKey</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="LineEditWithStatus" name="m_txtAppKey" native="true"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="m_lblUsername_4">
<property name="text">
<string>Redirect URL</string>
</property>
<property name="buddy">
<cstring>m_txtRedirectUrl</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="LineEditWithStatus" name="m_txtRedirectUrl" native="true"/>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="m_lblInfo">
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="m_btnRegisterApi">
<property name="text">
<string>Get my own Application ID</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Only download newest X messages per feed</string>
</property>
<property name="buddy">
<cstring>m_spinLimitMessages</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="m_spinLimitMessages">
<property name="maximumSize">
<size>
<width>140</width>
<height>16777215</height>
</size>
</property>
<property name="suffix">
<string> message(s)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QPushButton" name="m_btnTestSetup">
<property name="text">
<string>&amp;Login</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LabelWithStatus" name="m_lblTestResult" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0" colspan="2">
<widget class="QDialogButtonBox" name="m_buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LineEditWithStatus</class>
<extends>QWidget</extends>
<header>lineeditwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LabelWithStatus</class>
<extends>QWidget</extends>
<header>labelwithstatus.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>m_btnRegisterApi</tabstop>
<tabstop>m_spinLimitMessages</tabstop>
<tabstop>m_btnTestSetup</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>m_buttonBox</sender>
<signal>accepted()</signal>
<receiver>FormEditInoreaderAccount</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_buttonBox</sender>
<signal>rejected()</signal>
<receiver>FormEditInoreaderAccount</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -2,6 +2,126 @@
#include "services/inoreader/gui/inoreaderaccountdetails.h"
InoreaderAccountDetails::InoreaderAccountDetails(QWidget* parent) : QWidget(parent) {
#include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "network-web/oauth2service.h"
#include "network-web/webfactory.h"
#include "services/inoreader/definitions.h"
#include "services/inoreader/network/inoreadernetworkfactory.h"
InoreaderAccountDetails::InoreaderAccountDetails(QWidget* parent)
: QWidget(parent), m_oauth(new OAuth2Service(INOREADER_OAUTH_AUTH_URL, INOREADER_OAUTH_TOKEN_URL,
INOREADER_OAUTH_CLI_ID, INOREADER_OAUTH_CLI_KEY,
INOREADER_OAUTH_SCOPE, this)) {
m_ui.setupUi(this);
GuiUtilities::setLabelAsNotice(*m_ui.m_lblInfo, true);
m_ui.m_lblInfo->setText(tr("Specified redirect URL must start with \"http://localhost\" and "
"must be configured in your OAuth \"application\".\n\n"
"It is highly recommended to create your own \"App ID\". "
"Because predefined one may be limited due to usage quotas if used by "
"too many users simultaneously."));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("Not tested yet."),
tr("Not tested yet."));
m_ui.m_lblTestResult->label()->setWordWrap(true);
m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("User-visible username"));
setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtAppId);
setTabOrder(m_ui.m_txtAppId, m_ui.m_txtAppKey);
setTabOrder(m_ui.m_txtAppKey, m_ui.m_txtRedirectUrl);
setTabOrder(m_ui.m_txtRedirectUrl, m_ui.m_spinLimitMessages);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_btnTestSetup);
connect(m_ui.m_txtAppId->lineEdit(), &BaseLineEdit::textChanged, this, &InoreaderAccountDetails::checkOAuthValue);
connect(m_ui.m_txtAppKey->lineEdit(), &BaseLineEdit::textChanged, this, &InoreaderAccountDetails::checkOAuthValue);
connect(m_ui.m_txtRedirectUrl->lineEdit(), &BaseLineEdit::textChanged, this, &InoreaderAccountDetails::checkOAuthValue);
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &InoreaderAccountDetails::checkUsername);
connect(m_ui.m_btnTestSetup, &QPushButton::clicked, this, &InoreaderAccountDetails::testSetup);
connect(m_ui.m_btnRegisterApi, &QPushButton::clicked, this, &InoreaderAccountDetails::registerApi);
m_ui.m_spinLimitMessages->setValue(INOREADER_DEFAULT_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMinimum(INOREADER_MIN_BATCH_SIZE);
m_ui.m_spinLimitMessages->setMaximum(INOREADER_MAX_BATCH_SIZE);
checkUsername(m_ui.m_txtUsername->lineEdit()->text());
m_ui.m_txtAppId->lineEdit()->setText(INOREADER_OAUTH_CLI_ID);
m_ui.m_txtAppKey->lineEdit()->setText(INOREADER_OAUTH_CLI_KEY);
m_ui.m_txtRedirectUrl->lineEdit()->setText(OAUTH_REDIRECT_URI);
hookNetwork();
}
void InoreaderAccountDetails::testSetup() {
if (m_oauth->clientId() != m_ui.m_txtAppId->lineEdit()->text() ||
m_oauth->clientSecret() != m_ui.m_txtAppKey->lineEdit()->text() ||
m_oauth->redirectUrl() != m_ui.m_txtRedirectUrl->lineEdit()->text()) {
// User changed some important settings. Log out.
m_oauth->logout();
}
m_oauth->setClientId(m_ui.m_txtAppId->lineEdit()->text());
m_oauth->setClientSecret(m_ui.m_txtAppKey->lineEdit()->text());
m_oauth->setRedirectUrl(m_ui.m_txtRedirectUrl->lineEdit()->text());
if (m_oauth->login()) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("You are already logged in."),
tr("Access granted."));
}
}
void InoreaderAccountDetails::checkUsername(const QString& username) {
if (username.isEmpty()) {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("No username entered."));
}
else {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some username entered."));
}
}
void InoreaderAccountDetails::onAuthFailed() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("You did not grant access."),
tr("There was error during testing."));
}
void InoreaderAccountDetails::onAuthError(const QString& error, const QString& detailed_description) {
Q_UNUSED(error)
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("There is error. %1").arg(detailed_description),
tr("There was error during testing."));
}
void InoreaderAccountDetails::onAuthGranted() {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Tested successfully. You may be prompted to login once more."),
tr("Your access was approved."));
}
void InoreaderAccountDetails::hookNetwork() {
connect(m_oauth, &OAuth2Service::tokensReceived, this, &InoreaderAccountDetails::onAuthGranted);
connect(m_oauth, &OAuth2Service::tokensRetrieveError, this, &InoreaderAccountDetails::onAuthError);
connect(m_oauth, &OAuth2Service::authFailed, this, &InoreaderAccountDetails::onAuthFailed);
}
void InoreaderAccountDetails::registerApi() {
qApp->web()->openUrlInExternalBrowser(INOREADER_REG_API_URL);
}
void InoreaderAccountDetails::checkOAuthValue(const QString& value) {
auto* line_edit = qobject_cast<LineEditWithStatus*>(sender()->parent());
if (line_edit != nullptr) {
if (value.isEmpty()) {
line_edit->setStatus(WidgetWithStatus::StatusType::Error, tr("Empty value is entered."));
}
else {
line_edit->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some value is entered."));
}
}
}

View File

@ -7,14 +7,31 @@
#include "ui_inoreaderaccountdetails.h"
class OAuth2Service;
class InoreaderAccountDetails : public QWidget {
Q_OBJECT
friend class FormEditInoreaderAccount;
public:
explicit InoreaderAccountDetails(QWidget* parent = nullptr);
private slots:
void registerApi();
void testSetup();;
void checkOAuthValue(const QString& value);
void checkUsername(const QString& username);
void onAuthFailed();
void onAuthError(const QString& error, const QString& detailed_description);
void onAuthGranted();
private:
void hookNetwork();
private:
Ui::InoreaderAccountDetails m_ui;
OAuth2Service* m_oauth;
};
#endif // INOREADERACCOUNTDETAILS_H

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>437</height>
<width>427</width>
<height>265</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout_4">
@ -23,6 +23,12 @@
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>OAuth 2.0 settings</string>
</property>
@ -30,7 +36,7 @@
<item row="0" column="0">
<widget class="QLabel" name="m_lblUsername_2">
<property name="text">
<string>Application ID</string>
<string>App ID</string>
</property>
<property name="buddy">
<cstring>m_txtAppId</cstring>
@ -43,7 +49,7 @@
<item row="1" column="0">
<widget class="QLabel" name="m_lblUsername_3">
<property name="text">
<string>Application key</string>
<string>App key</string>
</property>
<property name="buddy">
<cstring>m_txtAppKey</cstring>
@ -71,7 +77,7 @@
<item>
<widget class="QPushButton" name="m_btnRegisterApi">
<property name="text">
<string>Get my own Application ID</string>
<string>Get my own App ID</string>
</property>
</widget>
</item>
@ -92,6 +98,15 @@
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="m_lblInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
@ -138,12 +153,6 @@
</item>
<item row="0" column="1">
<widget class="LabelWithStatus" name="m_lblTestResult" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
@ -156,12 +165,6 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>448</width>
<height>167</height>
</size>
</property>
</spacer>
</item>
</layout>

View File

@ -16,7 +16,7 @@
ServiceRoot* InoreaderEntryPoint::createNewRoot() const {
FormEditInoreaderAccount form_acc(qApp->mainFormWidget());
return form_acc.execForCreate();
return form_acc.addEditAccount<InoreaderServiceRoot>();
}
QList<ServiceRoot*> InoreaderEntryPoint::initializeSubtree() const {

View File

@ -94,7 +94,7 @@ bool InoreaderServiceRoot::canBeEdited() const {
bool InoreaderServiceRoot::editViaGui() {
FormEditInoreaderAccount form_pointer(qApp->mainFormWidget());
form_pointer.execForEdit(this);
form_pointer.addEditAccount(this);
return true;
}

View File

@ -18,19 +18,6 @@ FormEditOwnCloudAccount::FormEditOwnCloudAccount(QWidget* parent)
m_details->m_ui.m_txtUrl->setFocus();
}
OwnCloudServiceRoot* FormEditOwnCloudAccount::addEditAccount(OwnCloudServiceRoot* account_to_edit) {
if (account_to_edit == nullptr) {
// User is adding new TT-RSS account.
setWindowTitle(tr("Add new Nextcloud News account"));
}
else {
setEditableAccount(account_to_edit);
}
exec();
return account<OwnCloudServiceRoot>();
}
void FormEditOwnCloudAccount::apply() {
FormAccountDetails::apply();

View File

@ -14,8 +14,6 @@ class FormEditOwnCloudAccount : public FormAccountDetails {
public:
explicit FormEditOwnCloudAccount(QWidget* parent = nullptr);
OwnCloudServiceRoot* addEditAccount(OwnCloudServiceRoot* account_to_edit = nullptr);
protected slots:
virtual void apply();

View File

@ -13,7 +13,7 @@
ServiceRoot* OwnCloudServiceEntryPoint::createNewRoot() const {
FormEditOwnCloudAccount form_acc(qApp->mainFormWidget());
return form_acc.addEditAccount();
return form_acc.addEditAccount<OwnCloudServiceRoot>();
}
QList<ServiceRoot*> OwnCloudServiceEntryPoint::initializeSubtree() const {

View File

@ -16,19 +16,6 @@ FormEditTtRssAccount::FormEditTtRssAccount(QWidget* parent)
m_details->m_ui.m_txtUrl->setFocus();
}
TtRssServiceRoot* FormEditTtRssAccount::addEditAccount(TtRssServiceRoot* account_to_edit) {
if (account_to_edit == nullptr) {
// User is adding new TT-RSS account.
setWindowTitle(tr("Add new TT-RSS account"));
}
else {
setEditableAccount(account_to_edit);
}
exec();
return account<TtRssServiceRoot>();
}
void FormEditTtRssAccount::apply() {
FormAccountDetails::apply();

View File

@ -15,8 +15,6 @@ class FormEditTtRssAccount : public FormAccountDetails {
public:
explicit FormEditTtRssAccount(QWidget* parent = nullptr);
TtRssServiceRoot* addEditAccount(TtRssServiceRoot* account_to_edit = nullptr);
protected slots:
virtual void apply();

View File

@ -35,7 +35,7 @@ QString TtRssServiceEntryPoint::code() const {
ServiceRoot* TtRssServiceEntryPoint::createNewRoot() const {
FormEditTtRssAccount form_acc(qApp->mainFormWidget());
return form_acc.addEditAccount();
return form_acc.addEditAccount<TtRssServiceRoot>();
}
QList<ServiceRoot*> TtRssServiceEntryPoint::initializeSubtree() const {