diff --git a/CMakeLists.txt b/CMakeLists.txt index a6db4df14..862e36c9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -327,6 +327,8 @@ add_subdirectory(src/librssguard-standard) add_subdirectory(src/librssguard-feedly) add_subdirectory(src/librssguard-gmail) add_subdirectory(src/librssguard-greader) +add_subdirectory(src/librssguard-ttrss) +add_subdirectory(src/librssguard-nextcloud) # GUI executable. add_subdirectory(src/rssguard) diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt index 71b780fe9..f5529c2f6 100644 --- a/src/librssguard/CMakeLists.txt +++ b/src/librssguard/CMakeLists.txt @@ -324,54 +324,6 @@ set(SOURCES services/abstract/serviceroot.h services/abstract/unreadnode.cpp services/abstract/unreadnode.h - services/owncloud/definitions.h - services/owncloud/gui/formeditowncloudaccount.cpp - services/owncloud/gui/formeditowncloudaccount.h - services/owncloud/gui/owncloudaccountdetails.cpp - services/owncloud/gui/owncloudaccountdetails.h - services/owncloud/owncloudfeed.cpp - services/owncloud/owncloudfeed.h - services/owncloud/owncloudnetworkfactory.cpp - services/owncloud/owncloudnetworkfactory.h - services/owncloud/owncloudserviceentrypoint.cpp - services/owncloud/owncloudserviceentrypoint.h - services/owncloud/owncloudserviceroot.cpp - services/owncloud/owncloudserviceroot.h - services/reddit/definitions.h - services/reddit/gui/formeditredditaccount.cpp - services/reddit/gui/formeditredditaccount.h - services/reddit/gui/redditaccountdetails.cpp - services/reddit/gui/redditaccountdetails.h - services/reddit/redditcategory.cpp - services/reddit/redditcategory.h - services/reddit/redditentrypoint.cpp - services/reddit/redditentrypoint.h - services/reddit/redditnetworkfactory.cpp - services/reddit/redditnetworkfactory.h - services/reddit/redditserviceroot.cpp - services/reddit/redditserviceroot.h - services/reddit/redditsubscription.cpp - services/reddit/redditsubscription.h - services/tt-rss/definitions.h - services/tt-rss/gui/formeditttrssaccount.cpp - services/tt-rss/gui/formeditttrssaccount.h - services/tt-rss/gui/formttrssfeeddetails.cpp - services/tt-rss/gui/formttrssfeeddetails.h - services/tt-rss/gui/formttrssnote.cpp - services/tt-rss/gui/formttrssnote.h - services/tt-rss/gui/ttrssaccountdetails.cpp - services/tt-rss/gui/ttrssaccountdetails.h - services/tt-rss/gui/ttrssfeeddetails.cpp - services/tt-rss/gui/ttrssfeeddetails.h - services/tt-rss/ttrssfeed.cpp - services/tt-rss/ttrssfeed.h - services/tt-rss/ttrssnetworkfactory.cpp - services/tt-rss/ttrssnetworkfactory.h - services/tt-rss/ttrssnotetopublish.h - services/tt-rss/ttrssserviceentrypoint.cpp - services/tt-rss/ttrssserviceentrypoint.h - services/tt-rss/ttrssserviceroot.cpp - services/tt-rss/ttrssserviceroot.h ) set(UI_FILES @@ -415,11 +367,6 @@ set(UI_FILES services/abstract/gui/formaddeditprobe.ui services/abstract/gui/formcategorydetails.ui services/abstract/gui/formfeeddetails.ui - services/owncloud/gui/owncloudaccountdetails.ui - services/reddit/gui/redditaccountdetails.ui - services/tt-rss/gui/formttrssnote.ui - services/tt-rss/gui/ttrssaccountdetails.ui - services/tt-rss/gui/ttrssfeeddetails.ui ) if(ENABLE_MEDIAPLAYER) diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index fc5e60533..fbb76b581 100644 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -8,7 +8,7 @@ #define SERVICE_CODE_STD_RSS "std-rss" #define SERVICE_CODE_TT_RSS "tt-rss" -#define SERVICE_CODE_OWNCLOUD "owncloud" +#define SERVICE_CODE_NEXTCLOUD "nextcloud" #define SERVICE_CODE_GREADER "greader" #define SERVICE_CODE_FEEDLY "feedly" #define SERVICE_CODE_INOREADER "inoreader" diff --git a/src/librssguard/miscellaneous/feedreader.cpp b/src/librssguard/miscellaneous/feedreader.cpp index 8d234089f..d17fda1eb 100644 --- a/src/librssguard/miscellaneous/feedreader.cpp +++ b/src/librssguard/miscellaneous/feedreader.cpp @@ -15,10 +15,8 @@ #include "miscellaneous/pluginfactory.h" #include "miscellaneous/settings.h" #include "services/abstract/cacheforserviceroot.h" +#include "services/abstract/serviceentrypoint.h" #include "services/abstract/serviceroot.h" -#include "services/owncloud/owncloudserviceentrypoint.h" -#include "services/reddit/redditentrypoint.h" -#include "services/tt-rss/ttrssserviceentrypoint.h" #include #include @@ -66,14 +64,6 @@ FeedReader::~FeedReader() { QList FeedReader::feedServices() { if (m_feedServices.isEmpty()) { - m_feedServices.append(new OwnCloudServiceEntryPoint()); - -#if !defined(NDEBUG) - m_feedServices.append(new RedditEntryPoint()); -#endif - - m_feedServices.append(new TtRssServiceEntryPoint()); - PluginFactory plugin_loader; // Add dynamically loaded plugins. diff --git a/src/librssguard/services/owncloud/definitions.h b/src/librssguard/services/owncloud/definitions.h deleted file mode 100644 index 1b740bf39..000000000 --- a/src/librssguard/services/owncloud/definitions.h +++ /dev/null @@ -1,13 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef OWNCLOUD_DEFINITIONS_H -#define OWNCLOUD_DEFINITIONS_H - -#define OWNCLOUD_CONTENT_TYPE_JSON "application/json; charset=utf-8" -#define OWNCLOUD_API_VERSION "1.2" -#define OWNCLOUD_API_PATH "index.php/apps/news/api/v1-2/" -#define OWNCLOUD_MIN_VERSION "6.0.5" -#define OWNCLOUD_UNLIMITED_BATCH_SIZE -1 -#define OWNCLOUD_DEFAULT_BATCH_SIZE 100 - -#endif // OWNCLOUD_DEFINITIONS_H diff --git a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp b/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp deleted file mode 100644 index 9eef6ef9b..000000000 --- a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/owncloud/gui/formeditowncloudaccount.h" - -#include "miscellaneous/iconfactory.h" -#include "services/owncloud/gui/owncloudaccountdetails.h" -#include "services/owncloud/owncloudnetworkfactory.h" -#include "services/owncloud/owncloudserviceroot.h" - -FormEditOwnCloudAccount::FormEditOwnCloudAccount(QWidget* parent) - : FormAccountDetails(qApp->icons()->miscIcon(QSL("nextcloud")), parent), m_details(new OwnCloudAccountDetails(this)) { - insertCustomTab(m_details, tr("Server setup"), 0); - activateTab(0); - - connect(m_details->m_ui.m_btnTestSetup, &QPushButton::clicked, this, &FormEditOwnCloudAccount::performTest); - - m_details->m_ui.m_txtUrl->setFocus(); -} - -void FormEditOwnCloudAccount::apply() { - FormAccountDetails::apply(); - - bool using_another_acc = - m_details->m_ui.m_txtUsername->lineEdit()->text() != account()->network()->authUsername() || - m_details->m_ui.m_txtUrl->lineEdit()->text() != account()->network()->url(); - - account()->network()->setUrl(m_details->m_ui.m_txtUrl->lineEdit()->text()); - account()->network()->setAuthUsername(m_details->m_ui.m_txtUsername->lineEdit()->text()); - account()->network()->setAuthPassword(m_details->m_ui.m_txtPassword->lineEdit()->text()); - account()->network()->setForceServerSideUpdate(m_details->m_ui.m_checkServerSideUpdate - ->isChecked()); - account()->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value()); - account() - ->network() - ->setDownloadOnlyUnreadMessages(m_details->m_ui.m_checkDownloadOnlyUnreadMessages->isChecked()); - - account()->saveAccountDataToDatabase(); - accept(); - - if (!m_creatingNew && using_another_acc) { - account()->completelyRemoveAllData(); - account()->start(true); - } -} - -void FormEditOwnCloudAccount::loadAccountData() { - FormAccountDetails::loadAccountData(); - - OwnCloudServiceRoot* existing_root = account(); - - m_details->m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->authUsername()); - m_details->m_ui.m_txtPassword->lineEdit()->setText(existing_root->network()->authPassword()); - m_details->m_ui.m_txtUrl->lineEdit()->setText(existing_root->network()->url()); - m_details->m_ui.m_checkDownloadOnlyUnreadMessages->setChecked(existing_root->network()->downloadOnlyUnreadMessages()); - m_details->m_ui.m_checkServerSideUpdate->setChecked(existing_root->network()->forceServerSideUpdate()); - m_details->m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize()); -} - -void FormEditOwnCloudAccount::performTest() { - m_details->performTest(m_proxyDetails->proxy()); -} diff --git a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.h b/src/librssguard/services/owncloud/gui/formeditowncloudaccount.h deleted file mode 100644 index 63ab52a05..000000000 --- a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.h +++ /dev/null @@ -1,30 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef FORMEDITOWNCLOUDACCOUNT_H -#define FORMEDITOWNCLOUDACCOUNT_H - -#include "services/abstract/gui/formaccountdetails.h" - -class OwnCloudAccountDetails; -class OwnCloudServiceRoot; - -class FormEditOwnCloudAccount : public FormAccountDetails { - Q_OBJECT - - public: - explicit FormEditOwnCloudAccount(QWidget* parent = nullptr); - - protected slots: - virtual void apply(); - - protected: - virtual void loadAccountData(); - - private slots: - void performTest(); - - private: - OwnCloudAccountDetails* m_details; -}; - -#endif // FORMEDITOWNCLOUDACCOUNT_H diff --git a/src/librssguard/services/owncloud/gui/owncloudaccountdetails.cpp b/src/librssguard/services/owncloud/gui/owncloudaccountdetails.cpp deleted file mode 100644 index a3d2999e2..000000000 --- a/src/librssguard/services/owncloud/gui/owncloudaccountdetails.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/owncloud/gui/owncloudaccountdetails.h" - -#include "definitions/definitions.h" -#include "miscellaneous/systemfactory.h" -#include "services/owncloud/definitions.h" -#include "services/owncloud/owncloudnetworkfactory.h" - -OwnCloudAccountDetails::OwnCloudAccountDetails(QWidget* parent) : QWidget(parent) { - m_ui.setupUi(this); - - m_ui.m_lblTestResult->label()->setWordWrap(true); - m_ui.m_lblServerSideUpdateInformation - ->setHelpText(tr("Leaving this option on causes that updates " - "of feeds will be probably much slower and may time-out often."), - true); - m_ui.m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your Nextcloud account")); - m_ui.m_txtPassword->lineEdit()->setPasswordMode(true); - m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your Nextcloud account")); - m_ui.m_txtUrl->lineEdit()->setPlaceholderText(tr("URL of your Nextcloud server, without any API path")); - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information, - tr("No test done yet."), - tr("Here, results of connection test are shown.")); - - connect(m_ui.m_spinLimitMessages, - static_cast(&QSpinBox::valueChanged), - this, - [=](int value) { - if (value <= 0) { - m_ui.m_spinLimitMessages->setSuffix(QSL(" ") + tr("= unlimited")); - } - else { - m_ui.m_spinLimitMessages->setSuffix(QSL(" ") + tr("articles")); - } - }); - - connect(m_ui.m_txtPassword->lineEdit(), &BaseLineEdit::textChanged, this, &OwnCloudAccountDetails::onPasswordChanged); - connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &OwnCloudAccountDetails::onUsernameChanged); - connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &OwnCloudAccountDetails::onUrlChanged); - - setTabOrder(m_ui.m_txtUrl->lineEdit(), m_ui.m_checkDownloadOnlyUnreadMessages); - setTabOrder(m_ui.m_checkDownloadOnlyUnreadMessages, m_ui.m_spinLimitMessages); - setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_checkServerSideUpdate); - setTabOrder(m_ui.m_checkServerSideUpdate, m_ui.m_txtUsername->lineEdit()); - setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtPassword->lineEdit()); - setTabOrder(m_ui.m_txtPassword->lineEdit(), m_ui.m_btnTestSetup); - - onPasswordChanged(); - onUsernameChanged(); - onUrlChanged(); -} - -void OwnCloudAccountDetails::performTest(const QNetworkProxy& custom_proxy) { - OwnCloudNetworkFactory factory; - - factory.setAuthUsername(m_ui.m_txtUsername->lineEdit()->text()); - factory.setAuthPassword(m_ui.m_txtPassword->lineEdit()->text()); - factory.setUrl(m_ui.m_txtUrl->lineEdit()->text()); - factory.setForceServerSideUpdate(m_ui.m_checkServerSideUpdate->isChecked()); - - OwnCloudStatusResponse result = factory.status(custom_proxy); - - if (result.networkError() != QNetworkReply::NetworkError::NoError) { - m_ui.m_lblTestResult - ->setStatus(WidgetWithStatus::StatusType::Error, - tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(result.networkError())), - tr("Network error, have you entered correct Nextcloud endpoint and password?")); - } - else if (result.isLoaded()) { - if (!SystemFactory::isVersionEqualOrNewer(result.version(), QSL(OWNCLOUD_MIN_VERSION))) { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Installed version: %1, required at least: %2.") - .arg(result.version(), QSL(OWNCLOUD_MIN_VERSION)), - tr("Selected Nextcloud News server is running unsupported version.")); - } - else { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok, - tr("Installed version: %1, required at least: %2.") - .arg(result.version(), QSL(OWNCLOUD_MIN_VERSION)), - tr("Nextcloud News server is okay.")); - } - } - else { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Unspecified error, did you enter correct URL?"), - tr("Unspecified error, did you enter correct URL?")); - } -} - -void OwnCloudAccountDetails::onUsernameChanged() { - const QString username = m_ui.m_txtUsername->lineEdit()->text(); - - if (username.isEmpty()) { - m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("Username cannot be empty.")); - } - else { - m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Username is okay.")); - } -} - -void OwnCloudAccountDetails::onPasswordChanged() { - const QString password = m_ui.m_txtPassword->lineEdit()->text(); - - if (password.isEmpty()) { - m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Error, tr("Password cannot be empty.")); - } - else { - m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Ok, tr("Password is okay.")); - } -} - -void OwnCloudAccountDetails::onUrlChanged() { - const QString url = m_ui.m_txtUrl->lineEdit()->text(); - - if (url.isEmpty()) { - m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Error, tr("URL cannot be empty.")); - } - else { - m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Ok, tr("URL is okay.")); - } -} diff --git a/src/librssguard/services/owncloud/gui/owncloudaccountdetails.h b/src/librssguard/services/owncloud/gui/owncloudaccountdetails.h deleted file mode 100644 index c5eb568fa..000000000 --- a/src/librssguard/services/owncloud/gui/owncloudaccountdetails.h +++ /dev/null @@ -1,29 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef OWNCLOUDACCOUNTDETAILS_H -#define OWNCLOUDACCOUNTDETAILS_H - -#include "ui_owncloudaccountdetails.h" - -#include -#include - -class OwnCloudAccountDetails : public QWidget { - Q_OBJECT - - friend class FormEditOwnCloudAccount; - - public: - explicit OwnCloudAccountDetails(QWidget* parent = nullptr); - - private slots: - void performTest(const QNetworkProxy& custom_proxy); - void onUsernameChanged(); - void onPasswordChanged(); - void onUrlChanged(); - - private: - Ui::OwnCloudAccountDetails m_ui; -}; - -#endif // OWNCLOUDACCOUNTDETAILS_H diff --git a/src/librssguard/services/owncloud/gui/owncloudaccountdetails.ui b/src/librssguard/services/owncloud/gui/owncloudaccountdetails.ui deleted file mode 100644 index 1218bb9b7..000000000 --- a/src/librssguard/services/owncloud/gui/owncloudaccountdetails.ui +++ /dev/null @@ -1,201 +0,0 @@ - - - OwnCloudAccountDetails - - - - 0 - 0 - 433 - 363 - - - - - - - - - URL - - - m_txtUrl - - - - - - - - - - - - Download unread articles only - - - - - - - - - Only download newest X articles per feed - - - m_spinLimitMessages - - - - - - - - 140 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - - - Authentication - - - false - - - false - - - - - - Username - - - m_txtUsername - - - - - - - - - - Password - - - m_txtPassword - - - - - - - - - - - - - - - &Test setup - - - - - - - - 0 - 0 - - - - Qt::RightToLeft - - - - - - - - - Qt::Vertical - - - - 409 - 35 - - - - - - - - Force execution of server-side feeds update - - - - - - - - LineEditWithStatus - QWidget -
lineeditwithstatus.h
- 1 -
- - LabelWithStatus - QWidget -
labelwithstatus.h
- 1 -
- - MessageCountSpinBox - QSpinBox -
messagecountspinbox.h
-
- - HelpSpoiler - QWidget -
helpspoiler.h
- 1 -
-
- - m_checkDownloadOnlyUnreadMessages - m_checkServerSideUpdate - m_spinLimitMessages - m_btnTestSetup - - - -
diff --git a/src/librssguard/services/owncloud/owncloudfeed.cpp b/src/librssguard/services/owncloud/owncloudfeed.cpp deleted file mode 100644 index 152ea7333..000000000 --- a/src/librssguard/services/owncloud/owncloudfeed.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/owncloud/owncloudfeed.h" - -#include "database/databasequeries.h" -#include "services/owncloud/owncloudnetworkfactory.h" -#include "services/owncloud/owncloudserviceroot.h" - -#include - -OwnCloudFeed::OwnCloudFeed(RootItem* parent) : Feed(parent) {} - -bool OwnCloudFeed::canBeDeleted() const { - return true; -} - -bool OwnCloudFeed::deleteItem() { - if (serviceRoot()->network()->deleteFeed(customId(), getParentServiceRoot()->networkProxy()) && removeItself()) { - serviceRoot()->requestItemRemoval(this); - return true; - } - else { - return false; - } -} - -bool OwnCloudFeed::removeItself() { - QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); - - return DatabaseQueries::deleteFeed(database, this, serviceRoot()->accountId()); -} - -OwnCloudServiceRoot* OwnCloudFeed::serviceRoot() const { - return qobject_cast(getParentServiceRoot()); -} diff --git a/src/librssguard/services/owncloud/owncloudfeed.h b/src/librssguard/services/owncloud/owncloudfeed.h deleted file mode 100644 index 08b3e5a11..000000000 --- a/src/librssguard/services/owncloud/owncloudfeed.h +++ /dev/null @@ -1,24 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef OWNCLOUDFEED_H -#define OWNCLOUDFEED_H - -#include "services/abstract/feed.h" - -class OwnCloudServiceRoot; - -class OwnCloudFeed : public Feed { - Q_OBJECT - - public: - explicit OwnCloudFeed(RootItem* parent = nullptr); - - virtual bool canBeDeleted() const; - virtual bool deleteItem(); - - private: - bool removeItself(); - OwnCloudServiceRoot* serviceRoot() const; -}; - -#endif // OWNCLOUDFEED_H diff --git a/src/librssguard/services/owncloud/owncloudnetworkfactory.cpp b/src/librssguard/services/owncloud/owncloudnetworkfactory.cpp deleted file mode 100644 index cf5f3e9d4..000000000 --- a/src/librssguard/services/owncloud/owncloudnetworkfactory.cpp +++ /dev/null @@ -1,660 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/owncloud/owncloudnetworkfactory.h" - -#include "miscellaneous/application.h" -#include "miscellaneous/settings.h" -#include "miscellaneous/textfactory.h" -#include "network-web/networkfactory.h" -#include "services/abstract/category.h" -#include "services/abstract/rootitem.h" -#include "services/owncloud/definitions.h" -#include "services/owncloud/owncloudfeed.h" - -#include - -#include -#include -#include -#include - -OwnCloudNetworkFactory::OwnCloudNetworkFactory() - : m_url(QString()), m_fixedUrl(QString()), m_downloadOnlyUnreadMessages(false), m_forceServerSideUpdate(false), - m_authUsername(QString()), m_authPassword(QString()), m_batchSize(OWNCLOUD_DEFAULT_BATCH_SIZE), - m_urlUser(QString()), m_urlStatus(QString()), m_urlFolders(QString()), m_urlFeeds(QString()), - m_urlMessages(QString()), m_urlFeedsUpdate(QString()), m_urlDeleteFeed(QString()), m_urlRenameFeed(QString()) {} - -OwnCloudNetworkFactory::~OwnCloudNetworkFactory() = default; - -QString OwnCloudNetworkFactory::url() const { - return m_url; -} - -void OwnCloudNetworkFactory::setUrl(const QString& url) { - m_url = url; - - if (url.endsWith('/')) { - m_fixedUrl = url; - } - else { - m_fixedUrl = url + '/'; - } - - // Store endpoints. - m_urlUser = m_fixedUrl + OWNCLOUD_API_PATH + "user"; - m_urlStatus = m_fixedUrl + OWNCLOUD_API_PATH + "status"; - m_urlFolders = m_fixedUrl + OWNCLOUD_API_PATH + "folders"; - m_urlFeeds = m_fixedUrl + OWNCLOUD_API_PATH + "feeds"; - m_urlMessages = m_fixedUrl + OWNCLOUD_API_PATH + "items?id=%1&batchSize=%2&type=%3&getRead=%4"; - m_urlFeedsUpdate = m_fixedUrl + OWNCLOUD_API_PATH + "feeds/update?userId=%1&feedId=%2"; - m_urlDeleteFeed = m_fixedUrl + OWNCLOUD_API_PATH + "feeds/%1"; - m_urlRenameFeed = m_fixedUrl + OWNCLOUD_API_PATH + "feeds/%1/rename"; -} - -bool OwnCloudNetworkFactory::forceServerSideUpdate() const { - return m_forceServerSideUpdate; -} - -void OwnCloudNetworkFactory::setForceServerSideUpdate(bool force_update) { - m_forceServerSideUpdate = force_update; -} - -QString OwnCloudNetworkFactory::authUsername() const { - return m_authUsername; -} - -void OwnCloudNetworkFactory::setAuthUsername(const QString& auth_username) { - m_authUsername = auth_username; -} - -QString OwnCloudNetworkFactory::authPassword() const { - return m_authPassword; -} - -void OwnCloudNetworkFactory::setAuthPassword(const QString& auth_password) { - m_authPassword = auth_password; -} - -OwnCloudStatusResponse OwnCloudNetworkFactory::status(const QNetworkProxy& custom_proxy) { - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_urlStatus, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QByteArray(), - result_raw, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy); - OwnCloudStatusResponse status_response(network_reply.m_networkError, QString::fromUtf8(result_raw)); - - qDebugNN << LOGSEC_NEXTCLOUD << "Raw status data is:" << QUOTE_W_SPACE_DOT(result_raw); - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Obtaining status info failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - return status_response; -} - -OwnCloudGetFeedsCategoriesResponse OwnCloudNetworkFactory::feedsCategories(const QNetworkProxy& custom_proxy) { - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_urlFolders, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QByteArray(), - result_raw, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy); - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Obtaining of categories failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - return OwnCloudGetFeedsCategoriesResponse(network_reply.m_networkError); - } - - QString content_categories = QString::fromUtf8(result_raw); - - // Now, obtain feeds. - network_reply = NetworkFactory::performNetworkOperation(m_urlFeeds, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QByteArray(), - result_raw, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy); - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Obtaining of feeds failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - return OwnCloudGetFeedsCategoriesResponse(network_reply.m_networkError); - } - - QString content_feeds = QString::fromUtf8(result_raw); - - return OwnCloudGetFeedsCategoriesResponse(network_reply.m_networkError, content_categories, content_feeds); -} - -bool OwnCloudNetworkFactory::deleteFeed(const QString& feed_id, const QNetworkProxy& custom_proxy) { - QString final_url = m_urlDeleteFeed.arg(feed_id); - QByteArray raw_output; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(final_url, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QByteArray(), - raw_output, - QNetworkAccessManager::Operation::DeleteOperation, - headers, - false, - {}, - {}, - custom_proxy); - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Obtaining of categories failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - return false; - } - else { - return true; - } -} - -bool OwnCloudNetworkFactory::createFeed(const QString& url, int parent_id, const QNetworkProxy& custom_proxy) { - QJsonObject json; - - json[QSL("url")] = url; - - auto nextcloud_version = status(custom_proxy).version(); - - if (SystemFactory::isVersionEqualOrNewer(nextcloud_version, QSL("15.1.0"))) { - json[QSL("folderId")] = parent_id == 0 ? QJsonValue(QJsonValue::Type::Null) : parent_id; - } - else { - json[QSL("folderId")] = parent_id; - } - - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_urlFeeds, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - custom_proxy); - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Creating of category failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - return false; - } - else { - return true; - } -} - -bool OwnCloudNetworkFactory::renameFeed(const QString& new_name, - const QString& custom_feed_id, - const QNetworkProxy& custom_proxy) { - QString final_url = m_urlRenameFeed.arg(custom_feed_id); - QByteArray result_raw; - QJsonObject json; - - json[QSL("feedTitle")] = new_name; - - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(final_url, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PutOperation, - headers, - false, - {}, - {}, - custom_proxy); - - if (network_reply.m_networkError != QNetworkReply::NetworkError::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Renaming of feed failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - return false; - } - else { - return true; - } -} - -OwnCloudGetMessagesResponse OwnCloudNetworkFactory::getMessages(int feed_id, const QNetworkProxy& custom_proxy) { - if (forceServerSideUpdate()) { - triggerFeedUpdate(feed_id, custom_proxy); - } - - QString final_url = m_urlMessages.arg(QString::number(feed_id), - QString::number(batchSize() <= 0 ? -1 : batchSize()), - QString::number(0), - m_downloadOnlyUnreadMessages ? QSL("false") : QSL("true")); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(final_url, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QByteArray(), - result_raw, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy); - OwnCloudGetMessagesResponse msgs_response(network_reply.m_networkError, QString::fromUtf8(result_raw)); - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Obtaining messages failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - return msgs_response; -} - -QNetworkReply::NetworkError OwnCloudNetworkFactory::triggerFeedUpdate(int feed_id, const QNetworkProxy& custom_proxy) { - // Now, we can trigger the update. - QByteArray raw_output; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_urlFeedsUpdate.arg(authUsername(), QString::number(feed_id)), - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QByteArray(), - raw_output, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy); - - if (network_reply.m_networkError != QNetworkReply::NetworkError::NoError) { - qCriticalNN << LOGSEC_NEXTCLOUD << "Feeds update failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - return network_reply.m_networkError; -} - -NetworkResult OwnCloudNetworkFactory::markMessagesRead(RootItem::ReadStatus status, - const QStringList& custom_ids, - const QNetworkProxy& custom_proxy) { - QJsonObject json; - QJsonArray ids; - QString final_url; - - if (status == RootItem::ReadStatus::Read) { - final_url = m_fixedUrl + QSL(OWNCLOUD_API_PATH) + QSL("items/read/multiple"); - } - else { - final_url = m_fixedUrl + QSL(OWNCLOUD_API_PATH) + QSL("items/unread/multiple"); - } - - for (const QString& id : custom_ids) { - ids.append(QJsonValue(id.toInt())); - } - - json[QSL("items")] = ids; - - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - QByteArray output; - - return NetworkFactory::performNetworkOperation(final_url, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - output, - QNetworkAccessManager::Operation::PutOperation, - headers, - false, - {}, - {}, - custom_proxy); -} - -NetworkResult OwnCloudNetworkFactory::markMessagesStarred(RootItem::Importance importance, - const QStringList& feed_ids, - const QStringList& guid_hashes, - const QNetworkProxy& custom_proxy) { - QJsonObject json; - QJsonArray ids; - QString final_url; - - if (importance == RootItem::Importance::Important) { - final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/star/multiple"; - } - else { - final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/unstar/multiple"; - } - - for (int i = 0; i < feed_ids.size(); i++) { - QJsonObject item; - - item[QSL("feedId")] = feed_ids.at(i); - item[QSL("guidHash")] = guid_hashes.at(i); - ids.append(item); - } - - json[QSL("items")] = ids; - - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, OWNCLOUD_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - QByteArray output; - - return NetworkFactory::performNetworkOperation(final_url, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - output, - QNetworkAccessManager::Operation::PutOperation, - headers, - false, - {}, - {}, - custom_proxy); -} - -int OwnCloudNetworkFactory::batchSize() const { - return m_batchSize; -} - -void OwnCloudNetworkFactory::setBatchSize(int batch_size) { - m_batchSize = batch_size; -} - -bool OwnCloudNetworkFactory::downloadOnlyUnreadMessages() const { - return m_downloadOnlyUnreadMessages; -} - -void OwnCloudNetworkFactory::setDownloadOnlyUnreadMessages(bool dowload_only_unread_messages) { - m_downloadOnlyUnreadMessages = dowload_only_unread_messages; -} - -OwnCloudResponse::OwnCloudResponse(QNetworkReply::NetworkError response, const QString& raw_content) - : m_networkError(response), m_rawContent(QJsonDocument::fromJson(raw_content.toUtf8()).object()), - m_emptyString(raw_content.isEmpty()) {} - -OwnCloudResponse::~OwnCloudResponse() = default; - -bool OwnCloudResponse::isLoaded() const { - return !m_emptyString && !m_rawContent.isEmpty(); -} - -QString OwnCloudResponse::toString() const { - return QJsonDocument(m_rawContent).toJson(QJsonDocument::JsonFormat::Compact); -} - -QNetworkReply::NetworkError OwnCloudResponse::networkError() const { - return m_networkError; -} - -OwnCloudStatusResponse::OwnCloudStatusResponse(QNetworkReply::NetworkError response, const QString& raw_content) - : OwnCloudResponse(response, raw_content) {} - -OwnCloudStatusResponse::~OwnCloudStatusResponse() = default; - -QString OwnCloudStatusResponse::version() const { - if (isLoaded()) { - return m_rawContent[QSL("version")].toString(); - } - else { - return QString(); - } -} - -OwnCloudGetFeedsCategoriesResponse::OwnCloudGetFeedsCategoriesResponse(QNetworkReply::NetworkError response, - QString raw_categories, - QString raw_feeds) - : OwnCloudResponse(response), m_contentCategories(std::move(raw_categories)), m_contentFeeds(std::move(raw_feeds)) {} - -OwnCloudGetFeedsCategoriesResponse::~OwnCloudGetFeedsCategoriesResponse() = default; - -RootItem* OwnCloudGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons) const { - auto* parent = new RootItem(); - QMap cats; - - // Top-level feed have "folderId" set to "0" or JSON "null" value. - cats.insert(QSL("0"), parent); - - // Process categories first, then process feeds. - auto json_folders = QJsonDocument::fromJson(m_contentCategories.toUtf8()).object()[QSL("folders")].toArray(); - - for (const QJsonValue& cat : std::as_const(json_folders)) { - QJsonObject item = cat.toObject(); - auto* category = new Category(); - - category->setTitle(item[QSL("name")].toString()); - category->setCustomId(QString::number(item[QSL("id")].toInt())); - cats.insert(category->customId(), category); - - // All categories in Nextcloud are top-level. - parent->appendChild(category); - } - - // We have categories added, now add all feeds. - auto json_feeds = QJsonDocument::fromJson(m_contentFeeds.toUtf8()).object()[QSL("feeds")].toArray(); - - for (const QJsonValue& fed : std::as_const(json_feeds)) { - QJsonObject item = fed.toObject(); - auto* feed = new OwnCloudFeed(); - - if (obtain_icons) { - QString icon_path = item[QSL("faviconLink")].toString(); - - if (!icon_path.isEmpty()) { - QByteArray icon_data; - - if (NetworkFactory::performNetworkOperation(icon_path, - DOWNLOAD_TIMEOUT, - QByteArray(), - icon_data, - QNetworkAccessManager::Operation::GetOperation) - .m_networkError == QNetworkReply::NetworkError::NoError) { - // Icon downloaded, set it up. - QPixmap icon_pixmap; - - icon_pixmap.loadFromData(icon_data); - feed->setIcon(QIcon(icon_pixmap)); - } - } - } - - feed->setCustomId(QString::number(item[QSL("id")].toInt())); - feed->setSource(item[QSL("url")].toString()); - - if (feed->source().isEmpty()) { - feed->setSource(item[QSL("link")].toString()); - } - - feed->setTitle(item[QSL("title")].toString()); - - if (feed->title().isEmpty()) { - if (feed->source().isEmpty()) { - // We cannot add feed which has no title and no url to RSS Guard!!! - qCriticalNN << LOGSEC_NEXTCLOUD << "Skipping feed with custom ID" << QUOTE_W_SPACE(feed->customId()) - << "from adding to RSS Guard because it has no title and url."; - continue; - } - else { - feed->setTitle(feed->source()); - } - } - - // NOTE: Starting with News 15.1.0, top-level feeds do not have parent folder ID 0, but JSON "null". - // Luckily, if folder ID is not convertible to int, then default 0 value is returned. - cats.value(QString::number(item[QSL("folderId")].toInt(0)))->appendChild(feed); - qDebugNN << LOGSEC_NEXTCLOUD << "Custom ID of next fetched processed feed is" - << QUOTE_W_SPACE_DOT(feed->customId()); - } - - return parent; -} - -OwnCloudGetMessagesResponse::OwnCloudGetMessagesResponse(QNetworkReply::NetworkError response, - const QString& raw_content) - : OwnCloudResponse(response, raw_content) {} - -OwnCloudGetMessagesResponse::~OwnCloudGetMessagesResponse() = default; - -QList OwnCloudGetMessagesResponse::messages() const { - QList msgs; - auto json_items = m_rawContent[QSL("items")].toArray(); - - for (const QJsonValue& message : std::as_const(json_items)) { - QJsonObject message_map = message.toObject(); - Message msg; - - msg.m_author = message_map[QSL("author")].toString(); - msg.m_contents = message_map[QSL("body")].toString(); - msg.m_created = TextFactory::parseDateTime(message_map[QSL("pubDate")].toDouble() * 1000); - msg.m_createdFromFeed = true; - msg.m_customId = message_map[QSL("id")].toVariant().toString(); - msg.m_customHash = message_map[QSL("guidHash")].toString(); - msg.m_rawContents = QJsonDocument(message_map).toJson(QJsonDocument::JsonFormat::Compact); - - // In case body is empty, check for content in mediaDescription if item is available. - if (msg.m_contents.isEmpty() && !message_map[QSL("mediaDescription")].isUndefined()) { - msg.m_contents = message_map[QSL("mediaDescription")].toString(); - } - - // Check for mediaThumbnail and append as first enclosure to be viewed in internal viewer. - if (!message_map[QSL("mediaThumbnail")].isUndefined()) { - Enclosure enclosure; - - enclosure.m_mimeType = QSL("image/jpg"); - enclosure.m_url = message_map[QSL("mediaThumbnail")].toString(); - - msg.m_enclosures.append(enclosure); - } - - QString enclosure_link = message_map[QSL("enclosureLink")].toString(); - - if (!enclosure_link.isEmpty()) { - Enclosure enclosure; - - enclosure.m_mimeType = message_map[QSL("enclosureMime")].toString(); - enclosure.m_url = enclosure_link; - - if (enclosure.m_mimeType.isEmpty()) { - enclosure.m_mimeType = QSL("image/png"); - } - - if (!message_map[QSL("enclosureMime")].toString().isEmpty() || - !enclosure_link.startsWith(QSL("https://www.youtube.com/v/"))) { - msg.m_enclosures.append(enclosure); - } - } - - msg.m_feedId = message_map[QSL("feedId")].toVariant().toString(); - msg.m_isImportant = message_map[QSL("starred")].toBool(); - msg.m_isRead = !message_map[QSL("unread")].toBool(); - msg.m_title = message_map[QSL("title")].toString(); - msg.m_url = message_map[QSL("url")].toString(); - - if (msg.m_title.simplified().isEmpty()) { - msg.m_title = message_map[QSL("mediaDescription")].toString(); - } - - if (msg.m_title.simplified().isEmpty()) { - msg.m_title = msg.m_url; - } - - msgs.append(msg); - } - - return msgs; -} diff --git a/src/librssguard/services/owncloud/owncloudnetworkfactory.h b/src/librssguard/services/owncloud/owncloudnetworkfactory.h deleted file mode 100644 index d9049d31c..000000000 --- a/src/librssguard/services/owncloud/owncloudnetworkfactory.h +++ /dev/null @@ -1,138 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef OWNCLOUDNETWORKFACTORY_H -#define OWNCLOUDNETWORKFACTORY_H - -#include "core/message.h" -#include "network-web/networkfactory.h" -#include "services/abstract/rootitem.h" - -#include -#include -#include -#include -#include - -class OwnCloudResponse { - public: - explicit OwnCloudResponse(QNetworkReply::NetworkError response, const QString& raw_content = QString()); - virtual ~OwnCloudResponse(); - - bool isLoaded() const; - QString toString() const; - QNetworkReply::NetworkError networkError() const; - - protected: - QNetworkReply::NetworkError m_networkError; - QJsonObject m_rawContent; - bool m_emptyString; -}; - -class OwnCloudGetMessagesResponse : public OwnCloudResponse { - public: - explicit OwnCloudGetMessagesResponse(QNetworkReply::NetworkError response, const QString& raw_content = QString()); - virtual ~OwnCloudGetMessagesResponse(); - - QList messages() const; -}; - -class OwnCloudStatusResponse : public OwnCloudResponse { - public: - explicit OwnCloudStatusResponse(QNetworkReply::NetworkError response, const QString& raw_content = QString()); - virtual ~OwnCloudStatusResponse(); - - QString version() const; -}; - -class RootItem; - -class OwnCloudGetFeedsCategoriesResponse : public OwnCloudResponse { - public: - explicit OwnCloudGetFeedsCategoriesResponse(QNetworkReply::NetworkError response, - QString raw_categories = QString(), - QString raw_feeds = QString()); - virtual ~OwnCloudGetFeedsCategoriesResponse(); - - // Returns tree of feeds/categories. - // Top-level root of the tree is not needed here. - // Returned items do not have primary IDs assigned. - RootItem* feedsCategories(bool obtain_icons) const; - - private: - QString m_contentCategories; - QString m_contentFeeds; -}; - -class OwnCloudNetworkFactory { - public: - explicit OwnCloudNetworkFactory(); - virtual ~OwnCloudNetworkFactory(); - - QString url() const; - void setUrl(const QString& url); - - bool forceServerSideUpdate() const; - void setForceServerSideUpdate(bool force_update); - - QString authUsername() const; - void setAuthUsername(const QString& auth_username); - - QString authPassword() const; - void setAuthPassword(const QString& auth_password); - - // Gets/sets the amount of messages to obtain during single feed update. - int batchSize() const; - void setBatchSize(int batch_size); - - bool downloadOnlyUnreadMessages() const; - void setDownloadOnlyUnreadMessages(bool dowload_only_unread_messages); - - // Operations. - - // Get version info. - OwnCloudStatusResponse status(const QNetworkProxy& custom_proxy); - - // Get feeds & categories (used for sync-in). - OwnCloudGetFeedsCategoriesResponse feedsCategories(const QNetworkProxy& custom_proxy); - - // Feed operations. - bool deleteFeed(const QString& feed_id, const QNetworkProxy& custom_proxy); - bool createFeed(const QString& url, int parent_id, const QNetworkProxy& custom_proxy); - bool renameFeed(const QString& new_name, const QString& custom_feed_id, const QNetworkProxy& custom_proxy); - - // Get messages for given feed. - OwnCloudGetMessagesResponse getMessages(int feed_id, const QNetworkProxy& custom_proxy); - - // Misc methods. - QNetworkReply::NetworkError triggerFeedUpdate(int feed_id, const QNetworkProxy& custom_proxy); - - NetworkResult markMessagesRead(RootItem::ReadStatus status, - const QStringList& custom_ids, - const QNetworkProxy& custom_proxy); - - NetworkResult markMessagesStarred(RootItem::Importance importance, - const QStringList& feed_ids, - const QStringList& guid_hashes, - const QNetworkProxy& custom_proxy); - - private: - QString m_url; - QString m_fixedUrl; - bool m_downloadOnlyUnreadMessages; - bool m_forceServerSideUpdate; - QString m_authUsername; - QString m_authPassword; - int m_batchSize; - - // Endpoints. - QString m_urlUser; - QString m_urlStatus; - QString m_urlFolders; - QString m_urlFeeds; - QString m_urlMessages; - QString m_urlFeedsUpdate; - QString m_urlDeleteFeed; - QString m_urlRenameFeed; -}; - -#endif // OWNCLOUDNETWORKFACTORY_H diff --git a/src/librssguard/services/owncloud/owncloudserviceentrypoint.cpp b/src/librssguard/services/owncloud/owncloudserviceentrypoint.cpp deleted file mode 100644 index d98129c7d..000000000 --- a/src/librssguard/services/owncloud/owncloudserviceentrypoint.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/owncloud/owncloudserviceentrypoint.h" - -#include "database/databasequeries.h" -#include "definitions/definitions.h" -#include "miscellaneous/application.h" -#include "miscellaneous/iconfactory.h" -#include "services/owncloud/definitions.h" -#include "services/owncloud/gui/formeditowncloudaccount.h" -#include "services/owncloud/owncloudserviceroot.h" - -ServiceRoot* OwnCloudServiceEntryPoint::createNewRoot() const { - FormEditOwnCloudAccount form_acc(qApp->mainFormWidget()); - - return form_acc.addEditAccount(); -} - -QList OwnCloudServiceEntryPoint::initializeSubtree() const { - QSqlDatabase database = qApp->database()->driver()->connection(QSL("OwnCloudServiceEntryPoint")); - - return DatabaseQueries::getAccounts(database, code()); -} - -QString OwnCloudServiceEntryPoint::name() const { - return QSL("Nextcloud News"); -} - -QString OwnCloudServiceEntryPoint::code() const { - return QSL(SERVICE_CODE_OWNCLOUD); -} - -QString OwnCloudServiceEntryPoint::description() const { - return QObject::tr("The News app is an RSS/Atom feed aggregator. " - "It is part of Nextcloud suite. This plugin implements %1 API.") - .arg(QSL(OWNCLOUD_API_VERSION)); -} - -QString OwnCloudServiceEntryPoint::author() const { - return QSL(APP_AUTHOR); -} - -QIcon OwnCloudServiceEntryPoint::icon() const { - return qApp->icons()->miscIcon(QSL("nextcloud")); -} diff --git a/src/librssguard/services/owncloud/owncloudserviceentrypoint.h b/src/librssguard/services/owncloud/owncloudserviceentrypoint.h deleted file mode 100644 index bd358e19d..000000000 --- a/src/librssguard/services/owncloud/owncloudserviceentrypoint.h +++ /dev/null @@ -1,19 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef OWNCLOUDSERVICEENTRYPOINT_H -#define OWNCLOUDSERVICEENTRYPOINT_H - -#include "services/abstract/serviceentrypoint.h" - -class OwnCloudServiceEntryPoint : public ServiceEntryPoint { - public: - virtual ServiceRoot* createNewRoot() const; - virtual QList initializeSubtree() const; - virtual QString name() const; - virtual QString code() const; - virtual QString description() const; - virtual QString author() const; - virtual QIcon icon() const; -}; - -#endif // OWNCLOUDSERVICEENTRYPOINT_H diff --git a/src/librssguard/services/owncloud/owncloudserviceroot.cpp b/src/librssguard/services/owncloud/owncloudserviceroot.cpp deleted file mode 100644 index d453dc8b4..000000000 --- a/src/librssguard/services/owncloud/owncloudserviceroot.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/owncloud/owncloudserviceroot.h" - -#include "database/databasequeries.h" -#include "definitions/definitions.h" -#include "exceptions/feedfetchexception.h" -#include "exceptions/networkexception.h" -#include "miscellaneous/application.h" -#include "miscellaneous/textfactory.h" -#include "services/owncloud/gui/formeditowncloudaccount.h" -#include "services/owncloud/owncloudfeed.h" -#include "services/owncloud/owncloudnetworkfactory.h" -#include "services/owncloud/owncloudserviceentrypoint.h" - -OwnCloudServiceRoot::OwnCloudServiceRoot(RootItem* parent) - : ServiceRoot(parent), m_network(new OwnCloudNetworkFactory()) { - setIcon(OwnCloudServiceEntryPoint().icon()); -} - -OwnCloudServiceRoot::~OwnCloudServiceRoot() { - delete m_network; -} - -bool OwnCloudServiceRoot::isSyncable() const { - return true; -} - -bool OwnCloudServiceRoot::canBeEdited() const { - return true; -} - -FormAccountDetails* OwnCloudServiceRoot::accountSetupDialog() const { - return new FormEditOwnCloudAccount(qApp->mainFormWidget()); -} - -void OwnCloudServiceRoot::editItems(const QList& items) { - if (items.first()->kind() == RootItem::Kind::ServiceRoot) { - QScopedPointer p(qobject_cast(accountSetupDialog())); - - p->addEditAccount(this); - return; - } - - ServiceRoot::editItems(items); -} - -bool OwnCloudServiceRoot::supportsFeedAdding() const { - return false; -} - -bool OwnCloudServiceRoot::supportsCategoryAdding() const { - return false; -} - -void OwnCloudServiceRoot::start(bool freshly_activated) { - if (!freshly_activated) { - DatabaseQueries::loadRootFromDatabase(this); - loadCacheFromFile(); - } - - updateTitle(); - - if (getSubTreeFeeds().isEmpty()) { - syncIn(); - } -} - -QString OwnCloudServiceRoot::code() const { - return OwnCloudServiceEntryPoint().code(); -} - -OwnCloudNetworkFactory* OwnCloudServiceRoot::network() const { - return m_network; -} - -void OwnCloudServiceRoot::saveAllCachedData(bool ignore_errors) { - auto msg_cache = takeMessageCache(); - QMapIterator i(msg_cache.m_cachedStatesRead); - - // Save the actual data read/unread. - while (i.hasNext()) { - i.next(); - auto key = i.key(); - QStringList ids = i.value(); - - if (!ids.isEmpty()) { - auto res = network()->markMessagesRead(key, ids, networkProxy()); - - if (!ignore_errors && res.m_networkError != QNetworkReply::NetworkError::NoError) { - addMessageStatesToCache(ids, key); - } - } - } - - QMapIterator> j(msg_cache.m_cachedStatesImportant); - - // Save the actual data important/not important. - while (j.hasNext()) { - j.next(); - auto key = j.key(); - QList messages = j.value(); - - if (!messages.isEmpty()) { - QStringList feed_ids, guid_hashes; - - for (const Message& msg : messages) { - feed_ids.append(msg.m_feedId); - guid_hashes.append(msg.m_customHash); - } - - auto res = network()->markMessagesStarred(key, feed_ids, guid_hashes, networkProxy()); - - if (!ignore_errors && res.m_networkError != QNetworkReply::NetworkError::NoError) { - addMessageStatesToCache(messages, key); - } - } - } -} - -void OwnCloudServiceRoot::updateTitle() { - setTitle(m_network->authUsername() + QSL(" (Nextcloud News)")); -} - -RootItem* OwnCloudServiceRoot::obtainNewTreeForSyncIn() const { - OwnCloudGetFeedsCategoriesResponse feed_cats_response = m_network->feedsCategories(networkProxy()); - - if (feed_cats_response.networkError() == QNetworkReply::NetworkError::NoError) { - return feed_cats_response.feedsCategories(true); - } - else { - throw NetworkException(feed_cats_response.networkError(), - tr("cannot get list of feeds, network error '%1'").arg(feed_cats_response.networkError())); - } -} - -QVariantHash OwnCloudServiceRoot::customDatabaseData() const { - QVariantHash data = ServiceRoot::customDatabaseData(); - - data[QSL("auth_username")] = m_network->authUsername(); - data[QSL("auth_password")] = TextFactory::encrypt(m_network->authPassword()); - data[QSL("url")] = m_network->url(); - data[QSL("force_update")] = m_network->forceServerSideUpdate(); - data[QSL("batch_size")] = m_network->batchSize(); - data[QSL("download_only_unread")] = m_network->downloadOnlyUnreadMessages(); - - return data; -} - -void OwnCloudServiceRoot::setCustomDatabaseData(const QVariantHash& data) { - ServiceRoot::setCustomDatabaseData(data); - - m_network->setAuthUsername(data[QSL("auth_username")].toString()); - m_network->setAuthPassword(TextFactory::decrypt(data[QSL("auth_password")].toString())); - m_network->setUrl(data[QSL("url")].toString()); - m_network->setForceServerSideUpdate(data[QSL("force_update")].toBool()); - m_network->setBatchSize(data[QSL("batch_size")].toInt()); - m_network->setDownloadOnlyUnreadMessages(data[QSL("download_only_unread")].toBool()); -} - -QList OwnCloudServiceRoot::obtainNewMessages(Feed* feed, - const QHash& - stated_messages, - const QHash& tagged_messages) { - Q_UNUSED(stated_messages) - Q_UNUSED(tagged_messages) - - OwnCloudGetMessagesResponse messages = network()->getMessages(feed->customNumericId(), networkProxy()); - - if (messages.networkError() != QNetworkReply::NetworkError::NoError) { - throw FeedFetchException(Feed::Status::NetworkError); - } - else { - return messages.messages(); - } -} diff --git a/src/librssguard/services/owncloud/owncloudserviceroot.h b/src/librssguard/services/owncloud/owncloudserviceroot.h deleted file mode 100644 index c74a46d14..000000000 --- a/src/librssguard/services/owncloud/owncloudserviceroot.h +++ /dev/null @@ -1,48 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef OWNCLOUDSERVICEROOT_H -#define OWNCLOUDSERVICEROOT_H - -#include "services/abstract/cacheforserviceroot.h" -#include "services/abstract/serviceroot.h" - -#include - -class OwnCloudNetworkFactory; -class Mutex; - -class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot { - Q_OBJECT - - public: - explicit OwnCloudServiceRoot(RootItem* parent = nullptr); - virtual ~OwnCloudServiceRoot(); - - virtual bool isSyncable() const; - virtual bool canBeEdited() const; - virtual void editItems(const QList& items); - virtual FormAccountDetails* accountSetupDialog() const; - virtual bool supportsFeedAdding() const; - virtual bool supportsCategoryAdding() const; - virtual void start(bool freshly_activated); - virtual QString code() const; - virtual void saveAllCachedData(bool ignore_errors); - virtual QVariantHash customDatabaseData() const; - virtual void setCustomDatabaseData(const QVariantHash& data); - virtual QList obtainNewMessages(Feed* feed, - const QHash& stated_messages, - const QHash& tagged_messages); - - OwnCloudNetworkFactory* network() const; - - protected: - virtual RootItem* obtainNewTreeForSyncIn() const; - - private: - void updateTitle(); - - private: - OwnCloudNetworkFactory* m_network; -}; - -#endif // OWNCLOUDSERVICEROOT_H diff --git a/src/librssguard/services/reddit/definitions.h b/src/librssguard/services/reddit/definitions.h deleted file mode 100644 index aa433a402..000000000 --- a/src/librssguard/services/reddit/definitions.h +++ /dev/null @@ -1,23 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef REDDIT_DEFINITIONS_H -#define REDDIT_DEFINITIONS_H - -#define REDDIT_OAUTH_REDIRECT_URI_PORT 14499 -#define REDDIT_OAUTH_AUTH_URL "https://www.reddit.com/api/v1/authorize" -#define REDDIT_OAUTH_TOKEN_URL "https://www.reddit.com/api/v1/access_token" -#define REDDIT_OAUTH_SCOPE "identity mysubreddits read" - -#define REDDIT_REG_API_URL "https://www.reddit.com/prefs/apps" - -#define REDDIT_API_GET_PROFILE "https://oauth.reddit.com/api/v1/me" -#define REDDIT_API_SUBREDDITS "https://oauth.reddit.com/subreddits/mine/subscriber?limit=%1" -#define REDDIT_API_HOT "https://oauth.reddit.com%1hot?limit=%2&count=%3&g=%4" - -#define REDDIT_DEFAULT_BATCH_SIZE 100 -#define REDDIT_MAX_BATCH_SIZE 999 - -#define REDDIT_CONTENT_TYPE_HTTP "application/http" -#define REDDIT_CONTENT_TYPE_JSON "application/json" - -#endif // REDDIT_DEFINITIONS_H diff --git a/src/librssguard/services/reddit/gui/formeditredditaccount.cpp b/src/librssguard/services/reddit/gui/formeditredditaccount.cpp deleted file mode 100644 index 73d20d589..000000000 --- a/src/librssguard/services/reddit/gui/formeditredditaccount.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/reddit/gui/formeditredditaccount.h" - -#include "miscellaneous/application.h" -#include "miscellaneous/iconfactory.h" -#include "network-web/oauth2service.h" -#include "services/reddit/gui/redditaccountdetails.h" -#include "services/reddit/redditserviceroot.h" - -FormEditRedditAccount::FormEditRedditAccount(QWidget* parent) - : FormAccountDetails(qApp->icons()->miscIcon(QSL("reddit")), parent), m_details(new RedditAccountDetails(this)) { - insertCustomTab(m_details, tr("Server setup"), 0); - activateTab(0); - - m_details->m_ui.m_txtUsername->setFocus(); - connect(m_details->m_ui.m_btnTestSetup, &QPushButton::clicked, this, [this]() { - m_details->testSetup(m_proxyDetails->proxy()); - }); -} - -void FormEditRedditAccount::apply() { - FormAccountDetails::apply(); - - bool using_another_acc = - m_details->m_ui.m_txtUsername->lineEdit()->text() != account()->network()->username(); - - // Make sure that the data copied from GUI are used for brand new login. - account()->network()->oauth()->logout(false); - account()->network()->oauth()->setClientId(m_details->m_ui.m_txtAppId->lineEdit()->text()); - account()->network()->oauth()->setClientSecret(m_details->m_ui.m_txtAppKey->lineEdit()->text()); - account()->network()->oauth()->setRedirectUrl(m_details->m_ui.m_txtRedirectUrl->lineEdit()->text(), - true); - - account()->network()->setUsername(m_details->m_ui.m_txtUsername->lineEdit()->text()); - account()->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value()); - account()->network()->setDownloadOnlyUnreadMessages(m_details->m_ui.m_cbDownloadOnlyUnreadMessages - ->isChecked()); - - account()->saveAccountDataToDatabase(); - accept(); - - if (!m_creatingNew) { - if (using_another_acc) { - account()->completelyRemoveAllData(); - } - - account()->start(true); - } -} - -void FormEditRedditAccount::loadAccountData() { - FormAccountDetails::loadAccountData(); - - m_details->m_oauth = account()->network()->oauth(); - m_details->hookNetwork(); - - // Setup the GUI. - 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_details->m_ui.m_txtUsername->lineEdit()->setText(account()->network()->username()); - m_details->m_ui.m_spinLimitMessages->setValue(account()->network()->batchSize()); - m_details->m_ui.m_cbDownloadOnlyUnreadMessages - ->setChecked(account()->network()->downloadOnlyUnreadMessages()); -} diff --git a/src/librssguard/services/reddit/gui/formeditredditaccount.h b/src/librssguard/services/reddit/gui/formeditredditaccount.h deleted file mode 100644 index 0a7890b93..000000000 --- a/src/librssguard/services/reddit/gui/formeditredditaccount.h +++ /dev/null @@ -1,28 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef FORMEDITREDDITACCOUNT_H -#define FORMEDITREDDITACCOUNT_H - -#include "services/abstract/gui/formaccountdetails.h" -#include "services/reddit/redditnetworkfactory.h" - -class RedditServiceRoot; -class RedditAccountDetails; - -class FormEditRedditAccount : public FormAccountDetails { - Q_OBJECT - - public: - explicit FormEditRedditAccount(QWidget* parent = nullptr); - - protected slots: - virtual void apply(); - - protected: - virtual void loadAccountData(); - - private: - RedditAccountDetails* m_details; -}; - -#endif // FORMEDITREDDITACCOUNT_H diff --git a/src/librssguard/services/reddit/gui/redditaccountdetails.cpp b/src/librssguard/services/reddit/gui/redditaccountdetails.cpp deleted file mode 100644 index 6c2a727d1..000000000 --- a/src/librssguard/services/reddit/gui/redditaccountdetails.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/reddit/gui/redditaccountdetails.h" - -#include "exceptions/applicationexception.h" -#include "miscellaneous/application.h" -#include "network-web/oauth2service.h" -#include "network-web/webfactory.h" -#include "services/reddit/definitions.h" -#include "services/reddit/redditnetworkfactory.h" - -RedditAccountDetails::RedditAccountDetails(QWidget* parent) : QWidget(parent), m_oauth(nullptr), m_lastProxy({}) { - m_ui.setupUi(this); - - m_ui.m_lblInfo->setHelpText(tr("You have to fill in your client ID/secret and also fill in correct redirect URL."), - true); - 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, &RedditAccountDetails::checkOAuthValue); - connect(m_ui.m_txtAppKey->lineEdit(), &BaseLineEdit::textChanged, this, &RedditAccountDetails::checkOAuthValue); - connect(m_ui.m_txtRedirectUrl->lineEdit(), &BaseLineEdit::textChanged, this, &RedditAccountDetails::checkOAuthValue); - connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &RedditAccountDetails::checkUsername); - connect(m_ui.m_btnRegisterApi, &QPushButton::clicked, this, &RedditAccountDetails::registerApi); - - emit m_ui.m_txtUsername->lineEdit()->textChanged(m_ui.m_txtUsername->lineEdit()->text()); - emit m_ui.m_txtAppId->lineEdit()->textChanged(m_ui.m_txtAppId->lineEdit()->text()); - emit m_ui.m_txtAppKey->lineEdit()->textChanged(m_ui.m_txtAppKey->lineEdit()->text()); - emit m_ui.m_txtRedirectUrl->lineEdit()->textChanged(m_ui.m_txtAppKey->lineEdit()->text()); - - hookNetwork(); -} - -void RedditAccountDetails::testSetup(const QNetworkProxy& custom_proxy) { - m_oauth->logout(true); - 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(), true); - - m_lastProxy = custom_proxy; - m_oauth->login(); -} - -void RedditAccountDetails::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 RedditAccountDetails::onAuthFailed() { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("You did not grant access."), - tr("There was error during testing.")); -} - -void RedditAccountDetails::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 RedditAccountDetails::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.")); - - try { - RedditNetworkFactory fac; - - fac.setOauth(m_oauth); - - auto resp = fac.me(m_lastProxy); - - m_ui.m_txtUsername->lineEdit()->setText(resp[QSL("name")].toString()); - } - catch (const ApplicationException& ex) { - qCriticalNN << LOGSEC_REDDIT << "Failed to obtain profile with error:" << QUOTE_W_SPACE_DOT(ex.message()); - } -} - -void RedditAccountDetails::hookNetwork() { - connect(m_oauth, &OAuth2Service::tokensRetrieved, this, &RedditAccountDetails::onAuthGranted); - connect(m_oauth, &OAuth2Service::tokensRetrieveError, this, &RedditAccountDetails::onAuthError); - connect(m_oauth, &OAuth2Service::authFailed, this, &RedditAccountDetails::onAuthFailed); -} - -void RedditAccountDetails::registerApi() { - qApp->web()->openUrlInExternalBrowser(QSL(REDDIT_REG_API_URL)); -} - -void RedditAccountDetails::checkOAuthValue(const QString& value) { - auto* line_edit = qobject_cast(sender()->parent()); - - if (line_edit != nullptr) { - if (value.isEmpty()) { -#if defined(REDDIT_OFFICIAL_SUPPORT) - line_edit->setStatus(WidgetWithStatus::StatusType::Ok, tr("Preconfigured client ID/secret will be used.")); -#else - line_edit->setStatus(WidgetWithStatus::StatusType::Error, tr("Empty value is entered.")); -#endif - } - else { - line_edit->setStatus(WidgetWithStatus::StatusType::Ok, tr("Some value is entered.")); - } - } -} diff --git a/src/librssguard/services/reddit/gui/redditaccountdetails.h b/src/librssguard/services/reddit/gui/redditaccountdetails.h deleted file mode 100644 index 13e5a3877..000000000 --- a/src/librssguard/services/reddit/gui/redditaccountdetails.h +++ /dev/null @@ -1,43 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef REDDITACCOUNTDETAILS_H -#define REDDITACCOUNTDETAILS_H - -#include "ui_redditaccountdetails.h" - -#include -#include - -class OAuth2Service; - -class RedditAccountDetails : public QWidget { - Q_OBJECT - - friend class FormEditRedditAccount; - - public: - explicit RedditAccountDetails(QWidget* parent = nullptr); - - public slots: - void testSetup(const QNetworkProxy& custom_proxy); - - private slots: - void registerApi(); - 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::RedditAccountDetails m_ui; - - // Pointer to live OAuth. - OAuth2Service* m_oauth; - QNetworkProxy m_lastProxy; -}; - -#endif // REDDITACCOUNTDETAILS_H diff --git a/src/librssguard/services/reddit/gui/redditaccountdetails.ui b/src/librssguard/services/reddit/gui/redditaccountdetails.ui deleted file mode 100644 index da0a54a31..000000000 --- a/src/librssguard/services/reddit/gui/redditaccountdetails.ui +++ /dev/null @@ -1,202 +0,0 @@ - - - RedditAccountDetails - - - - 0 - 0 - 431 - 259 - - - - - - - Username - - - - - - - - - - - 0 - 1 - - - - OAuth 2.0 settings - - - - - - Client ID - - - m_txtAppId - - - - - - - - - - Client secret - - - m_txtAppKey - - - - - - - - - - Redirect URL - - - m_txtRedirectUrl - - - - - - - - - - - - Get my credentials - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - Only download newest X articles per feed - - - m_spinLimitMessages - - - - - - - - 140 - 16777215 - - - - - - - - - - - - &Login - - - - - - - Qt::RightToLeft - - - - - - - - - Qt::Vertical - - - - 410 - 0 - - - - - - - - Download unread articles only - - - - - - - - LineEditWithStatus - QWidget -
lineeditwithstatus.h
- 1 -
- - LabelWithStatus - QWidget -
labelwithstatus.h
- 1 -
- - MessageCountSpinBox - QSpinBox -
messagecountspinbox.h
-
- - HelpSpoiler - QWidget -
helpspoiler.h
- 1 -
-
- - m_btnRegisterApi - m_cbDownloadOnlyUnreadMessages - m_spinLimitMessages - m_btnTestSetup - - - -
diff --git a/src/librssguard/services/reddit/redditcategory.cpp b/src/librssguard/services/reddit/redditcategory.cpp deleted file mode 100644 index 0a5c51c64..000000000 --- a/src/librssguard/services/reddit/redditcategory.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/reddit/redditcategory.h" - -RedditCategory::RedditCategory(Type type, RootItem* parent_item) : Category(parent_item), m_type(type) { - updateTitle(); -} - -RedditCategory::Type RedditCategory::type() const { - return m_type; -} - -void RedditCategory::updateTitle() { - switch (m_type) { - case Type::Subscriptions: - setTitle(tr("Subscriptions")); - break; - } -} diff --git a/src/librssguard/services/reddit/redditcategory.h b/src/librssguard/services/reddit/redditcategory.h deleted file mode 100644 index 7e584eac9..000000000 --- a/src/librssguard/services/reddit/redditcategory.h +++ /dev/null @@ -1,27 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef REDDITCATEGORY_H -#define REDDITCATEGORY_H - -#include "services/abstract/category.h" - -class RedditCategory : public Category { - Q_OBJECT - - public: - enum class Type { - Subscriptions = 1 - }; - - explicit RedditCategory(Type type = Type::Subscriptions, RootItem* parent_item = nullptr); - - Type type() const; - - private: - void updateTitle(); - - private: - Type m_type; -}; - -#endif // REDDITCATEGORY_H diff --git a/src/librssguard/services/reddit/redditentrypoint.cpp b/src/librssguard/services/reddit/redditentrypoint.cpp deleted file mode 100644 index 45b727068..000000000 --- a/src/librssguard/services/reddit/redditentrypoint.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/reddit/redditentrypoint.h" - -#include "database/databasequeries.h" -#include "definitions/definitions.h" -#include "miscellaneous/application.h" -#include "miscellaneous/iconfactory.h" -#include "services/reddit/gui/formeditredditaccount.h" -#include "services/reddit/redditserviceroot.h" - -#include - -ServiceRoot* RedditEntryPoint::createNewRoot() const { - FormEditRedditAccount form_acc(qApp->mainFormWidget()); - - return form_acc.addEditAccount(); -} - -QList RedditEntryPoint::initializeSubtree() const { - QSqlDatabase database = qApp->database()->driver()->connection(QSL("RedditEntryPoint")); - - return DatabaseQueries::getAccounts(database, code()); -} - -QString RedditEntryPoint::name() const { - return QSL("Reddit"); -} - -QString RedditEntryPoint::code() const { - return QSL(SERVICE_CODE_REDDIT); -} - -QString RedditEntryPoint::description() const { - return QObject::tr("Simplistic Reddit client."); -} - -QString RedditEntryPoint::author() const { - return QSL(APP_AUTHOR); -} - -QIcon RedditEntryPoint::icon() const { - return qApp->icons()->miscIcon(QSL("reddit")); -} diff --git a/src/librssguard/services/reddit/redditentrypoint.h b/src/librssguard/services/reddit/redditentrypoint.h deleted file mode 100644 index 74a47caf1..000000000 --- a/src/librssguard/services/reddit/redditentrypoint.h +++ /dev/null @@ -1,19 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef REDDITENTRYPOINT_H -#define REDDITENTRYPOINT_H - -#include "services/abstract/serviceentrypoint.h" - -class RedditEntryPoint : public ServiceEntryPoint { - public: - virtual ServiceRoot* createNewRoot() const; - virtual QList initializeSubtree() const; - virtual QString name() const; - virtual QString code() const; - virtual QString description() const; - virtual QString author() const; - virtual QIcon icon() const; -}; - -#endif // REDDITENTRYPOINT_H diff --git a/src/librssguard/services/reddit/redditnetworkfactory.cpp b/src/librssguard/services/reddit/redditnetworkfactory.cpp deleted file mode 100644 index 893edf26c..000000000 --- a/src/librssguard/services/reddit/redditnetworkfactory.cpp +++ /dev/null @@ -1,322 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/reddit/redditnetworkfactory.h" - -#include "database/databasequeries.h" -#include "definitions/definitions.h" -#include "exceptions/applicationexception.h" -#include "exceptions/networkexception.h" -#include "miscellaneous/application.h" -#include "miscellaneous/settings.h" -#include "network-web/networkfactory.h" -#include "network-web/oauth2service.h" -#include "services/reddit/definitions.h" -#include "services/reddit/redditserviceroot.h" -#include "services/reddit/redditsubscription.h" - -#include -#include -#include -#include -#include -#include - -RedditNetworkFactory::RedditNetworkFactory(QObject* parent) - : QObject(parent), m_service(nullptr), m_username(QString()), m_batchSize(REDDIT_DEFAULT_BATCH_SIZE), - m_downloadOnlyUnreadMessages(false), m_oauth2(new OAuth2Service(QSL(REDDIT_OAUTH_AUTH_URL), - QSL(REDDIT_OAUTH_TOKEN_URL), - {}, - {}, - QSL(REDDIT_OAUTH_SCOPE), - this)) { - initializeOauth(); -} - -void RedditNetworkFactory::setService(RedditServiceRoot* service) { - m_service = service; -} - -OAuth2Service* RedditNetworkFactory::oauth() const { - return m_oauth2; -} - -QString RedditNetworkFactory::username() const { - return m_username; -} - -int RedditNetworkFactory::batchSize() const { - return m_batchSize; -} - -void RedditNetworkFactory::setBatchSize(int batch_size) { - m_batchSize = batch_size; -} - -void RedditNetworkFactory::initializeOauth() { - m_oauth2->setUseHttpBasicAuthWithClientData(true); - m_oauth2->setRedirectUrl(QSL(OAUTH_REDIRECT_URI) + QL1C(':') + QString::number(REDDIT_OAUTH_REDIRECT_URI_PORT), true); - - connect(m_oauth2, &OAuth2Service::tokensRetrieveError, this, &RedditNetworkFactory::onTokensError); - connect(m_oauth2, &OAuth2Service::authFailed, this, &RedditNetworkFactory::onAuthFailed); - connect(m_oauth2, - &OAuth2Service::tokensRetrieved, - this, - [this](QString access_token, QString refresh_token, int expires_in) { - Q_UNUSED(expires_in) - Q_UNUSED(access_token) - - if (m_service != nullptr && !refresh_token.isEmpty()) { - QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); - - DatabaseQueries::storeNewOauthTokens(database, refresh_token, m_service->accountId()); - } - }); -} - -bool RedditNetworkFactory::downloadOnlyUnreadMessages() const { - return m_downloadOnlyUnreadMessages; -} - -void RedditNetworkFactory::setDownloadOnlyUnreadMessages(bool download_only_unread_messages) { - m_downloadOnlyUnreadMessages = download_only_unread_messages; -} - -void RedditNetworkFactory::setOauth(OAuth2Service* oauth) { - m_oauth2 = oauth; -} - -void RedditNetworkFactory::setUsername(const QString& username) { - m_username = username; -} - -QVariantHash RedditNetworkFactory::me(const QNetworkProxy& custom_proxy) { - QString bearer = m_oauth2->bearer().toLocal8Bit(); - - if (bearer.isEmpty()) { - throw ApplicationException(tr("you are not logged in")); - } - - QList> headers; - - headers.append(QPair(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), - m_oauth2->bearer().toLocal8Bit())); - - int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray output; - auto result = NetworkFactory::performNetworkOperation(QSL(REDDIT_API_GET_PROFILE), - timeout, - {}, - output, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy) - .m_networkError; - - if (result != QNetworkReply::NetworkError::NoError) { - throw NetworkException(result, output); - } - else { - QJsonDocument doc = QJsonDocument::fromJson(output); - - return doc.object().toVariantHash(); - } -} - -QList RedditNetworkFactory::subreddits(const QNetworkProxy& custom_proxy) { - QString bearer = m_oauth2->bearer().toLocal8Bit(); - - if (bearer.isEmpty()) { - throw ApplicationException(tr("you are not logged in")); - } - - QList> headers; - - headers.append(QPair(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), - m_oauth2->bearer().toLocal8Bit())); - - int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QString after; - QList subs; - - do { - QByteArray output; - QString final_url = QSL(REDDIT_API_SUBREDDITS).arg(QString::number(100)); - - if (!after.isEmpty()) { - final_url += QSL("&after=%1").arg(after); - } - - auto result = NetworkFactory::performNetworkOperation(final_url, - timeout, - {}, - output, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy) - .m_networkError; - - if (result != QNetworkReply::NetworkError::NoError) { - throw NetworkException(result, output); - } - else { - QJsonDocument doc = QJsonDocument::fromJson(output); - QJsonObject root_doc = doc.object(); - - after = root_doc["data"].toObject()["after"].toString(); - - for (const QJsonValue& sub_val : root_doc["data"].toObject()["children"].toArray()) { - const auto sub_obj = sub_val.toObject()["data"].toObject(); - - RedditSubscription* new_sub = new RedditSubscription(); - - new_sub->setCustomId(sub_obj["id"].toString()); - new_sub->setTitle(sub_obj["title"].toString()); - new_sub->setDescription(sub_obj["public_description"].toString()); - - new_sub->setPrefixedName(sub_obj["url"].toString()); - - QPixmap icon; - QString icon_url = sub_obj["community_icon"].toString(); - - if (icon_url.isEmpty()) { - icon_url = sub_obj["icon_img"].toString(); - } - - if (icon_url.contains(QL1S("?"))) { - icon_url = icon_url.mid(0, icon_url.indexOf(QL1S("?"))); - } - - if (!icon_url.isEmpty() && - NetworkFactory::downloadIcon({{icon_url, true}}, timeout, icon, headers, custom_proxy) == - QNetworkReply::NetworkError::NoError) { - new_sub->setIcon(icon); - } - - subs.append(new_sub); - } - } - } - while (!after.isEmpty()); - - // posty dle jmena redditu - // https://oauth.reddit.com//new - // - // komenty pro post dle id postu - // https://oauth.reddit.com//comments/ - - return subs; -} - -QList RedditNetworkFactory::hot(const QString& sub_name, const QNetworkProxy& custom_proxy) { - QString bearer = m_oauth2->bearer().toLocal8Bit(); - - if (bearer.isEmpty()) { - throw ApplicationException(tr("you are not logged in")); - } - - QList> headers; - - headers.append(QPair(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), - m_oauth2->bearer().toLocal8Bit())); - - int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QString after; - QList msgs; - - int desired_count = batchSize(); - - do { - int next_batch = desired_count <= 0 ? 100 : std::min(100, int(desired_count - msgs.size())); - - QByteArray output; - QString final_url = - QSL(REDDIT_API_HOT).arg(sub_name, QString::number(next_batch), QString::number(msgs.size()), QSL("GLOBAL")); - - if (!after.isEmpty()) { - final_url += QSL("&after=%1").arg(after); - } - - auto result = NetworkFactory::performNetworkOperation(final_url, - timeout, - {}, - output, - QNetworkAccessManager::Operation::GetOperation, - headers, - false, - {}, - {}, - custom_proxy) - .m_networkError; - - if (result != QNetworkReply::NetworkError::NoError) { - throw NetworkException(result, output); - } - else { - QJsonDocument doc = QJsonDocument::fromJson(output); - QJsonObject root_doc = doc.object(); - - after = root_doc["data"].toObject()["after"].toString(); - - for (const QJsonValue& sub_val : root_doc["data"].toObject()["children"].toArray()) { - const auto msg_obj = sub_val.toObject()["data"].toObject(); - - Message new_msg; - - new_msg.m_customId = msg_obj["id"].toString(); - new_msg.m_title = msg_obj["title"].toString(); - new_msg.m_author = msg_obj["author"].toString(); - new_msg.m_createdFromFeed = true; - new_msg.m_created = - QDateTime::fromSecsSinceEpoch(msg_obj["created_utc"].toVariant().toLongLong(), Qt::TimeSpec::UTC); - new_msg.m_url = QSL("https://reddit.com") + msg_obj["permalink"].toString(); - new_msg.m_contents = - msg_obj["description_html"] - .toString(); // když prazdny, je poustnutej třeba obrazek či odkaz?, viz property "post_hint"? - new_msg.m_rawContents = QJsonDocument(msg_obj).toJson(QJsonDocument::JsonFormat::Compact); - - msgs.append(new_msg); - } - } - } - while (!after.isEmpty() && (desired_count <= 0 || desired_count > msgs.size())); - - // posty dle jmena redditu - // https://oauth.reddit.com//new - // - // komenty pro post dle id postu - // https://oauth.reddit.com//comments/ - - return msgs; -} - -void RedditNetworkFactory::onTokensError(const QString& error, const QString& error_description) { - Q_UNUSED(error) - - qApp->showGuiMessage(Notification::Event::LoginFailure, - {tr("Reddit: authentication error"), - tr("Click this to login again. Error is: '%1'").arg(error_description), - QSystemTrayIcon::MessageIcon::Critical}, - {}, - {tr("Login"), [this]() { - m_oauth2->setAccessToken(QString()); - m_oauth2->setRefreshToken(QString()); - m_oauth2->login(); - }}); -} - -void RedditNetworkFactory::onAuthFailed() { - qApp->showGuiMessage(Notification::Event::LoginFailure, - {tr("Reddit: authorization denied"), - tr("Click this to login again."), - QSystemTrayIcon::MessageIcon::Critical}, - {}, - {tr("Login"), [this]() { - m_oauth2->login(); - }}); -} diff --git a/src/librssguard/services/reddit/redditnetworkfactory.h b/src/librssguard/services/reddit/redditnetworkfactory.h deleted file mode 100644 index 4ce33b940..000000000 --- a/src/librssguard/services/reddit/redditnetworkfactory.h +++ /dev/null @@ -1,60 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef REDDITNETWORKFACTORY_H -#define REDDITNETWORKFACTORY_H - -#include "core/message.h" -#include "services/abstract/feed.h" -#include "services/abstract/rootitem.h" - -#include -#include - -class RootItem; -class RedditServiceRoot; -class OAuth2Service; -class Downloader; - -struct Subreddit {}; - -class RedditNetworkFactory : public QObject { - Q_OBJECT - - public: - explicit RedditNetworkFactory(QObject* parent = nullptr); - - void setService(RedditServiceRoot* service); - - OAuth2Service* oauth() const; - void setOauth(OAuth2Service* oauth); - - QString username() const; - void setUsername(const QString& username); - - int batchSize() const; - void setBatchSize(int batch_size); - - bool downloadOnlyUnreadMessages() const; - void setDownloadOnlyUnreadMessages(bool download_only_unread_messages); - - // API methods. - QVariantHash me(const QNetworkProxy& custom_proxy); - QList subreddits(const QNetworkProxy& custom_proxy); - QList hot(const QString& sub_name, const QNetworkProxy& custom_proxy); - - private slots: - void onTokensError(const QString& error, const QString& error_description); - void onAuthFailed(); - - private: - void initializeOauth(); - - private: - RedditServiceRoot* m_service; - QString m_username; - int m_batchSize; - bool m_downloadOnlyUnreadMessages; - OAuth2Service* m_oauth2; -}; - -#endif // REDDITNETWORKFACTORY_H diff --git a/src/librssguard/services/reddit/redditserviceroot.cpp b/src/librssguard/services/reddit/redditserviceroot.cpp deleted file mode 100644 index 7e6752373..000000000 --- a/src/librssguard/services/reddit/redditserviceroot.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/reddit/redditserviceroot.h" - -#include "database/databasequeries.h" -#include "miscellaneous/application.h" -#include "network-web/oauth2service.h" -#include "services/reddit/gui/formeditredditaccount.h" -#include "services/reddit/redditcategory.h" -#include "services/reddit/redditentrypoint.h" -#include "services/reddit/redditnetworkfactory.h" -#include "services/reddit/redditsubscription.h" - -#include - -RedditServiceRoot::RedditServiceRoot(RootItem* parent) - : ServiceRoot(parent), m_network(new RedditNetworkFactory(this)) { - m_network->setService(this); - setIcon(RedditEntryPoint().icon()); -} - -void RedditServiceRoot::updateTitle() { - setTitle(TextFactory::extractUsernameFromEmail(m_network->username()) + QSL(" (Reddit)")); -} - -RootItem* RedditServiceRoot::obtainNewTreeForSyncIn() const { - auto* root = new RootItem(); - - auto feeds = m_network->subreddits(networkProxy()); - - for (auto* feed : feeds) { - root->appendChild(feed); - } - - return root; -} - -QVariantHash RedditServiceRoot::customDatabaseData() const { - QVariantHash data = ServiceRoot::customDatabaseData(); - - data[QSL("username")] = m_network->username(); - data[QSL("batch_size")] = m_network->batchSize(); - data[QSL("download_only_unread")] = m_network->downloadOnlyUnreadMessages(); - data[QSL("client_id")] = m_network->oauth()->clientId(); - data[QSL("client_secret")] = m_network->oauth()->clientSecret(); - data[QSL("refresh_token")] = m_network->oauth()->refreshToken(); - data[QSL("redirect_uri")] = m_network->oauth()->redirectUrl(); - - return data; -} - -void RedditServiceRoot::setCustomDatabaseData(const QVariantHash& data) { - ServiceRoot::setCustomDatabaseData(data); - - m_network->setUsername(data[QSL("username")].toString()); - m_network->setBatchSize(data[QSL("batch_size")].toInt()); - m_network->setDownloadOnlyUnreadMessages(data[QSL("download_only_unread")].toBool()); - m_network->oauth()->setClientId(data[QSL("client_id")].toString()); - m_network->oauth()->setClientSecret(data[QSL("client_secret")].toString()); - m_network->oauth()->setRefreshToken(data[QSL("refresh_token")].toString()); - m_network->oauth()->setRedirectUrl(data[QSL("redirect_uri")].toString(), true); -} - -QList RedditServiceRoot::obtainNewMessages(Feed* feed, - const QHash& - stated_messages, - const QHash& tagged_messages) { - Q_UNUSED(stated_messages) - Q_UNUSED(tagged_messages) - Q_UNUSED(feed) - - QList messages = m_network->hot(qobject_cast(feed)->prefixedName(), networkProxy()); - - return messages; -} - -bool RedditServiceRoot::isSyncable() const { - return true; -} - -bool RedditServiceRoot::canBeEdited() const { - return true; -} - -void RedditServiceRoot::editItems(const QList& items) { - if (items.first()->kind() == RootItem::Kind::ServiceRoot) { - QScopedPointer p(qobject_cast(accountSetupDialog())); - - p->addEditAccount(this); - return; - } - - ServiceRoot::editItems(items); -} - -FormAccountDetails* RedditServiceRoot::accountSetupDialog() const { - return new FormEditRedditAccount(qApp->mainFormWidget()); -} - -bool RedditServiceRoot::supportsFeedAdding() const { - return false; -} - -bool RedditServiceRoot::supportsCategoryAdding() const { - return false; -} - -void RedditServiceRoot::start(bool freshly_activated) { - if (!freshly_activated) { - DatabaseQueries::loadRootFromDatabase(this); - loadCacheFromFile(); - } - - updateTitle(); - - if (getSubTreeFeeds().isEmpty()) { - m_network->oauth()->login([this]() { - syncIn(); - }); - } - else { - m_network->oauth()->login(); - } -} - -QString RedditServiceRoot::code() const { - return RedditEntryPoint().code(); -} - -QString RedditServiceRoot::additionalTooltip() const { - return ServiceRoot::additionalTooltip() + QSL("\n") + - tr("Authentication status: %1\n" - "Login tokens expiration: %2") - .arg(network()->oauth()->isFullyLoggedIn() ? tr("logged-in") : tr("NOT logged-in"), - network()->oauth()->tokensExpireIn().isValid() ? network()->oauth()->tokensExpireIn().toString() - : QSL("-")); -} - -void RedditServiceRoot::saveAllCachedData(bool ignore_errors) { - Q_UNUSED(ignore_errors) - auto msg_cache = takeMessageCache(); -} diff --git a/src/librssguard/services/reddit/redditserviceroot.h b/src/librssguard/services/reddit/redditserviceroot.h deleted file mode 100644 index 568faa1ac..000000000 --- a/src/librssguard/services/reddit/redditserviceroot.h +++ /dev/null @@ -1,54 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef REDDITSERVICEROOT_H -#define REDDITSERVICEROOT_H - -#include "services/abstract/cacheforserviceroot.h" -#include "services/abstract/serviceroot.h" - -class RedditNetworkFactory; - -class RedditServiceRoot : public ServiceRoot, public CacheForServiceRoot { - Q_OBJECT - - public: - explicit RedditServiceRoot(RootItem* parent = nullptr); - - void setNetwork(RedditNetworkFactory* network); - RedditNetworkFactory* network() const; - - virtual bool isSyncable() const; - virtual bool canBeEdited() const; - virtual void editItems(const QList& items); - virtual FormAccountDetails* accountSetupDialog() const; - virtual bool supportsFeedAdding() const; - virtual bool supportsCategoryAdding() const; - virtual void start(bool freshly_activated); - virtual QString code() const; - virtual QString additionalTooltip() const; - virtual void saveAllCachedData(bool ignore_errors); - virtual QVariantHash customDatabaseData() const; - virtual void setCustomDatabaseData(const QVariantHash& data); - virtual QList obtainNewMessages(Feed* feed, - const QHash& stated_messages, - const QHash& tagged_messages); - - protected: - virtual RootItem* obtainNewTreeForSyncIn() const; - - private: - void updateTitle(); - - private: - RedditNetworkFactory* m_network; -}; - -inline void RedditServiceRoot::setNetwork(RedditNetworkFactory* network) { - m_network = network; -} - -inline RedditNetworkFactory* RedditServiceRoot::network() const { - return m_network; -} - -#endif // REDDITSERVICEROOT_H diff --git a/src/librssguard/services/reddit/redditsubscription.cpp b/src/librssguard/services/reddit/redditsubscription.cpp deleted file mode 100644 index 320db3e9b..000000000 --- a/src/librssguard/services/reddit/redditsubscription.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/reddit/redditsubscription.h" - -#include "definitions/definitions.h" -#include "services/reddit/redditserviceroot.h" - -RedditSubscription::RedditSubscription(RootItem* parent) : Feed(parent), m_prefixedName(QString()) {} - -RedditServiceRoot* RedditSubscription::serviceRoot() const { - return qobject_cast(getParentServiceRoot()); -} - -QString RedditSubscription::prefixedName() const { - return m_prefixedName; -} - -void RedditSubscription::setPrefixedName(const QString& prefixed_name) { - m_prefixedName = prefixed_name; -} - -QVariantHash RedditSubscription::customDatabaseData() const { - QVariantHash data; - - data.insert(QSL("prefixed_name"), prefixedName()); - - return data; -} - -void RedditSubscription::setCustomDatabaseData(const QVariantHash& data) { - setPrefixedName(data.value(QSL("prefixed_name")).toString()); -} diff --git a/src/librssguard/services/reddit/redditsubscription.h b/src/librssguard/services/reddit/redditsubscription.h deleted file mode 100644 index 99e774305..000000000 --- a/src/librssguard/services/reddit/redditsubscription.h +++ /dev/null @@ -1,28 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef REDDITSUBSCRIPTION_H -#define REDDITSUBSCRIPTION_H - -#include "services/abstract/feed.h" - -class RedditServiceRoot; - -class RedditSubscription : public Feed { - Q_OBJECT - - public: - explicit RedditSubscription(RootItem* parent = nullptr); - - RedditServiceRoot* serviceRoot() const; - - QString prefixedName() const; - void setPrefixedName(const QString& prefixed_name); - - virtual QVariantHash customDatabaseData() const; - virtual void setCustomDatabaseData(const QVariantHash& data); - - private: - QString m_prefixedName; -}; - -#endif // REDDITSUBSCRIPTION_H diff --git a/src/librssguard/services/tt-rss/definitions.h b/src/librssguard/services/tt-rss/definitions.h deleted file mode 100644 index b76994be2..000000000 --- a/src/librssguard/services/tt-rss/definitions.h +++ /dev/null @@ -1,49 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSS_DEFINITIONS_H -#define TTRSS_DEFINITIONS_H - -#define TTRSS_MINIMAL_API_LEVEL 9 -#define TTRSS_CONTENT_TYPE_JSON "application/json; charset=utf-8" - -/// -/// Errors. -/// -#define TTRSS_NOT_LOGGED_IN "NOT_LOGGED_IN" // Error when user needs to login before making an operation. -#define TTRSS_UNKNOWN_METHOD "UNKNOWN_METHOD" // Given "op" is not recognized. -#define TTRSS_INCORRECT_USAGE "INCORRECT_USAGE" // Given "op" was used with bad parameters. - -// Limitations -#define TTRSS_DEFAULT_MESSAGES 100 -#define TTRSS_MAX_MESSAGES 200 - -// General return status codes. -#define TTRSS_API_STATUS_OK 0 -#define TTRSS_API_STATUS_ERR 1 -#define TTRSS_CONTENT_NOT_LOADED -1 - -// Login. -#define TTRSS_API_DISABLED "API_DISABLED" // API is not enabled. -#define TTRSS_LOGIN_ERROR "LOGIN_ERROR" // Incorrect password/username. - -// Get feed tree. -#define TTRSS_GFT_TYPE_CATEGORY "category" - -// "Published" feed/label. -#define TTRSS_PUBLISHED_LABEL_ID -2 -#define TTRSS_PUBLISHED_FEED_ID 0 - -// Subscribe to feed. -#define STF_UNKNOWN -1 -#define STF_EXISTS 0 -#define STF_INVALID_URL 2 -#define STF_UNREACHABLE_URL 5 -#define STF_URL_NO_FEED 3 -#define STF_URL_MANY_FEEDS 4 -#define STF_INSERTED 1 - -// Unsubscribe from feed. -#define UFF_FEED_NOT_FOUND "FEED_NOT_FOUND" -#define UFF_OK "OK" - -#endif // TTRSS_DEFINITIONS_H diff --git a/src/librssguard/services/tt-rss/gui/formeditttrssaccount.cpp b/src/librssguard/services/tt-rss/gui/formeditttrssaccount.cpp deleted file mode 100644 index 4316ec65d..000000000 --- a/src/librssguard/services/tt-rss/gui/formeditttrssaccount.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/gui/formeditttrssaccount.h" - -#include "miscellaneous/iconfactory.h" -#include "services/tt-rss/gui/ttrssaccountdetails.h" -#include "services/tt-rss/ttrssnetworkfactory.h" -#include "services/tt-rss/ttrssserviceroot.h" - -FormEditTtRssAccount::FormEditTtRssAccount(QWidget* parent) - : FormAccountDetails(qApp->icons()->miscIcon(QSL("tt-rss")), parent), m_details(new TtRssAccountDetails(this)) { - insertCustomTab(m_details, tr("Server setup"), 0); - activateTab(0); - - connect(m_details->m_ui.m_btnTestSetup, &QPushButton::clicked, this, &FormEditTtRssAccount::performTest); - m_details->m_ui.m_txtUrl->setFocus(); -} - -void FormEditTtRssAccount::apply() { - FormAccountDetails::apply(); - - bool using_another_acc = - m_details->m_ui.m_txtUsername->lineEdit()->text() != account()->network()->username() || - m_details->m_ui.m_txtUrl->lineEdit()->text() != account()->network()->url(); - - account()->network()->logout(m_account->networkProxy()); - account()->network()->setUrl(m_details->m_ui.m_txtUrl->lineEdit()->text()); - account()->network()->setUsername(m_details->m_ui.m_txtUsername->lineEdit()->text()); - account()->network()->setPassword(m_details->m_ui.m_txtPassword->lineEdit()->text()); - account()->network()->setAuthIsUsed(m_details->m_ui.m_gbHttpAuthentication->isChecked()); - account()->network()->setAuthUsername(m_details->m_ui.m_txtHttpUsername->lineEdit()->text()); - account()->network()->setAuthPassword(m_details->m_ui.m_txtHttpPassword->lineEdit()->text()); - account()->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value()); - account()->network()->setIntelligentSynchronization(m_details->m_ui.m_cbNewAlgorithm->isChecked()); - account()->network()->setForceServerSideUpdate(m_details->m_ui.m_checkServerSideUpdate - ->isChecked()); - account() - ->network() - ->setDownloadOnlyUnreadMessages(m_details->m_ui.m_checkDownloadOnlyUnreadMessages->isChecked()); - - account()->saveAccountDataToDatabase(); - accept(); - - if (!m_creatingNew && using_another_acc) { - account()->completelyRemoveAllData(); - account()->start(true); - } -} - -void FormEditTtRssAccount::loadAccountData() { - FormAccountDetails::loadAccountData(); - - TtRssServiceRoot* existing_root = account(); - - m_details->m_ui.m_gbHttpAuthentication->setChecked(existing_root->network()->authIsUsed()); - m_details->m_ui.m_txtHttpPassword->lineEdit()->setText(existing_root->network()->authPassword()); - m_details->m_ui.m_txtHttpUsername->lineEdit()->setText(existing_root->network()->authUsername()); - m_details->m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->username()); - m_details->m_ui.m_txtPassword->lineEdit()->setText(existing_root->network()->password()); - m_details->m_ui.m_txtUrl->lineEdit()->setText(existing_root->network()->url()); - m_details->m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize()); - m_details->m_ui.m_checkServerSideUpdate->setChecked(existing_root->network()->forceServerSideUpdate()); - m_details->m_ui.m_checkDownloadOnlyUnreadMessages->setChecked(existing_root->network()->downloadOnlyUnreadMessages()); - m_details->m_ui.m_cbNewAlgorithm->setChecked(existing_root->network()->intelligentSynchronization()); -} - -void FormEditTtRssAccount::performTest() { - m_details->performTest(m_proxyDetails->proxy()); -} diff --git a/src/librssguard/services/tt-rss/gui/formeditttrssaccount.h b/src/librssguard/services/tt-rss/gui/formeditttrssaccount.h deleted file mode 100644 index 2357b2a17..000000000 --- a/src/librssguard/services/tt-rss/gui/formeditttrssaccount.h +++ /dev/null @@ -1,31 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef FORMEDITACCOUNT_H -#define FORMEDITACCOUNT_H - -#include "services/abstract/gui/formaccountdetails.h" - -class RootItem; -class TtRssServiceRoot; -class TtRssAccountDetails; - -class FormEditTtRssAccount : public FormAccountDetails { - Q_OBJECT - - public: - explicit FormEditTtRssAccount(QWidget* parent = nullptr); - - protected slots: - virtual void apply(); - - protected: - virtual void loadAccountData(); - - private slots: - void performTest(); - - private: - TtRssAccountDetails* m_details; -}; - -#endif // FORMEDITACCOUNT_H diff --git a/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.cpp b/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.cpp deleted file mode 100644 index a91a33d11..000000000 --- a/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/gui/formttrssfeeddetails.h" - -#include "exceptions/applicationexception.h" -#include "miscellaneous/application.h" -#include "services/abstract/gui/authenticationdetails.h" -#include "services/tt-rss/definitions.h" -#include "services/tt-rss/gui/ttrssfeeddetails.h" -#include "services/tt-rss/ttrssnetworkfactory.h" -#include "services/tt-rss/ttrssserviceroot.h" - -#include -#include - -FormTtRssFeedDetails::FormTtRssFeedDetails(ServiceRoot* service_root, - RootItem* parent_to_select, - const QString& url, - QWidget* parent) - : FormFeedDetails(service_root, parent), m_feedDetails(new TtRssFeedDetails(this)), - m_authDetails(new AuthenticationDetails(true, this)), m_parentToSelect(parent_to_select), m_urlToProcess(url) {} - -void FormTtRssFeedDetails::apply() { - if (!m_creatingNew) { - // NOTE: We can only edit base properties, therefore - // base method is fine. - FormFeedDetails::apply(); - } - else { - RootItem* parent = m_feedDetails->ui.m_cmbParentCategory->currentData().value(); - auto* root = qobject_cast(parent->getParentServiceRoot()); - const int category_id = parent->kind() == RootItem::Kind::ServiceRoot ? 0 : parent->customNumericId(); - const TtRssSubscribeToFeedResponse response = - root->network()->subscribeToFeed(m_feedDetails->ui.m_txtUrl->lineEdit()->text(), - category_id, - m_serviceRoot->networkProxy(), - m_authDetails->authenticationType() == - NetworkFactory::NetworkAuthentication::Basic, - m_authDetails->username(), - m_authDetails->password()); - - if (response.code() == STF_INSERTED) { - // Feed was added online. - qApp->showGuiMessage(Notification::Event::GeneralEvent, - {tr("Feed added"), - tr("Feed was added, obtaining new tree of feeds now."), - QSystemTrayIcon::MessageIcon::Information}); - QTimer::singleShot(300, root, &TtRssServiceRoot::syncIn); - } - else { - throw ApplicationException(tr("API returned error code %1").arg(QString::number(response.code()))); - } - } -} - -void FormTtRssFeedDetails::loadFeedData() { - FormFeedDetails::loadFeedData(); - - if (m_creatingNew) { - insertCustomTab(m_feedDetails, tr("General"), 0); - insertCustomTab(m_authDetails, tr("Network"), 1); - activateTab(0); - - m_feedDetails->loadCategories(m_serviceRoot->getSubTreeCategories(), m_serviceRoot, m_parentToSelect); - - if (!m_urlToProcess.isEmpty()) { - m_feedDetails->ui.m_txtUrl->lineEdit()->setText(m_urlToProcess); - } - - m_feedDetails->ui.m_txtUrl->lineEdit()->selectAll(); - m_feedDetails->ui.m_txtUrl->setFocus(); - } -} diff --git a/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.h b/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.h deleted file mode 100644 index 49ed09333..000000000 --- a/src/librssguard/services/tt-rss/gui/formttrssfeeddetails.h +++ /dev/null @@ -1,32 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef FORMTTRSSFEEDDETAILS_H -#define FORMTTRSSFEEDDETAILS_H - -#include "services/abstract/gui/formfeeddetails.h" - -class TtRssFeed; -class TtRssFeedDetails; -class AuthenticationDetails; - -class FormTtRssFeedDetails : public FormFeedDetails { - public: - explicit FormTtRssFeedDetails(ServiceRoot* service_root, - RootItem* parent_to_select = nullptr, - const QString& url = QString(), - QWidget* parent = nullptr); - - protected slots: - virtual void apply(); - - private: - virtual void loadFeedData(); - - private: - TtRssFeedDetails* m_feedDetails; - AuthenticationDetails* m_authDetails; - RootItem* m_parentToSelect; - QString m_urlToProcess; -}; - -#endif // FORMTTRSSFEEDDETAILS_H diff --git a/src/librssguard/services/tt-rss/gui/formttrssnote.cpp b/src/librssguard/services/tt-rss/gui/formttrssnote.cpp deleted file mode 100644 index afe7f8814..000000000 --- a/src/librssguard/services/tt-rss/gui/formttrssnote.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/gui/formttrssnote.h" - -#include "gui/guiutilities.h" -#include "gui/messagebox.h" -#include "miscellaneous/application.h" -#include "miscellaneous/iconfactory.h" -#include "services/tt-rss/definitions.h" -#include "services/tt-rss/ttrssnetworkfactory.h" -#include "services/tt-rss/ttrssnotetopublish.h" -#include "services/tt-rss/ttrssserviceroot.h" - -#include - -FormTtRssNote::FormTtRssNote(TtRssServiceRoot* root) - : QDialog(qApp->mainFormWidget()), m_root(root), m_titleOk(false), m_urlOk(false) { - m_ui.setupUi(this); - - GuiUtilities::applyDialogProperties(*this, - qApp->icons()->fromTheme(QSL("emblem-shared")), - tr("Share note to \"Published\" feed")); - - setTabOrder(m_ui.m_txtTitle->lineEdit(), m_ui.m_txtUrl->lineEdit()); - setTabOrder(m_ui.m_txtUrl->lineEdit(), m_ui.m_txtContent); - setTabOrder(m_ui.m_txtContent, m_ui.m_btnBox); - - connect(m_ui.m_txtTitle->lineEdit(), &BaseLineEdit::textChanged, this, &FormTtRssNote::onTitleChanged); - connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &FormTtRssNote::onUrlChanged); - connect(m_ui.m_btnBox, &QDialogButtonBox::accepted, this, &FormTtRssNote::sendNote); - - emit m_ui.m_txtTitle->lineEdit()->textChanged({}); - emit m_ui.m_txtUrl->lineEdit()->textChanged({}); -} - -void FormTtRssNote::sendNote() { - TtRssNoteToPublish note; - - note.m_content = m_ui.m_txtContent->toPlainText(); - note.m_url = m_ui.m_txtUrl->lineEdit()->text(); - note.m_title = m_ui.m_txtTitle->lineEdit()->text(); - - auto res = m_root->network()->shareToPublished(note, m_root->networkProxy()); - - if (res.status() == TTRSS_API_STATUS_OK) { - accept(); - } - else { - MsgBox::show({}, - QMessageBox::Icon::Critical, - tr("Cannot share note"), - tr("There was an error, when trying to send your custom note."), - {}, - res.error()); - } -} - -void FormTtRssNote::onTitleChanged(const QString& text) { - m_titleOk = !text.simplified().isEmpty(); - - m_ui.m_txtTitle->setStatus(m_titleOk ? WidgetWithStatus::StatusType::Ok : WidgetWithStatus::StatusType::Error, - tr("Enter non-empty title.")); - - updateOkButton(); -} - -void FormTtRssNote::onUrlChanged(const QString& text) { - m_urlOk = text.startsWith(URI_SCHEME_HTTPS) || text.startsWith(URI_SCHEME_HTTP); - - m_ui.m_txtUrl->setStatus(m_urlOk ? WidgetWithStatus::StatusType::Ok : WidgetWithStatus::StatusType::Error, - tr("Enter valid URL.")); - - updateOkButton(); -} - -void FormTtRssNote::updateOkButton() { - m_ui.m_btnBox->button(QDialogButtonBox::StandardButton::Ok)->setEnabled(m_urlOk && m_titleOk); -} diff --git a/src/librssguard/services/tt-rss/gui/formttrssnote.h b/src/librssguard/services/tt-rss/gui/formttrssnote.h deleted file mode 100644 index fa8d478a0..000000000 --- a/src/librssguard/services/tt-rss/gui/formttrssnote.h +++ /dev/null @@ -1,33 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef FORMTTRSSNOTE_H -#define FORMTTRSSNOTE_H - -#include "ui_formttrssnote.h" - -#include - -class TtRssServiceRoot; - -class FormTtRssNote : public QDialog { - Q_OBJECT - - public: - explicit FormTtRssNote(TtRssServiceRoot* root); - - private slots: - void sendNote(); - void onTitleChanged(const QString& text); - void onUrlChanged(const QString& text); - - private: - void updateOkButton(); - - private: - Ui::FormTtRssNote m_ui; - TtRssServiceRoot* m_root; - bool m_titleOk; - bool m_urlOk; -}; - -#endif // FORMTTRSSNOTE_H diff --git a/src/librssguard/services/tt-rss/gui/formttrssnote.ui b/src/librssguard/services/tt-rss/gui/formttrssnote.ui deleted file mode 100644 index e84325232..000000000 --- a/src/librssguard/services/tt-rss/gui/formttrssnote.ui +++ /dev/null @@ -1,105 +0,0 @@ - - - FormTtRssNote - - - - 0 - 0 - 400 - 340 - - - - - - - Title - - - m_txtTitle - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - URL - - - m_txtUrl - - - - - - - Content - - - m_txtContent - - - - - - - - - - - LineEditWithStatus - QWidget -
lineeditwithstatus.h
- 1 -
-
- - - - m_btnBox - rejected() - FormTtRssNote - reject() - - - 295 - 327 - - - 286 - 274 - - - - -
diff --git a/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.cpp b/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.cpp deleted file mode 100644 index aeb3e4a0d..000000000 --- a/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/gui/ttrssaccountdetails.h" - -#include "definitions/definitions.h" -#include "network-web/networkfactory.h" -#include "services/tt-rss/definitions.h" -#include "services/tt-rss/ttrssnetworkfactory.h" - -TtRssAccountDetails::TtRssAccountDetails(QWidget* parent) : QWidget(parent) { - m_ui.setupUi(this); - - m_ui.m_lblTestResult->label()->setWordWrap(true); - m_ui.m_lblNewAlgorithm - ->setHelpText(tr("If you select intelligent synchronization, then only not-yet-fetched " - "or updated articles are downloaded. Network usage is greatly reduced and " - "overall synchronization speed is greatly improved, but " - "first feed fetching could be slow anyway if your feed contains " - "huge number of articles.

" - "Also, make sure to install api_newsplus TT-RSS " - "plugin to your server instance."), - true, - true); - m_ui.m_lblServerSideUpdateInformation - ->setHelpText(tr("Leaving this option on causes that updates " - "of feeds will be probably much slower and may time-out often."), - true); - m_ui.m_txtHttpUsername->lineEdit()->setPlaceholderText(tr("HTTP authentication username")); - m_ui.m_txtHttpPassword->lineEdit()->setPlaceholderText(tr("HTTP authentication password")); - m_ui.m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your TT-RSS account")); - m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your TT-RSS account")); - m_ui.m_txtUrl->lineEdit()->setPlaceholderText(tr("URL of your TT-RSS instance WITHOUT trailing \"/api/\" string")); - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information, - tr("No test done yet."), - tr("Here, results of connection test are shown.")); - - setTabOrder(m_ui.m_txtUrl->lineEdit(), m_ui.m_checkDownloadOnlyUnreadMessages); - setTabOrder(m_ui.m_checkDownloadOnlyUnreadMessages, m_ui.m_spinLimitMessages); - setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_cbNewAlgorithm); - setTabOrder(m_ui.m_cbNewAlgorithm, m_ui.m_checkServerSideUpdate); - setTabOrder(m_ui.m_checkServerSideUpdate, m_ui.m_txtUsername->lineEdit()); - setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtPassword->lineEdit()); - setTabOrder(m_ui.m_txtPassword->lineEdit(), m_ui.m_gbHttpAuthentication); - setTabOrder(m_ui.m_gbHttpAuthentication, m_ui.m_txtHttpUsername->lineEdit()); - setTabOrder(m_ui.m_txtHttpUsername->lineEdit(), m_ui.m_txtHttpPassword->lineEdit()); - setTabOrder(m_ui.m_txtHttpPassword->lineEdit(), m_ui.m_btnTestSetup); - - m_ui.m_txtHttpPassword->lineEdit()->setPasswordMode(true); - m_ui.m_txtPassword->lineEdit()->setPasswordMode(true); - - connect(m_ui.m_txtPassword->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onPasswordChanged); - connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onUsernameChanged); - connect(m_ui.m_txtHttpPassword->lineEdit(), - &BaseLineEdit::textChanged, - this, - &TtRssAccountDetails::onHttpPasswordChanged); - connect(m_ui.m_txtHttpUsername->lineEdit(), - &BaseLineEdit::textChanged, - this, - &TtRssAccountDetails::onHttpUsernameChanged); - connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onUrlChanged); - connect(m_ui.m_gbHttpAuthentication, &QGroupBox::toggled, this, &TtRssAccountDetails::onHttpPasswordChanged); - connect(m_ui.m_gbHttpAuthentication, &QGroupBox::toggled, this, &TtRssAccountDetails::onHttpUsernameChanged); - - onPasswordChanged(); - onUsernameChanged(); - onUrlChanged(); - onHttpPasswordChanged(); - onHttpUsernameChanged(); -} - -void TtRssAccountDetails::performTest(const QNetworkProxy& proxy) { - TtRssNetworkFactory factory; - - factory.setUsername(m_ui.m_txtUsername->lineEdit()->text()); - factory.setPassword(m_ui.m_txtPassword->lineEdit()->text()); - factory.setUrl(m_ui.m_txtUrl->lineEdit()->text()); - factory.setAuthIsUsed(m_ui.m_gbHttpAuthentication->isChecked()); - factory.setAuthUsername(m_ui.m_txtHttpUsername->lineEdit()->text()); - factory.setAuthPassword(m_ui.m_txtHttpPassword->lineEdit()->text()); - factory.setForceServerSideUpdate(m_ui.m_checkServerSideUpdate->isChecked()); - factory.setBatchSize(m_ui.m_spinLimitMessages->value()); - - TtRssLoginResponse result = factory.login(proxy); - - if (result.isLoaded()) { - if (result.hasError()) { - QString error = result.error(); - - if (error == QSL(TTRSS_API_DISABLED)) { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("API access on selected server is not enabled."), - tr("API access on selected server is not enabled.")); - } - else if (error == QSL(TTRSS_LOGIN_ERROR)) { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Entered credentials are incorrect."), - tr("Entered credentials are incorrect.")); - } - else { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Other error occurred, contact developers."), - tr("Other error occurred, contact developers.")); - } - } - else if (result.apiLevel() < TTRSS_MINIMAL_API_LEVEL) { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Installed version: %1, required at least: %2.") - .arg(QString::number(result.apiLevel()), - QString::number(TTRSS_MINIMAL_API_LEVEL)), - tr("Selected Tiny Tiny RSS server is running unsupported version of API.")); - } - else { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok, - tr("Installed version: %1, required at least: %2.") - .arg(QString::number(result.apiLevel()), - QString::number(TTRSS_MINIMAL_API_LEVEL)), - tr("Tiny Tiny RSS server is okay.")); - } - } - else if (factory.lastError() != QNetworkReply::NoError) { - m_ui.m_lblTestResult - ->setStatus(WidgetWithStatus::StatusType::Error, - tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(factory.lastError())), - tr("Network error, have you entered correct Tiny Tiny RSS API endpoint and password?")); - } - else { - m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, - tr("Unspecified error, did you enter correct URL?"), - tr("Unspecified error, did you enter correct URL?")); - } -} - -void TtRssAccountDetails::onUsernameChanged() { - const QString username = m_ui.m_txtUsername->lineEdit()->text(); - - if (username.isEmpty()) { - m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("Username cannot be empty.")); - } - else { - m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Username is okay.")); - } -} - -void TtRssAccountDetails::onPasswordChanged() { - const QString password = m_ui.m_txtPassword->lineEdit()->text(); - - if (password.isEmpty()) { - m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Error, tr("Password cannot be empty.")); - } - else { - m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Ok, tr("Password is okay.")); - } -} - -void TtRssAccountDetails::onHttpUsernameChanged() { - const bool is_username_ok = - !m_ui.m_gbHttpAuthentication->isChecked() || !m_ui.m_txtHttpUsername->lineEdit()->text().isEmpty(); - - m_ui.m_txtHttpUsername->setStatus(is_username_ok ? LineEditWithStatus::StatusType::Ok - : LineEditWithStatus::StatusType::Warning, - is_username_ok ? tr("Username is ok or it is not needed.") - : tr("Username is empty.")); -} - -void TtRssAccountDetails::onHttpPasswordChanged() { - const bool is_username_ok = - !m_ui.m_gbHttpAuthentication->isChecked() || !m_ui.m_txtHttpPassword->lineEdit()->text().isEmpty(); - - m_ui.m_txtHttpPassword->setStatus(is_username_ok ? LineEditWithStatus::StatusType::Ok - : LineEditWithStatus::StatusType::Warning, - is_username_ok ? tr("Password is ok or it is not needed.") - : tr("Password is empty.")); -} - -void TtRssAccountDetails::onUrlChanged() { - const QString url = m_ui.m_txtUrl->lineEdit()->text(); - - if (url.isEmpty()) { - m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Error, tr("URL cannot be empty.")); - } - else if (url.endsWith(QL1S("/api/")) || url.endsWith(QL1S("/api"))) { - m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Warning, tr("URL should NOT end with \"/api/\".")); - } - else { - m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Ok, tr("URL is okay.")); - } -} diff --git a/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.h b/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.h deleted file mode 100644 index 279db27dd..000000000 --- a/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.h +++ /dev/null @@ -1,34 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSSACCOUNTDETAILS_H -#define TTRSSACCOUNTDETAILS_H - -#include "ui_ttrssaccountdetails.h" - -#include -#include - -class TtRssServiceRoot; - -class TtRssAccountDetails : public QWidget { - Q_OBJECT - - friend class FormEditTtRssAccount; - - public: - explicit TtRssAccountDetails(QWidget* parent = nullptr); - - private slots: - void performTest(const QNetworkProxy& proxy); - - void onUsernameChanged(); - void onPasswordChanged(); - void onHttpUsernameChanged(); - void onHttpPasswordChanged(); - void onUrlChanged(); - - private: - Ui::TtRssAccountDetails m_ui; -}; - -#endif // TTRSSACCOUNTDETAILS_H diff --git a/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.ui b/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.ui deleted file mode 100644 index 2692e93f5..000000000 --- a/src/librssguard/services/tt-rss/gui/ttrssaccountdetails.ui +++ /dev/null @@ -1,252 +0,0 @@ - - - TtRssAccountDetails - - - - 0 - 0 - 432 - 396 - - - - - - - Qt::Vertical - - - - 408 - 30 - - - - - - - - - - URL - - - m_txtUrl - - - - - - - - - - - - - - Only download newest X articles per feed - - - m_spinLimitMessages - - - - - - - - 140 - 16777215 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Download unread articles only - - - - - - - Intelligent synchronization algorithm - - - - - - - Force execution of server-side feeds update - - - - - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - - - Authentication - - - false - - - false - - - - - - Username - - - m_txtUsername - - - - - - - - - - Password - - - m_txtPassword - - - - - - - - - - - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - - - Requires HTTP authentication - - - false - - - true - - - false - - - - - - Username - - - m_txtHttpUsername - - - - - - - - - - Password - - - m_txtHttpPassword - - - - - - - - - - - - - - - &Test setup - - - - - - - - 0 - 0 - - - - Qt::RightToLeft - - - - - - - - - - - - - - - - LabelWithStatus - QWidget -
labelwithstatus.h
- 1 -
- - LineEditWithStatus - QWidget -
lineeditwithstatus.h
- 1 -
- - MessageCountSpinBox - QSpinBox -
messagecountspinbox.h
-
- - HelpSpoiler - QWidget -
helpspoiler.h
- 1 -
-
- - -
diff --git a/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.cpp b/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.cpp deleted file mode 100644 index 3e5963679..000000000 --- a/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/gui/ttrssfeeddetails.h" - -#include "definitions/definitions.h" -#include "services/abstract/category.h" - -TtRssFeedDetails::TtRssFeedDetails(QWidget* parent) : QWidget(parent) { - ui.setupUi(this); - - ui.m_txtUrl->lineEdit()->setPlaceholderText(tr("Full feed URL including scheme")); - ui.m_txtUrl->lineEdit()->setToolTip(tr("Provide URL for your feed.")); - - connect(ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssFeedDetails::onUrlChanged); - onUrlChanged(QString()); -} - -void TtRssFeedDetails::onUrlChanged(const QString& new_url) { - if (QRegularExpression(QSL(URL_REGEXP)).match(new_url).hasMatch()) { - // New url is well-formed. - ui.m_txtUrl->setStatus(LineEditWithStatus::StatusType::Ok, tr("The URL is ok.")); - } - else if (!new_url.simplified().isEmpty()) { - // New url is not well-formed but is not empty on the other hand. - ui.m_txtUrl->setStatus( - LineEditWithStatus::StatusType::Warning, - tr(R"(The URL does not meet standard pattern. Does your URL start with "http://" or "https://" prefix.)")); - } - else { - // New url is empty. - ui.m_txtUrl->setStatus(LineEditWithStatus::StatusType::Error, tr("The URL is empty.")); - } -} - -void TtRssFeedDetails::loadCategories(const QList& categories, - RootItem* root_item, - RootItem* parent_to_select) { - ui.m_cmbParentCategory->addItem(root_item->fullIcon(), root_item->title(), QVariant::fromValue(root_item)); - - for (Category* category : categories) { - ui.m_cmbParentCategory->addItem(category->fullIcon(), category->title(), QVariant::fromValue(category)); - } - - if (parent_to_select != nullptr) { - if (parent_to_select->kind() == RootItem::Kind::Category) { - ui.m_cmbParentCategory->setCurrentIndex(ui.m_cmbParentCategory->findData(QVariant::fromValue(parent_to_select))); - } - else if (parent_to_select->kind() == RootItem::Kind::Feed) { - int target_item = ui.m_cmbParentCategory->findData(QVariant::fromValue(parent_to_select->parent())); - - if (target_item >= 0) { - ui.m_cmbParentCategory->setCurrentIndex(target_item); - } - } - } -} diff --git a/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.h b/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.h deleted file mode 100644 index d6eadb785..000000000 --- a/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.h +++ /dev/null @@ -1,31 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSSFEEDDETAILS_H -#define TTRSSFEEDDETAILS_H - -#include "ui_ttrssfeeddetails.h" - -#include - -class Category; -class RootItem; - -class TtRssFeedDetails : public QWidget { - Q_OBJECT - - friend class FormTtRssFeedDetails; - - public: - explicit TtRssFeedDetails(QWidget* parent = nullptr); - - private slots: - void onUrlChanged(const QString& new_url); - - private: - void loadCategories(const QList& categories, RootItem* root_item, RootItem* parent_to_select = nullptr); - - private: - Ui::TtRssFeedDetails ui; -}; - -#endif // TTRSSFEEDDETAILS_H diff --git a/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.ui b/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.ui deleted file mode 100644 index 6e3c75e55..000000000 --- a/src/librssguard/services/tt-rss/gui/ttrssfeeddetails.ui +++ /dev/null @@ -1,68 +0,0 @@ - - - TtRssFeedDetails - - - - 0 - 0 - 367 - 202 - - - - Form - - - - - - Parent folder - - - m_cmbParentCategory - - - - - - - Select parent item for your feed. - - - - 12 - 12 - - - - true - - - - - - - URL - - - m_txtUrl - - - - - - - - - - - LineEditWithStatus - QWidget -
lineeditwithstatus.h
- 1 -
-
- - -
diff --git a/src/librssguard/services/tt-rss/ttrssfeed.cpp b/src/librssguard/services/tt-rss/ttrssfeed.cpp deleted file mode 100644 index 01cf8f9b0..000000000 --- a/src/librssguard/services/tt-rss/ttrssfeed.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/ttrssfeed.h" - -#include "database/databasequeries.h" -#include "definitions/definitions.h" -#include "miscellaneous/application.h" -#include "miscellaneous/iconfactory.h" -#include "services/tt-rss/definitions.h" -#include "services/tt-rss/ttrssnetworkfactory.h" -#include "services/tt-rss/ttrssserviceroot.h" - -#include - -TtRssFeed::TtRssFeed(RootItem* parent) : Feed(parent), m_actionShareToPublished(nullptr) {} - -TtRssServiceRoot* TtRssFeed::serviceRoot() const { - return qobject_cast(getParentServiceRoot()); -} - -bool TtRssFeed::canBeDeleted() const { - return true; -} - -bool TtRssFeed::deleteItem() { - TtRssUnsubscribeFeedResponse response = - serviceRoot()->network()->unsubscribeFeed(customNumericId(), getParentServiceRoot()->networkProxy()); - - if (response.code() == QSL(UFF_OK) && removeItself()) { - serviceRoot()->requestItemRemoval(this); - return true; - } - else { - qWarningNN << LOGSEC_TTRSS - << "Unsubscribing from feed failed, received JSON:" << QUOTE_W_SPACE_DOT(response.toString()); - return false; - } -} - -QList TtRssFeed::contextMenuFeedsList() { - auto menu = Feed::contextMenuFeedsList(); - - if (customNumericId() == TTRSS_PUBLISHED_FEED_ID) { - if (m_actionShareToPublished == nullptr) { - m_actionShareToPublished = - new QAction(qApp->icons()->fromTheme(QSL("emblem-shared")), tr("Share to published"), this); - - connect(m_actionShareToPublished, &QAction::triggered, serviceRoot(), &TtRssServiceRoot::shareToPublished); - } - - menu.append(m_actionShareToPublished); - } - - return menu; -} - -bool TtRssFeed::removeItself() { - QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); - - return DatabaseQueries::deleteFeed(database, this, serviceRoot()->accountId()); -} diff --git a/src/librssguard/services/tt-rss/ttrssfeed.h b/src/librssguard/services/tt-rss/ttrssfeed.h deleted file mode 100644 index 81b4ee3be..000000000 --- a/src/librssguard/services/tt-rss/ttrssfeed.h +++ /dev/null @@ -1,28 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSSFEED_H -#define TTRSSFEED_H - -#include "services/abstract/feed.h" - -class TtRssServiceRoot; - -class TtRssFeed : public Feed { - Q_OBJECT - - public: - explicit TtRssFeed(RootItem* parent = nullptr); - - virtual bool canBeDeleted() const; - virtual bool deleteItem(); - virtual QList contextMenuFeedsList(); - - private: - TtRssServiceRoot* serviceRoot() const; - bool removeItself(); - - private: - QAction* m_actionShareToPublished; -}; - -#endif // TTRSSFEED_H diff --git a/src/librssguard/services/tt-rss/ttrssnetworkfactory.cpp b/src/librssguard/services/tt-rss/ttrssnetworkfactory.cpp deleted file mode 100644 index 2b6c28174..000000000 --- a/src/librssguard/services/tt-rss/ttrssnetworkfactory.cpp +++ /dev/null @@ -1,1205 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/ttrssnetworkfactory.h" - -#include "3rd-party/boolinq/boolinq.h" -#include "definitions/definitions.h" -#include "exceptions/feedfetchexception.h" -#include "miscellaneous/application.h" -#include "miscellaneous/iconfactory.h" -#include "miscellaneous/settings.h" -#include "miscellaneous/textfactory.h" -#include "network-web/networkfactory.h" -#include "services/abstract/category.h" -#include "services/abstract/label.h" -#include "services/abstract/labelsnode.h" -#include "services/abstract/rootitem.h" -#include "services/abstract/serviceroot.h" -#include "services/tt-rss/definitions.h" -#include "services/tt-rss/ttrssfeed.h" - -#include -#include -#include -#include - -TtRssNetworkFactory::TtRssNetworkFactory() - : m_bareUrl(QString()), m_fullUrl(QString()), m_username(QString()), m_password(QString()), - m_batchSize(TTRSS_DEFAULT_MESSAGES), m_forceServerSideUpdate(false), m_intelligentSynchronization(false), - m_authIsUsed(false), m_authUsername(QString()), m_authPassword(QString()), m_sessionId(QString()), - m_lastError(QNetworkReply::NetworkError::NoError) {} - -QString TtRssNetworkFactory::url() const { - return m_bareUrl; -} - -void TtRssNetworkFactory::setUrl(const QString& url) { - m_bareUrl = url; - - if (!m_bareUrl.endsWith(QSL("/"))) { - m_bareUrl = m_bareUrl + QSL("/"); - } - - if (!m_bareUrl.endsWith(QSL("api/"))) { - m_fullUrl = m_bareUrl + QSL("api/"); - } - else { - m_fullUrl = m_bareUrl; - } -} - -QString TtRssNetworkFactory::username() const { - return m_username; -} - -void TtRssNetworkFactory::setUsername(const QString& username) { - m_username = username; -} - -QString TtRssNetworkFactory::password() const { - return m_password; -} - -void TtRssNetworkFactory::setPassword(const QString& password) { - m_password = password; -} - -QDateTime TtRssNetworkFactory::lastLoginTime() const { - return m_lastLoginTime; -} - -QNetworkReply::NetworkError TtRssNetworkFactory::lastError() const { - return m_lastError; -} - -TtRssLoginResponse TtRssNetworkFactory::login(const QNetworkProxy& proxy) { - if (!m_sessionId.isEmpty()) { - qWarningNN << LOGSEC_TTRSS << "Session ID is not empty before login, logging out first."; - logout(proxy); - } - - QJsonObject json; - - json[QSL("op")] = QSL("login"); - json[QSL("user")] = m_username; - json[QSL("password")] = m_password; - - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssLoginResponse login_response(QString::fromUtf8(result_raw)); - - if (network_reply.m_networkError == QNetworkReply::NoError) { - m_sessionId = login_response.sessionId(); - m_lastLoginTime = QDateTime::currentDateTime(); - } - else { - qWarningNN << LOGSEC_TTRSS << "Login failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return login_response; -} - -TtRssResponse TtRssNetworkFactory::logout(const QNetworkProxy& proxy) { - if (!m_sessionId.isEmpty()) { - QJsonObject json; - - json[QSL("op")] = QSL("logout"); - json[QSL("sid")] = m_sessionId; - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - qApp->settings() - ->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)) - .toInt(), - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - - m_lastError = network_reply.m_networkError; - - if (m_lastError == QNetworkReply::NetworkError::NoError) { - m_sessionId.clear(); - } - else { - qWarningNN << LOGSEC_TTRSS << "Logout failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - return TtRssResponse(QString::fromUtf8(result_raw)); - } - else { - qWarningNN << LOGSEC_TTRSS << "Cannot logout because session ID is empty."; - m_lastError = QNetworkReply::NetworkError::NoError; - return TtRssResponse(); - } -} - -TtRssGetLabelsResponse TtRssNetworkFactory::getLabels(const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("getLabels"); - json[QSL("sid")] = m_sessionId; - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssGetLabelsResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssGetLabelsResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS << "getLabels failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssResponse TtRssNetworkFactory::shareToPublished(const TtRssNoteToPublish& note, const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("shareToPublished"); - json[QSL("sid")] = m_sessionId; - json[QSL("title")] = note.m_title; - json[QSL("url")] = note.m_url; - json[QSL("content")] = note.m_content; - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS - << "shareToPublished failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("getFeedTree"); - json[QSL("sid")] = m_sessionId; - json[QSL("include_empty")] = true; - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssGetFeedsCategoriesResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssGetFeedsCategoriesResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS << "getFeedTree failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssGetCompactHeadlinesResponse TtRssNetworkFactory::getCompactHeadlines(int feed_id, - int limit, - int skip, - const QString& view_mode, - const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("getCompactHeadlines"); - json[QSL("sid")] = m_sessionId; - json[QSL("feed_id")] = feed_id; - json[QSL("limit")] = limit; - // json[QSL("skip")] = skip; - json[QSL("view_mode")] = view_mode; - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssGetCompactHeadlinesResponse result(QString::fromUtf8(result_raw)); - - if (result.isUnknownMethod()) { - qCriticalNN << LOGSEC_TTRSS << "'getCompactHeadlines' method is not installed."; - - throw FeedFetchException(Feed::Status::OtherError, - QSL("'getCompactHeadlines' method is not installed on your TT-RSS instance. Install " - "'api_newsplus' plugin.")); - } - else if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssGetCompactHeadlinesResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NetworkError::NoError) { - qWarningNN << LOGSEC_TTRSS - << "getCompactHeadlines failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - - return result; -} - -TtRssGetHeadlinesResponse TtRssNetworkFactory::getArticle(const QStringList& article_ids, const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("getArticle"); - json[QSL("sid")] = m_sessionId; - json[QSL("article_id")] = article_ids.join(QL1C(',')); - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssGetHeadlinesResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssGetHeadlinesResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NetworkError::NoError) { - qWarningNN << LOGSEC_TTRSS << "getArticle failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, - int limit, - int skip, - bool show_content, - bool include_attachments, - bool sanitize, - bool unread_only, - const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("getHeadlines"); - json[QSL("sid")] = m_sessionId; - json[QSL("feed_id")] = feed_id; - json[QSL("force_update")] = m_forceServerSideUpdate; - json[QSL("limit")] = limit; - json[QSL("skip")] = skip; - json[QSL("view_mode")] = unread_only ? QSL("unread") : QSL("all_articles"); - json[QSL("show_content")] = show_content; - json[QSL("include_attachments")] = include_attachments; - json[QSL("sanitize")] = sanitize; - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssGetHeadlinesResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssGetHeadlinesResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS << "getHeadlines failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssResponse TtRssNetworkFactory::setArticleLabel(const QStringList& article_ids, - const QString& label_custom_id, - bool assign, - const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("setArticleLabel"); - json[QSL("sid")] = m_sessionId; - json[QSL("article_ids")] = article_ids.join(QSL(",")); - json[QSL("label_id")] = label_custom_id.toInt(); - json[QSL("assign")] = assign; - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS << "setArticleLabel failed with error" - << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList& ids, - UpdateArticle::OperatingField field, - UpdateArticle::Mode mode, - const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("updateArticle"); - json[QSL("sid")] = m_sessionId; - json[QSL("article_ids")] = ids.join(QSL(",")); - json[QSL("mode")] = int(mode); - json[QSL("field")] = int(field); - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssUpdateArticleResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssUpdateArticleResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS << "updateArticle failed with error" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssSubscribeToFeedResponse TtRssNetworkFactory::subscribeToFeed(const QString& url, - int category_id, - const QNetworkProxy& proxy, - bool protectd, - const QString& username, - const QString& password) { - QJsonObject json; - - json[QSL("op")] = QSL("subscribeToFeed"); - json[QSL("sid")] = m_sessionId; - json[QSL("feed_url")] = url; - json[QSL("category_id")] = category_id; - - if (protectd) { - json[QSL("login")] = username; - json[QSL("password")] = password; - } - - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssSubscribeToFeedResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssSubscribeToFeedResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS << "updateArticle failed with error" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -TtRssUnsubscribeFeedResponse TtRssNetworkFactory::unsubscribeFeed(int feed_id, const QNetworkProxy& proxy) { - QJsonObject json; - - json[QSL("op")] = QSL("unsubscribeFeed"); - json[QSL("sid")] = m_sessionId; - json[QSL("feed_id")] = feed_id; - const int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); - QByteArray result_raw; - QList> headers; - - headers << QPair(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON); - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - m_authUsername, - m_authPassword); - - NetworkResult network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - TtRssUnsubscribeFeedResponse result(QString::fromUtf8(result_raw)); - - if (result.isNotLoggedIn()) { - // We are not logged in. - login(proxy); - json[QSL("sid")] = m_sessionId; - network_reply = - NetworkFactory::performNetworkOperation(m_fullUrl, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - result_raw, - QNetworkAccessManager::Operation::PostOperation, - headers, - false, - {}, - {}, - proxy); - result = TtRssUnsubscribeFeedResponse(QString::fromUtf8(result_raw)); - } - - if (network_reply.m_networkError != QNetworkReply::NoError) { - qWarningNN << LOGSEC_TTRSS << "getFeeds failed with error" << QUOTE_W_SPACE_DOT(network_reply.m_networkError); - } - - m_lastError = network_reply.m_networkError; - return result; -} - -int TtRssNetworkFactory::batchSize() const { - return m_batchSize; -} - -void TtRssNetworkFactory::setBatchSize(int batch_size) { - m_batchSize = batch_size; -} - -bool TtRssNetworkFactory::intelligentSynchronization() const { - return m_intelligentSynchronization; -} - -void TtRssNetworkFactory::setIntelligentSynchronization(bool intelligent_synchronization) { - m_intelligentSynchronization = intelligent_synchronization; -} - -bool TtRssNetworkFactory::downloadOnlyUnreadMessages() const { - return m_downloadOnlyUnreadMessages; -} - -void TtRssNetworkFactory::setDownloadOnlyUnreadMessages(bool download_only_unread_messages) { - m_downloadOnlyUnreadMessages = download_only_unread_messages; -} - -bool TtRssNetworkFactory::forceServerSideUpdate() const { - return m_forceServerSideUpdate; -} - -void TtRssNetworkFactory::setForceServerSideUpdate(bool force_server_side_update) { - m_forceServerSideUpdate = force_server_side_update; -} - -bool TtRssNetworkFactory::authIsUsed() const { - return m_authIsUsed; -} - -void TtRssNetworkFactory::setAuthIsUsed(bool auth_is_used) { - m_authIsUsed = auth_is_used; -} - -QString TtRssNetworkFactory::authUsername() const { - return m_authUsername; -} - -void TtRssNetworkFactory::setAuthUsername(const QString& auth_username) { - m_authUsername = auth_username; -} - -QString TtRssNetworkFactory::authPassword() const { - return m_authPassword; -} - -void TtRssNetworkFactory::setAuthPassword(const QString& auth_password) { - m_authPassword = auth_password; -} - -TtRssResponse::TtRssResponse(const QString& raw_content) { - m_rawContent = QJsonDocument::fromJson(raw_content.toUtf8()).object(); -} - -TtRssResponse::~TtRssResponse() = default; - -bool TtRssResponse::isLoaded() const { - return !m_rawContent.isEmpty(); -} - -int TtRssResponse::seq() const { - if (!isLoaded()) { - return TTRSS_CONTENT_NOT_LOADED; - } - else { - return m_rawContent[QSL("seq")].toInt(); - } -} - -int TtRssResponse::status() const { - if (!isLoaded()) { - return TTRSS_CONTENT_NOT_LOADED; - } - else { - return m_rawContent[QSL("status")].toInt(); - } -} - -bool TtRssResponse::isNotLoggedIn() const { - return status() == TTRSS_API_STATUS_ERR && hasError() && error() == QSL(TTRSS_NOT_LOGGED_IN); -} - -bool TtRssResponse::isUnknownMethod() const { - return status() == TTRSS_API_STATUS_ERR && hasError() && error() == QSL(TTRSS_UNKNOWN_METHOD); -} - -QString TtRssResponse::toString() const { - return QJsonDocument(m_rawContent).toJson(QJsonDocument::JsonFormat::Compact); -} - -TtRssLoginResponse::TtRssLoginResponse(const QString& raw_content) : TtRssResponse(raw_content) {} - -TtRssLoginResponse::~TtRssLoginResponse() = default; -int TtRssLoginResponse::apiLevel() const { - if (!isLoaded()) { - return TTRSS_CONTENT_NOT_LOADED; - } - else { - return m_rawContent[QSL("content")].toObject()[QSL("api_level")].toInt(); - } -} - -QString TtRssLoginResponse::sessionId() const { - if (!isLoaded()) { - return QString(); - } - else { - return m_rawContent[QSL("content")].toObject()[QSL("session_id")].toString(); - } -} - -QString TtRssResponse::error() const { - if (!isLoaded()) { - return QString(); - } - else { - return m_rawContent[QSL("content")].toObject()[QSL("error")].toString(); - } -} - -bool TtRssResponse::hasError() const { - if (!isLoaded()) { - return false; - } - else { - return m_rawContent[QSL("content")].toObject().contains(QSL("error")); - } -} - -TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString& raw_content) - : TtRssResponse(raw_content) {} - -TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() = default; - -RootItem* TtRssGetFeedsCategoriesResponse::feedsCategories(TtRssNetworkFactory* network, - bool obtain_icons, - const QNetworkProxy& proxy, - const QString& base_address) const { - auto* parent = new RootItem(); - - // Chop the "api/" from the end of the address. - qDebugNN << LOGSEC_TTRSS << "Base address to get feed icons is" << QUOTE_W_SPACE_DOT(base_address); - - if (status() == TTRSS_API_STATUS_OK) { - // We have data, construct object tree according to data. - QJsonArray items_to_process = - m_rawContent[QSL("content")].toObject()[QSL("categories")].toObject()[QSL("items")].toArray(); - QVector> pairs; - pairs.reserve(items_to_process.size()); - - for (const QJsonValue& item : items_to_process) { - pairs.append(QPair(parent, item)); - } - - while (!pairs.isEmpty()) { - QPair pair = pairs.takeFirst(); - RootItem* act_parent = pair.first; - QJsonObject item = pair.second.toObject(); - int item_id = item[QSL("bare_id")].toInt(); - bool is_category = item.contains(QSL("type")) && item[QSL("type")].toString() == QSL(TTRSS_GFT_TYPE_CATEGORY); - - if (item_id >= 0) { - if (is_category) { - if (item_id == 0) { - // This is "Uncategorized" category, all its feeds belong to top-level root. - if (item.contains(QSL("items"))) { - auto ite = item[QSL("items")].toArray(); - - for (const QJsonValue& child_feed : std::as_const(ite)) { - pairs.append(QPair(parent, child_feed)); - } - } - } - else { - auto* category = new Category(); - - category->setTitle(item[QSL("name")].toString()); - category->setCustomId(QString::number(item_id)); - act_parent->appendChild(category); - - if (item.contains(QSL("items"))) { - auto ite = item[QSL("items")].toArray(); - - for (const QJsonValue& child : std::as_const(ite)) { - pairs.append(QPair(category, child)); - } - } - } - } - else { - // We have feed. - auto* feed = new TtRssFeed(); - - if (obtain_icons) { - QString icon_path = - item[QSL("icon")].type() == QJsonValue::Type::String ? item[QSL("icon")].toString() : QString(); - - if (!icon_path.isEmpty()) { - QString full_icon_address = QUrl(base_address).resolved(icon_path).toString(); - QPixmap icon; - QList> headers; - - if (network->authIsUsed()) { - headers << NetworkFactory::generateBasicAuthHeader(NetworkFactory::NetworkAuthentication::Basic, - network->authUsername(), - network->authPassword()); - } - - auto res = - NetworkFactory::downloadIcon({{full_icon_address, true}}, DOWNLOAD_TIMEOUT, icon, headers, proxy); - - if (res == QNetworkReply::NetworkError::NoError) { - feed->setIcon(icon); - } - else { - qWarningNN << LOGSEC_TTRSS << "Failed to download icon with error" << QUOTE_W_SPACE_DOT(res); - } - } - } - - feed->setTitle(item[QSL("name")].toString()); - feed->setCustomId(QString::number(item_id)); - - act_parent->appendChild(feed); - } - } - } - - // Append special "published" feed to hold "notes" created by user - // via "shareToPublished" method. These "notes" are not normal articles - // because they do not belong to any feed. - // We have feed. - auto* published_feed = new TtRssFeed(); - - published_feed->setTitle(QSL("[SYSTEM] ") + QObject::tr("User-published articles")); - published_feed->setCustomId(QString::number(0)); - published_feed->setKeepOnTop(true); - - parent->appendChild(published_feed); - } - - return parent; -} - -TtRssGetHeadlinesResponse::TtRssGetHeadlinesResponse(const QString& raw_content) : TtRssResponse(raw_content) {} - -TtRssGetHeadlinesResponse::~TtRssGetHeadlinesResponse() = default; - -TtRssGetArticleResponse::TtRssGetArticleResponse(const QString& raw_content) : TtRssResponse(raw_content) {} - -QList TtRssGetArticleResponse::messages(ServiceRoot* root) const { - return {}; -} - -TtRssGetArticleResponse::~TtRssGetArticleResponse() = default; - -QList TtRssGetHeadlinesResponse::messages(ServiceRoot* root) const { - QList messages; - auto active_labels = root->labelsNode() != nullptr ? root->labelsNode()->labels() : QList(); - auto json_msgs = m_rawContent[QSL("content")].toArray(); - auto* published_lbl = boolinq::from(active_labels).firstOrDefault([](const Label* lbl) { - return lbl->customNumericId() == TTRSS_PUBLISHED_LABEL_ID; - }); - - for (const QJsonValue& item : std::as_const(json_msgs)) { - QJsonObject mapped = item.toObject(); - Message message; - - message.m_author = mapped[QSL("author")].toString(); - message.m_isRead = !mapped[QSL("unread")].toBool(); - message.m_isImportant = mapped[QSL("marked")].toBool(); - message.m_contents = mapped[QSL("content")].toString(); - message.m_rawContents = QJsonDocument(mapped).toJson(QJsonDocument::JsonFormat::Compact); - - if (published_lbl != nullptr && mapped[QSL("published")].toBool()) { - // Article is published, set label. - message.m_assignedLabels.append(published_lbl); - } - - auto json_labels = mapped[QSL("labels")].toArray(); - - for (const QJsonValue& lbl_val : std::as_const(json_labels)) { - QString lbl_custom_id = QString::number(lbl_val.toArray().at(0).toInt()); - Label* label = - boolinq::from(active_labels.begin(), active_labels.end()).firstOrDefault([lbl_custom_id](Label* lbl) { - return lbl->customId() == lbl_custom_id; - }); - - if (label != nullptr) { - message.m_assignedLabels.append(label); - } - else { - qWarningNN << LOGSEC_TTRSS << "Label with custom ID" << QUOTE_W_SPACE(lbl_custom_id) - << "was not found. Maybe you need to perform sync-in to download it from server."; - } - } - - // Multiply by 1000 because Tiny Tiny RSS API does not include miliseconds in Unix - // date/time number. - const qint64 t = static_cast(mapped[QSL("updated")].toDouble()) * 1000; - - message.m_created = TextFactory::parseDateTime(t); - message.m_createdFromFeed = true; - message.m_customId = QString::number(mapped[QSL("id")].toInt()); - message.m_feedId = mapped[QSL("feed_id")].type() == QJsonValue::Type::Double - ? QString::number(mapped[QSL("feed_id")].toInt()) - : mapped[QSL("feed_id")].toString(); - message.m_title = mapped[QSL("title")].toString(); - message.m_url = mapped[QSL("link")].toString(); - - if (mapped.contains(QSL("attachments"))) { - // Process enclosures. - auto json_att = mapped[QSL("attachments")].toArray(); - - for (const QJsonValue& attachment : std::as_const(json_att)) { - QJsonObject mapped_attachemnt = attachment.toObject(); - Enclosure enclosure; - - enclosure.m_mimeType = mapped_attachemnt[QSL("content_type")].toString(); - enclosure.m_url = mapped_attachemnt[QSL("content_url")].toString(); - message.m_enclosures.append(enclosure); - } - } - - messages.append(message); - } - - return messages; -} - -TtRssUpdateArticleResponse::TtRssUpdateArticleResponse(const QString& raw_content) : TtRssResponse(raw_content) {} - -TtRssUpdateArticleResponse::~TtRssUpdateArticleResponse() = default; - -QString TtRssUpdateArticleResponse::updateStatus() const { - if (m_rawContent.contains(QSL("content"))) { - return m_rawContent[QSL("content")].toObject()[QSL("status")].toString(); - } - else { - return QString(); - } -} - -int TtRssUpdateArticleResponse::articlesUpdated() const { - if (m_rawContent.contains(QSL("content"))) { - return m_rawContent[QSL("content")].toObject()[QSL("updated")].toInt(); - } - else { - return 0; - } -} - -TtRssSubscribeToFeedResponse::TtRssSubscribeToFeedResponse(const QString& raw_content) : TtRssResponse(raw_content) {} - -TtRssSubscribeToFeedResponse::~TtRssSubscribeToFeedResponse() = default; -int TtRssSubscribeToFeedResponse::code() const { - if (m_rawContent.contains(QSL("content"))) { - return m_rawContent[QSL("content")].toObject()[QSL("status")].toObject()[QSL("code")].toInt(); - } - else { - return STF_UNKNOWN; - } -} - -TtRssUnsubscribeFeedResponse::TtRssUnsubscribeFeedResponse(const QString& raw_content) : TtRssResponse(raw_content) {} - -TtRssUnsubscribeFeedResponse::~TtRssUnsubscribeFeedResponse() = default; -QString TtRssUnsubscribeFeedResponse::code() const { - if (m_rawContent.contains(QSL("content"))) { - QJsonObject map = m_rawContent[QSL("content")].toObject(); - - if (map.contains(QSL("error"))) { - return map[QSL("error")].toString(); - } - else if (map.contains(QSL("status"))) { - return map[QSL("status")].toString(); - } - } - - return QString(); -} - -TtRssGetLabelsResponse::TtRssGetLabelsResponse(const QString& raw_content) : TtRssResponse(raw_content) {} - -QList TtRssGetLabelsResponse::labels() const { - QList labels; - auto json_labels = m_rawContent[QSL("content")].toArray(); - - // Add "Published" label. - // - // NOTE: In TT-RSS there is a problem with "published" feature: - // 1. If user has article in existing feed, he can mark it as "published" and in - // that case, the "published" behaves more like a label. - // 2. If user uses feature "shareToPublished", he essentially creates new textual - // note, which is then assigned to "Published feed" but can be also assigned label from 1). - // - // This label solves situation 1). 2) is solved in other way (creating static system feed). - QString published_caption = QSL("[SYSTEM] ") + QObject::tr("Published articles"); - auto* published_lbl = new Label(published_caption, TextFactory::generateColorFromText(published_caption)); - - published_lbl->setKeepOnTop(true); - published_lbl->setCustomId(QString::number(TTRSS_PUBLISHED_LABEL_ID)); - labels.append(published_lbl); - - for (const QJsonValue& lbl_val : std::as_const(json_labels)) { - QJsonObject lbl_obj = lbl_val.toObject(); - Label* lbl = new Label(lbl_obj[QSL("caption")].toString(), QColor(lbl_obj[QSL("fg_color")].toString())); - - lbl->setCustomId(QString::number(lbl_obj[QSL("id")].toInt())); - labels.append(lbl); - } - - return labels; -} - -TtRssGetCompactHeadlinesResponse::TtRssGetCompactHeadlinesResponse(const QString& raw_content) - : TtRssResponse(raw_content) {} - -TtRssGetCompactHeadlinesResponse::~TtRssGetCompactHeadlinesResponse() = default; - -QStringList TtRssGetCompactHeadlinesResponse::ids() const { - auto json_ids = m_rawContent[QSL("content")].toArray(); - QStringList msg_ids; - - for (const QJsonValue& id_val : std::as_const(json_ids)) { - msg_ids.append(QString::number(id_val.toObject()[QSL("id")].toInt())); - } - - return msg_ids; -} diff --git a/src/librssguard/services/tt-rss/ttrssnetworkfactory.h b/src/librssguard/services/tt-rss/ttrssnetworkfactory.h deleted file mode 100644 index a548d9a3f..000000000 --- a/src/librssguard/services/tt-rss/ttrssnetworkfactory.h +++ /dev/null @@ -1,246 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSSNETWORKFACTORY_H -#define TTRSSNETWORKFACTORY_H - -#include "core/message.h" -#include "services/tt-rss/ttrssnotetopublish.h" - -#include -#include -#include -#include - -class RootItem; -class TtRssFeed; -class Label; - -class TtRssResponse { - public: - explicit TtRssResponse(const QString& raw_content = QString()); - virtual ~TtRssResponse(); - - bool isLoaded() const; - - int seq() const; - int status() const; - QString error() const; - bool hasError() const; - bool isNotLoggedIn() const; - bool isUnknownMethod() const; - QString toString() const; - - protected: - QJsonObject m_rawContent; -}; - -class TtRssLoginResponse : public TtRssResponse { - public: - explicit TtRssLoginResponse(const QString& raw_content = QString()); - virtual ~TtRssLoginResponse(); - - int apiLevel() const; - QString sessionId() const; -}; - -class TtRssGetLabelsResponse : public TtRssResponse { - public: - explicit TtRssGetLabelsResponse(const QString& raw_content = QString()); - - QList labels() const; -}; - -class TtRssNetworkFactory; - -class TtRssGetFeedsCategoriesResponse : public TtRssResponse { - public: - explicit TtRssGetFeedsCategoriesResponse(const QString& raw_content = QString()); - virtual ~TtRssGetFeedsCategoriesResponse(); - - // Returns tree of feeds/categories. - // Top-level root of the tree is not needed here. - // Returned items do not have primary IDs assigned. - RootItem* feedsCategories(TtRssNetworkFactory* network, - bool obtain_icons, - const QNetworkProxy& proxy, - const QString& base_address = QString()) const; -}; - -class ServiceRoot; - -class TtRssGetHeadlinesResponse : public TtRssResponse { - public: - explicit TtRssGetHeadlinesResponse(const QString& raw_content = QString()); - virtual ~TtRssGetHeadlinesResponse(); - - QList messages(ServiceRoot* root) const; -}; - -class TtRssGetArticleResponse : public TtRssResponse { - public: - explicit TtRssGetArticleResponse(const QString& raw_content = QString()); - virtual ~TtRssGetArticleResponse(); - - QList messages(ServiceRoot* root) const; -}; - -class TtRssGetCompactHeadlinesResponse : public TtRssResponse { - public: - explicit TtRssGetCompactHeadlinesResponse(const QString& raw_content = QString()); - virtual ~TtRssGetCompactHeadlinesResponse(); - - QStringList ids() const; -}; - -class TtRssUpdateArticleResponse : public TtRssResponse { - public: - explicit TtRssUpdateArticleResponse(const QString& raw_content = QString()); - virtual ~TtRssUpdateArticleResponse(); - - QString updateStatus() const; - int articlesUpdated() const; -}; - -class TtRssSubscribeToFeedResponse : public TtRssResponse { - public: - explicit TtRssSubscribeToFeedResponse(const QString& raw_content = QString()); - virtual ~TtRssSubscribeToFeedResponse(); - - int code() const; -}; - -class TtRssUnsubscribeFeedResponse : public TtRssResponse { - public: - explicit TtRssUnsubscribeFeedResponse(const QString& raw_content = QString()); - virtual ~TtRssUnsubscribeFeedResponse(); - - QString code() const; -}; - -namespace UpdateArticle { - enum class Mode { - SetToFalse = 0, - SetToTrue = 1, - Togggle = 2 - }; - - enum class OperatingField { - Starred = 0, - Published = 1, - Unread = 2 - }; - -} // namespace UpdateArticle - -class TtRssNetworkFactory { - public: - explicit TtRssNetworkFactory(); - - QString url() const; - void setUrl(const QString& url); - - QString username() const; - void setUsername(const QString& username); - - QString password() const; - void setPassword(const QString& password); - - bool authIsUsed() const; - void setAuthIsUsed(bool auth_is_used); - - QString authUsername() const; - void setAuthUsername(const QString& auth_username); - - QString authPassword() const; - void setAuthPassword(const QString& auth_password); - - bool forceServerSideUpdate() const; - void setForceServerSideUpdate(bool force_server_side_update); - - bool downloadOnlyUnreadMessages() const; - void setDownloadOnlyUnreadMessages(bool download_only_unread_messages); - - // Metadata. - QDateTime lastLoginTime() const; - QNetworkReply::NetworkError lastError() const; - - // Operations. - - // Logs user in. - TtRssLoginResponse login(const QNetworkProxy& proxy); - - // Logs user out. - TtRssResponse logout(const QNetworkProxy& proxy); - - // Gets list of labels from the server. - TtRssGetLabelsResponse getLabels(const QNetworkProxy& proxy); - - // Shares new item to "published" feed. - TtRssResponse shareToPublished(const TtRssNoteToPublish& note, const QNetworkProxy& proxy); - - // Gets feeds from the server. - TtRssGetFeedsCategoriesResponse getFeedsCategories(const QNetworkProxy& proxy); - - // Gets message IDs from the server. - TtRssGetCompactHeadlinesResponse getCompactHeadlines(int feed_id, - int limit, - int skip, - const QString& view_mode, - const QNetworkProxy& proxy); - - TtRssGetHeadlinesResponse getArticle(const QStringList& article_ids, const QNetworkProxy& proxy); - - // Gets headlines (messages) from the server. - TtRssGetHeadlinesResponse getHeadlines(int feed_id, - int limit, - int skip, - bool show_content, - bool include_attachments, - bool sanitize, - bool unread_only, - const QNetworkProxy& proxy); - - TtRssResponse setArticleLabel(const QStringList& article_ids, - const QString& label_custom_id, - bool assign, - const QNetworkProxy& proxy); - - TtRssUpdateArticleResponse updateArticles(const QStringList& ids, - UpdateArticle::OperatingField field, - UpdateArticle::Mode mode, - const QNetworkProxy& proxy); - - TtRssSubscribeToFeedResponse subscribeToFeed(const QString& url, - int category_id, - const QNetworkProxy& proxy, - bool protectd = false, - const QString& username = QString(), - const QString& password = QString()); - - TtRssUnsubscribeFeedResponse unsubscribeFeed(int feed_id, const QNetworkProxy& proxy); - - int batchSize() const; - void setBatchSize(int batch_size); - - bool intelligentSynchronization() const; - void setIntelligentSynchronization(bool intelligent_synchronization); - - private: - QString m_bareUrl; - QString m_fullUrl; - QString m_username; - QString m_password; - int m_batchSize; - bool m_forceServerSideUpdate; - bool m_downloadOnlyUnreadMessages; - bool m_intelligentSynchronization; - bool m_authIsUsed; - QString m_authUsername; - QString m_authPassword; - QString m_sessionId; - QDateTime m_lastLoginTime; - - QNetworkReply::NetworkError m_lastError; -}; - -#endif // TTRSSNETWORKFACTORY_H diff --git a/src/librssguard/services/tt-rss/ttrssnotetopublish.h b/src/librssguard/services/tt-rss/ttrssnotetopublish.h deleted file mode 100644 index 077ed239f..000000000 --- a/src/librssguard/services/tt-rss/ttrssnotetopublish.h +++ /dev/null @@ -1,15 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSSNOTETOPUBLISH_H -#define TTRSSNOTETOPUBLISH_H - -#include - -struct TtRssNoteToPublish { - public: - QString m_title; - QString m_url; - QString m_content; -}; - -#endif // TTRSSNOTETOPUBLISH_H diff --git a/src/librssguard/services/tt-rss/ttrssserviceentrypoint.cpp b/src/librssguard/services/tt-rss/ttrssserviceentrypoint.cpp deleted file mode 100644 index 5a29b2d6d..000000000 --- a/src/librssguard/services/tt-rss/ttrssserviceentrypoint.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/ttrssserviceentrypoint.h" - -#include "database/databasequeries.h" -#include "definitions/definitions.h" -#include "miscellaneous/iconfactory.h" -#include "services/tt-rss/definitions.h" -#include "services/tt-rss/gui/formeditttrssaccount.h" -#include "services/tt-rss/ttrssserviceroot.h" - -QString TtRssServiceEntryPoint::name() const { - return QSL("Tiny Tiny RSS"); -} - -QString TtRssServiceEntryPoint::description() const { - return QObject::tr("This service offers integration with Tiny Tiny RSS.\n\n" - "Tiny Tiny RSS is an open source web-based news feed (RSS/Atom) reader and aggregator, " - "designed to allow you to read news from any location, while feeling as close to a real " - "desktop application as possible.\n\nAt least API level %1 is required.") - .arg(TTRSS_MINIMAL_API_LEVEL); -} - -QString TtRssServiceEntryPoint::author() const { - return QSL(APP_AUTHOR); -} - -QIcon TtRssServiceEntryPoint::icon() const { - return qApp->icons()->miscIcon(QSL("tt-rss")); -} - -QString TtRssServiceEntryPoint::code() const { - return QSL(SERVICE_CODE_TT_RSS); -} - -ServiceRoot* TtRssServiceEntryPoint::createNewRoot() const { - FormEditTtRssAccount form_acc(qApp->mainFormWidget()); - - return form_acc.addEditAccount(); -} - -QList TtRssServiceEntryPoint::initializeSubtree() const { - // Check DB if standard account is enabled. - QSqlDatabase database = qApp->database()->driver()->connection(QSL("TtRssServiceEntryPoint")); - - return DatabaseQueries::getAccounts(database, code()); -} diff --git a/src/librssguard/services/tt-rss/ttrssserviceentrypoint.h b/src/librssguard/services/tt-rss/ttrssserviceentrypoint.h deleted file mode 100644 index 74b018f3b..000000000 --- a/src/librssguard/services/tt-rss/ttrssserviceentrypoint.h +++ /dev/null @@ -1,19 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSSSERVICEENTRYPOINT_H -#define TTRSSSERVICEENTRYPOINT_H - -#include "services/abstract/serviceentrypoint.h" - -class TtRssServiceEntryPoint : public ServiceEntryPoint { - public: - virtual QString name() const; - virtual QString description() const; - virtual QString author() const; - virtual QIcon icon() const; - virtual QString code() const; - virtual ServiceRoot* createNewRoot() const; - virtual QList initializeSubtree() const; -}; - -#endif // TTRSSSERVICEENTRYPOINT_H diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp deleted file mode 100644 index c24291039..000000000 --- a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp +++ /dev/null @@ -1,422 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#include "services/tt-rss/ttrssserviceroot.h" - -#include "3rd-party/boolinq/boolinq.h" -#include "database/databasequeries.h" -#include "exceptions/feedfetchexception.h" -#include "exceptions/networkexception.h" -#include "miscellaneous/application.h" -#include "miscellaneous/mutex.h" -#include "miscellaneous/textfactory.h" -#include "network-web/networkfactory.h" -#include "services/abstract/labelsnode.h" -#include "services/tt-rss/definitions.h" -#include "services/tt-rss/gui/formeditttrssaccount.h" -#include "services/tt-rss/gui/formttrssfeeddetails.h" -#include "services/tt-rss/gui/formttrssnote.h" -#include "services/tt-rss/ttrssfeed.h" -#include "services/tt-rss/ttrssnetworkfactory.h" -#include "services/tt-rss/ttrssserviceentrypoint.h" - -#include -#include - -TtRssServiceRoot::TtRssServiceRoot(RootItem* parent) : ServiceRoot(parent), m_network(new TtRssNetworkFactory()) { - setIcon(TtRssServiceEntryPoint().icon()); -} - -TtRssServiceRoot::~TtRssServiceRoot() { - delete m_network; -} - -ServiceRoot::LabelOperation TtRssServiceRoot::supportedLabelOperations() const { - return ServiceRoot::LabelOperation::Synchronised; -} - -void TtRssServiceRoot::start(bool freshly_activated) { - if (!freshly_activated) { - DatabaseQueries::loadRootFromDatabase(this); - loadCacheFromFile(); - - auto lbls = labelsNode()->labels(); - - boolinq::from(lbls).for_each([](Label* lbl) { - if (lbl->customNumericId() == TTRSS_PUBLISHED_LABEL_ID) { - lbl->setKeepOnTop(true); - } - }); - - boolinq::from(childItems()).for_each([](RootItem* child) { - if (child->kind() == RootItem::Kind::Feed && child->customNumericId() == TTRSS_PUBLISHED_FEED_ID) { - child->setKeepOnTop(true); - } - }); - } - - updateTitle(); - - if (getSubTreeFeeds().isEmpty()) { - syncIn(); - } -} - -void TtRssServiceRoot::stop() { - m_network->logout(networkProxy()); - qDebugNN << LOGSEC_TTRSS << "Stopping Tiny Tiny RSS account, logging out with result" - << QUOTE_W_SPACE_DOT(m_network->lastError()); -} - -QString TtRssServiceRoot::code() const { - return TtRssServiceEntryPoint().code(); -} - -bool TtRssServiceRoot::isSyncable() const { - return true; -} - -FormAccountDetails* TtRssServiceRoot::accountSetupDialog() const { - return new FormEditTtRssAccount(qApp->mainFormWidget()); -} - -void TtRssServiceRoot::editItems(const QList& items) { - if (items.first()->kind() == RootItem::Kind::ServiceRoot) { - QScopedPointer p(qobject_cast(accountSetupDialog())); - - p->addEditAccount(this); - return; - } - - ServiceRoot::editItems(items); -} - -bool TtRssServiceRoot::supportsFeedAdding() const { - return true; -} - -bool TtRssServiceRoot::supportsCategoryAdding() const { - return false; -} - -void TtRssServiceRoot::addNewFeed(RootItem* selected_item, const QString& url) { - if (!qApp->feedUpdateLock()->tryLock()) { - // Lock was not obtained because - // it is used probably by feed updater or application - // is quitting. - qApp->showGuiMessage(Notification::Event::GeneralEvent, - {tr("Cannot add item"), - tr("Cannot add feed because another critical operation is ongoing."), - QSystemTrayIcon::MessageIcon::Warning}); - - return; - } - - QScopedPointer form_pointer(new FormTtRssFeedDetails(this, - selected_item, - url, - qApp->mainFormWidget())); - - form_pointer->addEditFeed(); - qApp->feedUpdateLock()->unlock(); -} - -bool TtRssServiceRoot::canBeEdited() const { - return true; -} - -void TtRssServiceRoot::saveAllCachedData(bool ignore_errors) { - auto msg_cache = takeMessageCache(); - QMapIterator i(msg_cache.m_cachedStatesRead); - - // Save the actual data read/unread. - while (i.hasNext()) { - i.next(); - auto key = i.key(); - QStringList ids = i.value(); - - if (!ids.isEmpty()) { - auto res = network()->updateArticles(ids, - UpdateArticle::OperatingField::Unread, - key == RootItem::ReadStatus::Unread ? UpdateArticle::Mode::SetToTrue - : UpdateArticle::Mode::SetToFalse, - networkProxy()); - - if (!ignore_errors && (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError())) { - addMessageStatesToCache(ids, key); - } - } - } - - QMapIterator> j(msg_cache.m_cachedStatesImportant); - - // Save the actual data important/not important. - while (j.hasNext()) { - j.next(); - auto key = j.key(); - QList messages = j.value(); - - if (!messages.isEmpty()) { - QStringList ids = customIDsOfMessages(messages); - auto res = network()->updateArticles(ids, - UpdateArticle::OperatingField::Starred, - key == RootItem::Importance::Important ? UpdateArticle::Mode::SetToTrue - : UpdateArticle::Mode::SetToFalse, - networkProxy()); - - if (!ignore_errors && (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError())) { - addMessageStatesToCache(messages, key); - } - } - } - - QMapIterator k(msg_cache.m_cachedLabelAssignments); - - // Assign label for these messages. - while (k.hasNext()) { - k.next(); - auto label_custom_id = k.key(); - QStringList messages = k.value(); - - if (!messages.isEmpty()) { - TtRssResponse res; - - if (label_custom_id.toInt() == TTRSS_PUBLISHED_LABEL_ID) { - // "published" label must be added in other method. - res = network()->updateArticles(messages, - UpdateArticle::OperatingField::Published, - UpdateArticle::Mode::SetToTrue, - networkProxy()); - } - else { - res = network()->setArticleLabel(messages, label_custom_id, true, networkProxy()); - } - - if (!ignore_errors && (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError())) { - addLabelsAssignmentsToCache(messages, label_custom_id, true); - } - } - } - - QMapIterator l(msg_cache.m_cachedLabelDeassignments); - - // Remove label from these messages. - while (l.hasNext()) { - l.next(); - auto label_custom_id = l.key(); - QStringList messages = l.value(); - - if (!messages.isEmpty()) { - TtRssResponse res; - - if (label_custom_id.toInt() == TTRSS_PUBLISHED_LABEL_ID) { - // "published" label must be removed in other method. - res = network()->updateArticles(messages, - UpdateArticle::OperatingField::Published, - UpdateArticle::Mode::SetToFalse, - networkProxy()); - } - else { - res = network()->setArticleLabel(messages, label_custom_id, false, networkProxy()); - } - - if (!ignore_errors && (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError())) { - addLabelsAssignmentsToCache(messages, label_custom_id, false); - } - } - } -} - -QVariantHash TtRssServiceRoot::customDatabaseData() const { - QVariantHash data = ServiceRoot::customDatabaseData(); - - data[QSL("username")] = m_network->username(); - data[QSL("password")] = TextFactory::encrypt(m_network->password()); - data[QSL("auth_protected")] = m_network->authIsUsed(); - data[QSL("auth_username")] = m_network->authUsername(); - data[QSL("auth_password")] = TextFactory::encrypt(m_network->authPassword()); - data[QSL("url")] = m_network->url(); - data[QSL("force_update")] = m_network->forceServerSideUpdate(); - data[QSL("batch_size")] = m_network->batchSize(); - data[QSL("download_only_unread")] = m_network->downloadOnlyUnreadMessages(); - data[QSL("intelligent_synchronization")] = m_network->intelligentSynchronization(); - - return data; -} - -void TtRssServiceRoot::setCustomDatabaseData(const QVariantHash& data) { - ServiceRoot::setCustomDatabaseData(data); - - m_network->setUsername(data[QSL("username")].toString()); - m_network->setPassword(TextFactory::decrypt(data[QSL("password")].toString())); - m_network->setAuthIsUsed(data[QSL("auth_protected")].toBool()); - m_network->setAuthUsername(data[QSL("auth_username")].toString()); - m_network->setAuthPassword(TextFactory::decrypt(data[QSL("auth_password")].toString())); - m_network->setUrl(data[QSL("url")].toString()); - m_network->setForceServerSideUpdate(data[QSL("force_update")].toBool()); - m_network->setBatchSize(data[QSL("batch_size")].toInt()); - m_network->setDownloadOnlyUnreadMessages(data[QSL("download_only_unread")].toBool()); - m_network->setIntelligentSynchronization(data[QSL("intelligent_synchronization")].toBool()); -} - -QList TtRssServiceRoot::obtainNewMessages(Feed* feed, - const QHash& - stated_messages, - const QHash& tagged_messages) { - Q_UNUSED(tagged_messages) - - if (m_network->intelligentSynchronization()) { - return obtainMessagesIntelligently(feed, stated_messages); - } - else { - return obtainMessagesViaHeadlines(feed); - } -} - -QList TtRssServiceRoot::obtainMessagesIntelligently(Feed* feed, - const QHash& stated_messages) { - // 1. Get unread IDs for a feed. - // 2. Get read IDs for a feed. - // 3. Get starred IDs for a feed. - // 4. Determine IDs needed to download. - // 5. Download needed articles. - const QStringList remote_all_ids_list = - m_network->downloadOnlyUnreadMessages() - ? QStringList() - : m_network->getCompactHeadlines(feed->customNumericId(), 1000000, 0, QSL("all_articles"), networkProxy()).ids(); - const QStringList remote_unread_ids_list = - m_network->getCompactHeadlines(feed->customNumericId(), 1000000, 0, QSL("unread"), networkProxy()).ids(); - const QStringList remote_starred_ids_list = - m_network->getCompactHeadlines(feed->customNumericId(), 1000000, 0, QSL("marked"), networkProxy()).ids(); - - const QSet remote_all_ids = FROM_LIST_TO_SET(QSet, remote_all_ids_list); - - // 1. - auto local_unread_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Unread); - const QSet remote_unread_ids = FROM_LIST_TO_SET(QSet, remote_unread_ids_list); - const QSet local_unread_ids = FROM_LIST_TO_SET(QSet, local_unread_ids_list); - - // 2. - const auto local_read_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Read); - const QSet remote_read_ids = remote_all_ids - remote_unread_ids; - const QSet local_read_ids = FROM_LIST_TO_SET(QSet, local_read_ids_list); - - // 3. - const auto local_starred_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Starred); - const QSet remote_starred_ids = FROM_LIST_TO_SET(QSet, remote_starred_ids_list); - const QSet local_starred_ids = FROM_LIST_TO_SET(QSet, local_starred_ids_list); - - // 4. - QSet to_download; - - if (!m_network->downloadOnlyUnreadMessages()) { - to_download += remote_all_ids - local_read_ids - local_unread_ids; - } - else { - to_download += remote_unread_ids - local_read_ids - local_unread_ids; - } - - auto moved_read = local_read_ids & remote_unread_ids; - - to_download += moved_read; - - if (!m_network->downloadOnlyUnreadMessages()) { - auto moved_unread = local_unread_ids & remote_read_ids; - - to_download += moved_unread; - } - - auto moved_starred = (local_starred_ids + remote_starred_ids) - (local_starred_ids & remote_starred_ids); - - to_download += moved_starred; - - // 5. - auto msgs = m_network->getArticle(to_download.values(), networkProxy()); - - return msgs.messages(this); -} - -QList TtRssServiceRoot::obtainMessagesViaHeadlines(Feed* feed) { - QList messages; - int newly_added_messages = 0; - int limit = network()->batchSize() <= 0 ? TTRSS_MAX_MESSAGES : network()->batchSize(); - int skip = 0; - - do { - TtRssGetHeadlinesResponse headlines = network()->getHeadlines(feed->customNumericId(), - limit, - skip, - true, - true, - false, - network()->downloadOnlyUnreadMessages(), - networkProxy()); - - if (network()->lastError() != QNetworkReply::NetworkError::NoError) { - throw FeedFetchException(Feed::Status::NetworkError, headlines.error()); - } - else { - QList new_messages = headlines.messages(this); - - messages << new_messages; - newly_added_messages = new_messages.size(); - skip += newly_added_messages; - } - } - while (newly_added_messages > 0 && (network()->batchSize() <= 0 || messages.size() < network()->batchSize())); - - return messages; -} - -QString TtRssServiceRoot::additionalTooltip() const { - return ServiceRoot::additionalTooltip() + QSL("\n") + - tr("Username: %1\nServer: %2\n" - "Last error: %3\nLast login on: %4") - .arg(m_network->username(), - m_network->url(), - NetworkFactory::networkErrorText(m_network->lastError()), - m_network->lastLoginTime().isValid() - ? QLocale().toString(m_network->lastLoginTime(), QLocale::FormatType::ShortFormat) - : QSL("-")); -} - -TtRssNetworkFactory* TtRssServiceRoot::network() const { - return m_network; -} - -void TtRssServiceRoot::shareToPublished() { - FormTtRssNote(this).exec(); -} - -void TtRssServiceRoot::updateTitle() { - QString host = QUrl(m_network->url()).host(); - - if (host.isEmpty()) { - host = m_network->url(); - } - - setTitle(TextFactory::extractUsernameFromEmail(m_network->username()) + QSL(" (Tiny Tiny RSS)")); -} - -RootItem* TtRssServiceRoot::obtainNewTreeForSyncIn() const { - TtRssGetFeedsCategoriesResponse feed_cats = m_network->getFeedsCategories(networkProxy()); - TtRssGetLabelsResponse labels = m_network->getLabels(networkProxy()); - - auto lst_error = m_network->lastError(); - - if (lst_error == QNetworkReply::NoError) { - auto* tree = feed_cats.feedsCategories(m_network, true, networkProxy(), m_network->url()); - auto* lblroot = new LabelsNode(tree); - - lblroot->setChildItems(labels.labels()); - tree->appendChild(lblroot); - - return tree; - } - else { - throw NetworkException(lst_error, tr("cannot get list of feeds, network error '%1'").arg(lst_error)); - } -} - -bool TtRssServiceRoot::wantsBaggedIdsOfExistingMessages() const { - return m_network->intelligentSynchronization(); -} diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.h b/src/librssguard/services/tt-rss/ttrssserviceroot.h deleted file mode 100644 index 190813386..000000000 --- a/src/librssguard/services/tt-rss/ttrssserviceroot.h +++ /dev/null @@ -1,61 +0,0 @@ -// For license of this file, see /LICENSE.md. - -#ifndef TTRSSSERVICEROOT_H -#define TTRSSSERVICEROOT_H - -#include "services/abstract/cacheforserviceroot.h" -#include "services/abstract/serviceroot.h" - -#include - -class TtRssCategory; -class TtRssFeed; -class TtRssNetworkFactory; - -class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot { - Q_OBJECT - - public: - explicit TtRssServiceRoot(RootItem* parent = nullptr); - virtual ~TtRssServiceRoot(); - - virtual bool wantsBaggedIdsOfExistingMessages() const; - virtual LabelOperation supportedLabelOperations() const; - virtual void start(bool freshly_activated); - virtual void stop(); - virtual QString code() const; - virtual bool isSyncable() const; - virtual bool canBeEdited() const; - virtual void editItems(const QList& items); - virtual FormAccountDetails* accountSetupDialog() const; - virtual bool supportsFeedAdding() const; - virtual bool supportsCategoryAdding() const; - virtual void addNewFeed(RootItem* selected_item, const QString& url = QString()); - virtual QString additionalTooltip() const; - virtual void saveAllCachedData(bool ignore_errors); - virtual QVariantHash customDatabaseData() const; - virtual void setCustomDatabaseData(const QVariantHash& data); - virtual QList obtainNewMessages(Feed* feed, - const QHash& stated_messages, - const QHash& tagged_messages); - - // Access to network. - TtRssNetworkFactory* network() const; - - public slots: - void shareToPublished(); - - protected: - virtual RootItem* obtainNewTreeForSyncIn() const; - - private: - void updateTitle(); - QList obtainMessagesIntelligently(Feed* feed, - const QHash& stated_messages); - QList obtainMessagesViaHeadlines(Feed* feed); - - private: - TtRssNetworkFactory* m_network; -}; - -#endif // TTRSSSERVICEROOT_H