diff options
Diffstat (limited to 'lib/events')
-rw-r--r-- | lib/events/eventrelation.cpp | 38 | ||||
-rw-r--r-- | lib/events/eventrelation.h | 52 | ||||
-rw-r--r-- | lib/events/reactionevent.cpp | 29 | ||||
-rw-r--r-- | lib/events/reactionevent.h | 32 | ||||
-rw-r--r-- | lib/events/roommessageevent.cpp | 77 | ||||
-rw-r--r-- | lib/events/roommessageevent.h | 27 |
6 files changed, 137 insertions, 118 deletions
diff --git a/lib/events/eventrelation.cpp b/lib/events/eventrelation.cpp new file mode 100644 index 00000000..04972f45 --- /dev/null +++ b/lib/events/eventrelation.cpp @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2022 Kitsune Ral <kitsune-ral@users.sf.net> +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "eventrelation.h" + +#include "../logging.h" +#include "event.h" + +using namespace Quotient; + +void JsonObjectConverter<EventRelation>::dumpTo(QJsonObject& jo, + const EventRelation& pod) +{ + if (pod.type.isEmpty()) { + qCWarning(MAIN) << "Empty relation type; won't dump to JSON"; + return; + } + jo.insert(RelTypeKey, pod.type); + jo.insert(EventIdKey, pod.eventId); + if (pod.type == EventRelation::AnnotationType) + jo.insert(QStringLiteral("key"), pod.key); +} + +void JsonObjectConverter<EventRelation>::fillFrom(const QJsonObject& jo, + EventRelation& pod) +{ + if (const auto replyJson = jo.value(EventRelation::ReplyType).toObject(); + !replyJson.isEmpty()) { + pod.type = EventRelation::ReplyType; + fromJson(replyJson[EventIdKeyL], pod.eventId); + } else { + // The experimental logic for generic relationships (MSC1849) + fromJson(jo[RelTypeKey], pod.type); + fromJson(jo[EventIdKeyL], pod.eventId); + if (pod.type == EventRelation::AnnotationType) + fromJson(jo["key"_ls], pod.key); + } +} diff --git a/lib/events/eventrelation.h b/lib/events/eventrelation.h new file mode 100644 index 00000000..e445ee42 --- /dev/null +++ b/lib/events/eventrelation.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2022 Kitsune Ral <kitsune-ral@users.sf.net> +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include "converters.h" + +namespace Quotient { + +[[maybe_unused]] constexpr auto RelatesToKey = "m.relates_to"_ls; +constexpr auto RelTypeKey = "rel_type"_ls; + +struct QUOTIENT_API EventRelation { + using reltypeid_t = QLatin1String; + + QString type; + QString eventId; + QString key = {}; // Only used for m.annotation for now + + static constexpr auto ReplyType = "m.in_reply_to"_ls; + static constexpr auto AnnotationType = "m.annotation"_ls; + static constexpr auto ReplacementType = "m.replace"_ls; + + static EventRelation replyTo(QString eventId) + { + return { ReplyType, std::move(eventId) }; + } + static EventRelation annotate(QString eventId, QString key) + { + return { AnnotationType, std::move(eventId), std::move(key) }; + } + static EventRelation replace(QString eventId) + { + return { ReplacementType, std::move(eventId) }; + } + + [[deprecated("Use ReplyRelation variable instead")]] + static constexpr auto Reply() { return ReplyType; } + [[deprecated("Use AnnotationRelation variable instead")]] // + static constexpr auto Annotation() { return AnnotationType; } + [[deprecated("Use ReplacementRelation variable instead")]] // + static constexpr auto Replacement() { return ReplacementType; } +}; + +template <> +struct QUOTIENT_API JsonObjectConverter<EventRelation> { + static void dumpTo(QJsonObject& jo, const EventRelation& pod); + static void fillFrom(const QJsonObject& jo, EventRelation& pod); +}; + +} + diff --git a/lib/events/reactionevent.cpp b/lib/events/reactionevent.cpp deleted file mode 100644 index b53fffd6..00000000 --- a/lib/events/reactionevent.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2019 Kitsune Ral <kitsune-ral@users.sf.net> -// SPDX-License-Identifier: LGPL-2.1-or-later - -#include "reactionevent.h" - -using namespace Quotient; - -void JsonObjectConverter<EventRelation>::dumpTo( - QJsonObject& jo, const EventRelation& pod) -{ - if (pod.type.isEmpty()) { - qCWarning(MAIN) << "Empty relation type; won't dump to JSON"; - return; - } - jo.insert(QStringLiteral("rel_type"), pod.type); - jo.insert(EventIdKey, pod.eventId); - if (pod.type == EventRelation::Annotation()) - jo.insert(QStringLiteral("key"), pod.key); -} - -void JsonObjectConverter<EventRelation>::fillFrom( - const QJsonObject& jo, EventRelation& pod) -{ - // The experimental logic for generic relationships (MSC1849) - fromJson(jo["rel_type"_ls], pod.type); - fromJson(jo[EventIdKeyL], pod.eventId); - if (pod.type == EventRelation::Annotation()) - fromJson(jo["key"_ls], pod.key); -} diff --git a/lib/events/reactionevent.h b/lib/events/reactionevent.h index ce11eaed..b3cb3ca7 100644 --- a/lib/events/reactionevent.h +++ b/lib/events/reactionevent.h @@ -4,38 +4,10 @@ #pragma once #include "roomevent.h" +#include "eventrelation.h" namespace Quotient { -struct QUOTIENT_API EventRelation { - using reltypeid_t = const char*; - static constexpr reltypeid_t Reply() { return "m.in_reply_to"; } - static constexpr reltypeid_t Annotation() { return "m.annotation"; } - static constexpr reltypeid_t Replacement() { return "m.replace"; } - - QString type; - QString eventId; - QString key = {}; // Only used for m.annotation for now - - static EventRelation replyTo(QString eventId) - { - return { Reply(), std::move(eventId) }; - } - static EventRelation annotate(QString eventId, QString key) - { - return { Annotation(), std::move(eventId), std::move(key) }; - } - static EventRelation replace(QString eventId) - { - return { Replacement(), std::move(eventId) }; - } -}; -template <> -struct QUOTIENT_API JsonObjectConverter<EventRelation> { - static void dumpTo(QJsonObject& jo, const EventRelation& pod); - static void fillFrom(const QJsonObject& jo, EventRelation& pod); -}; - class QUOTIENT_API ReactionEvent : public RoomEvent { public: DEFINE_EVENT_TYPEID("m.reaction", ReactionEvent) @@ -47,7 +19,7 @@ public: explicit ReactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj) {} EventRelation relation() const { - return contentPart<EventRelation>("m.relates_to"_ls); + return contentPart<EventRelation>(RelatesToKey); } }; REGISTER_EVENT_TYPE(ReactionEvent) diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp index 5ab0f845..d63352cb 100644 --- a/lib/events/roommessageevent.cpp +++ b/lib/events/roommessageevent.cpp @@ -6,6 +6,7 @@ #include "roommessageevent.h" #include "logging.h" +#include "events/eventrelation.h" #include <QtCore/QFileInfo> #include <QtCore/QMimeDatabase> @@ -20,7 +21,6 @@ using namespace EventContent; using MsgType = RoomMessageEvent::MsgType; namespace { // Supporting internal definitions - constexpr auto RelatesToKey = "m.relates_to"_ls; constexpr auto MsgTypeKey = "msgtype"_ls; constexpr auto FormattedBodyKey = "formatted_body"_ls; @@ -84,9 +84,9 @@ MsgType jsonToMsgType(const QString& matrixType) return MsgType::Unknown; } -inline bool isReplacement(const Omittable<RelatesTo>& rel) +inline bool isReplacement(const Omittable<EventRelation>& rel) { - return rel && rel->type == RelatesTo::ReplacementTypeId(); + return rel && rel->type == EventRelation::ReplacementType; } } // anonymous namespace @@ -95,32 +95,33 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody, const QString& jsonMsgType, TypedBase* content) { - auto json = content ? content->toJson() : QJsonObject(); - if (json.contains(RelatesToKey)) { + QJsonObject json; + if (content) { + // TODO: replace with content->fillJson(json) when it starts working + json = content->toJson(); if (jsonMsgType != TextTypeKey && jsonMsgType != NoticeTypeKey && jsonMsgType != EmoteTypeKey) { - json.remove(RelatesToKey); - qCWarning(EVENTS) - << RelatesToKey << "cannot be used in" << jsonMsgType - << "messages; the relation has been stripped off"; - } else { - // After the above, we know for sure that the content is TextContent - // and that its RelatesTo structure is not omitted - auto* textContent = static_cast<const TextContent*>(content); - Q_ASSERT(textContent && textContent->relatesTo.has_value()); - if (textContent->relatesTo->type == RelatesTo::ReplacementTypeId()) { - auto newContentJson = json.take("m.new_content"_ls).toObject(); - newContentJson.insert(BodyKey, plainBody); - newContentJson.insert(MsgTypeKey, jsonMsgType); - json.insert(QStringLiteral("m.new_content"), newContentJson); - json[MsgTypeKey] = jsonMsgType; - json[BodyKeyL] = "* " + plainBody; - return json; + if (json.contains(RelatesToKey)) { + json.remove(RelatesToKey); + qCWarning(EVENTS) + << RelatesToKey << "cannot be used in" << jsonMsgType + << "messages; the relation has been stripped off"; } + } else if (auto* textContent = static_cast<const TextContent*>(content); + textContent->relatesTo + && textContent->relatesTo->type + == EventRelation::ReplacementType) { + auto newContentJson = json.take("m.new_content"_ls).toObject(); + newContentJson.insert(BodyKey, plainBody); + newContentJson.insert(MsgTypeKey, jsonMsgType); + json.insert(QStringLiteral("m.new_content"), newContentJson); + json[MsgTypeKey] = jsonMsgType; + json[BodyKeyL] = "* " + plainBody; + return json; } } - json.insert(QStringLiteral("msgtype"), jsonMsgType); - json.insert(QStringLiteral("body"), plainBody); + json.insert(MsgTypeKey, jsonMsgType); + json.insert(BodyKey, plainBody); return json; } @@ -269,7 +270,7 @@ QString RoomMessageEvent::rawMsgTypeForFile(const QFileInfo& fi) } TextContent::TextContent(QString text, const QString& contentType, - Omittable<RelatesTo> relatesTo) + Omittable<EventRelation> relatesTo) : mimeType(QMimeDatabase().mimeTypeForName(contentType)) , body(std::move(text)) , relatesTo(std::move(relatesTo)) @@ -278,26 +279,8 @@ TextContent::TextContent(QString text, const QString& contentType, mimeType = QMimeDatabase().mimeTypeForName("text/html"); } -namespace Quotient { -// Overload the default fromJson<> logic that defined in converters.h -// as we want -template <> -Omittable<RelatesTo> fromJson(const QJsonValue& jv) -{ - const auto jo = jv.toObject(); - if (jo.isEmpty()) - return none; - const auto replyJson = jo.value(RelatesTo::ReplyTypeId()).toObject(); - if (!replyJson.isEmpty()) - return replyTo(fromJson<QString>(replyJson[EventIdKeyL])); - - return RelatesTo { jo.value("rel_type"_ls).toString(), - jo.value(EventIdKeyL).toString() }; -} -} // namespace Quotient - TextContent::TextContent(const QJsonObject& json) - : relatesTo(fromJson<Omittable<RelatesTo>>(json[RelatesToKey])) + : relatesTo(fromJson<Omittable<EventRelation>>(json[RelatesToKey])) { QMimeDatabase db; static const auto PlainTextMimeType = db.mimeTypeForName("text/plain"); @@ -331,13 +314,13 @@ void TextContent::fillJson(QJsonObject* json) const if (relatesTo) { json->insert( QStringLiteral("m.relates_to"), - relatesTo->type == RelatesTo::ReplyTypeId() + relatesTo->type == EventRelation::ReplyType ? QJsonObject { { relatesTo->type, QJsonObject { { EventIdKey, relatesTo->eventId } } } } - : QJsonObject { { "rel_type", relatesTo->type }, + : QJsonObject { { RelTypeKey, relatesTo->type }, { EventIdKey, relatesTo->eventId } }); - if (relatesTo->type == RelatesTo::ReplacementTypeId()) { + if (relatesTo->type == EventRelation::ReplacementType) { QJsonObject newContentJson; if (mimeType.inherits("text/html")) { newContentJson.insert(FormatKey, HtmlContentTypeId); diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h index 0c901b7a..44ef05fb 100644 --- a/lib/events/roommessageevent.h +++ b/lib/events/roommessageevent.h @@ -6,6 +6,7 @@ #pragma once #include "eventcontent.h" +#include "eventrelation.h" #include "roomevent.h" class QFileInfo; @@ -97,23 +98,25 @@ REGISTER_EVENT_TYPE(RoomMessageEvent) using MessageEventType = RoomMessageEvent::MsgType; namespace EventContent { - // Additional event content types - struct RelatesTo { - static constexpr const char* ReplyTypeId() { return "m.in_reply_to"; } - static constexpr const char* ReplacementTypeId() { return "m.replace"; } - QString type; // The only supported relation so far - QString eventId; + struct [[deprecated("Use Quotient::EventRelation instead")]] RelatesTo + : EventRelation { + static constexpr auto ReplyTypeId() { return Reply(); } + static constexpr auto ReplacementTypeId() { return Replacement(); } }; - inline RelatesTo replyTo(QString eventId) + [[deprecated("Use EventRelation::replyTo() instead")]] + inline auto replyTo(QString eventId) { - return { RelatesTo::ReplyTypeId(), std::move(eventId) }; + return EventRelation::replyTo(std::move(eventId)); } - inline RelatesTo replacementOf(QString eventId) + [[deprecated("Use EventRelation::replace() instead")]] + inline auto replacementOf(QString eventId) { - return { RelatesTo::ReplacementTypeId(), std::move(eventId) }; + return EventRelation::replace(std::move(eventId)); } + // Additional event content types + /** * Rich text content for m.text, m.emote, m.notice * @@ -123,14 +126,14 @@ namespace EventContent { class QUOTIENT_API TextContent : public TypedBase { public: TextContent(QString text, const QString& contentType, - Omittable<RelatesTo> relatesTo = none); + Omittable<EventRelation> relatesTo = none); explicit TextContent(const QJsonObject& json); QMimeType type() const override { return mimeType; } QMimeType mimeType; QString body; - Omittable<RelatesTo> relatesTo; + Omittable<EventRelation> relatesTo; protected: void fillJson(QJsonObject* json) const override; |