diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-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 | 38 | ||||
-rw-r--r-- | lib/events/roommessageevent.h | 27 | ||||
-rw-r--r-- | lib/room.cpp | 11 | ||||
-rw-r--r-- | lib/room.h | 5 | ||||
-rw-r--r-- | quotest/quotest.cpp | 2 |
10 files changed, 128 insertions, 109 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fd5f1dca..df193b94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ list(APPEND lib_SRCS lib/events/stateevent.h lib/events/stateevent.cpp lib/events/simplestateevents.h lib/events/eventcontent.h lib/events/eventcontent.cpp + lib/events/eventrelation.h lib/events/eventrelation.cpp lib/events/roomcreateevent.h lib/events/roomcreateevent.cpp lib/events/roomtombstoneevent.h lib/events/roomtombstoneevent.cpp lib/events/roommessageevent.h lib/events/roommessageevent.cpp @@ -162,7 +163,7 @@ list(APPEND lib_SRCS lib/events/typingevent.h lib/events/typingevent.cpp lib/events/accountdataevents.h lib/events/receiptevent.h lib/events/receiptevent.cpp - lib/events/reactionevent.h lib/events/reactionevent.cpp + lib/events/reactionevent.h lib/events/callinviteevent.h lib/events/callinviteevent.cpp lib/events/callcandidatesevent.h lib/events/callanswerevent.h lib/events/callanswerevent.cpp 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..c07a4f3c 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 @@ -105,10 +105,10 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody, << "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 + // and that its EventRelation structure is not omitted auto* textContent = static_cast<const TextContent*>(content); Q_ASSERT(textContent && textContent->relatesTo.has_value()); - if (textContent->relatesTo->type == RelatesTo::ReplacementTypeId()) { + if (textContent->relatesTo->type == EventRelation::ReplacementType) { auto newContentJson = json.take("m.new_content"_ls).toObject(); newContentJson.insert(BodyKey, plainBody); newContentJson.insert(MsgTypeKey, jsonMsgType); @@ -269,7 +269,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 +278,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 +313,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; diff --git a/lib/room.cpp b/lib/room.cpp index 55efb5b9..ba63f50d 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -996,14 +996,14 @@ Room::findPendingEvent(const QString& txnId) const }); } -const Room::RelatedEvents Room::relatedEvents(const QString& evtId, - const char* relType) const +const Room::RelatedEvents Room::relatedEvents( + const QString& evtId, EventRelation::reltypeid_t relType) const { return d->relations.value({ evtId, relType }); } -const Room::RelatedEvents Room::relatedEvents(const RoomEvent& evt, - const char* relType) const +const Room::RelatedEvents Room::relatedEvents( + const RoomEvent& evt, EventRelation::reltypeid_t relType) const { return relatedEvents(evt.id(), relType); } @@ -2506,8 +2506,7 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction) } if (const auto* reaction = eventCast<ReactionEvent>(oldEvent)) { const auto& targetEvtId = reaction->relation().eventId; - const auto lookupKey = - qMakePair(targetEvtId, EventRelation::Annotation()); + const QPair lookupKey { targetEvtId, EventRelation::AnnotationType }; if (relations.contains(lookupKey)) { relations[lookupKey].removeOne(reaction); emit q->updatedEvent(targetEvtId); @@ -21,6 +21,7 @@ #include "events/roommessageevent.h" #include "events/roomcreateevent.h" #include "events/roomtombstoneevent.h" +#include "events/eventrelation.h" #include <QtCore/QJsonObject> #include <QtGui/QImage> @@ -394,9 +395,9 @@ public: PendingEvents::const_iterator findPendingEvent(const QString& txnId) const; const RelatedEvents relatedEvents(const QString& evtId, - const char* relType) const; + EventRelation::reltypeid_t relType) const; const RelatedEvents relatedEvents(const RoomEvent& evt, - const char* relType) const; + EventRelation::reltypeid_t relType) const; const RoomCreateEvent* creation() const { diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index 5a5642fe..40bc456b 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -381,7 +381,7 @@ TEST_IMPL(sendReaction) if (actualTargetEvtId != targetEvtId) return false; const auto reactions = targetRoom->relatedEvents( - targetEvtId, EventRelation::Annotation()); + targetEvtId, EventRelation::AnnotationType); // It's a test room, assuming no interference there should // be exactly one reaction if (reactions.size() != 1) |