Page MenuHomePhorge

No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None
diff --git a/src/client/actions/ephemeral.cpp b/src/client/actions/ephemeral.cpp
index 2f318c4..7e46a62 100644
--- a/src/client/actions/ephemeral.cpp
+++ b/src/client/actions/ephemeral.cpp
@@ -1,94 +1,95 @@
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <libkazv-config.hpp>
#include <status-utils.hpp>
#include "ephemeral.hpp"
namespace Kazv
{
ClientResult updateClient(ClientModel m, SetTypingAction a)
{
auto job = m.job<SetTypingJob>().make(
m.userId,
a.roomId,
a.typing,
a.timeoutMs)
.withData(json{{"roomId", a.roomId}});
m.addJob(std::move(job));
return { std::move(m), lager::noop };
}
ClientResult processResponse(ClientModel m, SetTypingResponse r)
{
auto roomId = r.dataStr("roomId");
if (! r.success()) {
m.addTrigger(SetTypingFailed{roomId, r.errorCode(), r.errorMessage()});
return { std::move(m), failWithResponse(r) };
}
m.addTrigger(SetTypingSuccessful{roomId});
return { std::move(m), lager::noop };
}
ClientResult updateClient(ClientModel m, PostReceiptAction a)
{
auto job = m.job<PostReceiptJob>().make(
a.roomId,
/* receiptType = */ "m.read"s,
- a.eventId)
+ a.eventId,
+ /* receipt = */ json::object())
.withData(json{{"roomId", a.roomId}});
m.addJob(std::move(job));
return { std::move(m), lager::noop };
}
ClientResult processResponse(ClientModel m, PostReceiptResponse r)
{
auto roomId = r.dataStr("roomId");
if (! r.success()) {
m.addTrigger(PostReceiptFailed{roomId, r.errorCode(), r.errorMessage()});
return { std::move(m), lager::noop };
}
m.addTrigger(PostReceiptSuccessful{roomId});
return { std::move(m), lager::noop };
}
ClientResult updateClient(ClientModel m, SetReadMarkerAction a)
{
auto job = m.job<SetReadMarkerJob>().make(
a.roomId,
/* mFullyRead = */ a.eventId)
.withData(json{{"roomId", a.roomId}});
m.addJob(std::move(job));
return { std::move(m), lager::noop };
}
ClientResult processResponse(ClientModel m, SetReadMarkerResponse r)
{
auto roomId = r.dataStr("roomId");
if (! r.success()) {
m.addTrigger(SetReadMarkerFailed{roomId, r.errorCode(), r.errorMessage()});
return { std::move(m), lager::noop };
}
m.addTrigger(SetReadMarkerSuccessful{roomId});
return { std::move(m), lager::noop };
}
}
diff --git a/src/tests/client/room/read-receipt-test.cpp b/src/tests/client/room/read-receipt-test.cpp
index 57bd646..8d403f1 100644
--- a/src/tests/client/room/read-receipt-test.cpp
+++ b/src/tests/client/room/read-receipt-test.cpp
@@ -1,208 +1,221 @@
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <libkazv-config.hpp>
#include <boost/asio.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_range_equals.hpp>
#include <lager/event_loop/boost_asio.hpp>
#include <asio-promise-handler.hpp>
#include <room/room-model.hpp>
#include <sdk-model.hpp>
#include <client/client.hpp>
+#include <client/actions/ephemeral.hpp>
#include <cprjobhandler.hpp>
#include <lagerstoreeventemitter.hpp>
#include <testfixtures/factory.hpp>
#include "client-test-util.hpp"
using namespace Kazv;
using namespace Kazv::Factory;
TEST_CASE("Adding an m.receipt ephemeral event", "[client][room][receipt]")
{
auto room = makeRoom();
auto receiptEvent = makeEvent(
withEventType("m.receipt")
// https://spec.matrix.org/v1.8/client-server-api/#events-5
| withEventContent(R"({
"$1435641916114394fHBLK:matrix.org": {
"m.read": {
"@rikj:jki.re": {
"ts": 1436451550453
}
},
"m.read.private": {
"@self:example.org": {
"ts": 1661384801651
}
}
}
})"_json));
room = RoomModel::update(room, AddEphemeralAction{{receiptEvent}});
auto receipt = room.readReceipts.at("@rikj:jki.re");
REQUIRE(
room.readReceipts.at("@rikj:jki.re")
==
ReadReceipt{"$1435641916114394fHBLK:matrix.org", 1436451550453}
);
REQUIRE(
room.eventReadUsers.at("$1435641916114394fHBLK:matrix.org")
==
immer::flex_vector<std::string>{"@rikj:jki.re", "@self:example.org"}
);
auto anotherReceiptEvent = makeEvent(
withEventType("m.receipt")
| withEventContent(json{
{"$123", {
{"m.read", {
{"@foo:example.com", {{"ts", 1796451550450}}}
}},
}},
}));
room = RoomModel::update(room, AddEphemeralAction{{anotherReceiptEvent}});
// the receipt that was there should still be there.
REQUIRE(
room.readReceipts.at("@rikj:jki.re")
==
ReadReceipt{"$1435641916114394fHBLK:matrix.org", 1436451550453}
);
REQUIRE(
room.readReceipts.at("@foo:example.com")
==
ReadReceipt{"$123", 1796451550450}
);
boost::asio::io_context io;
AsioPromiseHandler ph{io.get_executor()};
auto model = makeClient(withRoom(room));
auto store = createTestClientStoreFrom(model, ph);
auto client = Client(store.reader().map([](auto c) { return SdkModel{c}; }),
store,
std::nullopt);
auto r = client.room(room.roomId);
auto readers1 = r.eventReaders(lager::make_constant<std::string>("$1435641916114394fHBLK:matrix.org")).make().get();
auto expected1 = immer::flex_vector<EventReader>{{"@rikj:jki.re", 1436451550453}, {"@self:example.org", 1661384801651}};
REQUIRE_THAT(readers1, Catch::Matchers::UnorderedRangeEquals(expected1));
auto readers2 = r.eventReaders(lager::make_constant<std::string>("$123")).make().get();
auto expected2 = immer::flex_vector<EventReader>{{"@foo:example.com", 1796451550450}};
REQUIRE(readers2 == expected2);
}
TEST_CASE("Update a receipt for some user", "[client][room][receipt]")
{
auto room = makeRoom();
auto receiptEvent = makeEvent(
withEventType("m.receipt")
// https://spec.matrix.org/v1.8/client-server-api/#events-5
| withEventContent(R"({
"$1435641916114394fHBLK:matrix.org": {
"m.read": {
"@rikj:jki.re": {
"ts": 1436451550453
}
}
}
})"_json));
room = RoomModel::update(room, AddEphemeralAction{{receiptEvent}});
auto anotherReceiptEvent = makeEvent(
withEventType("m.receipt")
| withEventContent(json{
{"$123", {
{"m.read", {
{"@rikj:jki.re", {{"ts", 1796451550450}}}
}},
}},
}));
room = RoomModel::update(room, AddEphemeralAction{{anotherReceiptEvent}});
REQUIRE(
room.readReceipts.at("@rikj:jki.re")
==
ReadReceipt{"$123", 1796451550450}
);
REQUIRE(room.eventReadUsers.count("$1435641916114394fHBLK:matrix.org") == 0);
REQUIRE(room.eventReadUsers.count("$123") == 1);
boost::asio::io_context io;
AsioPromiseHandler ph{io.get_executor()};
auto model = makeClient(withRoom(room));
auto store = createTestClientStoreFrom(model, ph);
auto client = Client(store.reader().map([](auto c) { return SdkModel{c}; }),
store,
std::nullopt);
auto r = client.room(room.roomId);
auto readers1 = r.eventReaders(lager::make_constant<std::string>("$1435641916114394fHBLK:matrix.org")).make().get();
auto expected1 = immer::flex_vector<EventReader>{};
REQUIRE(readers1 == expected1);
auto readers2 = r.eventReaders(lager::make_constant<std::string>("$123")).make().get();
auto expected2 = immer::flex_vector<EventReader>{{"@rikj:jki.re", 1796451550450}};
REQUIRE(readers2 == expected2);
}
TEST_CASE("Posting receipts", "[client][room][receipt]")
{
auto r = makeRoom();
auto m = makeClient(withRoom(r));
boost::asio::io_context io;
SingleTypePromiseInterface<EffectStatus> sgph{AsioPromiseHandler{io.get_executor()}};
auto jh = Kazv::CprJobHandler{io.get_executor()};
auto ee = Kazv::LagerStoreEventEmitter(lager::with_boost_asio_event_loop{io.get_executor()});
auto sdk = Kazv::makeSdk(
SdkModel{m},
jh,
ee,
Kazv::AsioPromiseHandler{io.get_executor()},
zug::identity
);
auto ctx = sdk.context();
auto postReceiptCalled = 0;
std::string postReceiptRoomId;
std::string postReceiptEventId;
auto mockContext = typename Client::ContextT([&sgph, &postReceiptCalled, &postReceiptRoomId, &postReceiptEventId](const auto &action) {
if (std::holds_alternative<PostReceiptAction>(action)) {
++postReceiptCalled;
postReceiptRoomId = std::get<PostReceiptAction>(action).roomId;
postReceiptEventId = std::get<PostReceiptAction>(action).eventId;
return sgph.createResolved(EffectStatus(true, json::object()));
}
throw std::runtime_error{"unhandled action"};
}, sgph, lager::deps<>{});
auto client = Client(Client::InEventLoopTag{}, mockContext, sdk.context());
auto room = client.room(r.roomId);
room.postReceipt("$1")
.then([&io](auto) {
io.stop();
});
io.run();
REQUIRE(postReceiptCalled == 1);
REQUIRE(postReceiptRoomId == r.roomId);
REQUIRE(postReceiptEventId == "$1");
}
+
+TEST_CASE("PostReceiptAction", "[client][room][receipt]")
+{
+ auto m = makeClient();
+ auto [next, _ignore] = updateClient(m, PostReceiptAction{"!someroom:example.com", "$someevent"});
+ assert1Job(next);
+ for1stJob(next, [](const BaseJob &job) {
+ REQUIRE(job.jobId() == "PostReceipt");
+ REQUIRE(job.url().find("rooms/!someroom:example.com/receipt/m.read/$someevent") != std::string::npos);
+ REQUIRE(json::parse(std::get<Bytes>(job.requestBody())) == json::object());
+ });
+}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 9, 10:02 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1784675
Default Alt Text
(10 KB)

Event Timeline