diff --git a/CMakeLists.txt b/CMakeLists.txt index 18c197ed5a9b773e01c7b9b9c9d37773fe8048b3..554bcbe13e983e0d603e0649227d1f9af5db2d97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,7 @@ add_library(matrix_client lib/structs/events/power_levels.cpp lib/structs/events/redaction.cpp lib/structs/events/tag.cpp + lib/structs/events/tombstone.cpp lib/structs/events/topic.cpp lib/structs/events/messages/audio.cpp lib/structs/events/messages/emote.cpp diff --git a/include/mtx/events.hpp b/include/mtx/events.hpp index 83bff9dc1a781d94685022854bbd33fb29d26770..c0e2b843f00808412f77292ef0799f46d167c5de 100644 --- a/include/mtx/events.hpp +++ b/include/mtx/events.hpp @@ -48,6 +48,8 @@ enum class EventType RoomRedaction, /// m.room.pinned_events RoomPinnedEvents, + /// m.room.tombstone + RoomTombstone, // m.sticker Sticker, // m.tag @@ -136,6 +138,9 @@ to_json(json &obj, const Event<Content> &event) case EventType::RoomPinnedEvents: obj["type"] = "m.room.pinned_events"; break; + case EventType::RoomTombstone: + obj["type"] = "m.room.tombstone"; + break; case EventType::Sticker: obj["type"] = "m.sticker"; break; diff --git a/include/mtx/events/collections.hpp b/include/mtx/events/collections.hpp index a2e46266bf47ddd4bdfce69f74c8d94d696078c3..13adb68af62c114046ca997e5c7ee6f22696e79e 100644 --- a/include/mtx/events/collections.hpp +++ b/include/mtx/events/collections.hpp @@ -18,6 +18,7 @@ #include "mtx/events/power_levels.hpp" #include "mtx/events/redaction.hpp" #include "mtx/events/tag.hpp" +#include "mtx/events/tombstone.hpp" #include "mtx/events/topic.hpp" #include "mtx/events/messages/audio.hpp" @@ -54,6 +55,7 @@ using StateEvents = boost::variant<events::StateEvent<states::Aliases>, events::StateEvent<states::Name>, events::StateEvent<states::PinnedEvents>, events::StateEvent<states::PowerLevels>, + events::StateEvent<states::Tombstone>, events::StateEvent<states::Topic>, events::StateEvent<msgs::Redacted>>; @@ -69,6 +71,7 @@ using StrippedEvents = boost::variant<events::StrippedEvent<states::Aliases>, events::StrippedEvent<states::Name>, events::StrippedEvent<states::PinnedEvents>, events::StrippedEvent<states::PowerLevels>, + events::StrippedEvent<states::Tombstone>, events::StrippedEvent<states::Topic>>; //! Collection of @p StateEvent and @p RoomEvent. Those events would be @@ -85,6 +88,7 @@ using TimelineEvents = boost::variant<events::StateEvent<states::Aliases>, events::StateEvent<states::Name>, events::StateEvent<states::PinnedEvents>, events::StateEvent<states::PowerLevels>, + events::StateEvent<states::Tombstone>, events::StateEvent<states::Topic>, events::EncryptedEvent<msgs::Encrypted>, events::RedactionEvent<msgs::Redaction>, @@ -164,6 +168,10 @@ from_json(const json &obj, TimelineEvent &e) e.data = events::RedactionEvent<mtx::events::msg::Redaction>(obj); break; } + case events::EventType::RoomTombstone: { + e.data = events::StateEvent<Tombstone>(obj); + break; + } case events::EventType::RoomTopic: { e.data = events::StateEvent<Topic>(obj); break; diff --git a/include/mtx/events/tombstone.hpp b/include/mtx/events/tombstone.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4d1c7a0d43b345a94b8b828cbe1d108124e03271 --- /dev/null +++ b/include/mtx/events/tombstone.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <nlohmann/json.hpp> + +using json = nlohmann::json; + +namespace mtx { +namespace events { +namespace state { + +//! Content for the `m.room.tombstone` event. +// +//! A state event signifying that a room has been +//! upgraded to a different room version, and +//! that clients should go there. +struct Tombstone +{ + //! Required. A server-defined message. + std::string body; + //! Required. The new room the client should be visiting. + std::string replacement_room; +}; + +//! Deserialization method needed by @p nlohmann::json. +void +from_json(const json &obj, Tombstone &content); + +//! Serialization method needed by @p nlohmann::json. +void +to_json(json &obj, const Tombstone &content); + +} // namespace state +} // namespace events +} // namespace mtx diff --git a/lib/structs/events.cpp b/lib/structs/events.cpp index bdbbe00ddb0405d6d8eb1e7496a868ba656bef7d..5d1a89cd1e3b1c0c447d2b427652b1815b989579 100644 --- a/lib/structs/events.cpp +++ b/lib/structs/events.cpp @@ -42,6 +42,8 @@ getEventType(const std::string &type) return EventType::RoomRedaction; else if (type == "m.room.pinned_events") return EventType::RoomPinnedEvents; + else if (type == "m.room.tombstone") + return EventType::RoomTombstone; else if (type == "m.sticker") return EventType::Sticker; else if (type == "m.tag") @@ -88,6 +90,8 @@ to_string(EventType type) return "m.room.redaction"; case EventType::RoomPinnedEvents: return "m.room.pinned_events"; + case EventType::RoomTombstone: + return "m.room.tombstone"; case EventType::Sticker: return "m.sticker"; case EventType::Tag: diff --git a/lib/structs/events/tombstone.cpp b/lib/structs/events/tombstone.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b862632a4658278234d33324dd66308e20b7215a --- /dev/null +++ b/lib/structs/events/tombstone.cpp @@ -0,0 +1,27 @@ +#include <nlohmann/json.hpp> + +using json = nlohmann::json; + +#include "mtx/events/tombstone.hpp" + +namespace mtx { +namespace events { +namespace state { + +void +from_json(const json &obj, Tombstone &content) +{ + content.body = obj.at("body"); + content.replacement_room = obj.at("replacement_room"); +} + +void +to_json(json &obj, const Tombstone &content) +{ + obj["body"] = content.body; + obj["replacement_room"] = content.replacement_room; +} + +} // namespace state +} // namespace events +} // namespace mtx diff --git a/lib/structs/responses/common.cpp b/lib/structs/responses/common.cpp index e3e2dbd22f7fcd71b7b3a26784a9071d95569d94..67ce418b7f9831cdb874b2e2ffd7ccfe2f9d891f 100644 --- a/lib/structs/responses/common.cpp +++ b/lib/structs/responses/common.cpp @@ -93,6 +93,7 @@ parse_room_account_data_events( case events::EventType::RoomMessage: case events::EventType::RoomName: case events::EventType::RoomPowerLevels: + case events::EventType::RoomTombstone: case events::EventType::RoomTopic: case events::EventType::RoomRedaction: case events::EventType::RoomPinnedEvents: @@ -233,6 +234,15 @@ parse_timeline_events(const json &events, break; } + case events::EventType::RoomTombstone: { + try { + container.emplace_back(events::StateEvent<Tombstone>(e)); + } catch (json::exception &err) { + log_error(err, e); + } + + break; + } case events::EventType::RoomTopic: { try { container.emplace_back(events::StateEvent<Topic>(e)); @@ -474,6 +484,15 @@ parse_state_events(const json &events, break; } + case events::EventType::RoomTombstone: { + try { + container.emplace_back(events::StateEvent<Tombstone>(e)); + } catch (json::exception &err) { + log_error(err, e); + } + + break; + } case events::EventType::RoomTopic: { try { container.emplace_back(events::StateEvent<Topic>(e)); @@ -597,6 +616,15 @@ parse_stripped_events(const json &events, break; } + case events::EventType::RoomTombstone: { + try { + container.emplace_back(events::StrippedEvent<Tombstone>(e)); + } catch (json::exception &err) { + log_error(err, e); + } + + break; + } case events::EventType::RoomTopic: { try { container.emplace_back(events::StrippedEvent<Topic>(e)); diff --git a/tests/events.cpp b/tests/events.cpp index 574a07271406d7ce389d7ea7d88bf4ef13d66f21..234426ea2d7821d0fba8798202e9befe45f5e7ca 100644 --- a/tests/events.cpp +++ b/tests/events.cpp @@ -51,6 +51,7 @@ TEST(Events, Conversions) EXPECT_EQ("m.room.name", ns::to_string(ns::EventType::RoomName)); EXPECT_EQ("m.room.power_levels", ns::to_string(ns::EventType::RoomPowerLevels)); EXPECT_EQ("m.room.topic", ns::to_string(ns::EventType::RoomTopic)); + EXPECT_EQ("m.room.tombstone", ns::to_string(ns::EventType::RoomTombstone)); EXPECT_EQ("m.room.redaction", ns::to_string(ns::EventType::RoomRedaction)); EXPECT_EQ("m.room.pinned_events", ns::to_string(ns::EventType::RoomPinnedEvents)); EXPECT_EQ("m.tag", ns::to_string(ns::EventType::Tag)); @@ -547,6 +548,37 @@ TEST(StateEvents, PowerLevels) EXPECT_EQ(event.content.user_level("@not:matrix.org"), event.content.users_default); } +TEST(StateEvents, Tombstone) +{ + json data = R"({ + "content": { + "body": "This room has been replaced", + "replacement_room": "!newroom:example.org" + }, + "event_id": "$143273582443PhrSn:example.org", + "origin_server_ts": 1432735824653, + "room_id": "!jEsUZKDJdhlrceRyVU:example.org", + "sender": "@example:example.org", + "state_key": "", + "type": "m.room.tombstone", + "unsigned": { + "age": 1234 + } + })"_json; + + ns::StateEvent<ns::state::Tombstone> event = data; + + EXPECT_EQ(event.type, ns::EventType::RoomTombstone); + EXPECT_EQ(event.event_id, "$143273582443PhrSn:example.org"); + EXPECT_EQ(event.room_id, "!jEsUZKDJdhlrceRyVU:example.org"); + EXPECT_EQ(event.sender, "@example:example.org"); + EXPECT_EQ(event.origin_server_ts, 1432735824653); + EXPECT_EQ(event.unsigned_data.age, 1234); + EXPECT_EQ(event.state_key, ""); + EXPECT_EQ(event.content.body, "This room has been replaced"); + EXPECT_EQ(event.content.replacement_room, "!newroom:example.org"); +} + TEST(StateEvents, Topic) { json data = R"({