From 7ea11df0ad3c69c503d0148f11d252099729a927 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 18 Feb 2021 10:19:08 +0100 Subject: [PATCH] feedly can mark messages read, unread, important, unimportant --- .../exceptions/networkexception.cpp | 5 +- src/librssguard/exceptions/networkexception.h | 2 +- src/librssguard/services/feedly/definitions.h | 6 ++ .../services/feedly/feedlynetwork.cpp | 50 +++++++++- .../services/feedly/feedlynetwork.h | 4 +- .../services/feedly/feedlyserviceroot.cpp | 94 +++++++++++++++++++ 6 files changed, 154 insertions(+), 7 deletions(-) diff --git a/src/librssguard/exceptions/networkexception.cpp b/src/librssguard/exceptions/networkexception.cpp index 414a1f5d3..2679c6e9c 100644 --- a/src/librssguard/exceptions/networkexception.cpp +++ b/src/librssguard/exceptions/networkexception.cpp @@ -4,7 +4,10 @@ #include "network-web/networkfactory.h" -NetworkException::NetworkException(QNetworkReply::NetworkError error) : ApplicationException(NetworkFactory::networkErrorText(error)) {} +NetworkException::NetworkException(QNetworkReply::NetworkError error, const QString& message) + : ApplicationException(message.simplified().isEmpty() + ? NetworkFactory::networkErrorText(error) + : message), m_networkError(error) {} QNetworkReply::NetworkError NetworkException::networkError() const { return m_networkError; diff --git a/src/librssguard/exceptions/networkexception.h b/src/librssguard/exceptions/networkexception.h index abfb09749..5b93eb438 100644 --- a/src/librssguard/exceptions/networkexception.h +++ b/src/librssguard/exceptions/networkexception.h @@ -9,7 +9,7 @@ class NetworkException : public ApplicationException { public: - explicit NetworkException(QNetworkReply::NetworkError error); + explicit NetworkException(QNetworkReply::NetworkError error, const QString& message = QString()); QNetworkReply::NetworkError networkError() const; diff --git a/src/librssguard/services/feedly/definitions.h b/src/librssguard/services/feedly/definitions.h index 5e1cd9eac..8f2d2ed17 100755 --- a/src/librssguard/services/feedly/definitions.h +++ b/src/librssguard/services/feedly/definitions.h @@ -20,11 +20,17 @@ #define FEEDLY_API_SYSTEM_TAG_READ "global.read" #define FEEDLY_API_SYSTEM_TAG_SAVED "global.saved" +#define FEEDLY_MARKERS_READ "markAsRead" +#define FEEDLY_MARKERS_UNREAD "keepUnread" +#define FEEDLY_MARKERS_IMPORTANT "markAsSaved" +#define FEEDLY_MARKERS_UNIMPORTANT "markAsUnsaved" + #define FEEDLY_API_URL_AUTH "auth/auth" #define FEEDLY_API_URL_TOKEN "auth/token" #define FEEDLY_API_URL_PROFILE "profile" #define FEEDLY_API_URL_COLLETIONS "collections" #define FEEDLY_API_URL_TAGS "tags" #define FEEDLY_API_URL_STREAM_CONTENTS "streams/contents?streamId=%1" +#define FEEDLY_API_URL_MARKERS "markers" #endif // FEEDLY_DEFINITIONS_H diff --git a/src/librssguard/services/feedly/feedlynetwork.cpp b/src/librssguard/services/feedly/feedlynetwork.cpp index d4a883cb9..626d57106 100755 --- a/src/librssguard/services/feedly/feedlynetwork.cpp +++ b/src/librssguard/services/feedly/feedlynetwork.cpp @@ -45,6 +45,45 @@ FeedlyNetwork::FeedlyNetwork(QObject* parent) #endif } +void FeedlyNetwork::markers(const QString& action, const QStringList& msg_custom_ids) { + if (msg_custom_ids.isEmpty()) { + return; + } + + QString bear = bearer(); + + if (bear.isEmpty()) { + qCriticalNN << LOGSEC_FEEDLY << "Cannot mark entries, because bearer is empty."; + throw NetworkException(QNetworkReply::NetworkError::AuthenticationRequiredError); + } + + QString target_url = fullUrl(Service::Markers); + int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); + QByteArray output; + QJsonObject input; + + input["action"] = action; + input["type"] = QSL("entries"); + input["entryIds"] = QJsonArray::fromStringList(msg_custom_ids); + + QByteArray input_data = QJsonDocument(input).toJson(QJsonDocument::JsonFormat::Compact); + auto result = NetworkFactory::performNetworkOperation(target_url, + timeout, + input_data, + output, + QNetworkAccessManager::Operation::PostOperation, + { bearerHeader(bear), + { "Content-Type", "application/json" } }, + false, + {}, + {}, + m_service->networkProxy()); + + if (result.first != QNetworkReply::NetworkError::NoError) { + throw NetworkException(result.first, output); + } +} + QList FeedlyNetwork::streamContents(const QString& stream_id) { QString bear = bearer(); @@ -91,7 +130,7 @@ QList FeedlyNetwork::streamContents(const QString& stream_id) { m_service->networkProxy()); if (result.first != QNetworkReply::NetworkError::NoError) { - throw NetworkException(result.first); + throw NetworkException(result.first, output); } messages += decodeStreamContents(output, continuation); @@ -199,7 +238,7 @@ RootItem* FeedlyNetwork::collections(bool obtain_icons) { m_service->networkProxy()); if (result.first != QNetworkReply::NetworkError::NoError) { - throw NetworkException(result.first); + throw NetworkException(result.first, output); } return decodeCollections(output, obtain_icons, m_service->networkProxy(), timeout); @@ -290,7 +329,7 @@ QVariantHash FeedlyNetwork::profile(const QNetworkProxy& network_proxy) { network_proxy); if (result.first != QNetworkReply::NetworkError::NoError) { - throw NetworkException(result.first); + throw NetworkException(result.first, output); } return QJsonDocument::fromJson(output).object().toVariantHash(); @@ -319,7 +358,7 @@ QList FeedlyNetwork::tags() { m_service->networkProxy()); if (result.first != QNetworkReply::NetworkError::NoError) { - throw NetworkException(result.first); + throw NetworkException(result.first, output); } QJsonDocument json = QJsonDocument::fromJson(output); @@ -432,6 +471,9 @@ QString FeedlyNetwork::fullUrl(FeedlyNetwork::Service service) const { case Service::StreamContents: return QSL(FEEDLY_API_URL_BASE) + FEEDLY_API_URL_STREAM_CONTENTS; + case Service::Markers: + return QSL(FEEDLY_API_URL_BASE) + FEEDLY_API_URL_MARKERS; + default: return FEEDLY_API_URL_BASE; } diff --git a/src/librssguard/services/feedly/feedlynetwork.h b/src/librssguard/services/feedly/feedlynetwork.h index 6dc544be0..a46470249 100755 --- a/src/librssguard/services/feedly/feedlynetwork.h +++ b/src/librssguard/services/feedly/feedlynetwork.h @@ -21,6 +21,7 @@ class FeedlyNetwork : public QObject { explicit FeedlyNetwork(QObject* parent = nullptr); // API operations. + void markers(const QString& action, const QStringList& msg_custom_ids); QList streamContents(const QString& stream_id); QVariantHash profile(const QNetworkProxy& network_proxy); QList tags(); @@ -56,7 +57,8 @@ class FeedlyNetwork : public QObject { Profile, Collections, Tags, - StreamContents + StreamContents, + Markers }; QString fullUrl(Service service) const; diff --git a/src/librssguard/services/feedly/feedlyserviceroot.cpp b/src/librssguard/services/feedly/feedlyserviceroot.cpp index 748944947..e9de22cbc 100755 --- a/src/librssguard/services/feedly/feedlyserviceroot.cpp +++ b/src/librssguard/services/feedly/feedlyserviceroot.cpp @@ -13,6 +13,7 @@ #include "services/abstract/importantnode.h" #include "services/abstract/labelsnode.h" #include "services/abstract/recyclebin.h" +#include "services/feedly/definitions.h" #include "services/feedly/feedlyentrypoint.h" #include "services/feedly/feedlyfeed.h" #include "services/feedly/feedlynetwork.h" @@ -74,6 +75,99 @@ QString FeedlyServiceRoot::code() const { void FeedlyServiceRoot::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()) { + try { + network()->markers(key == RootItem::ReadStatus::Read + ? FEEDLY_MARKERS_READ + : FEEDLY_MARKERS_UNREAD, ids); + } + catch (const NetworkException& net_ex) { + qCriticalNN << LOGSEC_FEEDLY + << "Failed to synchronize read/unread state with error:" + << QUOTE_W_SPACE(net_ex.message()) + << "and HTTP code" + << QUOTE_W_SPACE_DOT(net_ex.networkError()); + + if (!ignore_errors) { + 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; + + for (const Message& msg : messages) { + ids.append(msg.m_customId); + } + + try { + network()->markers(key == RootItem::Importance::Important + ? FEEDLY_MARKERS_IMPORTANT + : FEEDLY_MARKERS_UNIMPORTANT, ids); + } + catch (const NetworkException& net_ex) { + qCriticalNN << LOGSEC_FEEDLY + << "Failed to synchronize important/unimportant state with error:" + << QUOTE_W_SPACE(net_ex.message()) + << "and HTTP code" + << QUOTE_W_SPACE_DOT(net_ex.networkError()); + + if (!ignore_errors) { + 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()) { + if (network()->editLabels(label_custom_id, true, messages) != QNetworkReply::NetworkError::NoError && !ignore_errors) { + 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()) { + if (network()->editLabels(label_custom_id, false, messages) != QNetworkReply::NetworkError::NoError && !ignore_errors) { + addLabelsAssignmentsToCache(messages, label_custom_id, false); + } + } + } + */ } void FeedlyServiceRoot::updateTitle() {