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() {
m_title = m_url = m_author = m_contents = m_rawContents = m_feedId = m_customId = m_customHash = QL1S("");
m_enclosures = QList<Enclosure>();
m_categories = QList<MessageCategory>();
m_accountId = m_id = 0;
m_score = 0.0;
m_isRead = m_isImportant = m_isDeleted = false;
@ -209,3 +210,13 @@ uint qHash(const Message& key, uint seed) {
uint qHash(const Message& key) {
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;
// 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.
class RSSGUARD_DLLSPEC Message {
public:
@ -64,6 +80,10 @@ class RSSGUARD_DLLSPEC Message {
double m_score;
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.
QList<Label*> m_assignedLabels;

View File

@ -8,6 +8,7 @@
#include "definitions/definitions.h"
#include "services/abstract/labelsnode.h"
#include <QRandomGenerator>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
@ -168,7 +169,7 @@ QString MessageObject::findLabelId(const QString& label_title) const {
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);
if (!lbl_id.isEmpty()) {
@ -176,13 +177,37 @@ QString MessageObject::createLabelId(const QString& title, const QString& hex_co
return lbl_id;
}
if (hex_color.isEmpty()) {
// Generate color.
return nullptr;
if ((m_account->supportedLabelOperations() & ServiceRoot::LabelOperation::Adding) !=
ServiceRoot::LabelOperation::Adding) {
qWarningNN << LOGSEC_CORE << "This account does not support creating labels.";
return nullptr;
}
// TODO: CONTINUE
return nullptr;
Label* new_lbl = 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 {
@ -310,6 +335,10 @@ QList<Label*> MessageObject::availableLabels() const {
return m_availableLabels;
}
QList<MessageCategory> MessageObject::categories() const {
return m_message->m_categories;
}
bool MessageObject::runningFilterWhenFetching() const {
return m_runningAfterFetching;
}

View File

@ -10,6 +10,7 @@
class MessageObject : public QObject {
Q_OBJECT
Q_PROPERTY(QList<MessageCategory> categories READ categories)
Q_PROPERTY(QList<Label*> assignedLabels READ assignedLabels)
Q_PROPERTY(QList<Label*> availableLabels READ availableLabels)
Q_PROPERTY(QString feedCustomId READ feedCustomId)
@ -93,7 +94,7 @@ class MessageObject : public QObject {
// Returns label custom ID given label title or creates
// 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.
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*> availableLabels() const;
QList<MessageCategory> categories() const;
bool runningFilterWhenFetching() const;
// 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.
return updated_messages;
}

View File

@ -128,3 +128,18 @@ QList<Enclosure> AtomParser::xmlMessageEnclosures(const QDomElement& msg_element
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 xmlMessageUrl(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 QString xmlMessageAuthor(const QDomElement& msg_element) const;
virtual QString feedAuthor() const;

View File

@ -76,6 +76,10 @@ QList<Enclosure> FeedParser::jsonMessageEnclosures(const QJsonObject& msg_elemen
return {};
}
QList<MessageCategory> FeedParser::jsonMessageCategories(const QJsonObject& msg_element) const {
return {};
}
QString FeedParser::jsonMessageRawContents(const QJsonObject& msg_element) const {
return {};
}
@ -105,6 +109,7 @@ QList<Message> FeedParser::messages() {
new_message.m_rawContents = xmlMessageRawContents(message_item);
new_message.m_enclosures = xmlMessageEnclosures(message_item);
new_message.m_enclosures.append(xmlMrssGetEnclosures(message_item));
new_message.m_categories.append(xmlMessageCategories(message_item));
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 {
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 QString xmlMessageId(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;
// JSON.
@ -41,13 +42,17 @@ class FeedParser {
virtual QDateTime jsonMessageDateCreated(const QJsonObject& msg_element) const;
virtual QString jsonMessageId(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;
protected:
QList<Enclosure> xmlMrssGetEnclosures(const QDomElement& msg_element) const;
QString xmlMrssTextFromPath(const QDomElement& msg_element, const QString& xml_path) 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:
bool m_isXml;