Added support older RSS formats and ATOM. Moreover, message SQL updates are now done in transactions.

This commit is contained in:
Martin Rotter 2013-12-27 14:48:16 +01:00
parent b4d60e01f1
commit c04805a6f7
8 changed files with 104 additions and 15 deletions

View file

@ -68,12 +68,12 @@ INSERT INTO Categories (id, parent_id, title, description, date_created, type) V
-- !
INSERT INTO Categories (id, parent_id, title, description, date_created, type) VALUES (2, -1, 'RSS Guard', 'News and updates on RSS Guard.', '2013-12-20T08:00:00-05:00', 0);
-- !
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Linux Today', 'Linux Today - Linux News on Internet Time.', '2013-12-20T08:00:00-05:00', 1, 'UTF-8', 'http://feeds.feedburner.com/linuxtoday/linux?format=xml', 2);
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Linux Today', 'Linux Today - Linux News on Internet Time.', '2013-12-20T08:00:00-05:00', 1, 'UTF-8', 'http://feeds.feedburner.com/linuxtoday/linux?format=xml', 1);
-- !
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('LinuxInsider', 'LinuxInsider: Linux News & Information from Around the World.', '2013-12-20T08:00:00-05:00', 1, 'UTF-8', 'http://www.linuxinsider.com/perl/syndication/rssfull.pl', 3);
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('LinuxInsider', 'LinuxInsider: Linux News & Information from Around the World.', '2013-12-20T08:00:00-05:00', 1, 'UTF-8', 'http://www.linuxinsider.com/perl/syndication/rssfull.pl', 2);
-- !
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Recent Commits', 'Recent commits for RSS Guard project.', '2013-12-20T08:00:00-05:00', 2, 'UTF-8', 'https://github.com/martinrotter/rssguard/commits/master.atom', 4);
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Recent Commits', 'Recent commits for RSS Guard project.', '2013-12-20T08:00:00-05:00', 2, 'UTF-8', 'https://github.com/martinrotter/rssguard/commits/master.atom', 3);
-- !
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Releases', 'Releases for RSS Guard.', '2013-12-20T08:00:00-05:00', 2, 'UTF-8', 'https://github.com/martinrotter/rssguard/releases.atom', 4);
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Releases', 'Releases for RSS Guard.', '2013-12-20T08:00:00-05:00', 2, 'UTF-8', 'https://github.com/martinrotter/rssguard/releases.atom', 3);
-- !
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Author''s Activity', 'RSS Guard author public activity overview.', '2013-12-20T08:00:00-05:00', 2, 'UTF-8', 'https://github.com/martinrotter.atom', 4);
INSERT INTO Feeds (title, description, date_created, category, encoding, url, type) VALUES ('Author''s Activity', 'RSS Guard author public activity overview.', '2013-12-20T08:00:00-05:00', 2, 'UTF-8', 'https://github.com/martinrotter.atom', 3);

View file

@ -99,7 +99,7 @@ QSqlDatabase DatabaseFactory::initialize(const QString &connection_name) {
QStringList statements = QString(file_init.readAll()).split(APP_DB_INIT_SPLIT,
QString::SkipEmptyParts);
query_db.exec("BEGIN TRANSACTION");
database.transaction();
foreach(const QString &statement, statements) {
query_db.exec(statement);
@ -110,7 +110,7 @@ QSqlDatabase DatabaseFactory::initialize(const QString &connection_name) {
}
}
query_db.exec("COMMIT");
database.commit();
qDebug("Database backend should be ready now.");
}
else {

View file

@ -255,10 +255,9 @@ void FeedsModel::loadFromDatabase() {
FeedsModelFeed::Type type = static_cast<FeedsModelFeed::Type>(query_feeds.value(FDS_DB_TYPE_INDEX).toInt());
switch (type) {
case FeedsModelFeed::StandardAtom:
case FeedsModelFeed::StandardAtom10:
case FeedsModelFeed::StandardRdf:
case FeedsModelFeed::StandardRss0X:
case FeedsModelFeed::StandardRss1X:
case FeedsModelFeed::StandardRss2X: {
FeedAssignmentItem pair;
pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt();

View file

@ -50,7 +50,7 @@ void FeedsModelFeed::setType(const Type &type) {
QString FeedsModelFeed::typeToString(FeedsModelFeed::Type type) {
switch (type) {
case StandardAtom:
case StandardAtom10:
return QObject::tr("ATOM 1.0");
case StandardRdf:

View file

@ -12,10 +12,9 @@ class FeedsModelFeed : public FeedsModelRootItem {
// NOTE: This is equivalent to attribute Feeds(type).
enum Type {
StandardRss0X = 0,
StandardRss1X = 1,
StandardRss2X = 2,
StandardRdf = 3,
StandardAtom = 4
StandardRss2X = 1,
StandardRdf = 2,
StandardAtom10 = 3
};
// Constructors and destructors.
@ -44,6 +43,7 @@ class FeedsModelFeed : public FeedsModelRootItem {
Type type() const;
void setType(const Type &type);
// Converts particular feed type to string.
static QString typeToString(Type type);
public slots:

View file

@ -182,6 +182,7 @@ void FeedsModelStandardFeed::update() {
QList<Message> messages;
switch (type()) {
case FeedsModelFeed::StandardRss0X:
case FeedsModelFeed::StandardRss2X:
messages = ParsingFactory::parseAsRSS20(formatted_feed_contents);
break;
@ -190,6 +191,9 @@ void FeedsModelStandardFeed::update() {
messages = ParsingFactory::parseAsRDF(formatted_feed_contents);
break;
case FeedsModelFeed::StandardAtom10:
messages = ParsingFactory::parseAsATOM10(formatted_feed_contents);
// TODO: Add support for other standard formats.
default:
@ -214,6 +218,13 @@ void FeedsModelStandardFeed::updateMessages(const QList<Message> &messages) {
"(feed, title, url, author, date_created, contents) "
"VALUES (:feed, :title, :url, :author, :date_created, :contents);");
if (!database.transaction()) {
database.rollback();
qDebug("Transaction start for message downloader failed.");
return;
}
foreach (const Message &message, messages) {
query_select.bindValue(":feed", feed_id);
query_select.bindValue(":title", message.m_title);
@ -248,4 +259,10 @@ void FeedsModelStandardFeed::updateMessages(const QList<Message> &messages) {
// online feed.
}
}
if (!database.commit()) {
database.rollback();
qDebug("Transaction commit for message downloader failed.");
}
}

View file

@ -145,6 +145,11 @@ QVariant MessagesModel::data(const QModelIndex &index, int role) const {
return TextFactory::parseDateTime(QSqlTableModel::data(index,
role).toString()).toString(Qt::DefaultLocaleShortDate);
}
else if (index_column == MSG_DB_AUTHOR_INDEX) {
QString author_name = QSqlTableModel::data(index, role).toString();
return author_name.isEmpty() ? "-" : author_name;
}
else if (index_column != MSG_DB_IMPORTANT_INDEX &&
index_column != MSG_DB_READ_INDEX) {
return QSqlTableModel::data(index, role);

View file

@ -11,7 +11,75 @@ ParsingFactory::ParsingFactory() {
QList<Message> ParsingFactory::parseAsATOM10(const QString &data) {
// TODO: Implement this.
return QList<Message>();
QList<Message> messages;
QDomDocument xml_file;
QDateTime current_time = QDateTime::currentDateTime();
xml_file.setContent(data, true);
// Pull out all messages.
QDomNodeList messages_in_xml = xml_file.elementsByTagName("entry");
for (int i = 0; i < messages_in_xml.size(); i++) {
QDomNode message_item = messages_in_xml.item(i);
Message new_message;
// Deal with titles & descriptions.
QString elem_title = message_item.namedItem("title").toElement().text().simplified();
QString elem_summary = message_item.namedItem("summary").toElement().text();
if (elem_summary.isEmpty()) {
elem_summary = message_item.namedItem("content").toElement().text();
}
// Now we obtained maximum of informations for title & description.
if (elem_title.isEmpty()) {
if (elem_summary.isEmpty()) {
// BOTH title and description are empty, skip this message.
continue;
}
else {
// Title is empty but description is not.
new_message.m_title = TextFactory::stripTags(elem_summary.simplified());
new_message.m_contents = elem_summary;
}
}
else {
// Title is not empty, description does not matter.
new_message.m_title = TextFactory::stripTags(elem_title);
new_message.m_contents = elem_summary;
}
// Deal with link.
QDomNodeList elem_links = message_item.toElement().elementsByTagName("link");
for (int i = 0; i < elem_links.size(); i++) {
QDomNode elem_link = elem_links.at(i);
if (elem_link.attributes().namedItem("rel").toAttr().value() == "alternate") {
new_message.m_url = elem_link.attributes().namedItem("href").toAttr().value();
break;
}
}
// Deal with authors.
new_message.m_author = TextFactory::escapeHtml(message_item.namedItem("author").namedItem("name").toElement().text());
// Deal with creation date.
new_message.m_created = TextFactory::parseDateTime(message_item.namedItem("updated").toElement().text());
new_message.m_createdFromFeed = !new_message.m_created.isNull();
if (!new_message.m_createdFromFeed) {
// Date was NOT obtained from the feed,
// set current date as creation date for the message.
new_message.m_created = current_time;
}
messages.append(new_message);
}
return messages;
}
QList<Message> ParsingFactory::parseAsRDF(const QString &data) {