1205 lines
48 KiB
C++
1205 lines
48 KiB
C++
// For license of this file, see <project-root-folder>/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 <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QPair>
|
|
#include <QVariant>
|
|
|
|
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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<QByteArray, QByteArray>> headers;
|
|
|
|
headers << QPair<QByteArray, QByteArray>(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<QPair<RootItem*, QJsonValue>> pairs;
|
|
pairs.reserve(items_to_process.size());
|
|
|
|
for (const QJsonValue& item : items_to_process) {
|
|
pairs.append(QPair<RootItem*, QJsonValue>(parent, item));
|
|
}
|
|
|
|
while (!pairs.isEmpty()) {
|
|
QPair<RootItem*, QJsonValue> 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 : qAsConst(ite)) {
|
|
pairs.append(QPair<RootItem*, QJsonValue>(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 : qAsConst(ite)) {
|
|
pairs.append(QPair<RootItem*, QJsonValue>(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<QPair<QByteArray, QByteArray>> 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<Message> TtRssGetArticleResponse::messages(ServiceRoot* root) const {
|
|
return {};
|
|
}
|
|
|
|
TtRssGetArticleResponse::~TtRssGetArticleResponse() = default;
|
|
|
|
QList<Message> TtRssGetHeadlinesResponse::messages(ServiceRoot* root) const {
|
|
QList<Message> messages;
|
|
auto active_labels = root->labelsNode() != nullptr ? root->labelsNode()->labels() : QList<Label*>();
|
|
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 : qAsConst(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 : qAsConst(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<qint64>(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 : qAsConst(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<RootItem*> TtRssGetLabelsResponse::labels() const {
|
|
QList<RootItem*> 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 : qAsConst(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 : qAsConst(json_ids)) {
|
|
msg_ids.append(QString::number(id_val.toObject()[QSL("id")].toInt()));
|
|
}
|
|
|
|
return msg_ids;
|
|
}
|