diff --git a/resources/desktop/com.github.rssguard.appdata.xml b/resources/desktop/com.github.rssguard.appdata.xml index 3de105cef..f0e281060 100644 --- a/resources/desktop/com.github.rssguard.appdata.xml +++ b/resources/desktop/com.github.rssguard.appdata.xml @@ -26,7 +26,7 @@ https://github.com/sponsors/martinrotter - + none diff --git a/src/librssguard/gui/dialogs/formupdate.cpp b/src/librssguard/gui/dialogs/formupdate.cpp index e8a4ea214..b9ac6ad79 100644 --- a/src/librssguard/gui/dialogs/formupdate.cpp +++ b/src/librssguard/gui/dialogs/formupdate.cpp @@ -170,8 +170,12 @@ void FormUpdate::loadAvailableFiles() { m_ui.m_tabInfo->setCurrentIndex(1); } -void FormUpdate::updateCompleted(const QUrl& url, QNetworkReply::NetworkError status, const QByteArray& contents) { +void FormUpdate::updateCompleted(const QUrl& url, + QNetworkReply::NetworkError status, + int http_code, + const QByteArray& contents) { Q_UNUSED(url) + Q_UNUSED(http_code) qDebugNN << LOGSEC_GUI << "Download of application update file was completed with code" << QUOTE_W_SPACE_DOT(status); diff --git a/src/librssguard/gui/dialogs/formupdate.h b/src/librssguard/gui/dialogs/formupdate.h index 8c64311a1..aacf6511f 100644 --- a/src/librssguard/gui/dialogs/formupdate.h +++ b/src/librssguard/gui/dialogs/formupdate.h @@ -14,10 +14,9 @@ #include class RSSGUARD_DLLSPEC FormUpdate : public QDialog { - Q_OBJECT + Q_OBJECT public: - // Constructors and destructors. explicit FormUpdate(QWidget* parent); @@ -32,7 +31,10 @@ class RSSGUARD_DLLSPEC FormUpdate : public QDialog { void startUpdate(); void updateProgress(qint64 bytes_received, qint64 bytes_total); - void updateCompleted(const QUrl &url, QNetworkReply::NetworkError status, const QByteArray& contents); + void updateCompleted(const QUrl& url, + QNetworkReply::NetworkError status, + int http_code, + const QByteArray& contents); void saveUpdateFile(const QByteArray& file_contents); private: diff --git a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp index 030d08e11..3a82ecd30 100644 --- a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp +++ b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp @@ -548,7 +548,12 @@ void TextBrowserViewer::downloadNextNeededResource() { } } -void TextBrowserViewer::resourceDownloaded(const QUrl& url, QNetworkReply::NetworkError status, QByteArray contents) { +void TextBrowserViewer::resourceDownloaded(const QUrl& url, + QNetworkReply::NetworkError status, + int http_code, + QByteArray contents) { + Q_UNUSED(http_code) + if (status == QNetworkReply::NetworkError::NoError) { m_loadedResources.insert(url, contents); } diff --git a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h index 84a62b7b7..5e7f9cdd2 100644 --- a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h +++ b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h @@ -86,7 +86,10 @@ class TextBrowserViewer : public QTextBrowser, public WebViewer { private slots: void reloadHtmlDelayed(); void downloadNextNeededResource(); - void resourceDownloaded(const QUrl& url, QNetworkReply::NetworkError status, QByteArray contents = QByteArray()); + void resourceDownloaded(const QUrl& url, + QNetworkReply::NetworkError status, + int http_code, + QByteArray contents = QByteArray()); private: bool m_resourcesEnabled; diff --git a/src/librssguard/network-web/downloader.cpp b/src/librssguard/network-web/downloader.cpp index b64924efd..0aa5a310d 100644 --- a/src/librssguard/network-web/downloader.cpp +++ b/src/librssguard/network-web/downloader.cpp @@ -17,8 +17,8 @@ Downloader::Downloader(QObject* parent) : QObject(parent), m_activeReply(nullptr), m_downloadManager(new SilentNetworkAccessManager(this)), m_timer(new QTimer(this)), m_inputData(QByteArray()), m_inputMultipartData(nullptr), m_targetProtected(false), - m_targetUsername(QString()), m_targetPassword(QString()), m_lastOutputData(QByteArray()), - m_lastOutputError(QNetworkReply::NoError) { + m_targetUsername(QString()), m_targetPassword(QString()), m_lastOutputData({}), + m_lastOutputError(QNetworkReply::NetworkError::NoError), m_lastHttpStatusCode(0) { m_timer->setInterval(DOWNLOAD_TIMEOUT); m_timer->setSingleShot(true); @@ -212,8 +212,9 @@ void Downloader::finished() { m_lastCookies = {}; } - m_lastContentType = reply->header(QNetworkRequest::ContentTypeHeader); + m_lastContentType = reply->header(QNetworkRequest::KnownHeaders::ContentTypeHeader); m_lastOutputError = reply->error(); + m_lastHttpStatusCode = reply->attribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute).toInt(); // original_url = m_activeReply->property("original_url").toUrl(); @@ -224,7 +225,7 @@ void Downloader::finished() { m_inputMultipartData->deleteLater(); } - emit completed(original_url, m_lastOutputError, m_lastOutputData); + emit completed(original_url, m_lastOutputError, m_lastHttpStatusCode, m_lastOutputData); } } @@ -335,6 +336,10 @@ void Downloader::runGetRequest(const QNetworkRequest& request) { connect(m_activeReply, &QNetworkReply::finished, this, &Downloader::finished); } +int Downloader::lastHttpStatusCode() const { + return m_lastHttpStatusCode; +} + QList Downloader::lastCookies() const { return m_lastCookies; } diff --git a/src/librssguard/network-web/downloader.h b/src/librssguard/network-web/downloader.h index 05890c14e..b48a60315 100644 --- a/src/librssguard/network-web/downloader.h +++ b/src/librssguard/network-web/downloader.h @@ -29,6 +29,7 @@ class Downloader : public QObject { QList lastOutputMultipartData() const; QVariant lastContentType() const; QList lastCookies() const; + int lastHttpStatusCode() const; void setProxy(const QNetworkProxy& proxy); @@ -68,9 +69,8 @@ class Downloader : public QObject { const QString& password = QString()); signals: - // Emitted when new progress is known. void progress(qint64 bytes_received, qint64 bytes_total); - void completed(const QUrl& url, QNetworkReply::NetworkError status, QByteArray contents = QByteArray()); + void completed(const QUrl& url, QNetworkReply::NetworkError status, int http_code, QByteArray contents = {}); private slots: @@ -111,8 +111,8 @@ class Downloader : public QObject { // Response data. QByteArray m_lastOutputData; QList m_lastOutputMultipartData; - QNetworkReply::NetworkError m_lastOutputError; + int m_lastHttpStatusCode; QVariant m_lastContentType; QList m_lastCookies; }; diff --git a/src/librssguard/network-web/googlesuggest.cpp b/src/librssguard/network-web/googlesuggest.cpp index a8f1c9196..2e9e5ada3 100644 --- a/src/librssguard/network-web/googlesuggest.cpp +++ b/src/librssguard/network-web/googlesuggest.cpp @@ -156,8 +156,12 @@ void GoogleSuggest::autoSuggest() { m_downloader->downloadFile(url); } -void GoogleSuggest::handleNetworkData(const QUrl& url, QNetworkReply::NetworkError status, const QByteArray& contents) { +void GoogleSuggest::handleNetworkData(const QUrl& url, + QNetworkReply::NetworkError status, + int http_code, + const QByteArray& contents) { Q_UNUSED(url) + Q_UNUSED(http_code) if (status == QNetworkReply::NetworkError::NoError) { QStringList choices; diff --git a/src/librssguard/network-web/googlesuggest.h b/src/librssguard/network-web/googlesuggest.h index 24b6fef6c..59717e3cb 100644 --- a/src/librssguard/network-web/googlesuggest.h +++ b/src/librssguard/network-web/googlesuggest.h @@ -54,7 +54,10 @@ class GoogleSuggest : public QObject { void doneCompletion(); void preventSuggest(); void autoSuggest(); - void handleNetworkData(const QUrl& url, QNetworkReply::NetworkError status, const QByteArray& contents); + void handleNetworkData(const QUrl& url, + QNetworkReply::NetworkError status, + int http_code, + const QByteArray& contents); private: LocationLineEdit* editor; diff --git a/src/librssguard/network-web/networkfactory.cpp b/src/librssguard/network-web/networkfactory.cpp index 36297631a..445584b17 100644 --- a/src/librssguard/network-web/networkfactory.cpp +++ b/src/librssguard/network-web/networkfactory.cpp @@ -270,6 +270,7 @@ NetworkResult NetworkFactory::performNetworkOperation(const QString& url, result.m_networkError = downloader.lastOutputError(); result.m_contentType = downloader.lastContentType().toString(); result.m_cookies = downloader.lastCookies(); + result.m_httpCode = downloader.lastHttpStatusCode(); return result; } @@ -309,12 +310,16 @@ NetworkResult NetworkFactory::performNetworkOperation(const QString& url, result.m_networkError = downloader.lastOutputError(); result.m_contentType = downloader.lastContentType().toString(); result.m_cookies = downloader.lastCookies(); + result.m_httpCode = downloader.lastHttpStatusCode(); return result; } NetworkResult::NetworkResult() - : m_networkError(QNetworkReply::NetworkError::NoError), m_contentType(QString()), m_cookies({}) {} + : m_networkError(QNetworkReply::NetworkError::NoError), m_httpCode(0), m_contentType(QString()), m_cookies({}) {} -NetworkResult::NetworkResult(QNetworkReply::NetworkError err, const QString& ct, const QList& cook) - : m_networkError(err), m_contentType(ct), m_cookies(cook) {} +NetworkResult::NetworkResult(QNetworkReply::NetworkError err, + int http_code, + const QString& ct, + const QList& cook) + : m_networkError(err), m_httpCode(http_code), m_contentType(ct), m_cookies(cook) {} diff --git a/src/librssguard/network-web/networkfactory.h b/src/librssguard/network-web/networkfactory.h index 458e3277e..0723669e9 100644 --- a/src/librssguard/network-web/networkfactory.h +++ b/src/librssguard/network-web/networkfactory.h @@ -14,18 +14,22 @@ #include struct NetworkResult { - QNetworkReply::NetworkError m_networkError; - QString m_contentType; - QList m_cookies; + QNetworkReply::NetworkError m_networkError; + int m_httpCode; + QString m_contentType; + QList m_cookies; - explicit NetworkResult(); - explicit NetworkResult(QNetworkReply::NetworkError err, const QString& ct, const QList& cook); + explicit NetworkResult(); + explicit NetworkResult(QNetworkReply::NetworkError err, + int http_code, + const QString& ct, + const QList& cook); }; class Downloader; class NetworkFactory { - Q_DECLARE_TR_FUNCTIONS(NetworkFactory) + Q_DECLARE_TR_FUNCTIONS(NetworkFactory) private: explicit NetworkFactory() = default; @@ -44,25 +48,32 @@ class NetworkFactory { int timeout, QIcon& output, const QList>& additional_headers, - const QNetworkProxy& custom_proxy = QNetworkProxy::ProxyType::DefaultProxy); - static NetworkResult performNetworkOperation(const QString& url, int timeout, + const QNetworkProxy& custom_proxy = + QNetworkProxy::ProxyType::DefaultProxy); + static NetworkResult performNetworkOperation(const QString& url, + int timeout, const QByteArray& input_data, QByteArray& output, QNetworkAccessManager::Operation operation, - const QList>& additional_headers = QList>(), + const QList>& additional_headers = + QList>(), bool protected_contents = false, const QString& username = QString(), const QString& password = QString(), - const QNetworkProxy& custom_proxy = QNetworkProxy::ProxyType::DefaultProxy); - static NetworkResult performNetworkOperation(const QString& url, int timeout, + const QNetworkProxy& custom_proxy = + QNetworkProxy::ProxyType::DefaultProxy); + static NetworkResult performNetworkOperation(const QString& url, + int timeout, QHttpMultiPart* input_data, QList& output, QNetworkAccessManager::Operation operation, - const QList>& additional_headers = QList>(), + const QList>& additional_headers = + QList>(), bool protected_contents = false, const QString& username = QString(), const QString& password = QString(), - const QNetworkProxy& custom_proxy = QNetworkProxy::ProxyType::DefaultProxy); + const QNetworkProxy& custom_proxy = + QNetworkProxy::ProxyType::DefaultProxy); }; #endif // NETWORKFACTORY_H diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index 9f5946cee..9be752c5b 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -442,11 +442,11 @@ void ServiceRoot::syncIn() { setIcon(qApp->icons()->fromTheme(QSL("view-refresh"))); itemChanged({this}); - qDebugNN << LOGSEC_CORE << "Starting sync-in process."; + try { + qDebugNN << LOGSEC_CORE << "Starting sync-in process."; - RootItem* new_tree = obtainNewTreeForSyncIn(); + RootItem* new_tree = obtainNewTreeForSyncIn(); - if (new_tree != nullptr) { qDebugNN << LOGSEC_CORE << "New feed tree for sync-in obtained."; auto feed_custom_data = storeCustomFeedsData(); @@ -498,8 +498,15 @@ void ServiceRoot::syncIn() { updateCounts(true); requestReloadMessageList(true); } - else { - qCriticalNN << LOGSEC_CORE << "New feed tree for sync-in NOT obtained."; + catch (const ApplicationException& ex) { + qCriticalNN << LOGSEC_CORE << "New feed tree for sync-in NOT obtained:" << QUOTE_W_SPACE_DOT(ex.message()); + + qApp->showGuiMessage(Notification::Event::GeneralEvent, + GuiMessage(tr("Error when fetching list of feeds"), + tr("Feeds & categories for account '%1' were not fetched, error: %2") + .arg(title(), ex.message()), + QSystemTrayIcon::MessageIcon::Critical), + GuiMessageDestination(true, true)); } setIcon(original_icon); diff --git a/src/librssguard/services/feedly/feedlynetwork.cpp b/src/librssguard/services/feedly/feedlynetwork.cpp index b4fd78d6f..e04549c99 100644 --- a/src/librssguard/services/feedly/feedlynetwork.cpp +++ b/src/librssguard/services/feedly/feedlynetwork.cpp @@ -2,7 +2,6 @@ #include "services/feedly/feedlynetwork.h" -#include "3rd-party/boolinq/boolinq.h" #include "3rd-party/boolinq/boolinq.h" #include "database/databasequeries.h" #include "exceptions/networkexception.h" @@ -26,19 +25,18 @@ FeedlyNetwork::FeedlyNetwork(QObject* parent) : QObject(parent), m_service(nullptr), #if defined(FEEDLY_OFFICIAL_SUPPORT) - m_oauth(new OAuth2Service(QSL(FEEDLY_API_URL_BASE) + QSL(FEEDLY_API_URL_AUTH), - QSL(FEEDLY_API_URL_BASE) + QSL(FEEDLY_API_URL_TOKEN), - TextFactory::decrypt(QSL(FEEDLY_CLIENT_ID), OAUTH_DECRYPTION_KEY), - TextFactory::decrypt(QSL(FEEDLY_CLIENT_SECRET), OAUTH_DECRYPTION_KEY), - QSL(FEEDLY_API_SCOPE), this)), + m_oauth(new OAuth2Service(QSL(FEEDLY_API_URL_BASE) + QSL(FEEDLY_API_URL_AUTH), + QSL(FEEDLY_API_URL_BASE) + QSL(FEEDLY_API_URL_TOKEN), + TextFactory::decrypt(QSL(FEEDLY_CLIENT_ID), OAUTH_DECRYPTION_KEY), + TextFactory::decrypt(QSL(FEEDLY_CLIENT_SECRET), OAUTH_DECRYPTION_KEY), + QSL(FEEDLY_API_SCOPE), + this)), #endif - m_username(QString()), - m_developerAccessToken(QString()), m_batchSize(FEEDLY_DEFAULT_BATCH_SIZE), m_downloadOnlyUnreadMessages(false), - m_intelligentSynchronization(true) { + m_username(QString()), m_developerAccessToken(QString()), m_batchSize(FEEDLY_DEFAULT_BATCH_SIZE), + m_downloadOnlyUnreadMessages(false), m_intelligentSynchronization(true) { #if defined(FEEDLY_OFFICIAL_SUPPORT) - m_oauth->setRedirectUrl(QSL(OAUTH_REDIRECT_URI) + QL1C(':') + QString::number(FEEDLY_API_REDIRECT_URI_PORT), - true); + m_oauth->setRedirectUrl(QSL(OAUTH_REDIRECT_URI) + QL1C(':') + QString::number(FEEDLY_API_REDIRECT_URI_PORT), true); connect(m_oauth, &OAuth2Service::tokensRetrieveError, this, &FeedlyNetwork::onTokensError); connect(m_oauth, &OAuth2Service::authFailed, this, &FeedlyNetwork::onAuthFailed); @@ -118,8 +116,7 @@ void FeedlyNetwork::untagEntries(const QString& tag_id, const QStringList& msg_c throw NetworkException(QNetworkReply::NetworkError::AuthenticationRequiredError); } - QString target_url = fullUrl(Service::TagEntries) + - QSL("/%1/").arg(QString(QUrl::toPercentEncoding(tag_id))); + QString target_url = fullUrl(Service::TagEntries) + QSL("/%1/").arg(QString(QUrl::toPercentEncoding(tag_id))); int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray output; int i = 0; @@ -129,16 +126,18 @@ void FeedlyNetwork::untagEntries(const QString& tag_id, const QStringList& msg_c i += FEEDLY_UNTAG_BATCH_SIZE; - auto ids = boolinq::from(msg_batch).select([](const QString& msg_id) { - return QString(QUrl::toPercentEncoding(msg_id)); - }).toStdList(); + auto ids = boolinq::from(msg_batch) + .select([](const QString& msg_id) { + return QString(QUrl::toPercentEncoding(msg_id)); + }) + .toStdList(); QString final_url = target_url + FROM_STD_LIST(QStringList, ids).join(','); auto result = NetworkFactory::performNetworkOperation(final_url, timeout, {}, output, QNetworkAccessManager::Operation::DeleteOperation, - { bearerHeader(bear) }, + {bearerHeader(bear)}, false, {}, {}, @@ -172,17 +171,17 @@ void FeedlyNetwork::tagEntries(const QString& tag_id, const QStringList& msg_cus input[QSL("entryIds")] = QJsonArray::fromStringList(msg_custom_ids); input_data = QJsonDocument(input).toJson(QJsonDocument::JsonFormat::Compact); - auto result = NetworkFactory::performNetworkOperation(target_url, - timeout, - input_data, - output, - QNetworkAccessManager::Operation::PutOperation, - { bearerHeader(bear), - { HTTP_HEADERS_CONTENT_TYPE, "application/json" } }, - false, - {}, - {}, - m_service->networkProxy()); + auto result = + NetworkFactory::performNetworkOperation(target_url, + timeout, + input_data, + output, + QNetworkAccessManager::Operation::PutOperation, + {bearerHeader(bear), {HTTP_HEADERS_CONTENT_TYPE, "application/json"}}, + false, + {}, + {}, + m_service->networkProxy()); if (result.m_networkError != QNetworkReply::NetworkError::NoError) { throw NetworkException(result.m_networkError, output); @@ -211,17 +210,17 @@ void FeedlyNetwork::markers(const QString& action, const QStringList& msg_custom input[QSL("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), - { HTTP_HEADERS_CONTENT_TYPE, "application/json" } }, - false, - {}, - {}, - m_service->networkProxy()); + auto result = + NetworkFactory::performNetworkOperation(target_url, + timeout, + input_data, + output, + QNetworkAccessManager::Operation::PostOperation, + {bearerHeader(bear), {HTTP_HEADERS_CONTENT_TYPE, "application/json"}}, + false, + {}, + {}, + m_service->networkProxy()); if (result.m_networkError != QNetworkReply::NetworkError::NoError) { throw NetworkException(result.m_networkError, output); @@ -245,21 +244,22 @@ QList FeedlyNetwork::entries(const QStringList& ids) { do { QJsonArray json; - for (int window = next_message + 1000; next_message < window && next_message < ids.size(); next_message++ ) { + for (int window = next_message + 1000; next_message < window && next_message < ids.size(); next_message++) { json.append(QJsonValue(ids.at(next_message))); } QByteArray output; - auto result = NetworkFactory::performNetworkOperation(target_url, - timeout, - QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), - output, - QNetworkAccessManager::Operation::PostOperation, - { bearerHeader(bear) }, - false, - {}, - {}, - m_service->networkProxy()); + auto result = + NetworkFactory::performNetworkOperation(target_url, + timeout, + QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact), + output, + QNetworkAccessManager::Operation::PostOperation, + {bearerHeader(bear)}, + false, + {}, + {}, + m_service->networkProxy()); if (result.m_networkError != QNetworkReply::NetworkError::NoError) { throw NetworkException(result.m_networkError, output); @@ -311,7 +311,7 @@ QList FeedlyNetwork::streamContents(const QString& stream_id) { {}, output, QNetworkAccessManager::Operation::GetOperation, - { bearerHeader(bear) }, + {bearerHeader(bear)}, false, {}, {}, @@ -323,8 +323,7 @@ QList FeedlyNetwork::streamContents(const QString& stream_id) { messages += decodeStreamContents(output, true, continuation); } - while (!continuation.isEmpty() && - (m_batchSize <= 0 || messages.size() < m_batchSize) && + while (!continuation.isEmpty() && (m_batchSize <= 0 || messages.size() < m_batchSize) && messages.size() <= FEEDLY_MAX_TOTAL_SIZE); return messages; @@ -369,7 +368,7 @@ QStringList FeedlyNetwork::streamIds(const QString& stream_id, bool unread_only, {}, output, QNetworkAccessManager::Operation::GetOperation, - { bearerHeader(bear) }, + {bearerHeader(bear)}, false, {}, {}, @@ -399,7 +398,9 @@ QStringList FeedlyNetwork::decodeStreamIds(const QByteArray& stream_ids, QString return messages; } -QList FeedlyNetwork::decodeStreamContents(const QByteArray& stream_contents, bool nested_items, QString& continuation) const { +QList FeedlyNetwork::decodeStreamContents(const QByteArray& stream_contents, + bool nested_items, + QString& continuation) const { QList messages; QJsonDocument json = QJsonDocument::fromJson(stream_contents); auto active_labels = m_service->labelsNode() != nullptr ? m_service->labelsNode()->labels() : QList(); @@ -423,14 +424,25 @@ QList FeedlyNetwork::decodeStreamContents(const QByteArray& stream_cont } message.m_createdFromFeed = true; - message.m_created = QDateTime::fromMSecsSinceEpoch(entry_obj[QSL("published")].toVariant().toLongLong(), - Qt::TimeSpec::UTC); + message.m_created = + QDateTime::fromMSecsSinceEpoch(entry_obj[QSL("published")].toVariant().toLongLong(), Qt::TimeSpec::UTC); message.m_customId = entry_obj[QSL("id")].toString(); message.m_isRead = !entry_obj[QSL("unread")].toBool(); message.m_url = entry_obj[QSL("canonicalUrl")].toString(); if (message.m_url.isEmpty()) { - message.m_url = entry_obj[QSL("canonical")].toObject()[QSL("href")].toString(); + auto canonical_arr = entry_obj[QSL("canonical")].toArray(); + + if (!canonical_arr.isEmpty()) { + message.m_url = canonical_arr.first().toObject()[QSL("href")].toString(); + } + else { + auto alternate_arr = entry_obj[QSL("alternate")].toArray(); + + if (!alternate_arr.isEmpty()) { + message.m_url = alternate_arr.first().toObject()[QSL("href")].toString(); + } + } } auto enclosures = entry_obj[QSL("enclosure")].toArray(); @@ -440,8 +452,8 @@ QList FeedlyNetwork::decodeStreamContents(const QByteArray& stream_cont const QString& enc_href = enc_obj[QSL("href")].toString(); if (!boolinq::from(message.m_enclosures).any([enc_href](const Enclosure& existing_enclosure) { - return existing_enclosure.m_url == enc_href; - })) { + return existing_enclosure.m_url == enc_href; + })) { message.m_enclosures.append(Enclosure(enc_href, enc_obj[QSL("type")].toString())); } } @@ -467,9 +479,7 @@ QList FeedlyNetwork::decodeStreamContents(const QByteArray& stream_cont message.m_assignedLabels.append(label); } else { - qCriticalNN << LOGSEC_FEEDLY - << "Failed to find live Label object for tag" - << QUOTE_W_SPACE_DOT(tag_id); + qCriticalNN << LOGSEC_FEEDLY << "Failed to find live Label object for tag" << QUOTE_W_SPACE_DOT(tag_id); } } } @@ -496,7 +506,7 @@ RootItem* FeedlyNetwork::collections(bool obtain_icons) { {}, output, QNetworkAccessManager::Operation::GetOperation, - { bearerHeader(bear) }, + {bearerHeader(bear)}, false, {}, {}, @@ -509,8 +519,10 @@ RootItem* FeedlyNetwork::collections(bool obtain_icons) { return decodeCollections(output, obtain_icons, m_service->networkProxy(), timeout); } -RootItem* FeedlyNetwork::decodeCollections(const QByteArray& json, bool obtain_icons, - const QNetworkProxy& proxy, int timeout) const { +RootItem* FeedlyNetwork::decodeCollections(const QByteArray& json, + bool obtain_icons, + const QNetworkProxy& proxy, + int timeout) const { QJsonDocument doc = QJsonDocument::fromJson(json); auto* parent = new RootItem(); QList used_feeds; @@ -529,9 +541,7 @@ RootItem* FeedlyNetwork::decodeCollections(const QByteArray& json, bool obtain_i QJsonObject fee_obj = fee.toObject(); if (used_feeds.contains(fee_obj[QSL("id")].toString())) { - qWarningNN << LOGSEC_FEEDLY - << "Feed" - << QUOTE_W_SPACE(fee_obj[QSL("id")].toString()) + qWarningNN << LOGSEC_FEEDLY << "Feed" << QUOTE_W_SPACE(fee_obj[QSL("id")].toString()) << "is already decoded and cannot be placed under several categories."; continue; } @@ -545,9 +555,9 @@ RootItem* FeedlyNetwork::decodeCollections(const QByteArray& json, bool obtain_i if (obtain_icons) { QIcon icon; - auto result = NetworkFactory::downloadIcon({ { fee_obj[QSL("iconUrl")].toString(), true }, - { fee_obj[QSL("website")].toString(), false }, - { fee_obj[QSL("logo")].toString(), true } }, + auto result = NetworkFactory::downloadIcon({{fee_obj[QSL("iconUrl")].toString(), true}, + {fee_obj[QSL("website")].toString(), false}, + {fee_obj[QSL("logo")].toString(), true}}, timeout, icon, {}, @@ -592,7 +602,7 @@ QVariantHash FeedlyNetwork::profile(const QNetworkProxy& network_proxy) { {}, output, QNetworkAccessManager::Operation::GetOperation, - { bearerHeader(bear) }, + {bearerHeader(bear)}, false, {}, {}, @@ -621,7 +631,7 @@ QList FeedlyNetwork::tags() { {}, output, QNetworkAccessManager::Operation::GetOperation, - { bearerHeader(bear) }, + {bearerHeader(bear)}, false, {}, {}, @@ -639,8 +649,7 @@ QList FeedlyNetwork::tags() { const QJsonObject& tag_obj = tag.toObject(); QString name_id = tag_obj[QSL("id")].toString(); - if (name_id.endsWith(FEEDLY_API_SYSTEM_TAG_READ) || - name_id.endsWith(FEEDLY_API_SYSTEM_TAG_SAVED)) { + if (name_id.endsWith(FEEDLY_API_SYSTEM_TAG_READ) || name_id.endsWith(FEEDLY_API_SYSTEM_TAG_SAVED)) { continue; } @@ -683,32 +692,30 @@ void FeedlyNetwork::setBatchSize(int batch_size) { void FeedlyNetwork::onTokensError(const QString& error, const QString& error_description) { Q_UNUSED(error) - qApp->showGuiMessage(Notification::Event::LoginFailure, { - tr("Feedly: authentication error"), - tr("Click this to login again. Error is: '%1'").arg(error_description), - QSystemTrayIcon::MessageIcon::Critical }, - {}, { - tr("Login"), - [this]() { - m_oauth->setAccessToken(QString()); - m_oauth->setRefreshToken(QString()); + qApp->showGuiMessage(Notification::Event::LoginFailure, + {tr("Feedly: authentication error"), + tr("Click this to login again. Error is: '%1'").arg(error_description), + QSystemTrayIcon::MessageIcon::Critical}, + {}, + {tr("Login"), [this]() { + m_oauth->setAccessToken(QString()); + m_oauth->setRefreshToken(QString()); - //m_oauth->logout(false); - m_oauth->login(); - } }); + // m_oauth->logout(false); + m_oauth->login(); + }}); } void FeedlyNetwork::onAuthFailed() { - qApp->showGuiMessage(Notification::Event::LoginFailure, { - tr("Feedly: authorization denied"), - tr("Click this to login again."), - QSystemTrayIcon::MessageIcon::Critical }, - {}, { - tr("Login"), - [this]() { - //m_oauth->logout(false); - m_oauth->login(); - } }); + qApp->showGuiMessage(Notification::Event::LoginFailure, + {tr("Feedly: authorization denied"), + tr("Click this to login again."), + QSystemTrayIcon::MessageIcon::Critical}, + {}, + {tr("Login"), [this]() { + // m_oauth->logout(false); + m_oauth->login(); + }}); } void FeedlyNetwork::onTokensRetrieved(const QString& access_token, const QString& refresh_token, int expires_in) { @@ -772,7 +779,7 @@ QString FeedlyNetwork::bearer() const { } QPair FeedlyNetwork::bearerHeader(const QString& bearer) const { - return { QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer.toLocal8Bit() }; + return {QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer.toLocal8Bit()}; } void FeedlyNetwork::setIntelligentSynchronization(bool intelligent_sync) { diff --git a/src/librssguard/services/feedly/feedlyserviceroot.cpp b/src/librssguard/services/feedly/feedlyserviceroot.cpp index 1922e2316..b82a0554a 100644 --- a/src/librssguard/services/feedly/feedlyserviceroot.cpp +++ b/src/librssguard/services/feedly/feedlyserviceroot.cpp @@ -23,8 +23,7 @@ #include "network-web/oauth2service.h" #endif -FeedlyServiceRoot::FeedlyServiceRoot(RootItem* parent) - : ServiceRoot(parent), m_network(new FeedlyNetwork(this)) { +FeedlyServiceRoot::FeedlyServiceRoot(RootItem* parent) : ServiceRoot(parent), m_network(new FeedlyNetwork(this)) { setIcon(FeedlyEntryPoint().icon()); m_network->setService(this); } @@ -75,7 +74,8 @@ void FeedlyServiceRoot::setCustomDatabaseData(const QVariantHash& data) { } QList FeedlyServiceRoot::obtainNewMessages(Feed* feed, - const QHash& stated_messages, + const QHash& + stated_messages, const QHash& tagged_messages) { Q_UNUSED(tagged_messages) @@ -128,16 +128,13 @@ void FeedlyServiceRoot::saveAllCachedData(bool ignore_errors) { if (!ids.isEmpty()) { try { - network()->markers(key == RootItem::ReadStatus::Read - ? QSL(FEEDLY_MARKERS_READ) - : QSL(FEEDLY_MARKERS_UNREAD), ids); + network()->markers(key == RootItem::ReadStatus::Read ? QSL(FEEDLY_MARKERS_READ) : QSL(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()); + << "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); @@ -162,16 +159,13 @@ void FeedlyServiceRoot::saveAllCachedData(bool ignore_errors) { } try { - network()->markers(key == RootItem::Importance::Important - ? FEEDLY_MARKERS_IMPORTANT - : FEEDLY_MARKERS_UNIMPORTANT, ids); + 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()); + 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); @@ -194,10 +188,8 @@ void FeedlyServiceRoot::saveAllCachedData(bool ignore_errors) { } catch (const NetworkException& net_ex) { qCriticalNN << LOGSEC_FEEDLY - << "Failed to synchronize tag assignments with error:" - << QUOTE_W_SPACE(net_ex.message()) - << "and HTTP code" - << QUOTE_W_SPACE_DOT(net_ex.networkError()); + << "Failed to synchronize tag assignments with error:" << QUOTE_W_SPACE(net_ex.message()) + << "and HTTP code" << QUOTE_W_SPACE_DOT(net_ex.networkError()); if (!ignore_errors) { addLabelsAssignmentsToCache(messages, label_custom_id, true); @@ -220,10 +212,8 @@ void FeedlyServiceRoot::saveAllCachedData(bool ignore_errors) { } catch (const NetworkException& net_ex) { qCriticalNN << LOGSEC_FEEDLY - << "Failed to synchronize tag DEassignments with error:" - << QUOTE_W_SPACE(net_ex.message()) - << "and HTTP code" - << QUOTE_W_SPACE_DOT(net_ex.networkError()); + << "Failed to synchronize tag DEassignments with error:" << QUOTE_W_SPACE(net_ex.message()) + << "and HTTP code" << QUOTE_W_SPACE_DOT(net_ex.networkError()); if (!ignore_errors) { addLabelsAssignmentsToCache(messages, label_custom_id, false); @@ -242,22 +232,14 @@ void FeedlyServiceRoot::updateTitle() { } RootItem* FeedlyServiceRoot::obtainNewTreeForSyncIn() const { - try { - auto tree = m_network->collections(true); - auto* lblroot = new LabelsNode(tree); - auto labels = m_network->tags(); + auto tree = m_network->collections(true); + auto* lblroot = new LabelsNode(tree); + auto labels = m_network->tags(); - lblroot->setChildItems(labels); - tree->appendChild(lblroot); + lblroot->setChildItems(labels); + tree->appendChild(lblroot); - return tree; - } - catch (const ApplicationException& ex) { - qCriticalNN << LOGSEC_FEEDLY - << "Failed to obtain new sync-in tree:" - << QUOTE_W_SPACE_DOT(ex.message()); - return nullptr; - } + return tree; } bool FeedlyServiceRoot::wantsBaggedIdsOfExistingMessages() const { diff --git a/src/librssguard/services/greader/greadernetwork.cpp b/src/librssguard/services/greader/greadernetwork.cpp index 4228fde6d..45721aba9 100644 --- a/src/librssguard/services/greader/greadernetwork.cpp +++ b/src/librssguard/services/greader/greadernetwork.cpp @@ -602,7 +602,7 @@ RootItem* GreaderNetwork::categoriesFeedsLabelsTree(bool obtain_icons, const QNe if (!ensureLogin(proxy)) { qCriticalNN << LOGSEC_GREADER << "Cannot get feed tree, not logged-in."; - return nullptr; + throw ApplicationException(tr("you are not logged-in, maybe wrong credentials")); } QByteArray output_labels; @@ -618,7 +618,11 @@ RootItem* GreaderNetwork::categoriesFeedsLabelsTree(bool obtain_icons, const QNe proxy); if (result_labels.m_networkError != QNetworkReply::NetworkError::NoError) { - return nullptr; + qCriticalNN << LOGSEC_GREADER + << "Cannot get labels tree, network error:" << QUOTE_W_SPACE_DOT(result_labels.m_networkError); + + throw NetworkException(result_labels.m_networkError, + tr("cannot get list of labels, HTTP code '%1'").arg(result_labels.m_httpCode)); } full_url = generateFullUrl(Operations::SubscriptionList); @@ -637,7 +641,9 @@ RootItem* GreaderNetwork::categoriesFeedsLabelsTree(bool obtain_icons, const QNe if (result_feeds.m_networkError != QNetworkReply::NetworkError::NoError) { qCriticalNN << LOGSEC_GREADER << "Cannot get feed tree, network error:" << QUOTE_W_SPACE_DOT(result_feeds.m_networkError); - return nullptr; + + throw NetworkException(result_labels.m_networkError, + tr("cannot get list of feeds, HTTP code '%1'").arg(result_feeds.m_httpCode)); } return decodeTagsSubscriptions(output_labels, output_feeds, obtain_icons, proxy); diff --git a/src/librssguard/services/owncloud/owncloudserviceroot.cpp b/src/librssguard/services/owncloud/owncloudserviceroot.cpp index 8992c1d23..3352dfdbe 100644 --- a/src/librssguard/services/owncloud/owncloudserviceroot.cpp +++ b/src/librssguard/services/owncloud/owncloudserviceroot.cpp @@ -5,6 +5,7 @@ #include "database/databasequeries.h" #include "definitions/definitions.h" #include "exceptions/feedfetchexception.h" +#include "exceptions/networkexception.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" #include "miscellaneous/mutex.h" @@ -124,7 +125,8 @@ RootItem* OwnCloudServiceRoot::obtainNewTreeForSyncIn() const { return feed_cats_response.feedsCategories(true); } else { - return nullptr; + throw NetworkException(feed_cats_response.networkError(), + tr("cannot get list of feeds, network error '%1'").arg(feed_cats_response.networkError())); } } @@ -151,7 +153,8 @@ void OwnCloudServiceRoot::setCustomDatabaseData(const QVariantHash& data) { } QList OwnCloudServiceRoot::obtainNewMessages(Feed* feed, - const QHash& stated_messages, + const QHash& + stated_messages, const QHash& tagged_messages) { Q_UNUSED(stated_messages) Q_UNUSED(tagged_messages) diff --git a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp index c4c224023..3984e69c2 100644 --- a/src/librssguard/services/tt-rss/ttrssserviceroot.cpp +++ b/src/librssguard/services/tt-rss/ttrssserviceroot.cpp @@ -5,6 +5,7 @@ #include "3rd-party/boolinq/boolinq.h" #include "database/databasequeries.h" #include "exceptions/feedfetchexception.h" +#include "exceptions/networkexception.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" #include "miscellaneous/mutex.h" @@ -26,8 +27,7 @@ #include #include -TtRssServiceRoot::TtRssServiceRoot(RootItem* parent) - : ServiceRoot(parent), m_network(new TtRssNetworkFactory()) { +TtRssServiceRoot::TtRssServiceRoot(RootItem* parent) : ServiceRoot(parent), m_network(new TtRssNetworkFactory()) { setIcon(TtRssServiceEntryPoint().icon()); } @@ -68,8 +68,7 @@ void TtRssServiceRoot::start(bool freshly_activated) { void TtRssServiceRoot::stop() { m_network->logout(networkProxy()); - qDebugNN << LOGSEC_TTRSS - << "Stopping Tiny Tiny RSS account, logging out with result" + qDebugNN << LOGSEC_TTRSS << "Stopping Tiny Tiny RSS account, logging out with result" << QUOTE_W_SPACE_DOT(m_network->lastError()); } @@ -101,15 +100,18 @@ void TtRssServiceRoot::addNewFeed(RootItem* selected_item, const QString& url) { // 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 }); + 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())); + QScopedPointer form_pointer(new FormTtRssFeedDetails(this, + selected_item, + url, + qApp->mainFormWidget())); form_pointer->addEditFeed(); qApp->feedUpdateLock()->unlock(); @@ -132,9 +134,8 @@ void TtRssServiceRoot::saveAllCachedData(bool ignore_errors) { if (!ids.isEmpty()) { auto res = network()->updateArticles(ids, UpdateArticle::OperatingField::Unread, - key == RootItem::ReadStatus::Unread - ? UpdateArticle::Mode::SetToTrue - : UpdateArticle::Mode::SetToFalse, + key == RootItem::ReadStatus::Unread ? UpdateArticle::Mode::SetToTrue + : UpdateArticle::Mode::SetToFalse, networkProxy()); if (!ignore_errors && (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError())) { @@ -155,9 +156,8 @@ void TtRssServiceRoot::saveAllCachedData(bool ignore_errors) { QStringList ids = customIDsOfMessages(messages); auto res = network()->updateArticles(ids, UpdateArticle::OperatingField::Starred, - key == RootItem::Importance::Important - ? UpdateArticle::Mode::SetToTrue - : UpdateArticle::Mode::SetToFalse, + key == RootItem::Importance::Important ? UpdateArticle::Mode::SetToTrue + : UpdateArticle::Mode::SetToFalse, networkProxy()); if (!ignore_errors && (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError())) { @@ -252,7 +252,8 @@ void TtRssServiceRoot::setCustomDatabaseData(const QVariantHash& data) { } QList TtRssServiceRoot::obtainNewMessages(Feed* feed, - const QHash& stated_messages, + const QHash& + stated_messages, const QHash& tagged_messages) { Q_UNUSED(stated_messages) Q_UNUSED(tagged_messages) @@ -263,8 +264,12 @@ QList TtRssServiceRoot::obtainNewMessages(Feed* feed, int skip = 0; do { - TtRssGetHeadlinesResponse headlines = network()->getHeadlines(feed->customNumericId(), limit, skip, - true, true, false, + TtRssGetHeadlinesResponse headlines = network()->getHeadlines(feed->customNumericId(), + limit, + skip, + true, + true, + false, network()->downloadOnlyUnreadMessages(), networkProxy()); @@ -286,12 +291,13 @@ QList TtRssServiceRoot::obtainNewMessages(Feed* feed, QString TtRssServiceRoot::additionalTooltip() const { return 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("-")); + "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 { @@ -315,8 +321,9 @@ void TtRssServiceRoot::updateTitle() { RootItem* TtRssServiceRoot::obtainNewTreeForSyncIn() const { TtRssGetFeedsCategoriesResponse feed_cats = m_network->getFeedsCategories(networkProxy()); TtRssGetLabelsResponse labels = m_network->getLabels(networkProxy()); + auto lst_error = m_network->lastError(); - if (m_network->lastError() == QNetworkReply::NoError) { + if (lst_error == QNetworkReply::NoError) { auto* tree = feed_cats.feedsCategories(m_network, true, networkProxy(), m_network->url()); auto* lblroot = new LabelsNode(tree); @@ -326,6 +333,6 @@ RootItem* TtRssServiceRoot::obtainNewTreeForSyncIn() const { return tree; } else { - return nullptr; + throw NetworkException(lst_error, tr("cannot get list of feeds, network error '%1'").arg(lst_error)); } }