From 4a8dc2a16ab29126337ee80615ea9d7c24653a1e Mon Sep 17 00:00:00 2001 From: James Graham Date: Sat, 21 Sep 2024 09:32:47 +0100 Subject: [PATCH] Move the EventRelation out of TextContent and into RoomMessageEvent as any message can now be replied to. --- Quotient/events/eventrelation.cpp | 6 +- Quotient/events/roommessageevent.cpp | 84 ++++++++++++---------------- Quotient/events/roommessageevent.h | 16 +++--- 3 files changed, 47 insertions(+), 59 deletions(-) diff --git a/Quotient/events/eventrelation.cpp b/Quotient/events/eventrelation.cpp index 357498bc..fa600a0f 100644 --- a/Quotient/events/eventrelation.cpp +++ b/Quotient/events/eventrelation.cpp @@ -17,7 +17,7 @@ void JsonObjectConverter::dumpTo(QJsonObject& jo, } if (pod.type == EventRelation::ReplyType) { - jo.insert(EventRelation::ReplyType, {{EventIdKey, pod.eventId}}); + jo.insert(EventRelation::ReplyType, {QJsonObject{{EventIdKey, pod.eventId}}}); return; } @@ -26,9 +26,9 @@ void JsonObjectConverter::dumpTo(QJsonObject& jo, if (pod.type == EventRelation::AnnotationType) jo.insert("key"_L1, pod.key); if (pod.type == EventRelation::ThreadType) { - jo.insert(EventRelation::ReplyType, {{EventIdKey, pod.inThreadReplyEventId}}); + jo.insert(EventRelation::ReplyType, {QJsonObject{{EventIdKey, pod.inThreadReplyEventId}}}); + jo.insert(IsFallingBackKey, pod.isFallingBack); } - jo.insert(IsFallingBackKey, pod.isFallingBack); } void JsonObjectConverter::fillFrom(const QJsonObject& jo, diff --git a/Quotient/events/roommessageevent.cpp b/Quotient/events/roommessageevent.cpp index b35bd962..876936e2 100644 --- a/Quotient/events/roommessageevent.cpp +++ b/Quotient/events/roommessageevent.cpp @@ -6,7 +6,9 @@ #include "roommessageevent.h" #include "../logging_categories_p.h" +#include #include "eventrelation.h" +#include #include #include @@ -86,49 +88,47 @@ inline bool isReplacement(const std::optional& rel) QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody, const QString& jsonMsgType, - TypedBase* content) + TypedBase* content, + std::optional relatesTo) { QJsonObject json; if (content) { // TODO: replace with content->fillJson(json) when it starts working json = content->toJson(); - if (jsonMsgType != TextTypeKey && jsonMsgType != NoticeTypeKey - && jsonMsgType != EmoteTypeKey) { - if (json.contains(RelatesToKey)) { - json.remove(RelatesToKey); - qCWarning(EVENTS) - << RelatesToKey << "cannot be used in" << jsonMsgType - << "messages; the relation has been stripped off"; + } + json.insert(MsgTypeKey, jsonMsgType); + json.insert(BodyKey, plainBody); + if (relatesTo.has_value()) { + json.insert(RelatesToKey, toJson(relatesTo.value())); + // JsonObjectConverter::dumpTo(json, relatesTo.value()); + if (auto* textContent = static_cast(content); relatesTo->type == EventRelation::ReplacementType) { + QJsonObject newContentJson; + if (content && textContent->mimeType.inherits("text/html"_L1)) { + newContentJson.insert("format"_L1, HtmlContentTypeId); + newContentJson.insert(FormattedBodyKey, textContent->body); } - } else if (auto* textContent = static_cast(content); - textContent->relatesTo - && textContent->relatesTo->type - == EventRelation::ReplacementType) { - auto newContentJson = json.take("m.new_content"_L1).toObject(); newContentJson.insert(BodyKey, plainBody); newContentJson.insert(MsgTypeKey, jsonMsgType); json.insert("m.new_content"_L1, newContentJson); - json[MsgTypeKey] = jsonMsgType; - json[BodyKey] = "* "_L1 + plainBody; - return json; + json.insert(BodyKey, "* "_L1 + plainBody); } } - json.insert(MsgTypeKey, jsonMsgType); - json.insert(BodyKey, plainBody); return json; } RoomMessageEvent::RoomMessageEvent(const QString& plainBody, const QString& jsonMsgType, - TypedBase* content) + TypedBase* content, + std::optional relatesTo) : RoomEvent( - basicJson(TypeId, assembleContentJson(plainBody, jsonMsgType, content))) + basicJson(TypeId, assembleContentJson(plainBody, jsonMsgType, content, relatesTo))) , _content(content) + , _relatesTo(relatesTo) {} RoomMessageEvent::RoomMessageEvent(const QString& plainBody, MsgType msgType, - TypedBase* content) - : RoomMessageEvent(plainBody, msgTypeToJson(msgType), content) + TypedBase* content, std::optional relatesTo) + : RoomMessageEvent(plainBody, msgTypeToJson(msgType), content, relatesTo) {} RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj) @@ -140,16 +140,22 @@ RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj) if (content.contains(MsgTypeKey) && content.contains(BodyKey)) { auto msgtype = content[MsgTypeKey].toString(); bool msgTypeFound = false; - for (const auto& mt : msgTypes) + for (const auto& mt : msgTypes) { if (mt.matrixType == msgtype) { _content = mt.maker(content); msgTypeFound = true; } + } if (!msgTypeFound) { qCWarning(EVENTS) << "RoomMessageEvent: unknown msg_type," << " full content dump follows"; qCWarning(EVENTS) << formatJson << content; + return; + } + + if (content.contains(RelatesToKey)) { + _relatesTo = fromJson>(content[RelatesToKey]); } } else { qCWarning(EVENTS) << "No body or msgtype in room message event"; @@ -198,7 +204,7 @@ bool RoomMessageEvent::hasThumbnail() const std::optional RoomMessageEvent::relatesTo() const { - return content() && hasTextContent() ? static_cast(content())->relatesTo : std::nullopt; + return _relatesTo; } QString RoomMessageEvent::upstreamEventId() const @@ -212,8 +218,7 @@ QString RoomMessageEvent::replacedEvent() const if (!content() || !hasTextContent()) return {}; - const auto& rel = static_cast(content())->relatesTo; - return isReplacement(rel) ? rel->eventId : QString(); + return isReplacement(_relatesTo) ? _relatesTo->eventId : QString(); } bool RoomMessageEvent::isReplaced() const @@ -320,23 +325,22 @@ QString RoomMessageEvent::rawMsgTypeForFile(const QFileInfo& fi) return rawMsgTypeForMimeType(QMimeDatabase().mimeTypeForFile(fi)); } -TextContent::TextContent(QString text, const QString& contentType, - std::optional relatesTo) +TextContent::TextContent(QString text, const QString& contentType) : mimeType(QMimeDatabase().mimeTypeForName(contentType)) , body(std::move(text)) - , relatesTo(std::move(relatesTo)) { if (contentType == HtmlContentTypeId) mimeType = QMimeDatabase().mimeTypeForName("text/html"_L1); } TextContent::TextContent(const QJsonObject& json) - : relatesTo(fromJson>(json[RelatesToKey])) { QMimeDatabase db; static const auto PlainTextMimeType = db.mimeTypeForName("text/plain"_L1); static const auto HtmlMimeType = db.mimeTypeForName("text/html"_L1); + const auto relatesTo = fromJson>(json[RelatesToKey]); + const auto actualJson = isReplacement(relatesTo) ? json.value("m.new_content"_L1).toObject() : json; @@ -355,28 +359,10 @@ TextContent::TextContent(const QJsonObject& json) void TextContent::fillJson(QJsonObject &json) const { - static const auto FormatKey = "format"_L1; - if (mimeType.inherits("text/html"_L1)) { - json.insert(FormatKey, HtmlContentTypeId); + json.insert("format"_L1, HtmlContentTypeId); json.insert(FormattedBodyKey, body); } - if (relatesTo) { - json.insert("m.relates_to"_L1, - relatesTo->type == EventRelation::ReplyType - ? QJsonObject{ { relatesTo->type, - QJsonObject{ { EventIdKey, relatesTo->eventId } } } } - : QJsonObject{ { RelTypeKey, relatesTo->type }, - { EventIdKey, relatesTo->eventId } }); - if (relatesTo->type == EventRelation::ReplacementType) { - QJsonObject newContentJson; - if (mimeType.inherits("text/html"_L1)) { - newContentJson.insert(FormatKey, HtmlContentTypeId); - newContentJson.insert(FormattedBodyKey, body); - } - json.insert("m.new_content"_L1, newContentJson); - } - } } LocationContent::LocationContent(const QString& geoUri, diff --git a/Quotient/events/roommessageevent.h b/Quotient/events/roommessageevent.h index c3e94782..97c56013 100644 --- a/Quotient/events/roommessageevent.h +++ b/Quotient/events/roommessageevent.h @@ -34,10 +34,12 @@ class QUOTIENT_API RoomMessageEvent : public RoomEvent { }; RoomMessageEvent(const QString& plainBody, const QString& jsonMsgType, - EventContent::TypedBase* content = nullptr); + EventContent::TypedBase* content = nullptr, + std::optional relatesTo = std:: nullopt); explicit RoomMessageEvent(const QString& plainBody, MsgType msgType = MsgType::Text, - EventContent::TypedBase* content = nullptr); + EventContent::TypedBase* content = nullptr, + std::optional relatesTo = std:: nullopt); explicit RoomMessageEvent(const QJsonObject& obj); @@ -48,7 +50,7 @@ class QUOTIENT_API RoomMessageEvent : public RoomEvent { void editContent(auto visitor) { visitor(*_content); - editJson()[ContentKey] = assembleContentJson(plainBody(), rawMsgtype(), _content.get()); + editJson()[ContentKey] = assembleContentJson(plainBody(), rawMsgtype(), _content.get(), _relatesTo); } QMimeType mimeType() const; //! \brief Determine whether the message has text content @@ -141,11 +143,13 @@ class QUOTIENT_API RoomMessageEvent : public RoomEvent { private: std::unique_ptr _content; + std::optional _relatesTo; // FIXME: should it really be static? static QJsonObject assembleContentJson(const QString& plainBody, const QString& jsonMsgType, - EventContent::TypedBase* content); + EventContent::TypedBase* content, + std::optional relatesTo); Q_ENUM(MsgType) }; @@ -164,15 +168,13 @@ namespace EventContent { */ class QUOTIENT_API TextContent : public TypedBase { public: - TextContent(QString text, const QString& contentType, - std::optional relatesTo = {}); + TextContent(QString text, const QString& contentType); explicit TextContent(const QJsonObject& json); QMimeType type() const override { return mimeType; } QMimeType mimeType; QString body; - std::optional relatesTo; protected: void fillJson(QJsonObject& json) const override;