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 "roomevent.h" |
7 | |
8 | namespace Quotient { |
9 | |
10 | class QUOTIENT_API StateEvent : public RoomEvent { |
11 | public: |
12 | QUO_BASE_EVENT(StateEvent, RoomEvent, "json.contains('state_key')" ) |
13 | |
14 | static bool isValid(const QJsonObject& fullJson) |
15 | { |
16 | return fullJson.contains(key: StateKeyKey); |
17 | } |
18 | |
19 | //! \brief Static setting of whether a given even type uses state keys |
20 | //! |
21 | //! Most event types don't use a state key; overriding this to `true` |
22 | //! for a given type changes the calls across Quotient to include state key |
23 | //! in their signatures; otherwise, state key is still accessible but |
24 | //! constructors and calls in, e.g., RoomStateView don't include it. |
25 | static constexpr auto needsStateKey = false; |
26 | |
27 | explicit StateEvent(event_type_t type, const QString& stateKey = {}, |
28 | const QJsonObject& contentJson = {}); |
29 | |
30 | //! Make a minimal correct Matrix state event JSON |
31 | static QJsonObject basicJson(const QString& matrixTypeId, |
32 | const QString& stateKey = {}, |
33 | const QJsonObject& contentJson = {}) |
34 | { |
35 | return { { TypeKey, matrixTypeId }, |
36 | { StateKeyKey, stateKey }, |
37 | { ContentKey, contentJson } }; |
38 | } |
39 | |
40 | QString replacedState() const; |
41 | virtual bool repeatsState() const; |
42 | |
43 | protected: |
44 | explicit StateEvent(const QJsonObject& json); |
45 | void dumpTo(QDebug dbg) const override; |
46 | }; |
47 | using StateEventBase |
48 | [[deprecated("StateEventBase is StateEvent now" )]] = StateEvent; |
49 | using StateEventPtr = event_ptr_tt<StateEvent>; |
50 | using StateEvents = EventsArray<StateEvent>; |
51 | |
52 | [[deprecated("Use StateEvent::basicJson() instead" )]] |
53 | inline QJsonObject basicStateEventJson(const QString& matrixTypeId, |
54 | const QJsonObject& content, |
55 | const QString& stateKey = {}) |
56 | { |
57 | return StateEvent::basicJson(matrixTypeId, stateKey, contentJson: content); |
58 | } |
59 | |
60 | /** |
61 | * A combination of event type and state key uniquely identifies a piece |
62 | * of state in Matrix. |
63 | * \sa |
64 | * https://matrix.org/docs/spec/client_server/unstable.html#types-of-room-events |
65 | */ |
66 | using StateEventKey = std::pair<QString, QString>; |
67 | |
68 | template <typename EventT, typename ContentT> |
69 | class EventTemplate<EventT, StateEvent, ContentT> |
70 | : public StateEvent { |
71 | public: |
72 | using content_type = ContentT; |
73 | |
74 | struct Prev { |
75 | explicit Prev() = default; |
76 | explicit Prev(const QJsonObject& unsignedJson) |
77 | : senderId(fromJson<QString>(jv: unsignedJson["prev_sender" _ls])) |
78 | , content( |
79 | fromJson<Omittable<ContentT>>(unsignedJson[PrevContentKey])) |
80 | {} |
81 | |
82 | QString senderId; |
83 | Omittable<ContentT> content; |
84 | }; |
85 | |
86 | explicit EventTemplate(const QJsonObject& fullJson) |
87 | : StateEvent(fullJson) |
88 | , _content(fromJson<ContentT>(Event::contentJson())) |
89 | , _prev(unsignedJson()) |
90 | {} |
91 | template <typename... ContentParamTs> |
92 | explicit EventTemplate(const QString& stateKey, |
93 | ContentParamTs&&... contentParams) |
94 | : StateEvent(EventT::TypeId, stateKey) |
95 | , _content { std::forward<ContentParamTs>(contentParams)... } |
96 | { |
97 | editJson().insert(ContentKey, toJson(_content)); |
98 | } |
99 | |
100 | const ContentT& content() const { return _content; } |
101 | |
102 | template <typename VisitorT> |
103 | void editContent(VisitorT&& visitor) |
104 | { |
105 | visitor(_content); |
106 | editJson()[ContentKey] = toJson(_content); |
107 | } |
108 | const Omittable<ContentT>& prevContent() const { return _prev.content; } |
109 | QString prevSenderId() const { return _prev.senderId; } |
110 | |
111 | private: |
112 | ContentT _content; |
113 | Prev _prev; |
114 | }; |
115 | |
116 | template <typename EventT, typename ContentT> |
117 | class KeyedStateEventBase |
118 | : public EventTemplate<EventT, StateEvent, ContentT> { |
119 | public: |
120 | static constexpr auto needsStateKey = true; |
121 | |
122 | using EventTemplate<EventT, StateEvent, ContentT>::EventTemplate; |
123 | }; |
124 | |
125 | template <typename EvT> |
126 | concept Keyed_State_Event = EvT::needsStateKey; |
127 | |
128 | template <typename EventT, typename ContentT> |
129 | class KeylessStateEventBase |
130 | : public EventTemplate<EventT, StateEvent, ContentT> { |
131 | private: |
132 | using base_type = EventTemplate<EventT, StateEvent, ContentT>; |
133 | |
134 | public: |
135 | template <typename... ContentParamTs> |
136 | explicit KeylessStateEventBase(ContentParamTs&&... contentParams) |
137 | : base_type(QString(), std::forward<ContentParamTs>(contentParams)...) |
138 | {} |
139 | |
140 | protected: |
141 | explicit KeylessStateEventBase(const QJsonObject& fullJson) |
142 | : base_type(fullJson) |
143 | {} |
144 | }; |
145 | |
146 | template <typename EvT> |
147 | concept Keyless_State_Event = !EvT::needsStateKey; |
148 | |
149 | } // namespace Quotient |
150 | Q_DECLARE_METATYPE(Quotient::StateEvent*) |
151 | Q_DECLARE_METATYPE(const Quotient::StateEvent*) |
152 | |