From a9fe39df92f7aeabf2116bd0ebaf297810be9e13 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 28 Jan 2021 14:46:54 +0100 Subject: [PATCH] Starting to work on #349. --- resources/graphics/misc/google.png | Bin 0 -> 9264 bytes resources/rssguard.qrc | 1 + resources/sql/db_update_mysql_18_19.sql | 12 ++ resources/sql/db_update_sqlite_18_19.sql | 12 ++ src/librssguard/definitions/definitions.h | 2 + src/librssguard/librssguard.pro | 14 ++ .../miscellaneous/databasequeries.cpp | 95 +++++++++ .../miscellaneous/databasequeries.h | 13 +- src/librssguard/miscellaneous/feedreader.cpp | 2 + .../abstract/gui/formaccountdetails.h | 4 +- .../services/greader/definitions.h | 6 + .../services/greader/greaderentrypoint.cpp | 44 ++++ .../services/greader/greaderentrypoint.h | 19 ++ .../services/greader/greaderfeed.cpp | 29 +++ .../services/greader/greaderfeed.h | 19 ++ .../services/greader/greadernetwork.cpp | 70 +++++++ .../services/greader/greadernetwork.h | 49 +++++ .../services/greader/greaderserviceroot.cpp | 153 ++++++++++++++ .../services/greader/greaderserviceroot.h | 61 ++++++ .../greader/gui/formeditgreaderaccount.cpp | 55 +++++ .../greader/gui/formeditgreaderaccount.h | 30 +++ .../greader/gui/greaderaccountdetails.cpp | 125 ++++++++++++ .../greader/gui/greaderaccountdetails.h | 36 ++++ .../greader/gui/greaderaccountdetails.ui | 188 ++++++++++++++++++ 24 files changed, 1034 insertions(+), 5 deletions(-) create mode 100644 resources/graphics/misc/google.png create mode 100755 resources/sql/db_update_mysql_18_19.sql create mode 100755 resources/sql/db_update_sqlite_18_19.sql create mode 100755 src/librssguard/services/greader/definitions.h create mode 100755 src/librssguard/services/greader/greaderentrypoint.cpp create mode 100755 src/librssguard/services/greader/greaderentrypoint.h create mode 100755 src/librssguard/services/greader/greaderfeed.cpp create mode 100755 src/librssguard/services/greader/greaderfeed.h create mode 100755 src/librssguard/services/greader/greadernetwork.cpp create mode 100755 src/librssguard/services/greader/greadernetwork.h create mode 100755 src/librssguard/services/greader/greaderserviceroot.cpp create mode 100755 src/librssguard/services/greader/greaderserviceroot.h create mode 100755 src/librssguard/services/greader/gui/formeditgreaderaccount.cpp create mode 100755 src/librssguard/services/greader/gui/formeditgreaderaccount.h create mode 100755 src/librssguard/services/greader/gui/greaderaccountdetails.cpp create mode 100755 src/librssguard/services/greader/gui/greaderaccountdetails.h create mode 100755 src/librssguard/services/greader/gui/greaderaccountdetails.ui diff --git a/resources/graphics/misc/google.png b/resources/graphics/misc/google.png new file mode 100644 index 0000000000000000000000000000000000000000..83638cbb22689d26fde651a339841d80acbcb829 GIT binary patch literal 9264 zcmV-0B+uK4P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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 SnG5p(0000graphics/misc/adblock.png graphics/misc/adblock-disabled.png graphics/misc/gmail.png + graphics/misc/google.png graphics/misc/image-placeholder.png graphics/misc/inoreader.png graphics/misc/nextcloud.png diff --git a/resources/sql/db_update_mysql_18_19.sql b/resources/sql/db_update_mysql_18_19.sql new file mode 100755 index 000000000..c2a2ec363 --- /dev/null +++ b/resources/sql/db_update_mysql_18_19.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS GoogleReaderApiAccounts ( + id INTEGER, + type INTEGER NOT NULL CHECK (type >= 1), + username TEXT NOT NULL, + password TEXT, + url TEXT NOT NULL, + msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1), + + FOREIGN KEY (id) REFERENCES Accounts (id) +); +-- ! +UPDATE Information SET inf_value = '19' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/sql/db_update_sqlite_18_19.sql b/resources/sql/db_update_sqlite_18_19.sql new file mode 100755 index 000000000..c2a2ec363 --- /dev/null +++ b/resources/sql/db_update_sqlite_18_19.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS GoogleReaderApiAccounts ( + id INTEGER, + type INTEGER NOT NULL CHECK (type >= 1), + username TEXT NOT NULL, + password TEXT, + url TEXT NOT NULL, + msg_limit INTEGER NOT NULL DEFAULT -1 CHECK (msg_limit >= -1), + + FOREIGN KEY (id) REFERENCES Accounts (id) +); +-- ! +UPDATE Information SET inf_value = '19' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index d00b6c590..f8c7ef97b 100755 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -12,6 +12,7 @@ #define SERVICE_CODE_STD_RSS "std-rss" #define SERVICE_CODE_TT_RSS "tt-rss" #define SERVICE_CODE_OWNCLOUD "owncloud" +#define SERVICE_CODE_GREADER "greader" #define SERVICE_CODE_INOREADER "inoreader" #define SERVICE_CODE_GMAIL "gmail" @@ -103,6 +104,7 @@ #define LOGSEC_CORE "core: " #define LOGSEC_DB "database: " #define LOGSEC_NEXTCLOUD "nextcloud: " +#define LOGSEC_GREADER "greader: " #define LOGSEC_INOREADER "inoreader: " #define LOGSEC_TTRSS "tt-rss: " #define LOGSEC_GMAIL "gmail: " diff --git a/src/librssguard/librssguard.pro b/src/librssguard/librssguard.pro index dfb602b1e..0c760247c 100644 --- a/src/librssguard/librssguard.pro +++ b/src/librssguard/librssguard.pro @@ -150,6 +150,13 @@ HEADERS += core/feeddownloader.h \ services/gmail/gui/formeditgmailaccount.h \ services/gmail/gui/gmailaccountdetails.h \ services/gmail/network/gmailnetworkfactory.h \ + services/greader/definitions.h \ + services/greader/greaderentrypoint.h \ + services/greader/greaderfeed.h \ + services/greader/greadernetwork.h \ + services/greader/greaderserviceroot.h \ + services/greader/gui/formeditgreaderaccount.h \ + services/greader/gui/greaderaccountdetails.h \ services/inoreader/definitions.h \ services/inoreader/gui/formeditinoreaderaccount.h \ services/inoreader/gui/inoreaderaccountdetails.h \ @@ -310,6 +317,12 @@ SOURCES += core/feeddownloader.cpp \ services/gmail/gui/formeditgmailaccount.cpp \ services/gmail/gui/gmailaccountdetails.cpp \ services/gmail/network/gmailnetworkfactory.cpp \ + services/greader/greaderentrypoint.cpp \ + services/greader/greaderfeed.cpp \ + services/greader/greadernetwork.cpp \ + services/greader/greaderserviceroot.cpp \ + services/greader/gui/formeditgreaderaccount.cpp \ + services/greader/gui/greaderaccountdetails.cpp \ services/inoreader/gui/formeditinoreaderaccount.cpp \ services/inoreader/gui/inoreaderaccountdetails.cpp \ services/inoreader/inoreaderentrypoint.cpp \ @@ -384,6 +397,7 @@ FORMS += gui/dialogs/formabout.ui \ services/abstract/gui/formfeeddetails.ui \ services/abstract/gui/authenticationdetails.ui \ services/gmail/gui/gmailaccountdetails.ui \ + services/greader/gui/greaderaccountdetails.ui \ services/inoreader/gui/inoreaderaccountdetails.ui \ services/owncloud/gui/owncloudaccountdetails.ui \ services/standard/gui/formstandardcategorydetails.ui \ diff --git a/src/librssguard/miscellaneous/databasequeries.cpp b/src/librssguard/miscellaneous/databasequeries.cpp index 9ba775d4e..43c4cfd05 100755 --- a/src/librssguard/miscellaneous/databasequeries.cpp +++ b/src/librssguard/miscellaneous/databasequeries.cpp @@ -13,6 +13,9 @@ #include "services/gmail/gmailfeed.h" #include "services/gmail/gmailserviceroot.h" #include "services/gmail/network/gmailnetworkfactory.h" +#include "services/greader/definitions.h" +#include "services/greader/greadernetwork.h" +#include "services/greader/greaderserviceroot.h" #include "services/inoreader/definitions.h" #include "services/inoreader/inoreaderfeed.h" #include "services/inoreader/inoreaderserviceroot.h" @@ -1675,6 +1678,46 @@ void DatabaseQueries::fillBaseAccountData(const QSqlDatabase& db, ServiceRoot* a } } +QList DatabaseQueries::getGreaderAccounts(const QSqlDatabase& db, bool* ok) { + QSqlQuery query(db); + QList roots; + + if (query.exec("SELECT * FROM GoogleReaderApiAccounts;")) { + while (query.next()) { + auto* root = new GreaderServiceRoot(); + + root->setId(query.value(0).toInt()); + root->setAccountId(query.value(0).toInt()); + root->network()->setService(GreaderServiceRoot::Service(query.value(1).toInt())); + root->network()->setUsername(query.value(2).toString()); + root->network()->setPassword(TextFactory::decrypt(query.value(3).toString())); + root->network()->setBaseUrl(query.value(4).toString()); + root->network()->setBatchSize(query.value(5).toInt()); + root->updateTitle(); + + fillBaseAccountData(db, root); + + roots.append(root); + } + + if (ok != nullptr) { + *ok = true; + } + } + else { + qWarningNN << LOGSEC_GREADER + << "Getting list of activated accounts failed: '" + << query.lastError().text() + << "'."; + + if (ok != nullptr) { + *ok = false; + } + } + + return roots; +} + QList DatabaseQueries::getOwnCloudAccounts(const QSqlDatabase& db, bool* ok) { QSqlQuery query(db); QList roots; @@ -1768,6 +1811,32 @@ bool DatabaseQueries::deleteOwnCloudAccount(const QSqlDatabase& db, int account_ return q.exec(); } +bool DatabaseQueries::overwriteGreaderAccount(const QSqlDatabase& db, const QString& username, const QString& password, + const QString& url, int batch_size, int account_id) { + QSqlQuery query(db); + + query.prepare("UPDATE GoogleReaderApiAccounts " + "SET username = :username, password = :password, url = :url, " + "msg_limit = :msg_limit " + "WHERE id = :id;"); + query.bindValue(QSL(":username"), username); + query.bindValue(QSL(":password"), TextFactory::encrypt(password)); + query.bindValue(QSL(":url"), url); + query.bindValue(QSL(":id"), account_id); + query.bindValue(QSL(":msg_limit"), batch_size <= 0 ? GREADER_UNLIMITED_BATCH_SIZE : batch_size); + + if (query.exec()) { + return true; + } + else { + qWarningNN << LOGSEC_GREADER + << "Updating account failed: '" + << query.lastError().text() + << "'."; + return false; + } +} + bool DatabaseQueries::overwriteOwnCloudAccount(const QSqlDatabase& db, const QString& username, const QString& password, const QString& url, bool force_server_side_feed_update, int batch_size, bool download_only_unread_messages, int account_id) { @@ -1797,6 +1866,32 @@ bool DatabaseQueries::overwriteOwnCloudAccount(const QSqlDatabase& db, const QSt } } +bool DatabaseQueries::createGreaderAccount(const QSqlDatabase& db, int id_to_assign, const QString& username, + const QString& password, GreaderServiceRoot::Service service, + const QString& url, int batch_size) { + QSqlQuery q(db); + + q.prepare("INSERT INTO GoogleReaderApiAccounts (id, type, username, password, url, msg_limit) " + "VALUES (:id, :service, :username, :password, :url, :msg_limit);"); + q.bindValue(QSL(":id"), id_to_assign); + q.bindValue(QSL(":username"), username); + q.bindValue(QSL(":service"), int(service)); + q.bindValue(QSL(":password"), TextFactory::encrypt(password)); + q.bindValue(QSL(":url"), url); + q.bindValue(QSL(":msg_limit"), batch_size <= 0 ? GREADER_UNLIMITED_BATCH_SIZE : batch_size); + + if (q.exec()) { + return true; + } + else { + qWarningNN << LOGSEC_GREADER + << "Inserting of new account failed: '" + << q.lastError().text() + << "'."; + return false; + } +} + bool DatabaseQueries::createOwnCloudAccount(const QSqlDatabase& db, int id_to_assign, const QString& username, const QString& password, const QString& url, bool force_server_side_feed_update, diff --git a/src/librssguard/miscellaneous/databasequeries.h b/src/librssguard/miscellaneous/databasequeries.h index 9453c1a3c..9241c86a4 100644 --- a/src/librssguard/miscellaneous/databasequeries.h +++ b/src/librssguard/miscellaneous/databasequeries.h @@ -9,6 +9,7 @@ #include "services/abstract/category.h" #include "services/abstract/label.h" #include "services/abstract/serviceroot.h" +#include "services/greader/greaderserviceroot.h" #include "services/standard/standardfeed.h" #include @@ -147,14 +148,22 @@ class DatabaseQueries { template static void fillFeedData(T* feed, const QSqlRecord& sql_record); + // Greader account. + static QList getGreaderAccounts(const QSqlDatabase& db, bool* ok = nullptr); + static bool createGreaderAccount(const QSqlDatabase& db, int id_to_assign, const QString& username, + const QString& password, GreaderServiceRoot::Service service, + const QString& url, int batch_size); + static bool overwriteGreaderAccount(const QSqlDatabase& db, const QString& username, const QString& password, + const QString& url, int batch_size, int account_id); + // Nextcloud account. static QList getOwnCloudAccounts(const QSqlDatabase& db, bool* ok = nullptr); static bool deleteOwnCloudAccount(const QSqlDatabase& db, int account_id); static bool overwriteOwnCloudAccount(const QSqlDatabase& db, const QString& username, const QString& password, const QString& url, bool force_server_side_feed_update, int batch_size, bool download_only_unread_messages, int account_id); - static bool createOwnCloudAccount(const QSqlDatabase& db, int id_to_assign, const QString& username, const QString& password, - const QString& url, bool force_server_side_feed_update, + static bool createOwnCloudAccount(const QSqlDatabase& db, int id_to_assign, const QString& username, + const QString& password, const QString& url, bool force_server_side_feed_update, bool download_only_unread_messages, int batch_size); // TT-RSS acccount. diff --git a/src/librssguard/miscellaneous/feedreader.cpp b/src/librssguard/miscellaneous/feedreader.cpp index 87caab1a3..4e184eb58 100644 --- a/src/librssguard/miscellaneous/feedreader.cpp +++ b/src/librssguard/miscellaneous/feedreader.cpp @@ -15,6 +15,7 @@ #include "services/abstract/cacheforserviceroot.h" #include "services/abstract/serviceroot.h" #include "services/gmail/gmailentrypoint.h" +#include "services/greader/greaderentrypoint.h" #include "services/inoreader/inoreaderentrypoint.h" #include "services/owncloud/owncloudserviceentrypoint.h" #include "services/standard/standardserviceentrypoint.h" @@ -55,6 +56,7 @@ QList FeedReader::feedServices() { if (m_feedServices.isEmpty()) { // NOTE: All installed services create their entry points here. m_feedServices.append(new GmailEntryPoint()); + m_feedServices.append(new GreaderEntryPoint()); m_feedServices.append(new InoreaderEntryPoint()); m_feedServices.append(new OwnCloudServiceEntryPoint()); m_feedServices.append(new StandardServiceEntryPoint()); diff --git a/src/librssguard/services/abstract/gui/formaccountdetails.h b/src/librssguard/services/abstract/gui/formaccountdetails.h index a80f6e141..8a9ee25fa 100644 --- a/src/librssguard/services/abstract/gui/formaccountdetails.h +++ b/src/librssguard/services/abstract/gui/formaccountdetails.h @@ -73,11 +73,9 @@ inline bool FormAccountDetails::applyInternal() { QSqlDatabase database = qApp->database()->connection(QSL("FormAccountDetails")); bool creating = m_account == nullptr; - if (m_account == nullptr) { + if (creating) { m_account = new T(); m_account->setAccountId(DatabaseQueries::createBaseAccount(database, m_account->code())); - - //m_account->setId(m_account->accountId()); } m_account->setNetworkProxy(m_proxyDetails->proxy()); diff --git a/src/librssguard/services/greader/definitions.h b/src/librssguard/services/greader/definitions.h new file mode 100755 index 000000000..f47edd8f3 --- /dev/null +++ b/src/librssguard/services/greader/definitions.h @@ -0,0 +1,6 @@ +#ifndef GREADER_DEFINITIONS_H +#define GREADER_DEFINITIONS_H + +#define GREADER_UNLIMITED_BATCH_SIZE -1 + +#endif // GREADER_DEFINITIONS_H diff --git a/src/librssguard/services/greader/greaderentrypoint.cpp b/src/librssguard/services/greader/greaderentrypoint.cpp new file mode 100755 index 000000000..a9871ad7a --- /dev/null +++ b/src/librssguard/services/greader/greaderentrypoint.cpp @@ -0,0 +1,44 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/greaderentrypoint.h" + +#include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "miscellaneous/databasequeries.h" +#include "miscellaneous/iconfactory.h" +#include "services/greader/definitions.h" +#include "services/greader/greaderserviceroot.h" +#include "services/greader/gui/formeditgreaderaccount.h" + +ServiceRoot* GreaderEntryPoint::createNewRoot() const { + FormEditGreaderAccount form_acc(qApp->mainFormWidget()); + + return form_acc.addEditAccount(); +} + +QList GreaderEntryPoint::initializeSubtree() const { + QSqlDatabase database = qApp->database()->connection(QSL("GreaderEntryPoint")); + + return DatabaseQueries::getGreaderAccounts(database); +} + +QString GreaderEntryPoint::name() const { + return QSL("Google Reader API"); +} + +QString GreaderEntryPoint::code() const { + return SERVICE_CODE_GREADER; +} + +QString GreaderEntryPoint::description() const { + return QObject::tr("Google Reader API is used by many online RSS readers. This is here to support") + + QSL(" FreshRSS, Bazqux, TheOldReader."); +} + +QString GreaderEntryPoint::author() const { + return APP_AUTHOR; +} + +QIcon GreaderEntryPoint::icon() const { + return qApp->icons()->miscIcon(QSL("google")); +} diff --git a/src/librssguard/services/greader/greaderentrypoint.h b/src/librssguard/services/greader/greaderentrypoint.h new file mode 100755 index 000000000..3cb92c374 --- /dev/null +++ b/src/librssguard/services/greader/greaderentrypoint.h @@ -0,0 +1,19 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GREADERENTRYPOINT_H +#define GREADERENTRYPOINT_H + +#include "services/abstract/serviceentrypoint.h" + +class GreaderEntryPoint : 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 // GREADERENTRYPOINT_H diff --git a/src/librssguard/services/greader/greaderfeed.cpp b/src/librssguard/services/greader/greaderfeed.cpp new file mode 100755 index 000000000..f8770d3d8 --- /dev/null +++ b/src/librssguard/services/greader/greaderfeed.cpp @@ -0,0 +1,29 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/greaderfeed.h" + +#include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" +#include "services/greader/greadernetwork.h" +#include "services/greader/greaderserviceroot.h" + +GreaderFeed::GreaderFeed(RootItem* parent) : Feed(parent) {} + +GreaderFeed::GreaderFeed(const QSqlRecord& record) : Feed(record) {} + +GreaderServiceRoot* GreaderFeed::serviceRoot() const { + return qobject_cast(getParentServiceRoot()); +} + +QList GreaderFeed::obtainNewMessages(bool* error_during_obtaining) { + Feed::Status error = Feed::Status::Normal; + QList messages = serviceRoot()->network()->messages(getParentServiceRoot(), customId(), error); + + setStatus(error); + + if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) { + *error_during_obtaining = true; + } + + return messages; +} diff --git a/src/librssguard/services/greader/greaderfeed.h b/src/librssguard/services/greader/greaderfeed.h new file mode 100755 index 000000000..e8cbfa40e --- /dev/null +++ b/src/librssguard/services/greader/greaderfeed.h @@ -0,0 +1,19 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GREADERFEED_H +#define GREADERFEED_H + +#include "services/abstract/feed.h" + +class GreaderServiceRoot; + +class GreaderFeed : public Feed { + public: + explicit GreaderFeed(RootItem* parent = nullptr); + explicit GreaderFeed(const QSqlRecord& record); + + GreaderServiceRoot* serviceRoot() const; + QList obtainNewMessages(bool* error_during_obtaining); +}; + +#endif // GREADERFEED_H diff --git a/src/librssguard/services/greader/greadernetwork.cpp b/src/librssguard/services/greader/greadernetwork.cpp new file mode 100755 index 000000000..2cada5296 --- /dev/null +++ b/src/librssguard/services/greader/greadernetwork.cpp @@ -0,0 +1,70 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/greadernetwork.h" + +GreaderNetwork::GreaderNetwork(QObject* parent) + : QObject(parent), m_service(GreaderServiceRoot::Service::FreshRss) {} + +QList GreaderNetwork::messages(ServiceRoot* root, const QString& stream_id, Feed::Status& error) { + return {}; +} + +NetworkResult GreaderNetwork::status(const QNetworkProxy& custom_proxy) const { + return NetworkResult(QNetworkReply::NetworkError::NoError, {}); +} + +GreaderServiceRoot::Service GreaderNetwork::service() const { + return m_service; +} + +void GreaderNetwork::setService(const GreaderServiceRoot::Service& service) { + m_service = service; +} + +QString GreaderNetwork::username() const { + return m_username; +} + +void GreaderNetwork::setUsername(const QString& username) { + m_username = username; +} + +QString GreaderNetwork::password() const { + return m_password; +} + +void GreaderNetwork::setPassword(const QString& password) { + m_password = password; +} + +QString GreaderNetwork::baseUrl() const { + return m_baseUrl; +} + +void GreaderNetwork::setBaseUrl(const QString& base_url) { + m_baseUrl = base_url; +} + +QString GreaderNetwork::serviceToString(GreaderServiceRoot::Service service) { + switch (service) { + case GreaderServiceRoot::Service::FreshRss: + return QSL("FreshRSS"); + + case GreaderServiceRoot::Service::Bazqux: + return QSL("Bazqux"); + + case GreaderServiceRoot::Service::TheOldReader: + return QSL("TheOldReader"); + + default: + return tr("Unknown service"); + } +} + +int GreaderNetwork::batchSize() const { + return m_batchSize; +} + +void GreaderNetwork::setBatchSize(int batch_size) { + m_batchSize = batch_size; +} diff --git a/src/librssguard/services/greader/greadernetwork.h b/src/librssguard/services/greader/greadernetwork.h new file mode 100755 index 000000000..3a7442fbe --- /dev/null +++ b/src/librssguard/services/greader/greadernetwork.h @@ -0,0 +1,49 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GREADERNETWORK_H +#define GREADERNETWORK_H + +#include + +#include "network-web/networkfactory.h" +#include "services/abstract/feed.h" +#include "services/greader/greaderserviceroot.h" + +class GreaderNetwork : public QObject { + Q_OBJECT + + public: + explicit GreaderNetwork(QObject* parent = nullptr); + + // Network operations. + QList messages(ServiceRoot* root, const QString& stream_id, Feed::Status& error); + + NetworkResult status(const QNetworkProxy& custom_proxy) const; + + // Metadata. + GreaderServiceRoot::Service service() const; + void setService(const GreaderServiceRoot::Service& service); + + QString username() const; + void setUsername(const QString& username); + + QString password() const; + void setPassword(const QString& password); + + QString baseUrl() const; + void setBaseUrl(const QString& base_url); + + static QString serviceToString(GreaderServiceRoot::Service service); + + int batchSize() const; + void setBatchSize(int batch_size); + + private: + GreaderServiceRoot::Service m_service; + QString m_username; + QString m_password; + QString m_baseUrl; + int m_batchSize; +}; + +#endif // GREADERNETWORK_H diff --git a/src/librssguard/services/greader/greaderserviceroot.cpp b/src/librssguard/services/greader/greaderserviceroot.cpp new file mode 100755 index 000000000..825a9ac75 --- /dev/null +++ b/src/librssguard/services/greader/greaderserviceroot.cpp @@ -0,0 +1,153 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/greaderserviceroot.h" + +#include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "miscellaneous/databasequeries.h" +#include "miscellaneous/iconfactory.h" +#include "miscellaneous/mutex.h" +#include "miscellaneous/textfactory.h" +#include "services/abstract/importantnode.h" +#include "services/abstract/recyclebin.h" +#include "services/greader/greaderentrypoint.h" +#include "services/greader/greaderfeed.h" +#include "services/greader/greadernetwork.h" +#include "services/greader/gui/formeditgreaderaccount.h" + +GreaderServiceRoot::GreaderServiceRoot(RootItem* parent) + : ServiceRoot(parent), m_network(new GreaderNetwork(this)) { + setIcon(GreaderEntryPoint().icon()); +} + +GreaderServiceRoot::~GreaderServiceRoot() {} + +bool GreaderServiceRoot::isSyncable() const { + return true; +} + +bool GreaderServiceRoot::canBeEdited() const { + return true; +} + +bool GreaderServiceRoot::canBeDeleted() const { + return true; +} + +bool GreaderServiceRoot::editViaGui() { + FormEditGreaderAccount form_pointer(qApp->mainFormWidget()); + + form_pointer.addEditAccount(this); + return true; +} + +bool GreaderServiceRoot::deleteViaGui() { + return false; +} + +void GreaderServiceRoot::start(bool freshly_activated) { + Q_UNUSED(freshly_activated) + loadFromDatabase(); + loadCacheFromFile(); + + if (childCount() <= 3) { + syncIn(); + } +} + +QString GreaderServiceRoot::code() const { + return GreaderEntryPoint().code(); +} + +void GreaderServiceRoot::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.first != 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.first != QNetworkReply::NetworkError::NoError) { + addMessageStatesToCache(messages, key); + } + } + }*/ +} + +void GreaderServiceRoot::updateTitle() { + setTitle(QString("%1 (%2)").arg(m_network->username(), + m_network->serviceToString(m_network->service()))); +} + +void GreaderServiceRoot::saveAccountDataToDatabase(bool creating_new) { + QSqlDatabase database = qApp->database()->connection(metaObject()->className()); + + if (!creating_new) { + if (DatabaseQueries::overwriteGreaderAccount(database, m_network->username(), + m_network->password(), m_network->baseUrl(), + m_network->batchSize(), accountId())) { + updateTitle(); + itemChanged(QList() << this); + } + } + else { + if (DatabaseQueries::createGreaderAccount(database, accountId(), m_network->username(), + m_network->password(), m_network->service(), + m_network->baseUrl(), m_network->batchSize())) { + updateTitle(); + } + } +} + +RootItem* GreaderServiceRoot::obtainNewTreeForSyncIn() const { + return nullptr; + + /*OwnCloudGetFeedsCategoriesResponse feed_cats_response = m_network->feedsCategories(networkProxy()); + + if (feed_cats_response.networkError() == QNetworkReply::NetworkError::NoError) { + return feed_cats_response.feedsCategories(true); + } + else { + return nullptr; + }*/ +} + +void GreaderServiceRoot::loadFromDatabase() { + QSqlDatabase database = qApp->database()->connection(metaObject()->className()); + Assignment categories = DatabaseQueries::getCategories(database, accountId()); + Assignment feeds = DatabaseQueries::getFeeds(database, qApp->feedReader()->messageFilters(), accountId()); + auto labels = DatabaseQueries::getLabels(database, accountId()); + + performInitialAssembly(categories, feeds, labels); +} diff --git a/src/librssguard/services/greader/greaderserviceroot.h b/src/librssguard/services/greader/greaderserviceroot.h new file mode 100755 index 000000000..8dff72123 --- /dev/null +++ b/src/librssguard/services/greader/greaderserviceroot.h @@ -0,0 +1,61 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GREADERSERVICEROOT_H +#define GREADERSERVICEROOT_H + +#include "services/abstract/cacheforserviceroot.h" +#include "services/abstract/serviceroot.h" + +#include + +class GreaderNetwork; + +class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot { + Q_OBJECT + + public: + enum class Service { + FreshRss = 1, + TheOldReader = 2, + Bazqux = 4 + }; + + explicit GreaderServiceRoot(RootItem* parent = nullptr); + virtual ~GreaderServiceRoot(); + + virtual bool isSyncable() const; + virtual bool canBeEdited() const; + virtual bool canBeDeleted() const; + virtual bool editViaGui(); + virtual bool deleteViaGui(); + virtual void start(bool freshly_activated); + virtual QString code() const; + virtual void saveAllCachedData(bool ignore_errors); + + void setNetwork(GreaderNetwork* network); + GreaderNetwork* network() const; + + void updateTitle(); + void saveAccountDataToDatabase(bool creating_new); + + protected: + virtual RootItem* obtainNewTreeForSyncIn() const; + + private: + void loadFromDatabase(); + + private: + GreaderNetwork* m_network; +}; + +Q_DECLARE_METATYPE(GreaderServiceRoot::Service) + +inline void GreaderServiceRoot::setNetwork(GreaderNetwork* network) { + m_network = network; +} + +inline GreaderNetwork* GreaderServiceRoot::network() const { + return m_network; +} + +#endif // GREADERSERVICEROOT_H diff --git a/src/librssguard/services/greader/gui/formeditgreaderaccount.cpp b/src/librssguard/services/greader/gui/formeditgreaderaccount.cpp new file mode 100755 index 000000000..ac83ff9bd --- /dev/null +++ b/src/librssguard/services/greader/gui/formeditgreaderaccount.cpp @@ -0,0 +1,55 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/gui/formeditgreaderaccount.h" + +#include "gui/guiutilities.h" +#include "miscellaneous/iconfactory.h" +#include "network-web/networkfactory.h" +#include "services/greader/definitions.h" +#include "services/greader/greadernetwork.h" +#include "services/greader/greaderserviceroot.h" +#include "services/greader/gui/greaderaccountdetails.h" + +FormEditGreaderAccount::FormEditGreaderAccount(QWidget* parent) + : FormAccountDetails(qApp->icons()->miscIcon(QSL("google")), parent), m_details(new GreaderAccountDetails(this)) { + insertCustomTab(m_details, tr("Server setup"), 0); + activateTab(0); + + connect(m_details->m_ui.m_btnTestSetup, &QPushButton::clicked, this, &FormEditGreaderAccount::performTest); + + m_details->m_ui.m_txtUrl->setFocus(); +} + +void FormEditGreaderAccount::apply() { + bool editing_account = !applyInternal(); + + account()->network()->setBaseUrl(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()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value()); + account()->network()->setService(m_details->service()); + + account()->saveAccountDataToDatabase(!editing_account); + accept(); + + if (editing_account) { + account()->completelyRemoveAllData(); + account()->syncIn(); + } +} + +void FormEditGreaderAccount::setEditableAccount(ServiceRoot* editable_account) { + FormAccountDetails::setEditableAccount(editable_account); + + GreaderServiceRoot* existing_root = account(); + + m_details->setService(existing_root->network()->service()); + 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()->baseUrl()); + m_details->m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize()); +} + +void FormEditGreaderAccount::performTest() { + m_details->performTest(m_proxyDetails->proxy()); +} diff --git a/src/librssguard/services/greader/gui/formeditgreaderaccount.h b/src/librssguard/services/greader/gui/formeditgreaderaccount.h new file mode 100755 index 000000000..2a267d21f --- /dev/null +++ b/src/librssguard/services/greader/gui/formeditgreaderaccount.h @@ -0,0 +1,30 @@ +// For license of this file, see /LICENSE.md. + +#ifndef FORMEDITGREADERACCOUNT_H +#define FORMEDITGREADERACCOUNT_H + +#include "services/abstract/gui/formaccountdetails.h" + +class GreaderAccountDetails; +class GreaderServiceRoot; + +class FormEditGreaderAccount : public FormAccountDetails { + Q_OBJECT + + public: + explicit FormEditGreaderAccount(QWidget* parent = nullptr); + + protected slots: + virtual void apply(); + + protected: + virtual void setEditableAccount(ServiceRoot* editable_account); + + private slots: + void performTest(); + + private: + GreaderAccountDetails* m_details; +}; + +#endif // FORMEDITGREADERACCOUNT_H diff --git a/src/librssguard/services/greader/gui/greaderaccountdetails.cpp b/src/librssguard/services/greader/gui/greaderaccountdetails.cpp new file mode 100755 index 000000000..ba91a861e --- /dev/null +++ b/src/librssguard/services/greader/gui/greaderaccountdetails.cpp @@ -0,0 +1,125 @@ +// For license of this file, see /LICENSE.md. + +#include "services/greader/gui/greaderaccountdetails.h" + +#include "definitions/definitions.h" +#include "gui/guiutilities.h" +#include "miscellaneous/systemfactory.h" +#include "services/greader/definitions.h" +#include "services/greader/greadernetwork.h" + +GreaderAccountDetails::GreaderAccountDetails(QWidget* parent) : QWidget(parent) { + m_ui.setupUi(this); + + for (auto serv : { GreaderServiceRoot::Service::FreshRss, + GreaderServiceRoot::Service::Bazqux, + GreaderServiceRoot::Service::TheOldReader }) { + m_ui.m_cmbService->addItem(GreaderNetwork::serviceToString(serv), + QVariant::fromValue(serv)); + } + + m_ui.m_lblTestResult->label()->setWordWrap(true); + m_ui.m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your Nextcloud account")); + 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.")); + m_ui.m_lblLimitMessages->setText( + tr("Limiting number of downloaded messages per feed makes updating of feeds faster but if your feed contains " + "bigger number of messages than specified limit, then some messages might not be downloaded during feed update.")); + + 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("messages")); + } + }); + + GuiUtilities::setLabelAsNotice(*m_ui.m_lblLimitMessages, true); + + connect(m_ui.m_checkShowPassword, &QCheckBox::toggled, this, &GreaderAccountDetails::displayPassword); + connect(m_ui.m_txtPassword->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::onPasswordChanged); + connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::onUsernameChanged); + connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::onUrlChanged); + + setTabOrder(m_ui.m_cmbService, m_ui.m_txtUrl->lineEdit()); + setTabOrder(m_ui.m_txtUrl->lineEdit(), m_ui.m_spinLimitMessages); + setTabOrder(m_ui.m_spinLimitMessages, 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_checkShowPassword); + setTabOrder(m_ui.m_checkShowPassword, m_ui.m_btnTestSetup); + + onPasswordChanged(); + onUsernameChanged(); + onUrlChanged(); + displayPassword(false); +} + +GreaderServiceRoot::Service GreaderAccountDetails::service() const { + return m_ui.m_cmbService->currentData().value(); +} + +void GreaderAccountDetails::setService(GreaderServiceRoot::Service service) { + m_ui.m_cmbService->setCurrentIndex(m_ui.m_cmbService->findData(QVariant::fromValue(service))); +} + +void GreaderAccountDetails::displayPassword(bool display) { + m_ui.m_txtPassword->lineEdit()->setEchoMode(display ? QLineEdit::Normal : QLineEdit::Password); +} + +void GreaderAccountDetails::performTest(const QNetworkProxy& custom_proxy) { + GreaderNetwork factory; + + factory.setUsername(m_ui.m_txtUsername->lineEdit()->text()); + factory.setPassword(m_ui.m_txtPassword->lineEdit()->text()); + factory.setBaseUrl(m_ui.m_txtUrl->lineEdit()->text()); + + NetworkResult result = factory.status(custom_proxy); + + if (result.first != QNetworkReply::NetworkError::NoError) { + m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, + tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(result.first)), + tr("Network error, have you entered correct Nextcloud 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 GreaderAccountDetails::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 GreaderAccountDetails::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 GreaderAccountDetails::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/greader/gui/greaderaccountdetails.h b/src/librssguard/services/greader/gui/greaderaccountdetails.h new file mode 100755 index 000000000..bc2450769 --- /dev/null +++ b/src/librssguard/services/greader/gui/greaderaccountdetails.h @@ -0,0 +1,36 @@ +// For license of this file, see /LICENSE.md. + +#ifndef GREADERACCOUNTDETAILS_H +#define GREADERACCOUNTDETAILS_H + +#include + +#include "ui_greaderaccountdetails.h" + +#include "services/greader/greaderserviceroot.h" + +#include + +class GreaderAccountDetails : public QWidget { + Q_OBJECT + + friend class FormEditGreaderAccount; + + public: + explicit GreaderAccountDetails(QWidget* parent = nullptr); + + GreaderServiceRoot::Service service() const; + void setService(GreaderServiceRoot::Service service); + + private slots: + void displayPassword(bool display); + void performTest(const QNetworkProxy& custom_proxy); + void onUsernameChanged(); + void onPasswordChanged(); + void onUrlChanged(); + + private: + Ui::GreaderAccountDetails m_ui; +}; + +#endif // GREADERACCOUNTDETAILS_H diff --git a/src/librssguard/services/greader/gui/greaderaccountdetails.ui b/src/librssguard/services/greader/gui/greaderaccountdetails.ui new file mode 100755 index 000000000..f575497fd --- /dev/null +++ b/src/librssguard/services/greader/gui/greaderaccountdetails.ui @@ -0,0 +1,188 @@ + + + GreaderAccountDetails + + + + 0 + 0 + 430 + 390 + + + + + + + Service + + + + + + + + + + URL + + + m_txtUrl + + + + + + + + + + + + Only download newest X messages per feed + + + m_spinLimitMessages + + + + + + + = unlimited + + + -1 + + + 1000 + + + -1 + + + + + + + + + + + + true + + + + + + + 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 + + + + + + + + + + + + + Show password + + + + + + + + + + + + &Test setup + + + + + + + + 0 + 0 + + + + Qt::RightToLeft + + + + + + + + + Qt::Vertical + + + + 409 + 60 + + + + + + + + + LineEditWithStatus + QWidget +
lineeditwithstatus.h
+ 1 +
+ + LabelWithStatus + QWidget +
labelwithstatus.h
+ 1 +
+
+ + m_spinLimitMessages + m_checkShowPassword + m_btnTestSetup + + + +