save ttrss work

This commit is contained in:
Martin Rotter 2022-09-02 08:59:09 +02:00
parent 89a77315b1
commit 8676bfc42d
8 changed files with 608 additions and 314 deletions

View file

@ -22,11 +22,10 @@
</screenshots>
<url type="homepage">https://github.com/martinrotter/rssguard</url>
<url type="bugtracker">https://github.com/martinrotter/rssguard/issues</url>
<url type="translate">https://www.transifex.com/martinrotter/rssguard</url>
<url type="donation">https://github.com/sponsors/martinrotter</url>
<content_rating type="oars-1.1" />
<releases>
<release version="4.2.3" date="2022-09-01"/>
<release version="4.2.3" date="2022-09-02"/>
</releases>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">none</content_attribute>

View file

@ -32,8 +32,12 @@ void FormEditTtRssAccount::apply() {
account<TtRssServiceRoot>()->network()->setAuthUsername(m_details->m_ui.m_txtHttpUsername->lineEdit()->text());
account<TtRssServiceRoot>()->network()->setAuthPassword(m_details->m_ui.m_txtHttpPassword->lineEdit()->text());
account<TtRssServiceRoot>()->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value());
account<TtRssServiceRoot>()->network()->setForceServerSideUpdate(m_details->m_ui.m_checkServerSideUpdate->isChecked());
account<TtRssServiceRoot>()->network()->setDownloadOnlyUnreadMessages(m_details->m_ui.m_checkDownloadOnlyUnreadMessages->isChecked());
account<TtRssServiceRoot>()->network()->setIntelligentSynchronization(m_details->m_ui.m_cbNewAlgorithm->isChecked());
account<TtRssServiceRoot>()->network()->setForceServerSideUpdate(m_details->m_ui.m_checkServerSideUpdate
->isChecked());
account<TtRssServiceRoot>()
->network()
->setDownloadOnlyUnreadMessages(m_details->m_ui.m_checkDownloadOnlyUnreadMessages->isChecked());
account<TtRssServiceRoot>()->saveAccountDataToDatabase();
accept();
@ -58,6 +62,7 @@ void FormEditTtRssAccount::loadAccountData() {
m_details->m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize());
m_details->m_ui.m_checkServerSideUpdate->setChecked(existing_root->network()->forceServerSideUpdate());
m_details->m_ui.m_checkDownloadOnlyUnreadMessages->setChecked(existing_root->network()->downloadOnlyUnreadMessages());
m_details->m_ui.m_cbNewAlgorithm->setChecked(existing_root->network()->intelligentSynchronization());
}
void FormEditTtRssAccount::performTest() {

View file

@ -11,9 +11,16 @@ TtRssAccountDetails::TtRssAccountDetails(QWidget* parent) : QWidget(parent) {
m_ui.setupUi(this);
m_ui.m_lblTestResult->label()->setWordWrap(true);
m_ui.m_lblServerSideUpdateInformation->setHelpText(tr("Leaving this option on causes that updates "
"of feeds will be probably much slower and may time-out often."),
true);
m_ui.m_lblNewAlgorithm->setHelpText(tr("If you select intelligent synchronization, then only not-yet-fetched "
"or updated articles are downloaded. Network usage is greatly reduced and "
"overall synchronization speed is greatly improved, but "
"first feed fetching could be slow anyway if your feed contains "
"huge number of articles."),
false);
m_ui.m_lblServerSideUpdateInformation
->setHelpText(tr("Leaving this option on causes that updates "
"of feeds will be probably much slower and may time-out often."),
true);
m_ui.m_txtHttpUsername->lineEdit()->setPlaceholderText(tr("HTTP authentication username"));
m_ui.m_txtHttpPassword->lineEdit()->setPlaceholderText(tr("HTTP authentication password"));
m_ui.m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your TT-RSS account"));
@ -25,7 +32,8 @@ TtRssAccountDetails::TtRssAccountDetails(QWidget* parent) : QWidget(parent) {
setTabOrder(m_ui.m_txtUrl->lineEdit(), m_ui.m_checkDownloadOnlyUnreadMessages);
setTabOrder(m_ui.m_checkDownloadOnlyUnreadMessages, m_ui.m_spinLimitMessages);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_checkServerSideUpdate);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_cbNewAlgorithm);
setTabOrder(m_ui.m_cbNewAlgorithm, m_ui.m_checkServerSideUpdate);
setTabOrder(m_ui.m_checkServerSideUpdate, m_ui.m_txtUsername->lineEdit());
setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtPassword->lineEdit());
setTabOrder(m_ui.m_txtPassword->lineEdit(), m_ui.m_gbHttpAuthentication);
@ -38,8 +46,14 @@ TtRssAccountDetails::TtRssAccountDetails(QWidget* parent) : QWidget(parent) {
connect(m_ui.m_txtPassword->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onPasswordChanged);
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onUsernameChanged);
connect(m_ui.m_txtHttpPassword->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onHttpPasswordChanged);
connect(m_ui.m_txtHttpUsername->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onHttpUsernameChanged);
connect(m_ui.m_txtHttpPassword->lineEdit(),
&BaseLineEdit::textChanged,
this,
&TtRssAccountDetails::onHttpPasswordChanged);
connect(m_ui.m_txtHttpUsername->lineEdit(),
&BaseLineEdit::textChanged,
this,
&TtRssAccountDetails::onHttpUsernameChanged);
connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &TtRssAccountDetails::onUrlChanged);
connect(m_ui.m_gbHttpAuthentication, &QGroupBox::toggled, this, &TtRssAccountDetails::onHttpPasswordChanged);
connect(m_ui.m_gbHttpAuthentication, &QGroupBox::toggled, this, &TtRssAccountDetails::onHttpUsernameChanged);
@ -87,21 +101,24 @@ void TtRssAccountDetails::performTest(const QNetworkProxy& proxy) {
}
else if (result.apiLevel() < TTRSS_MINIMAL_API_LEVEL) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("Installed version: %1, required at least: %2.").arg(QString::number(result.apiLevel()),
QString::number(TTRSS_MINIMAL_API_LEVEL)),
tr("Installed version: %1, required at least: %2.")
.arg(QString::number(result.apiLevel()),
QString::number(TTRSS_MINIMAL_API_LEVEL)),
tr("Selected Tiny Tiny RSS server is running unsupported version of API."));
}
else {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Installed version: %1, required at least: %2.").arg(QString::number(result.apiLevel()),
QString::number(TTRSS_MINIMAL_API_LEVEL)),
tr("Installed version: %1, required at least: %2.")
.arg(QString::number(result.apiLevel()),
QString::number(TTRSS_MINIMAL_API_LEVEL)),
tr("Tiny Tiny RSS server is okay."));
}
}
else if (factory.lastError() != QNetworkReply::NoError) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(factory.lastError())),
tr("Network error, have you entered correct Tiny Tiny RSS API endpoint and password?"));
else if (factory.lastError() != QNetworkReply::NoError) {
m_ui.m_lblTestResult
->setStatus(WidgetWithStatus::StatusType::Error,
tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(factory.lastError())),
tr("Network error, have you entered correct Tiny Tiny RSS API endpoint and password?"));
}
else {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
@ -133,25 +150,23 @@ void TtRssAccountDetails::onPasswordChanged() {
}
void TtRssAccountDetails::onHttpUsernameChanged() {
const bool is_username_ok = !m_ui.m_gbHttpAuthentication->isChecked() || !m_ui.m_txtHttpUsername->lineEdit()->text().isEmpty();
const bool is_username_ok =
!m_ui.m_gbHttpAuthentication->isChecked() || !m_ui.m_txtHttpUsername->lineEdit()->text().isEmpty();
m_ui.m_txtHttpUsername->setStatus(is_username_ok ?
LineEditWithStatus::StatusType::Ok :
LineEditWithStatus::StatusType::Warning,
is_username_ok ?
tr("Username is ok or it is not needed.") :
tr("Username is empty."));
m_ui.m_txtHttpUsername->setStatus(is_username_ok ? LineEditWithStatus::StatusType::Ok
: LineEditWithStatus::StatusType::Warning,
is_username_ok ? tr("Username is ok or it is not needed.")
: tr("Username is empty."));
}
void TtRssAccountDetails::onHttpPasswordChanged() {
const bool is_username_ok = !m_ui.m_gbHttpAuthentication->isChecked() || !m_ui.m_txtHttpPassword->lineEdit()->text().isEmpty();
const bool is_username_ok =
!m_ui.m_gbHttpAuthentication->isChecked() || !m_ui.m_txtHttpPassword->lineEdit()->text().isEmpty();
m_ui.m_txtHttpPassword->setStatus(is_username_ok ?
LineEditWithStatus::StatusType::Ok :
LineEditWithStatus::StatusType::Warning,
is_username_ok ?
tr("Password is ok or it is not needed.") :
tr("Password is empty."));
m_ui.m_txtHttpPassword->setStatus(is_username_ok ? LineEditWithStatus::StatusType::Ok
: LineEditWithStatus::StatusType::Warning,
is_username_ok ? tr("Password is ok or it is not needed.")
: tr("Password is empty."));
}
void TtRssAccountDetails::onUrlChanged() {

View file

@ -11,7 +11,7 @@
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="8" column="0">
<item row="10" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -41,13 +41,6 @@
</item>
</layout>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="m_checkDownloadOnlyUnreadMessages">
<property name="text">
<string>Download unread articles only</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
@ -85,17 +78,28 @@
</item>
</layout>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="m_checkDownloadOnlyUnreadMessages">
<property name="text">
<string>Download unread articles only</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="m_cbNewAlgorithm">
<property name="text">
<string>Intelligent synchronization algorithm</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="m_checkServerSideUpdate">
<property name="text">
<string>Force execution of server-side feeds update</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="HelpSpoiler" name="m_lblServerSideUpdateInformation" native="true"/>
</item>
<item row="5" column="0" colspan="2">
<item row="7" column="0" colspan="2">
<widget class="QGroupBox" name="m_gbAuthentication">
<property name="toolTip">
<string>Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported.</string>
@ -139,7 +143,7 @@
</layout>
</widget>
</item>
<item row="6" column="0" colspan="2">
<item row="8" column="0" colspan="2">
<widget class="QGroupBox" name="m_gbHttpAuthentication">
<property name="toolTip">
<string>Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported.</string>
@ -186,7 +190,7 @@
</layout>
</widget>
</item>
<item row="7" column="0" colspan="2">
<item row="9" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="m_btnTestSetup">
@ -210,21 +214,27 @@
</item>
</layout>
</item>
<item row="4" column="0" colspan="2">
<widget class="HelpSpoiler" name="m_lblNewAlgorithm" native="true"/>
</item>
<item row="6" column="0" colspan="2">
<widget class="HelpSpoiler" name="m_lblServerSideUpdateInformation" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LineEditWithStatus</class>
<extends>QWidget</extends>
<header>lineeditwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LabelWithStatus</class>
<extends>QWidget</extends>
<header>labelwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LineEditWithStatus</class>
<extends>QWidget</extends>
<header>lineeditwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>MessageCountSpinBox</class>
<extends>QSpinBox</extends>

View file

@ -22,9 +22,10 @@
#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_authIsUsed(false), m_authUsername(QString()), m_authPassword(QString()), m_sessionId(QString()),
m_lastError(QNetworkReply::NoError) {}
: m_bareUrl(QString()), m_fullUrl(QString()), m_username(QString()), m_password(QString()),
m_batchSize(TTRSS_DEFAULT_MESSAGES), m_forceServerSideUpdate(false), m_intelligentSynchronization(true),
m_authIsUsed(false), m_authUsername(QString()), m_authPassword(QString()), m_sessionId(QString()),
m_lastError(QNetworkReply::NoError) {}
QString TtRssNetworkFactory::url() const {
return m_bareUrl;
@ -71,8 +72,7 @@ QNetworkReply::NetworkError TtRssNetworkFactory::lastError() const {
TtRssLoginResponse TtRssNetworkFactory::login(const QNetworkProxy& proxy) {
if (!m_sessionId.isEmpty()) {
qWarningNN << LOGSEC_TTRSS
<< "Session ID is not empty before login, logging out first.";
qWarningNN << LOGSEC_TTRSS << "Session ID is not empty before login, logging out first.";
logout(proxy);
}
@ -88,18 +88,19 @@ TtRssLoginResponse TtRssNetworkFactory::login(const QNetworkProxy& proxy) {
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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) {
@ -107,9 +108,7 @@ TtRssLoginResponse TtRssNetworkFactory::login(const QNetworkProxy& proxy) {
m_lastLoginTime = QDateTime::currentDateTime();
}
else {
qWarningNN << LOGSEC_TTRSS
<< "Login failed with error:"
<< QUOTE_W_SPACE_DOT(network_reply.m_networkError);
qWarningNN << LOGSEC_TTRSS << "Login failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError);
}
m_lastError = network_reply.m_networkError;
@ -128,18 +127,19 @@ TtRssResponse TtRssNetworkFactory::logout(const QNetworkProxy& proxy) {
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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;
@ -147,16 +147,13 @@ TtRssResponse TtRssNetworkFactory::logout(const QNetworkProxy& proxy) {
m_sessionId.clear();
}
else {
qWarningNN << LOGSEC_TTRSS
<< "Logout failed with error:"
<< QUOTE_W_SPACE_DOT(network_reply.m_networkError);
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.";
qWarningNN << LOGSEC_TTRSS << "Cannot logout because session ID is empty.";
m_lastError = QNetworkReply::NetworkError::NoError;
return TtRssResponse();
}
@ -175,34 +172,35 @@ TtRssGetLabelsResponse TtRssNetworkFactory::getLabels(const QNetworkProxy& proxy
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(m_authUsername, m_authPassword);
NetworkResult network_reply = NetworkFactory::performNetworkOperation(m_fullUrl, timeout,
QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact),
result_raw,
QNetworkAccessManager::Operation::PostOperation,
headers);
NetworkResult network_reply =
NetworkFactory::performNetworkOperation(m_fullUrl,
timeout,
QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact),
result_raw,
QNetworkAccessManager::Operation::PostOperation,
headers);
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);
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);
qWarningNN << LOGSEC_TTRSS << "getLabels failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError);
}
m_lastError = network_reply.m_networkError;
@ -225,39 +223,40 @@ TtRssResponse TtRssNetworkFactory::shareToPublished(const TtRssNoteToPublish& no
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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);
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);
<< "shareToPublished failed with error:" << QUOTE_W_SPACE_DOT(network_reply.m_networkError);
}
m_lastError = network_reply.m_networkError;
@ -277,47 +276,166 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(const QN
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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);
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);
qWarningNN << LOGSEC_TTRSS << "getFeedTree 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,
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(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.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(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;
@ -339,47 +457,49 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, int lim
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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);
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);
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) {
TtRssResponse TtRssNetworkFactory::setArticleLabel(const QStringList& article_ids,
const QString& label_custom_id,
bool assign,
const QNetworkProxy& proxy) {
QJsonObject json;
json[QSL("op")] = QSL("setArticleLabel");
@ -395,38 +515,39 @@ TtRssResponse TtRssNetworkFactory::setArticleLabel(const QStringList& article_id
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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);
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"
qWarningNN << LOGSEC_TTRSS << "setArticleLabel failed with error"
<< QUOTE_W_SPACE_DOT(network_reply.m_networkError);
}
@ -453,48 +574,50 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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);
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);
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,
TtRssSubscribeToFeedResponse TtRssNetworkFactory::subscribeToFeed(const QString& url,
int category_id,
const QNetworkProxy& proxy,
bool protectd, const QString& username,
bool protectd,
const QString& username,
const QString& password) {
QJsonObject json;
@ -515,39 +638,39 @@ TtRssSubscribeToFeedResponse TtRssNetworkFactory::subscribeToFeed(const QString&
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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);
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);
qWarningNN << LOGSEC_TTRSS << "updateArticle failed with error" << QUOTE_W_SPACE_DOT(network_reply.m_networkError);
}
m_lastError = network_reply.m_networkError;
@ -567,39 +690,39 @@ TtRssUnsubscribeFeedResponse TtRssNetworkFactory::unsubscribeFeed(int feed_id, c
headers << QPair<QByteArray, QByteArray>(HTTP_HEADERS_CONTENT_TYPE, TTRSS_CONTENT_TYPE_JSON);
headers << NetworkFactory::generateBasicAuthHeader(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);
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);
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);
qWarningNN << LOGSEC_TTRSS << "getFeeds failed with error" << QUOTE_W_SPACE_DOT(network_reply.m_networkError);
}
m_lastError = network_reply.m_networkError;
@ -614,6 +737,14 @@ 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;
}
@ -729,7 +860,8 @@ bool TtRssResponse::hasError() const {
}
}
TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString& raw_content) : TtRssResponse(raw_content) {}
TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString& raw_content)
: TtRssResponse(raw_content) {}
TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() = default;
@ -740,14 +872,14 @@ RootItem* TtRssGetFeedsCategoriesResponse::feedsCategories(TtRssNetworkFactory*
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);
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());
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));
@ -793,7 +925,8 @@ RootItem* TtRssGetFeedsCategoriesResponse::feedsCategories(TtRssNetworkFactory*
auto* feed = new TtRssFeed();
if (obtain_icons) {
QString icon_path = item[QSL("icon")].type() == QJsonValue::String ? item[QSL("icon")].toString() : QString();
QString icon_path =
item[QSL("icon")].type() == QJsonValue::String ? item[QSL("icon")].toString() : QString();
if (!icon_path.isEmpty()) {
// Chop the "api/" suffix out and append
@ -802,23 +935,17 @@ RootItem* TtRssGetFeedsCategoriesResponse::feedsCategories(TtRssNetworkFactory*
QList<QPair<QByteArray, QByteArray>> headers;
if (network->authIsUsed()) {
headers << NetworkFactory::generateBasicAuthHeader(network->authUsername(),
network->authPassword());
headers << NetworkFactory::generateBasicAuthHeader(network->authUsername(), network->authPassword());
}
auto res = NetworkFactory::downloadIcon({ { full_icon_address, true } },
DOWNLOAD_TIMEOUT,
icon,
headers,
proxy);
auto res =
NetworkFactory::downloadIcon({{full_icon_address, true}}, DOWNLOAD_TIMEOUT, icon, headers, proxy);
if (res == QNetworkReply::NoError) {
feed->setIcon(icon);
}
else {
qWarningNN << LOGSEC_TTRSS
<< "Failed to download icon with error"
<< QUOTE_W_SPACE_DOT(res);
qWarningNN << LOGSEC_TTRSS << "Failed to download icon with error" << QUOTE_W_SPACE_DOT(res);
}
}
}
@ -851,6 +978,14 @@ TtRssGetHeadlinesResponse::TtRssGetHeadlinesResponse(const QString& 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*>();
@ -878,9 +1013,10 @@ QList<Message> TtRssGetHeadlinesResponse::messages(ServiceRoot* root) const {
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;
});
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);
@ -1006,3 +1142,19 @@ QList<RootItem*> TtRssGetLabelsResponse::labels() const {
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;
}

View file

@ -60,8 +60,10 @@ class TtRssGetFeedsCategoriesResponse : public TtRssResponse {
// Returns tree of feeds/categories.
// Top-level root of the tree is not needed here.
// Returned items do not have primary IDs assigned.
RootItem* feedsCategories(TtRssNetworkFactory* network, bool obtain_icons,
const QNetworkProxy& proxy, const QString& base_address = QString()) const;
RootItem* feedsCategories(TtRssNetworkFactory* network,
bool obtain_icons,
const QNetworkProxy& proxy,
const QString& base_address = QString()) const;
};
class ServiceRoot;
@ -74,6 +76,22 @@ class TtRssGetHeadlinesResponse : public TtRssResponse {
QList<Message> messages(ServiceRoot* root) const;
};
class TtRssGetArticleResponse : public TtRssResponse {
public:
explicit TtRssGetArticleResponse(const QString& raw_content = QString());
virtual ~TtRssGetArticleResponse();
QList<Message> messages(ServiceRoot* root) const;
};
class TtRssGetCompactHeadlinesResponse : public TtRssResponse {
public:
explicit TtRssGetCompactHeadlinesResponse(const QString& raw_content = QString());
virtual ~TtRssGetCompactHeadlinesResponse();
QStringList ids() const;
};
class TtRssUpdateArticleResponse : public TtRssResponse {
public:
explicit TtRssUpdateArticleResponse(const QString& raw_content = QString());
@ -100,19 +118,11 @@ class TtRssUnsubscribeFeedResponse : public TtRssResponse {
};
namespace UpdateArticle {
enum class Mode {
SetToFalse = 0,
SetToTrue = 1,
Togggle = 2
};
enum class Mode { SetToFalse = 0, SetToTrue = 1, Togggle = 2 };
enum class OperatingField {
Starred = 0,
Published = 1,
Unread = 2
};
enum class OperatingField { Starred = 0, Published = 1, Unread = 2 };
}
} // namespace UpdateArticle
class TtRssNetworkFactory {
public:
@ -163,22 +173,40 @@ class TtRssNetworkFactory {
// Gets feeds from the server.
TtRssGetFeedsCategoriesResponse getFeedsCategories(const QNetworkProxy& proxy);
// Gets message IDs from the server.
TtRssGetCompactHeadlinesResponse getCompactHeadlines(int feed_id,
int limit,
int skip,
const QString& view_mode,
const QNetworkProxy& proxy);
TtRssGetHeadlinesResponse getArticle(const QStringList& article_ids, const QNetworkProxy& proxy);
// Gets headlines (messages) from the server.
TtRssGetHeadlinesResponse getHeadlines(int feed_id, int limit, int skip,
bool show_content, bool include_attachments,
bool sanitize, bool unread_only,
TtRssGetHeadlinesResponse getHeadlines(int feed_id,
int limit,
int skip,
bool show_content,
bool include_attachments,
bool sanitize,
bool unread_only,
const QNetworkProxy& proxy);
TtRssResponse setArticleLabel(const QStringList& article_ids, const QString& label_custom_id,
bool assign, const QNetworkProxy& proxy);
TtRssResponse setArticleLabel(const QStringList& article_ids,
const QString& label_custom_id,
bool assign,
const QNetworkProxy& proxy);
TtRssUpdateArticleResponse updateArticles(const QStringList& ids,
UpdateArticle::OperatingField field,
UpdateArticle::Mode mode,
const QNetworkProxy& proxy);
TtRssSubscribeToFeedResponse subscribeToFeed(const QString& url, int category_id, const QNetworkProxy& proxy,
bool protectd = false, const QString& username = QString(),
TtRssSubscribeToFeedResponse subscribeToFeed(const QString& url,
int category_id,
const QNetworkProxy& proxy,
bool protectd = false,
const QString& username = QString(),
const QString& password = QString());
TtRssUnsubscribeFeedResponse unsubscribeFeed(int feed_id, const QNetworkProxy& proxy);
@ -186,6 +214,9 @@ class TtRssNetworkFactory {
int batchSize() const;
void setBatchSize(int batch_size);
bool intelligentSynchronization() const;
void setIntelligentSynchronization(bool intelligent_synchronization);
private:
QString m_bareUrl;
QString m_fullUrl;
@ -194,6 +225,7 @@ class TtRssNetworkFactory {
int m_batchSize;
bool m_forceServerSideUpdate;
bool m_downloadOnlyUnreadMessages;
bool m_intelligentSynchronization;
bool m_authIsUsed;
QString m_authUsername;
QString m_authPassword;

View file

@ -235,6 +235,7 @@ QVariantHash TtRssServiceRoot::customDatabaseData() const {
data[QSL("force_update")] = m_network->forceServerSideUpdate();
data[QSL("batch_size")] = m_network->batchSize();
data[QSL("download_only_unread")] = m_network->downloadOnlyUnreadMessages();
data[QSL("intelligent_synchronization")] = m_network->intelligentSynchronization();
return data;
}
@ -249,15 +250,87 @@ void TtRssServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setForceServerSideUpdate(data[QSL("force_update")].toBool());
m_network->setBatchSize(data[QSL("batch_size")].toInt());
m_network->setDownloadOnlyUnreadMessages(data[QSL("download_only_unread")].toBool());
m_network->setIntelligentSynchronization(data[QSL("intelligent_synchronization")].toBool());
}
QList<Message> TtRssServiceRoot::obtainNewMessages(Feed* feed,
const QHash<ServiceRoot::BagOfMessages, QStringList>&
stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
if (m_network->intelligentSynchronization()) {
return obtainMessagesIntelligently(feed, stated_messages);
}
else {
return obtainMessagesViaHeadlines(feed);
}
}
QList<Message> TtRssServiceRoot::obtainMessagesIntelligently(Feed* feed,
const QHash<BagOfMessages, QStringList>& stated_messages) {
// 1. Get unread IDs for a feed.
// 2. Get read IDs for a feed.
// 3. Get starred IDs for a feed.
// 4. Determine IDs needed to download.
// 5. Download needed articles.
const QStringList remote_all_ids_list =
m_network->downloadOnlyUnreadMessages()
? QStringList()
: m_network->getCompactHeadlines(feed->customNumericId(), 1000000, 0, QSL("all_articles"), networkProxy()).ids();
const QStringList remote_unread_ids_list =
m_network->getCompactHeadlines(feed->customNumericId(), 1000000, 0, QSL("unread"), networkProxy()).ids();
const QStringList remote_starred_ids_list =
m_network->getCompactHeadlines(feed->customNumericId(), 1000000, 0, QSL("marked"), networkProxy()).ids();
const QSet<QString> remote_all_ids = FROM_LIST_TO_SET(QSet<QString>, remote_all_ids_list);
// 1.
auto local_unread_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Unread);
const QSet<QString> remote_unread_ids = FROM_LIST_TO_SET(QSet<QString>, remote_unread_ids_list);
const QSet<QString> local_unread_ids = FROM_LIST_TO_SET(QSet<QString>, local_unread_ids_list);
// 2.
const auto local_read_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Read);
const QSet<QString> remote_read_ids = remote_all_ids - remote_unread_ids;
const QSet<QString> local_read_ids = FROM_LIST_TO_SET(QSet<QString>, local_read_ids_list);
// 3.
const auto local_starred_ids_list = stated_messages.value(ServiceRoot::BagOfMessages::Starred);
const QSet<QString> remote_starred_ids = FROM_LIST_TO_SET(QSet<QString>, remote_starred_ids_list);
const QSet<QString> local_starred_ids = FROM_LIST_TO_SET(QSet<QString>, local_starred_ids_list);
// 4.
QSet<QString> to_download;
if (!m_network->downloadOnlyUnreadMessages()) {
to_download += remote_all_ids - local_read_ids - local_unread_ids;
}
else {
to_download += remote_unread_ids - local_read_ids - local_unread_ids;
}
auto moved_read = local_read_ids & remote_unread_ids;
to_download += moved_read;
if (!m_network->downloadOnlyUnreadMessages()) {
auto moved_unread = local_unread_ids & remote_read_ids;
to_download += moved_unread;
}
auto moved_starred = (local_starred_ids + remote_starred_ids) - (local_starred_ids & remote_starred_ids);
to_download += moved_starred;
// 5.
auto msgs = m_network->getArticle(to_download.values(), networkProxy());
return msgs.messages(this);
}
QList<Message> TtRssServiceRoot::obtainMessagesViaHeadlines(Feed* feed) {
QList<Message> messages;
int newly_added_messages = 0;
int limit = network()->batchSize() <= 0 ? TTRSS_MAX_MESSAGES : network()->batchSize();
@ -336,3 +409,7 @@ RootItem* TtRssServiceRoot::obtainNewTreeForSyncIn() const {
throw NetworkException(lst_error, tr("cannot get list of feeds, network error '%1'").arg(lst_error));
}
}
bool TtRssServiceRoot::wantsBaggedIdsOfExistingMessages() const {
return m_network->intelligentSynchronization();
}

View file

@ -13,12 +13,13 @@ class TtRssFeed;
class TtRssNetworkFactory;
class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
Q_OBJECT
Q_OBJECT
public:
explicit TtRssServiceRoot(RootItem* parent = nullptr);
virtual ~TtRssServiceRoot();
virtual bool wantsBaggedIdsOfExistingMessages() const;
virtual LabelOperation supportedLabelOperations() const;
virtual void start(bool freshly_activated);
virtual void stop();
@ -48,6 +49,9 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
private:
void updateTitle();
QList<Message> obtainMessagesIntelligently(Feed* feed,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages);
QList<Message> obtainMessagesViaHeadlines(Feed* feed);
private:
TtRssNetworkFactory* m_network;