initial work on supporting embedded categories/labels in feeds/entries

This commit is contained in:
Martin Rotter 2023-06-06 07:35:07 +02:00
parent ff7e527399
commit f925bf3a77
9 changed files with 101 additions and 9 deletions

View File

@ -65,6 +65,7 @@ QString Enclosures::encodeEnclosuresToString(const QList<Enclosure>& enclosures)
Message::Message() { Message::Message() {
m_title = m_url = m_author = m_contents = m_rawContents = m_feedId = m_customId = m_customHash = QL1S(""); m_title = m_url = m_author = m_contents = m_rawContents = m_feedId = m_customId = m_customHash = QL1S("");
m_enclosures = QList<Enclosure>(); m_enclosures = QList<Enclosure>();
m_categories = QList<MessageCategory>();
m_accountId = m_id = 0; m_accountId = m_id = 0;
m_score = 0.0; m_score = 0.0;
m_isRead = m_isImportant = m_isDeleted = false; m_isRead = m_isImportant = m_isDeleted = false;
@ -209,3 +210,13 @@ uint qHash(const Message& key, uint seed) {
uint qHash(const Message& key) { uint qHash(const Message& key) {
return (uint(key.m_accountId) * 10000) + uint(key.m_id); return (uint(key.m_accountId) * 10000) + uint(key.m_id);
} }
MessageCategory::MessageCategory(const QString& title) : QObject(), m_title(title) {}
MessageCategory::MessageCategory(const MessageCategory& other) {
m_title = other.m_title;
}
QString MessageCategory::title() const {
return m_title;
}

View File

@ -31,6 +31,22 @@ class RSSGUARD_DLLSPEC Enclosures {
class Feed; class Feed;
// Represents RSS, JSON or ATOM category (or tag, label - depending on terminology of each entry.
class RSSGUARD_DLLSPEC MessageCategory : public QObject {
Q_OBJECT
Q_PROPERTY(QString title READ title)
public:
explicit MessageCategory(const QString& title);
MessageCategory(const MessageCategory& other);
QString title() const;
private:
QString m_title;
};
// Represents single message. // Represents single message.
class RSSGUARD_DLLSPEC Message { class RSSGUARD_DLLSPEC Message {
public: public:
@ -64,6 +80,10 @@ class RSSGUARD_DLLSPEC Message {
double m_score; double m_score;
QList<Enclosure> m_enclosures; QList<Enclosure> m_enclosures;
// List of assigned labels.
// This field is only field when fetching entries of a feed.
QList<MessageCategory> m_categories;
// List of custom IDs of labels assigned to this message. // List of custom IDs of labels assigned to this message.
QList<Label*> m_assignedLabels; QList<Label*> m_assignedLabels;

View File

@ -8,6 +8,7 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "services/abstract/labelsnode.h" #include "services/abstract/labelsnode.h"
#include <QRandomGenerator>
#include <QSqlDatabase> #include <QSqlDatabase>
#include <QSqlError> #include <QSqlError>
#include <QSqlQuery> #include <QSqlQuery>
@ -168,7 +169,7 @@ QString MessageObject::findLabelId(const QString& label_title) const {
return found_lbl != nullptr ? found_lbl->customId() : QString(); return found_lbl != nullptr ? found_lbl->customId() : QString();
} }
QString MessageObject::createLabelId(const QString& title, const QString& hex_color) const { QString MessageObject::createLabelId(const QString& title, const QString& hex_color) {
QString lbl_id = findLabelId(title); QString lbl_id = findLabelId(title);
if (!lbl_id.isEmpty()) { if (!lbl_id.isEmpty()) {
@ -176,13 +177,37 @@ QString MessageObject::createLabelId(const QString& title, const QString& hex_co
return lbl_id; return lbl_id;
} }
if (hex_color.isEmpty()) { if ((m_account->supportedLabelOperations() & ServiceRoot::LabelOperation::Adding) !=
// Generate color. ServiceRoot::LabelOperation::Adding) {
return nullptr; qWarningNN << LOGSEC_CORE << "This account does not support creating labels.";
return nullptr;
} }
// TODO: CONTINUE Label* new_lbl = nullptr;
return nullptr;
try {
auto rnd_color = QRandomGenerator::global()->bounded(0xFFFFFF);
auto rnd_color_name = QSL("#%1").arg(QString::number(rnd_color, 16));
new_lbl = new Label(title, hex_color.isEmpty() ? rnd_color_name : hex_color);
QSqlDatabase db = qApp->database()->driver()->threadSafeConnection(metaObject()->className());
DatabaseQueries::createLabel(db, new_lbl, m_account->accountId());
m_account->requestItemReassignment(new_lbl, m_account->labelsNode());
m_availableLabels.append(new_lbl);
return new_lbl->customId();
}
catch (const ApplicationException& ex) {
qCriticalNN << LOGSEC_CORE << "Cannot create label:" << QUOTE_W_SPACE_DOT(ex.message());
if (new_lbl != nullptr) {
new_lbl->deleteLater();
}
}
return {};
} }
void MessageObject::addEnclosure(const QString& url, const QString& mime_type) const { void MessageObject::addEnclosure(const QString& url, const QString& mime_type) const {
@ -310,6 +335,10 @@ QList<Label*> MessageObject::availableLabels() const {
return m_availableLabels; return m_availableLabels;
} }
QList<MessageCategory> MessageObject::categories() const {
return m_message->m_categories;
}
bool MessageObject::runningFilterWhenFetching() const { bool MessageObject::runningFilterWhenFetching() const {
return m_runningAfterFetching; return m_runningAfterFetching;
} }

View File

@ -10,6 +10,7 @@
class MessageObject : public QObject { class MessageObject : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QList<MessageCategory> categories READ categories)
Q_PROPERTY(QList<Label*> assignedLabels READ assignedLabels) Q_PROPERTY(QList<Label*> assignedLabels READ assignedLabels)
Q_PROPERTY(QList<Label*> availableLabels READ availableLabels) Q_PROPERTY(QList<Label*> availableLabels READ availableLabels)
Q_PROPERTY(QString feedCustomId READ feedCustomId) Q_PROPERTY(QString feedCustomId READ feedCustomId)
@ -93,7 +94,7 @@ class MessageObject : public QObject {
// Returns label custom ID given label title or creates // Returns label custom ID given label title or creates
// the label if it does not exist. // the label if it does not exist.
Q_INVOKABLE QString createLabelId(const QString& title, const QString& hex_color = {}) const; Q_INVOKABLE QString createLabelId(const QString& title, const QString& hex_color = {});
// Add multimedia attachment to the message. // Add multimedia attachment to the message.
Q_INVOKABLE void addEnclosure(const QString& url, const QString& mime_type) const; Q_INVOKABLE void addEnclosure(const QString& url, const QString& mime_type) const;
@ -102,6 +103,8 @@ class MessageObject : public QObject {
QList<Label*> assignedLabels() const; QList<Label*> assignedLabels() const;
QList<Label*> availableLabels() const; QList<Label*> availableLabels() const;
QList<MessageCategory> categories() const;
bool runningFilterWhenFetching() const; bool runningFilterWhenFetching() const;
// Generic Message's properties bindings. // Generic Message's properties bindings.

View File

@ -1015,6 +1015,5 @@ QPair<int, int> ServiceRoot::updateMessages(QList<Message>& messages, Feed* feed
} }
// NOTE: Do not update model items here. We update only once when all feeds are fetched. // NOTE: Do not update model items here. We update only once when all feeds are fetched.
return updated_messages; return updated_messages;
} }

View File

@ -128,3 +128,18 @@ QList<Enclosure> AtomParser::xmlMessageEnclosures(const QDomElement& msg_element
return enclosures; return enclosures;
} }
QList<MessageCategory> AtomParser::xmlMessageCategories(const QDomElement& msg_element) const {
QList<MessageCategory> cats;
QDomNodeList elem_cats = msg_element.toElement().elementsByTagNameNS(m_atomNamespace, QSL("category"));
for (int i = 0; i < elem_cats.size(); i++) {
QDomElement cat = elem_cats.at(i).toElement();
QString lbl = cat.attribute(QSL("label"));
QString term = cat.attribute(QSL("term"));
cats.append(MessageCategory(lbl.isEmpty() ? term : lbl));
}
return cats;
}

View File

@ -23,6 +23,7 @@ class AtomParser : public FeedParser {
virtual QString xmlMessageId(const QDomElement& msg_element) const; virtual QString xmlMessageId(const QDomElement& msg_element) const;
virtual QString xmlMessageUrl(const QDomElement& msg_element) const; virtual QString xmlMessageUrl(const QDomElement& msg_element) const;
virtual QList<Enclosure> xmlMessageEnclosures(const QDomElement& msg_element) const; virtual QList<Enclosure> xmlMessageEnclosures(const QDomElement& msg_element) const;
virtual QList<MessageCategory> xmlMessageCategories(const QDomElement& msg_element) const;
virtual QDomNodeList xmlMessageElements(); virtual QDomNodeList xmlMessageElements();
virtual QString xmlMessageAuthor(const QDomElement& msg_element) const; virtual QString xmlMessageAuthor(const QDomElement& msg_element) const;
virtual QString feedAuthor() const; virtual QString feedAuthor() const;

View File

@ -76,6 +76,10 @@ QList<Enclosure> FeedParser::jsonMessageEnclosures(const QJsonObject& msg_elemen
return {}; return {};
} }
QList<MessageCategory> FeedParser::jsonMessageCategories(const QJsonObject& msg_element) const {
return {};
}
QString FeedParser::jsonMessageRawContents(const QJsonObject& msg_element) const { QString FeedParser::jsonMessageRawContents(const QJsonObject& msg_element) const {
return {}; return {};
} }
@ -105,6 +109,7 @@ QList<Message> FeedParser::messages() {
new_message.m_rawContents = xmlMessageRawContents(message_item); new_message.m_rawContents = xmlMessageRawContents(message_item);
new_message.m_enclosures = xmlMessageEnclosures(message_item); new_message.m_enclosures = xmlMessageEnclosures(message_item);
new_message.m_enclosures.append(xmlMrssGetEnclosures(message_item)); new_message.m_enclosures.append(xmlMrssGetEnclosures(message_item));
new_message.m_categories.append(xmlMessageCategories(message_item));
messages.append(new_message); messages.append(new_message);
} }
@ -322,3 +327,7 @@ QString FeedParser::xmlMessageId(const QDomElement& msg_element) const {
QList<Enclosure> FeedParser::xmlMessageEnclosures(const QDomElement& msg_element) const { QList<Enclosure> FeedParser::xmlMessageEnclosures(const QDomElement& msg_element) const {
return {}; return {};
} }
QList<MessageCategory> FeedParser::xmlMessageCategories(const QDomElement& msg_element) const {
return {};
}

View File

@ -30,6 +30,7 @@ class FeedParser {
virtual QDateTime xmlMessageDateCreated(const QDomElement& msg_element) const; virtual QDateTime xmlMessageDateCreated(const QDomElement& msg_element) const;
virtual QString xmlMessageId(const QDomElement& msg_element) const; virtual QString xmlMessageId(const QDomElement& msg_element) const;
virtual QList<Enclosure> xmlMessageEnclosures(const QDomElement& msg_element) const; virtual QList<Enclosure> xmlMessageEnclosures(const QDomElement& msg_element) const;
virtual QList<MessageCategory> xmlMessageCategories(const QDomElement& msg_element) const;
virtual QString xmlMessageRawContents(const QDomElement& msg_element) const; virtual QString xmlMessageRawContents(const QDomElement& msg_element) const;
// JSON. // JSON.
@ -41,13 +42,17 @@ class FeedParser {
virtual QDateTime jsonMessageDateCreated(const QJsonObject& msg_element) const; virtual QDateTime jsonMessageDateCreated(const QJsonObject& msg_element) const;
virtual QString jsonMessageId(const QJsonObject& msg_element) const; virtual QString jsonMessageId(const QJsonObject& msg_element) const;
virtual QList<Enclosure> jsonMessageEnclosures(const QJsonObject& msg_element) const; virtual QList<Enclosure> jsonMessageEnclosures(const QJsonObject& msg_element) const;
virtual QList<MessageCategory> jsonMessageCategories(const QJsonObject& msg_element) const;
virtual QString jsonMessageRawContents(const QJsonObject& msg_element) const; virtual QString jsonMessageRawContents(const QJsonObject& msg_element) const;
protected: protected:
QList<Enclosure> xmlMrssGetEnclosures(const QDomElement& msg_element) const; QList<Enclosure> xmlMrssGetEnclosures(const QDomElement& msg_element) const;
QString xmlMrssTextFromPath(const QDomElement& msg_element, const QString& xml_path) const; QString xmlMrssTextFromPath(const QDomElement& msg_element, const QString& xml_path) const;
QString xmlRawChild(const QDomElement& container) const; QString xmlRawChild(const QDomElement& container) const;
QStringList xmlTextsFromPath(const QDomElement& element, const QString& namespace_uri, const QString& xml_path, bool only_first) const; QStringList xmlTextsFromPath(const QDomElement& element,
const QString& namespace_uri,
const QString& xml_path,
bool only_first) const;
protected: protected:
bool m_isXml; bool m_isXml;