remove redundant feed classes

This commit is contained in:
Martin Rotter 2021-03-03 12:05:25 +01:00
parent 10bf16a3b2
commit 081d25eca1
38 changed files with 313 additions and 470 deletions

View File

@ -120,7 +120,7 @@ void FeedDownloader::updateOneFeed(Feed* feed) {
bool error_during_obtaining = false;
int acc_id = feed->getParentServiceRoot()->accountId();
QElapsedTimer tmr; tmr.start();
QList<Message> msgs = feed->obtainNewMessages(&error_during_obtaining);
QList<Message> msgs = feed->getParentServiceRoot()->obtainNewMessages({ feed }, &error_during_obtaining);
qDebugNN << LOGSEC_FEEDDOWNLOADER << "Downloaded " << msgs.size() << " messages for feed ID '"
<< feed->customId() << "' URL: '" << feed->source() << "' title: '" << feed->title() << "' in thread: '"

View File

@ -154,14 +154,12 @@ HEADERS += core/feeddownloader.h \
services/abstract/serviceroot.h \
services/feedly/definitions.h \
services/feedly/feedlyentrypoint.h \
services/feedly/feedlyfeed.h \
services/feedly/feedlynetwork.h \
services/feedly/feedlyserviceroot.h \
services/feedly/gui/feedlyaccountdetails.h \
services/feedly/gui/formeditfeedlyaccount.h \
services/gmail/definitions.h \
services/gmail/gmailentrypoint.h \
services/gmail/gmailfeed.h \
services/gmail/gmailnetworkfactory.h \
services/gmail/gmailserviceroot.h \
services/gmail/gui/emailrecipientcontrol.h \
@ -171,7 +169,6 @@ HEADERS += core/feeddownloader.h \
services/gmail/gui/gmailaccountdetails.h \
services/greader/definitions.h \
services/greader/greaderentrypoint.h \
services/greader/greaderfeed.h \
services/greader/greadernetwork.h \
services/greader/greaderserviceroot.h \
services/greader/gui/formeditgreaderaccount.h \
@ -180,7 +177,6 @@ HEADERS += core/feeddownloader.h \
services/inoreader/gui/formeditinoreaderaccount.h \
services/inoreader/gui/inoreaderaccountdetails.h \
services/inoreader/inoreaderentrypoint.h \
services/inoreader/inoreaderfeed.h \
services/inoreader/inoreadernetworkfactory.h \
services/inoreader/inoreaderserviceroot.h \
services/owncloud/definitions.h \
@ -331,13 +327,11 @@ SOURCES += core/feeddownloader.cpp \
services/abstract/rootitem.cpp \
services/abstract/serviceroot.cpp \
services/feedly/feedlyentrypoint.cpp \
services/feedly/feedlyfeed.cpp \
services/feedly/feedlynetwork.cpp \
services/feedly/feedlyserviceroot.cpp \
services/feedly/gui/feedlyaccountdetails.cpp \
services/feedly/gui/formeditfeedlyaccount.cpp \
services/gmail/gmailentrypoint.cpp \
services/gmail/gmailfeed.cpp \
services/gmail/gmailnetworkfactory.cpp \
services/gmail/gmailserviceroot.cpp \
services/gmail/gui/emailrecipientcontrol.cpp \
@ -346,7 +340,6 @@ SOURCES += core/feeddownloader.cpp \
services/gmail/gui/formeditgmailaccount.cpp \
services/gmail/gui/gmailaccountdetails.cpp \
services/greader/greaderentrypoint.cpp \
services/greader/greaderfeed.cpp \
services/greader/greadernetwork.cpp \
services/greader/greaderserviceroot.cpp \
services/greader/gui/formeditgreaderaccount.cpp \
@ -354,7 +347,6 @@ SOURCES += core/feeddownloader.cpp \
services/inoreader/gui/formeditinoreaderaccount.cpp \
services/inoreader/gui/inoreaderaccountdetails.cpp \
services/inoreader/inoreaderentrypoint.cpp \
services/inoreader/inoreaderfeed.cpp \
services/inoreader/inoreadernetworkfactory.cpp \
services/inoreader/inoreaderserviceroot.cpp \
services/owncloud/gui/formeditowncloudaccount.cpp \

View File

@ -1483,57 +1483,13 @@ bool DatabaseQueries::storeAccountTree(const QSqlDatabase& db, RootItem* tree_ro
QSqlQuery query_category(db);
QSqlQuery query_feed(db);
// TODO: use createOvewriteAccount and createOverwriteFeed
/*
query_category.setForwardOnly(true);
query_feed.setForwardOnly(true);
query_category.prepare("INSERT INTO Categories (parent_id, title, account_id, custom_id) "
"VALUES (:parent_id, :title, :account_id, :custom_id);");
query_feed.prepare("INSERT INTO Feeds (title, icon, url, category, protected, update_type, update_interval, account_id, custom_id) "
"VALUES (:title, :icon, :url, :category, :protected, :update_type, :update_interval, :account_id, :custom_id);");
*/
// Iterate all children.
for (RootItem* child : tree_root->getSubTree()) {
if (child->kind() == RootItem::Kind::Category) {
/*
query_category.bindValue(QSL(":parent_id"), child->parent()->id());
query_category.bindValue(QSL(":title"), child->title());
query_category.bindValue(QSL(":account_id"), account_id);
query_category.bindValue(QSL(":custom_id"), child->customId());
if (query_category.exec()) {
child->setId(query_category.lastInsertId().toInt());
}
else {
return false;
}
*/
createOverwriteCategory(db, child->toCategory(), account_id, child->parent()->id());
}
else if (child->kind() == RootItem::Kind::Feed) {
createOverwriteFeed(db, child->toFeed(), account_id, child->parent()->id());
/*
Feed* feed = child->toFeed();
query_feed.bindValue(QSL(":title"), feed->title());
query_feed.bindValue(QSL(":icon"), qApp->icons()->toByteArray(feed->icon()));
query_feed.bindValue(QSL(":url"), feed->source());
query_feed.bindValue(QSL(":category"), feed->parent()->id());
query_feed.bindValue(QSL(":protected"), 0);
query_feed.bindValue(QSL(":update_type"), int(feed->autoUpdateType()));
query_feed.bindValue(QSL(":update_interval"), feed->autoUpdateInitialInterval());
query_feed.bindValue(QSL(":account_id"), account_id);
query_feed.bindValue(QSL(":custom_id"), feed->customId());
if (query_feed.exec()) {
feed->setId(query_feed.lastInsertId().toInt());
}
else {
return false;
}
*/
}
else if (child->kind() == RootItem::Kind::Labels) {
// Add all labels.

View File

@ -25,6 +25,12 @@ Feed::Feed(RootItem* parent)
setKind(RootItem::Kind::Feed);
}
Feed::Feed(const QString& title, const QString& custom_id, const QIcon& icon, RootItem* parent) : Feed(parent) {
setTitle(title);
setCustomId(custom_id);
setIcon(icon);
}
Feed::Feed(const Feed& other) : RootItem(other) {
setKind(RootItem::Kind::Feed);
@ -170,12 +176,6 @@ bool Feed::cleanMessages(bool clean_read_only) {
return getParentServiceRoot()->cleanFeeds(QList<Feed*>() << this, clean_read_only);
}
QList<Message> Feed::obtainNewMessages(bool* error_during_obtaining) {
Q_UNUSED(error_during_obtaining)
return {};
}
bool Feed::markAsReadUnread(RootItem::ReadStatus status) {
ServiceRoot* service = getParentServiceRoot();
auto* cache = dynamic_cast<CacheForServiceRoot*>(service);

View File

@ -36,15 +36,14 @@ class Feed : public RootItem {
OtherError = 5
};
// Constructors.
explicit Feed(RootItem* parent = nullptr);
explicit Feed(const Feed& other);
explicit Feed(const QString& title, const QString& custom_id, const QIcon& icon, RootItem* parent = nullptr);
virtual QList<Message> undeletedMessages() const;
virtual QString additionalTooltip() const;
virtual bool markAsReadUnread(ReadStatus status);
virtual bool cleanMessages(bool clean_read_only);
virtual QList<Message> obtainNewMessages(bool* error_during_obtaining);
virtual int countOfAllMessages() const;
virtual int countOfUnreadMessages() const;
virtual QVariantHash customDatabaseData() const;

View File

@ -88,6 +88,9 @@ class ServiceRoot : public RootItem {
virtual void start(bool freshly_activated);
virtual void stop();
// Obtains list of messages.
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) = 0;
// This method should prepare messages for given "item" (download them maybe?)
// into predefined "Messages" table
// and then use method QSqlTableModel::setFilter(....).

View File

@ -1,37 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/feedly/feedlyfeed.h"
#include "exceptions/applicationexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "services/feedly/feedlynetwork.h"
#include "services/feedly/feedlyserviceroot.h"
FeedlyFeed::FeedlyFeed(RootItem* parent) : Feed(parent) {}
FeedlyServiceRoot* FeedlyFeed::serviceRoot() const {
return qobject_cast<FeedlyServiceRoot*>(getParentServiceRoot());
}
QList<Message> FeedlyFeed::obtainNewMessages(bool* error_during_obtaining) {
try {
QList<Message> messages = serviceRoot()->network()->streamContents(customId());
setStatus(Feed::Status::Normal);
*error_during_obtaining = false;
return messages;;
}
catch (const ApplicationException& ex) {
setStatus(Feed::Status::NetworkError);
*error_during_obtaining = true;
qCriticalNN << LOGSEC_FEEDLY
<< "Problem"
<< QUOTE_W_SPACE(ex.message())
<< "when obtaining messages for feed"
<< QUOTE_W_SPACE_DOT(customId());
return {};
}
}

View File

@ -1,19 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef FEEDLYFEED_H
#define FEEDLYFEED_H
#include "services/abstract/feed.h"
class FeedlyServiceRoot;
class FeedlyFeed : public Feed {
public:
explicit FeedlyFeed(RootItem* parent = nullptr);
FeedlyServiceRoot* serviceRoot() const;
virtual QList<Message> obtainNewMessages(bool* error_during_obtaining);
};
#endif // FEEDLYFEED_H

View File

@ -13,7 +13,6 @@
#include "services/abstract/label.h"
#include "services/abstract/labelsnode.h"
#include "services/feedly/definitions.h"
#include "services/feedly/feedlyfeed.h"
#include "services/feedly/feedlyserviceroot.h"
#if defined(FEEDLY_OFFICIAL_SUPPORT)
@ -351,7 +350,7 @@ RootItem* FeedlyNetwork::decodeCollections(const QByteArray& json, bool obtain_i
continue;
}
auto* feed = new FeedlyFeed(category);
auto* feed = new Feed(category);
feed->setTitle(fee_obj["title"].toString());
feed->setDescription(fee_obj["description"].toString());

View File

@ -15,7 +15,6 @@
#include "services/abstract/recyclebin.h"
#include "services/feedly/definitions.h"
#include "services/feedly/feedlyentrypoint.h"
#include "services/feedly/feedlyfeed.h"
#include "services/feedly/feedlynetwork.h"
#include "services/feedly/gui/formeditfeedlyaccount.h"
@ -72,9 +71,34 @@ void FeedlyServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setDownloadOnlyUnreadMessages(data["download_only_unread"].toBool());
}
QList<Message> FeedlyServiceRoot::obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) {
QList<Message> messages;
for (Feed* feed : feeds) {
try {
messages << m_network->streamContents(feed->customId());
feed->setStatus(Feed::Status::Normal);
*error_during_obtaining = false;
}
catch (const ApplicationException& ex) {
feed->setStatus(Feed::Status::NetworkError);
*error_during_obtaining = true;
qCriticalNN << LOGSEC_FEEDLY
<< "Problem"
<< QUOTE_W_SPACE(ex.message())
<< "when obtaining messages for feed"
<< QUOTE_W_SPACE_DOT(customId());
}
}
return messages;
}
void FeedlyServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) {
DatabaseQueries::loadFromDatabase<Category, FeedlyFeed>(this);
DatabaseQueries::loadFromDatabase<Category, Feed>(this);
loadCacheFromFile();
}

View File

@ -23,6 +23,7 @@ class FeedlyServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual LabelOperation supportedLabelOperations() const;
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining);
FeedlyNetwork* network() const;

View File

@ -1,34 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/gmail/gmailfeed.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "services/gmail/definitions.h"
#include "services/gmail/gmailnetworkfactory.h"
#include "services/gmail/gmailserviceroot.h"
GmailFeed::GmailFeed(RootItem* parent) : Feed(parent) {}
GmailFeed::GmailFeed(const QString& title, const QString& custom_id, const QIcon& icon, RootItem* parent) : GmailFeed(parent) {
setTitle(title);
setCustomId(custom_id);
setIcon(icon);
}
GmailServiceRoot* GmailFeed::serviceRoot() const {
return qobject_cast<GmailServiceRoot*>(getParentServiceRoot());
}
QList<Message> GmailFeed::obtainNewMessages(bool* error_during_obtaining) {
Feed::Status error = Feed::Status::Normal;
QList<Message> messages = serviceRoot()->network()->messages(customId(), error, getParentServiceRoot()->networkProxy());
setStatus(error);
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError || error == Feed::Status::ParsingError) {
*error_during_obtaining = true;
}
return messages;
}

View File

@ -1,20 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef GMAILFEED_H
#define GMAILFEED_H
#include "services/abstract/feed.h"
class GmailServiceRoot;
class GmailFeed : public Feed {
public:
explicit GmailFeed(RootItem* parent = nullptr);
explicit GmailFeed(const QString& title, const QString& custom_id, const QIcon& icon, RootItem* parent = nullptr);
GmailServiceRoot* serviceRoot() const;
virtual QList<Message> obtainNewMessages(bool* error_during_obtaining);
};
#endif // GMAILFEED_H

View File

@ -15,7 +15,6 @@
#include "network-web/webfactory.h"
#include "services/abstract/category.h"
#include "services/gmail/definitions.h"
#include "services/gmail/gmailfeed.h"
#include "services/gmail/gmailserviceroot.h"
#include <QHttpMultiPart>

View File

@ -10,7 +10,6 @@
#include "services/abstract/recyclebin.h"
#include "services/gmail/definitions.h"
#include "services/gmail/gmailentrypoint.h"
#include "services/gmail/gmailfeed.h"
#include "services/gmail/gmailnetworkfactory.h"
#include "services/gmail/gui/formaddeditemail.h"
#include "services/gmail/gui/formdownloadattachment.h"
@ -34,14 +33,14 @@ void GmailServiceRoot::replyToEmail() {
RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const {
auto* root = new RootItem();
GmailFeed* inbox = new GmailFeed(tr("Inbox"), QSL(GMAIL_SYSTEM_LABEL_INBOX), qApp->icons()->fromTheme(QSL("mail-inbox")), root);
Feed* inbox = new Feed(tr("Inbox"), QSL(GMAIL_SYSTEM_LABEL_INBOX), qApp->icons()->fromTheme(QSL("mail-inbox")), root);
inbox->setKeepOnTop(true);
root->appendChild(inbox);
root->appendChild(new GmailFeed(tr("Sent"), QSL(GMAIL_SYSTEM_LABEL_SENT), qApp->icons()->fromTheme(QSL("mail-sent")), root));
root->appendChild(new GmailFeed(tr("Drafts"), QSL(GMAIL_SYSTEM_LABEL_DRAFT), qApp->icons()->fromTheme(QSL("gtk-edit")), root));
root->appendChild(new GmailFeed(tr("Spam"), QSL(GMAIL_SYSTEM_LABEL_SPAM), qApp->icons()->fromTheme(QSL("mail-mark-junk")), root));
root->appendChild(new Feed(tr("Sent"), QSL(GMAIL_SYSTEM_LABEL_SENT), qApp->icons()->fromTheme(QSL("mail-sent")), root));
root->appendChild(new Feed(tr("Drafts"), QSL(GMAIL_SYSTEM_LABEL_DRAFT), qApp->icons()->fromTheme(QSL("gtk-edit")), root));
root->appendChild(new Feed(tr("Spam"), QSL(GMAIL_SYSTEM_LABEL_SPAM), qApp->icons()->fromTheme(QSL("mail-mark-junk")), root));
return root;
}
@ -72,6 +71,25 @@ void GmailServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->oauth()->setRedirectUrl(data["redirect_uri"].toString());
}
QList<Message> GmailServiceRoot::obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) {
QList<Message> messages;
for (Feed* feed : feeds) {
Feed::Status error = Feed::Status::Normal;
messages << network()->messages(feed->customId(), error, networkProxy());
feed->setStatus(error);
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError || error == Feed::Status::ParsingError) {
*error_during_obtaining = true;
}
return messages;
}
return messages;
}
bool GmailServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const {
QString str_url = url.toString();
QString attachment_id = str_url.mid(str_url.indexOf(QL1C('?')) + 1);
@ -145,7 +163,7 @@ bool GmailServiceRoot::supportsCategoryAdding() const {
void GmailServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) {
DatabaseQueries::loadFromDatabase<Category, GmailFeed>(this);
DatabaseQueries::loadFromDatabase<Category, Feed>(this);
loadCacheFromFile();
}

View File

@ -31,6 +31,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining);
protected:
virtual RootItem* obtainNewTreeForSyncIn() const;

View File

@ -1,30 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/greader/greaderfeed.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "services/greader/greadernetwork.h"
#include "services/greader/greaderserviceroot.h"
GreaderFeed::GreaderFeed(RootItem* parent) : Feed(parent) {}
GreaderServiceRoot* GreaderFeed::serviceRoot() const {
return qobject_cast<GreaderServiceRoot*>(getParentServiceRoot());
}
QList<Message> GreaderFeed::obtainNewMessages(bool* error_during_obtaining) {
Feed::Status error = Feed::Status::Normal;
QList<Message> messages = serviceRoot()->network()->streamContents(getParentServiceRoot(),
customId(),
error,
getParentServiceRoot()->networkProxy());
setStatus(error);
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) {
*error_during_obtaining = true;
}
return messages;
}

View File

@ -1,19 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef GREADERFEED_H
#define GREADERFEED_H
#include "services/abstract/feed.h"
class GreaderServiceRoot;
class GreaderFeed : public Feed {
public:
explicit GreaderFeed(RootItem* parent = nullptr);
GreaderServiceRoot* serviceRoot() const;
virtual QList<Message> obtainNewMessages(bool* error_during_obtaining);
};
#endif // GREADERFEED_H

View File

@ -10,7 +10,6 @@
#include "services/abstract/label.h"
#include "services/abstract/labelsnode.h"
#include "services/greader/definitions.h"
#include "services/greader/greaderfeed.h"
#include <QJsonArray>
#include <QJsonDocument>
@ -289,7 +288,7 @@ RootItem* GreaderNetwork::decodeTagsSubscriptions(const QString& categories, con
}
// We have label (not "state").
auto* feed = new GreaderFeed();
auto* feed = new Feed();
feed->setDescription(url);
feed->setSource(url);

View File

@ -11,7 +11,6 @@
#include "services/abstract/importantnode.h"
#include "services/abstract/recyclebin.h"
#include "services/greader/greaderentrypoint.h"
#include "services/greader/greaderfeed.h"
#include "services/greader/greadernetwork.h"
#include "services/greader/gui/formeditgreaderaccount.h"
@ -55,9 +54,26 @@ void GreaderServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setBatchSize(data["batch_size"].toInt());
}
QList<Message> GreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) {
QList<Message> messages;
for (Feed* feed : feeds) {
Feed::Status error = Feed::Status::Normal;
messages << network()->streamContents(this, feed->customId(), error, networkProxy());
feed->setStatus(error);
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) {
*error_during_obtaining = true;
}
}
return messages;
}
void GreaderServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) {
DatabaseQueries::loadFromDatabase<Category, GreaderFeed>(this);
DatabaseQueries::loadFromDatabase<Category, Feed>(this);
loadCacheFromFile();
}

View File

@ -31,6 +31,7 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual LabelOperation supportedLabelOperations() const;
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining);
GreaderNetwork* network() const;

View File

@ -1,27 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/inoreader/inoreaderfeed.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "services/inoreader/inoreadernetworkfactory.h"
#include "services/inoreader/inoreaderserviceroot.h"
InoreaderFeed::InoreaderFeed(RootItem* parent) : Feed(parent) {}
InoreaderServiceRoot* InoreaderFeed::serviceRoot() const {
return qobject_cast<InoreaderServiceRoot*>(getParentServiceRoot());
}
QList<Message> InoreaderFeed::obtainNewMessages(bool* error_during_obtaining) {
Feed::Status error = Feed::Status::Normal;
QList<Message> messages = serviceRoot()->network()->messages(getParentServiceRoot(), customId(), error);
setStatus(error);
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) {
*error_during_obtaining = true;
}
return messages;
}

View File

@ -1,19 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef INOREADERFEED_H
#define INOREADERFEED_H
#include "services/abstract/feed.h"
class InoreaderServiceRoot;
class InoreaderFeed : public Feed {
public:
explicit InoreaderFeed(RootItem* parent = nullptr);
InoreaderServiceRoot* serviceRoot() const;
virtual QList<Message> obtainNewMessages(bool* error_during_obtaining);
};
#endif // INOREADERFEED_H

View File

@ -15,7 +15,6 @@
#include "services/abstract/category.h"
#include "services/abstract/labelsnode.h"
#include "services/inoreader/definitions.h"
#include "services/inoreader/inoreaderfeed.h"
#include "services/inoreader/inoreaderserviceroot.h"
#include <QJsonArray>
@ -418,7 +417,7 @@ RootItem* InoreaderNetworkFactory::decodeFeedCategoriesData(const QString& categ
}
// We have label (not "state").
auto* feed = new InoreaderFeed();
auto* feed = new Feed();
feed->setDescription(url);
feed->setSource(url);

View File

@ -11,7 +11,6 @@
#include "services/abstract/recyclebin.h"
#include "services/inoreader/gui/formeditinoreaderaccount.h"
#include "services/inoreader/inoreaderentrypoint.h"
#include "services/inoreader/inoreaderfeed.h"
#include "services/inoreader/inoreadernetworkfactory.h"
#include <QThread>
@ -54,6 +53,23 @@ void InoreaderServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->oauth()->setRedirectUrl(data["redirect_uri"].toString());
}
QList<Message> InoreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) {
QList<Message> messages;
for (Feed* feed : feeds) {
Feed::Status error = Feed::Status::Normal;
messages << network()->messages(this, feed->customId(), error);
feed->setStatus(error);
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) {
*error_during_obtaining = true;
}
}
return messages;
}
bool InoreaderServiceRoot::isSyncable() const {
return true;
}
@ -79,7 +95,7 @@ bool InoreaderServiceRoot::supportsCategoryAdding() const {
void InoreaderServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) {
DatabaseQueries::loadFromDatabase<Category, InoreaderFeed>(this);
DatabaseQueries::loadFromDatabase<Category, Feed>(this);
loadCacheFromFile();
}

View File

@ -29,6 +29,7 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining);
protected:
virtual RootItem* obtainNewTreeForSyncIn() const;

View File

@ -35,19 +35,3 @@ bool OwnCloudFeed::removeItself() {
OwnCloudServiceRoot* OwnCloudFeed::serviceRoot() const {
return qobject_cast<OwnCloudServiceRoot*>(getParentServiceRoot());
}
QList<Message> OwnCloudFeed::obtainNewMessages(bool* error_during_obtaining) {
OwnCloudGetMessagesResponse messages = serviceRoot()->network()->getMessages(customNumericId(),
getParentServiceRoot()->networkProxy());
if (messages.networkError() != QNetworkReply::NetworkError::NoError) {
setStatus(Feed::Status::NetworkError);
*error_during_obtaining = true;
serviceRoot()->itemChanged(QList<RootItem*>() << this);
return QList<Message>();
}
else {
*error_during_obtaining = false;
return messages.messages();
}
}

View File

@ -15,7 +15,6 @@ class OwnCloudFeed : public Feed {
virtual bool canBeDeleted() const;
virtual bool deleteViaGui();
virtual QList<Message> obtainNewMessages(bool* error_during_obtaining);
private:
bool removeItself();

View File

@ -148,3 +148,22 @@ void OwnCloudServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setBatchSize(data["batch_size"].toInt());
m_network->setDownloadOnlyUnreadMessages(data["download_only_unread"].toBool());
}
QList<Message> OwnCloudServiceRoot::obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) {
QList<Message> msgs;
for (Feed* feed : feeds) {
OwnCloudGetMessagesResponse messages = network()->getMessages(customNumericId(), networkProxy());
if (messages.networkError() != QNetworkReply::NetworkError::NoError) {
feed->setStatus(Feed::Status::NetworkError);
*error_during_obtaining = true;
}
else {
*error_during_obtaining = false;
msgs << messages.messages();
}
}
return msgs;
}

View File

@ -28,6 +28,7 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining);
OwnCloudNetworkFactory* network() const;

View File

@ -208,7 +208,7 @@ void StandardFeed::fetchMetadataForItself() {
// Notify the model about fact, that it needs to reload new information about
// this item, particularly the icon.
serviceRoot()->itemChanged(QList<RootItem*>() << this);
serviceRoot()->itemChanged({ this });
}
else {
qApp->showGuiMessage(tr("Metadata not fetched"),
@ -529,128 +529,6 @@ void StandardFeed::setEncoding(const QString& encoding) {
m_encoding = encoding;
}
QList<Message> StandardFeed::obtainNewMessages(bool* error_during_obtaining) {
QString formatted_feed_contents;
int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
if (sourceType() == SourceType::Url) {
qDebugNN << LOGSEC_CORE
<< "Downloading URL"
<< QUOTE_W_SPACE(source())
<< "to obtain feed data.";
QByteArray feed_contents;
QList<QPair<QByteArray, QByteArray>> headers;
headers << NetworkFactory::generateBasicAuthHeader(username(), password());
m_networkError = NetworkFactory::performNetworkOperation(source(),
download_timeout,
QByteArray(),
feed_contents,
QNetworkAccessManager::Operation::GetOperation,
headers,
false,
{},
{},
getParentServiceRoot()->networkProxy()).first;
if (m_networkError != QNetworkReply::NetworkError::NoError) {
qWarningNN << LOGSEC_CORE
<< "Error"
<< QUOTE_W_SPACE(m_networkError)
<< "during fetching of new messages for feed"
<< QUOTE_W_SPACE_DOT(source());
setStatus(Status::NetworkError);
*error_during_obtaining = true;
return QList<Message>();
}
else {
*error_during_obtaining = false;
}
// Encode downloaded data for further parsing.
QTextCodec* codec = QTextCodec::codecForName(encoding().toLocal8Bit());
if (codec == nullptr) {
// No suitable codec for this encoding was found.
// Use non-converted data.
formatted_feed_contents = feed_contents;
}
else {
formatted_feed_contents = codec->toUnicode(feed_contents);
}
}
else {
qDebugNN << LOGSEC_CORE
<< "Running custom script"
<< QUOTE_W_SPACE(source())
<< "to obtain feed data.";
// Use script to generate feed file.
try {
formatted_feed_contents = generateFeedFileWithScript(source(), download_timeout);
}
catch (const ScriptException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Custom script for generating feed file failed:"
<< QUOTE_W_SPACE_DOT(ex.message());
setStatus(Status::OtherError);
*error_during_obtaining = true;
return {};
}
}
if (!postProcessScript().simplified().isEmpty()) {
qDebugNN << LOGSEC_CORE
<< "Post-processing obtained feed data with custom script"
<< QUOTE_W_SPACE_DOT(postProcessScript());
try {
formatted_feed_contents = postProcessFeedFileWithScript(postProcessScript(),
formatted_feed_contents,
download_timeout);
}
catch (const ScriptException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Post-processing script for feed file failed:"
<< QUOTE_W_SPACE_DOT(ex.message());
setStatus(Status::OtherError);
*error_during_obtaining = true;
return {};
}
}
// Feed data are downloaded and encoded.
// Parse data and obtain messages.
QList<Message> messages;
switch (type()) {
case StandardFeed::Type::Rss0X:
case StandardFeed::Type::Rss2X:
messages = RssParser(formatted_feed_contents).messages();
break;
case StandardFeed::Type::Rdf:
messages = RdfParser().parseXmlData(formatted_feed_contents);
break;
case StandardFeed::Type::Atom10:
messages = AtomParser(formatted_feed_contents).messages();
break;
case StandardFeed::Type::Json:
messages = JsonParser(formatted_feed_contents).messages();
break;
default:
break;
}
return messages;
}
QStringList StandardFeed::prepareExecutionLine(const QString& execution_line) {
auto split_exec = execution_line.split('#',
#if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
@ -719,6 +597,10 @@ QString StandardFeed::runScriptProcess(const QStringList& cmd_args, const QStrin
}
}
void StandardFeed::setNetworkError(const QNetworkReply::NetworkError& network_error) {
m_networkError = network_error;
}
QString StandardFeed::generateFeedFileWithScript(const QString& execution_line, int run_timeout) {
auto prepared_query = prepareExecutionLine(execution_line);

View File

@ -77,8 +77,7 @@ class StandardFeed : public Feed {
void setPassword(const QString& password);
QNetworkReply::NetworkError networkError() const;
QList<Message> obtainNewMessages(bool* error_during_obtaining);
void setNetworkError(const QNetworkReply::NetworkError& network_error);
// Tries to guess feed hidden under given URL
// and uses given credentials.
@ -97,13 +96,7 @@ class StandardFeed : public Feed {
static QString typeToString(Type type);
static QString sourceTypeToString(SourceType type);
public slots:
void fetchMetadataForItself();
private:
StandardServiceRoot* serviceRoot() const;
bool removeItself();
// Scraping + post+processing.
static QStringList prepareExecutionLine(const QString& execution_line);
static QString generateFeedFileWithScript(const QString& execution_line, int run_timeout);
static QString postProcessFeedFileWithScript(const QString& execution_line,
@ -112,6 +105,13 @@ class StandardFeed : public Feed {
static QString runScriptProcess(const QStringList& cmd_args, const QString& working_directory,
int run_timeout, bool provide_input, const QString& input = {});
public slots:
void fetchMetadataForItself();
private:
StandardServiceRoot* serviceRoot() const;
bool removeItself();
private:
SourceType m_sourceType;
Type m_type;

View File

@ -5,20 +5,26 @@
#include "core/feedsmodel.h"
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "exceptions/scriptexception.h"
#include "gui/messagebox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/databasequeries.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/settings.h"
#include "network-web/networkfactory.h"
#include "services/abstract/gui/formcategorydetails.h"
#include "services/abstract/importantnode.h"
#include "services/abstract/labelsnode.h"
#include "services/abstract/recyclebin.h"
#include "services/standard/atomparser.h"
#include "services/standard/definitions.h"
#include "services/standard/gui/formeditstandardaccount.h"
#include "services/standard/gui/formstandardfeeddetails.h"
#include "services/standard/gui/formstandardimportexport.h"
#include "services/standard/jsonparser.h"
#include "services/standard/rdfparser.h"
#include "services/standard/rssparser.h"
#include "services/standard/standardcategory.h"
#include "services/standard/standardfeed.h"
#include "services/standard/standardfeedsimportexportmodel.h"
@ -28,6 +34,7 @@
#include <QClipboard>
#include <QSqlTableModel>
#include <QStack>
#include <QTextCodec>
StandardServiceRoot::StandardServiceRoot(RootItem* parent)
: ServiceRoot(parent) {
@ -132,6 +139,135 @@ Qt::ItemFlags StandardServiceRoot::additionalFlags() const {
return Qt::ItemFlag::ItemIsDropEnabled;
}
QList<Message> StandardServiceRoot::obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) {
QList<Message> msgs;
for (Feed* f : feeds) {
StandardFeed* feed = static_cast<StandardFeed*>(f);
QString formatted_feed_contents;
int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
if (feed->sourceType() == StandardFeed::SourceType::Url) {
qDebugNN << LOGSEC_CORE
<< "Downloading URL"
<< QUOTE_W_SPACE(feed->source())
<< "to obtain feed data.";
QByteArray feed_contents;
QList<QPair<QByteArray, QByteArray>> headers;
headers << NetworkFactory::generateBasicAuthHeader(feed->username(), feed->password());
feed->setNetworkError(NetworkFactory::performNetworkOperation(feed->source(),
download_timeout,
{},
feed_contents,
QNetworkAccessManager::Operation::GetOperation,
headers,
false,
{},
{},
networkProxy()).first);
if (feed->networkError() != QNetworkReply::NetworkError::NoError) {
qWarningNN << LOGSEC_CORE
<< "Error"
<< QUOTE_W_SPACE(feed->networkError())
<< "during fetching of new messages for feed"
<< QUOTE_W_SPACE_DOT(feed->source());
feed->setStatus(StandardFeed::Status::NetworkError);
*error_during_obtaining = true;
continue;
}
else {
*error_during_obtaining = false;
}
// Encode downloaded data for further parsing.
QTextCodec* codec = QTextCodec::codecForName(feed->encoding().toLocal8Bit());
if (codec == nullptr) {
// No suitable codec for this encoding was found.
// Use non-converted data.
formatted_feed_contents = feed_contents;
}
else {
formatted_feed_contents = codec->toUnicode(feed_contents);
}
}
else {
qDebugNN << LOGSEC_CORE
<< "Running custom script"
<< QUOTE_W_SPACE(feed->source())
<< "to obtain feed data.";
// Use script to generate feed file.
try {
formatted_feed_contents = StandardFeed::generateFeedFileWithScript(feed->source(), download_timeout);
}
catch (const ScriptException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Custom script for generating feed file failed:"
<< QUOTE_W_SPACE_DOT(ex.message());
feed->setStatus(Feed::Status::OtherError);
*error_during_obtaining = true;
continue;
}
}
if (!feed->postProcessScript().simplified().isEmpty()) {
qDebugNN << LOGSEC_CORE
<< "We will process feed data with post-process script"
<< QUOTE_W_SPACE_DOT(feed->postProcessScript());
try {
formatted_feed_contents = StandardFeed::postProcessFeedFileWithScript(feed->postProcessScript(),
formatted_feed_contents,
download_timeout);
}
catch (const ScriptException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Post-processing script for feed file failed:"
<< QUOTE_W_SPACE_DOT(ex.message());
feed->setStatus(Feed::Status::OtherError);
*error_during_obtaining = true;
continue;
}
}
// Feed data are downloaded and encoded.
// Parse data and obtain messages.
QList<Message> messages;
switch (feed->type()) {
case StandardFeed::Type::Rss0X:
case StandardFeed::Type::Rss2X:
messages = RssParser(formatted_feed_contents).messages();
break;
case StandardFeed::Type::Rdf:
messages = RdfParser().parseXmlData(formatted_feed_contents);
break;
case StandardFeed::Type::Atom10:
messages = AtomParser(formatted_feed_contents).messages();
break;
case StandardFeed::Type::Json:
messages = JsonParser(formatted_feed_contents).messages();
break;
default:
break;
}
msgs << messages;
}
return msgs;
}
void StandardServiceRoot::checkArgumentsForFeedAdding() {
for (const QString& arg : qApp->arguments().mid(1)) {
checkArgumentForFeedAdding(arg);

View File

@ -34,6 +34,8 @@ class StandardServiceRoot : public ServiceRoot {
Qt::ItemFlags additionalFlags() const;
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining);
// Returns menu to be shown in "Services -> service" menu.
QList<QAction*> serviceMenu();

View File

@ -39,38 +39,6 @@ bool TtRssFeed::deleteViaGui() {
}
}
QList<Message> TtRssFeed::obtainNewMessages(bool* error_during_obtaining) {
QList<Message> messages;
int newly_added_messages = 0;
int limit = TTRSS_MAX_MESSAGES;
int skip = 0;
do {
TtRssGetHeadlinesResponse headlines = serviceRoot()->network()->getHeadlines(customId().toInt(), limit, skip,
true, true, false,
serviceRoot()->network()->downloadOnlyUnreadMessages(),
getParentServiceRoot()->networkProxy());
if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) {
setStatus(Feed::Status::NetworkError);
*error_during_obtaining = true;
serviceRoot()->itemChanged(QList<RootItem*>() << this);
return QList<Message>();
}
else {
QList<Message> new_messages = headlines.messages(getParentServiceRoot());
messages.append(new_messages);
newly_added_messages = new_messages.size();
skip += newly_added_messages;
}
}
while (newly_added_messages > 0);
*error_during_obtaining = false;
return messages;
}
bool TtRssFeed::removeItself() {
QSqlDatabase database = qApp->database()->connection(metaObject()->className());

View File

@ -13,13 +13,11 @@ class TtRssFeed : public Feed {
public:
explicit TtRssFeed(RootItem* parent = nullptr);
TtRssServiceRoot* serviceRoot() const;
virtual bool canBeDeleted() const;
virtual bool deleteViaGui();
virtual QList<Message> obtainNewMessages(bool* error_during_obtaining);
private:
TtRssServiceRoot* serviceRoot() const;
bool removeItself();
};

View File

@ -211,6 +211,40 @@ void TtRssServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setDownloadOnlyUnreadMessages(data["download_only_unread"].toBool());
}
QList<Message> TtRssServiceRoot::obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining) {
QList<Message> messages;
for (Feed* feed : feeds) {
int newly_added_messages = 0;
int limit = TTRSS_MAX_MESSAGES;
int skip = 0;
do {
TtRssGetHeadlinesResponse headlines = network()->getHeadlines(customId().toInt(), limit, skip,
true, true, false,
network()->downloadOnlyUnreadMessages(),
networkProxy());
if (network()->lastError() != QNetworkReply::NetworkError::NoError) {
feed->setStatus(Feed::Status::NetworkError);
*error_during_obtaining = true;
itemChanged(QList<RootItem*>() << this);
continue;
}
else {
QList<Message> new_messages = headlines.messages(getParentServiceRoot());
messages << new_messages;
newly_added_messages = new_messages.size();
skip += newly_added_messages;
}
}
while (newly_added_messages > 0);
}
return messages;
}
QString TtRssServiceRoot::additionalTooltip() const {
return tr("Username: %1\nServer: %2\n"
"Last error: %3\nLast login on: %4").arg(m_network->username(),

View File

@ -33,6 +33,7 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds, bool* error_during_obtaining);
// Access to network.
TtRssNetworkFactory* network() const;