// SPDX-FileCopyrightText: 2018 Kitsune Ral // SPDX-License-Identifier: LGPL-2.1-or-later #pragma once #include "roomevent.h" namespace Quotient { class QUOTIENT_API StateEventBase : public RoomEvent { public: QUO_BASE_EVENT(StateEventBase, "json.contains('state_key')"_ls, RoomEvent::BaseMetaType) static bool isValid(const QJsonObject& fullJson) { return fullJson.contains(StateKeyKeyL); } //! \brief Static setting of whether a given even type uses state keys //! //! Most event types don't use a state key; overriding this to `true` //! for a given type changes the calls across Quotient to include state key //! in their signatures; otherwise, state key is still accessible but //! constructors and calls in, e.g., RoomStateView don't include it. static constexpr auto needsStateKey = false; explicit StateEventBase(const QJsonObject& json); explicit StateEventBase(Type type, const QString& stateKey = {}, const QJsonObject& contentJson = {}); //! Make a minimal correct Matrix state event JSON static QJsonObject basicJson(const QString& matrixTypeId, const QString& stateKey = {}, const QJsonObject& contentJson = {}) { return { { TypeKey, matrixTypeId }, { StateKeyKey, stateKey }, { ContentKey, contentJson } }; } QString replacedState() const; void dumpTo(QDebug dbg) const override; virtual bool repeatsState() const; }; using StateEventPtr = event_ptr_tt; using StateEvents = EventsArray; [[deprecated("Use StateEventBase::basicJson() instead")]] inline QJsonObject basicStateEventJson(const QString& matrixTypeId, const QJsonObject& content, const QString& stateKey = {}) { return StateEventBase::basicJson(matrixTypeId, stateKey, content); } /** * A combination of event type and state key uniquely identifies a piece * of state in Matrix. * \sa * https://matrix.org/docs/spec/client_server/unstable.html#types-of-room-events */ using StateEventKey = std::pair; template class EventTemplate : public StateEventBase { public: using content_type = ContentT; struct Prev { explicit Prev() = default; explicit Prev(const QJsonObject& unsignedJson) : senderId(fromJson(unsignedJson["prev_sender"_ls])) , content( fromJson>(unsignedJson[PrevContentKeyL])) {} QString senderId; Omittable content; }; explicit EventTemplate(const QJsonObject& fullJson) : StateEventBase(fullJson) , _content(fromJson(Event::contentJson())) , _prev(unsignedJson()) {} template explicit EventTemplate(const QString& stateKey, ContentParamTs&&... contentParams) : StateEventBase(EventT::TypeId, stateKey) , _content { std::forward(contentParams)... } { editJson().insert(ContentKey, toJson(_content)); } const ContentT& content() const { return _content; } template void editContent(VisitorT&& visitor) { visitor(_content); editJson()[ContentKeyL] = toJson(_content); } const Omittable& prevContent() const { return _prev.content; } QString prevSenderId() const { return _prev.senderId; } private: ContentT _content; Prev _prev; }; template class KeyedStateEventBase : public EventTemplate { public: static constexpr auto needsStateKey = true; using EventTemplate::EventTemplate; }; template concept Keyed_State_Event = EvT::needsStateKey; template class KeylessStateEventBase : public EventTemplate { private: using base_type = EventTemplate; public: explicit KeylessStateEventBase(const QJsonObject& fullJson) : base_type(fullJson) {} template explicit KeylessStateEventBase(ContentParamTs&&... contentParams) : base_type(QString(), std::forward(contentParams)...) {} }; template concept Keyless_State_Event = !EvT::needsStateKey; } // namespace Quotient Q_DECLARE_METATYPE(Quotient::StateEventBase*) Q_DECLARE_METATYPE(const Quotient::StateEventBase*)