libQuotient
A Qt library for building matrix clients
Loading...
Searching...
No Matches
roomevent.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include "event.h"
7
9
10#include <QtCore/QDateTime>
11
12namespace Quotient {
13
14constexpr inline auto EventIdKey = "event_id"_L1;
15constexpr inline auto RoomIdKey = "room_id"_L1;
16constexpr inline auto StateKeyKey = "state_key"_L1;
17constexpr inline auto RedactedCauseKey = "redacted_because"_L1;
18
19class RedactionEvent;
20class EncryptedEvent;
21
22// That check could look into Event and find most stuff already deleted...
23// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
24class QUOTIENT_API RoomEvent : public Event {
25public:
26 QUO_BASE_EVENT(RoomEvent, Event)
27
28 ~RoomEvent() override; // Don't inline this - see the private section
29
30 //! \brief A convenience function to get a display string for an event ID.
31 //! \return id() if the event id is not empty, otherwise transactionId();
32 //! this is useful to deal with pending and normal events uniformly.
33 //! \sa id(), transactionId()
34 QString displayId() const;
35
36 //! The event_id JSON value for the event.
37 QString id() const;
38
39 QDateTime originTimestamp() const;
40 QString roomId() const;
41 QString senderId() const;
42 bool isRedacted() const { return bool(_redactedBecause); }
43 const event_ptr_tt<RedactionEvent>& redactedBecause() const
44 {
45 return _redactedBecause;
46 }
47 QString redactionReason() const;
48
49 //! \brief Make a redacted event
50 //!
51 //! This applies the redaction procedure as defined by the CS API specification to the event's
52 //! JSON and returns the resulting new event.
53 //! \note It is the responsibility of the caller to dispose of the original event after that.
54 event_ptr_tt<RoomEvent> makeRedacted(const RedactionEvent &redaction) const;
55
56 //! The transaction_id JSON value for the event.
57 QString transactionId() const;
58
59 // State events are special in Matrix; so isStateEvent() and stateKey() are here,
60 // as an exception. For other event types (including base types), Event::is<>() and
61 // Quotient::is<>() should be used
62
63 bool isStateEvent() const;
64
65 QString stateKey() const;
66
67 //! \brief Fill the pending event object with the room id
68 void setRoomId(const QString& roomId);
69 //! \brief Fill the pending event object with the sender id
70 void setSender(const QString& senderId);
71 //! \brief Fill the pending event object with the transaction id
72 //! \param txnId - transaction id, normally obtained from
73 //! Connection::generateTxnId()
74 void setTransactionId(const QString& txnId);
75
76 //! \brief Add an event id to locally created events after they are sent
77 //!
78 //! When a new event is created locally, it has no id; the homeserver
79 //! assigns it once the event is sent. This function allows to add the id
80 //! once the confirmation from the server is received. There should be no id
81 //! set previously in the event. It's the responsibility of the code calling
82 //! addId() to notify clients about the change; there's no signal or
83 //! callback for that in RoomEvent.
84 void addId(const QString& newId);
85
86 void setOriginalEvent(event_ptr_tt<EncryptedEvent>&& originalEvent);
87 const EncryptedEvent* originalEvent() const { return _originalEvent.get(); }
88 const QJsonObject encryptedJson() const;
89
90 //! \brief Determine whether the event is a reply to another message.
91 //!
92 //! \param includeFallbacks include thread fallback replies for non-threaded clients.
93 //!
94 //! \return true if this event is a reply, i.e. it has `"m.in_reply_to"`
95 //! event ID and is not a thread fallback (except where \p includeFallbacks is true);
96 //! false otherwise.
97 //!
98 //! \note It's possible to reply to another message in a thread so this function
99 //! will return true for a `"rel_type"` of `"m.thread"` if `"is_falling_back"`
100 //! is false.
101 bool isReply(bool includeFallbacks = false) const;
102
103 //! \brief The ID for the event being replied to.
104 //!
105 //! \param includeFallbacks include thread fallback replies for non-threaded clients.
106 //!
107 //!
108 //! \return The event ID for a reply, this includes threaded replies where `"rel_type"`
109 //! is `"m.thread"` and `"is_falling_back"` is false (except where \p includeFallbacks is true).
110 QString replyEventId(bool includeFallbacks = false) const;
111
112 //! \brief The EventRelation for this event.
113 //!
114 //! \return an EventRelation object which can be checked for type if it exists,
115 //! std::nullopt otherwise.
116 std::optional<EventRelation> relatesTo() const;
117
118 //! \brief Set the event relation data
119 //!
120 //! Adds the relation to another event with the contents of \p er. If another relation
121 //! exists it is entirely overwritten.
122 void setRelation(const EventRelation &er);
123
124 //! \brief Remove the event relation data
125 //!
126 //! Clears any relation from this event to another event.
127 //! \sa setRelation
128 void clearRelation();
129
130 //! \brief Get relations to this event
131 //!
132 //! This is a counterpart of relatesTo(): it returns the list of (known, see the note) relations
133 //! to the current event.
134 //! \note This method uses `unsigned/m.relations` object that may not have fully accurate data.
135 //! Use with caution.
136 QJsonObject relationsToThis() const;
137
138 //! \brief Check whether there are other events relating to this
139 //! \note This method uses `unsigned/m.relations` object that may not have fully accurate data.
140 //! Use with caution.
141 bool hasRelationship(EventRelation::typeid_t relationTypeId) const;
142
143 //! \brief Obtain id of an event replaced by the current one
144 //! \sa RoomEvent::isReplaced, RoomEvent::replacedBy
145 QString replacedEvent() const;
146
147 //! \brief Determine whether the event has been replaced
148 //!
149 //! \return true if this event has been overridden by another event
150 //! with `"rel_type": "m.replace"`; false otherwise
151 bool isReplaced() const;
152
153 //! \brief Get the id of the event that replaced this one
154 //!
155 //! \return The id of the replacement event if the current event has been replaced
156 //! by another one; an empty string otherwise.
157 //! \sa isReplaced, replacedEvent
158 QString replacedBy() const;
159
160 //! \brief Make a replaced event
161 //!
162 //! \returns a clone of `*this` with content taken from \p replacementEvent as described in
163 //! https://spec.matrix.org/latest/client-server-api/#applying-mnew_content
164 //! \note Disposal of the original event after that is on the caller.
165 event_ptr_tt<RoomEvent> makeReplaced(const RoomEvent &replacementEvent) const;
166
167 //! \brief Determine whether the event is part of a thread.
168 //!
169 //! \return true if this event is part of a thread, i.e. it has
170 //! `"rel_type": "m.thread"` or `"m.relations": { "m.thread": {}}`;
171 //! false otherwise.
172 bool isThreaded() const;
173
174 //! \brief The event ID for the thread root event.
175 //!
176 //! \note This will return the ID of the event if it is the thread root.
177 //!
178 //! \note If the event is the thread root event and has not been updated with the server-side
179 //! the function will return an empty string as we can't tell if the message
180 //! is threaded.
181 //!
182 //! \return The event ID of the thread root if threaded, an empty string otherwise.
183 QString threadRootEventId()const;
184
185protected:
186 explicit RoomEvent(const QJsonObject& json);
187 void dumpTo(QDebug dbg) const override;
188
189 virtual void afterRelationChange() {}
190
191private:
192 QString _id;
193
194 // RedactionEvent is an incomplete type here so we cannot inline
195 // constructors using it and also destructors (with 'using', in particular).
196 event_ptr_tt<RedactionEvent> _redactedBecause;
197
198 event_ptr_tt<EncryptedEvent> _originalEvent;
199};
200using RoomEventPtr = event_ptr_tt<RoomEvent>;
201using RoomEvents = EventsArray<RoomEvent>;
202using RoomEventsRange = std::ranges::subrange<RoomEvents::iterator>;
203
204//! \brief Determine whether a given event type is that of a state event
205QUOTIENT_API bool isStateEvent(const QString& eventTypeId);
206
207} // namespace Quotient
208Q_DECLARE_METATYPE(Quotient::RoomEvent*)
209Q_DECLARE_METATYPE(const Quotient::RoomEvent*)
#define QUO_BASE_EVENT(CppType_, BaseCppType_,...)
Supply event metatype information in base event types.
Definition event.h:404
#define QUOTIENT_API