| 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 | |