Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85628889
D341.1786141036.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
21 KB
Referenced Files
None
Subscribers
None
D341.1786141036.diff
View Options
diff --git a/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml b/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml
--- a/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml
+++ b/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml
@@ -63,8 +63,8 @@
send(content);
}
- property var sendAccountData: Kazv.AsyncHandler {
- trigger: () => matrixSession.sendAccountData(Helpers.imagePackRoomsEventType, content);
+ property var updateStickerRooms: Kazv.AsyncHandler {
+ trigger: () => matrixSession.updateStickerRooms(content);
property var content
onResolved: (success, data) => {
if (!success) {
@@ -74,7 +74,7 @@
}
function send(content) {
- sendAccountData.content = content;
- sendAccountData.call();
+ updateStickerRooms.content = content;
+ updateStickerRooms.call();
}
}
diff --git a/src/contents/ui/room-settings/RoomStickerPacksPage.qml b/src/contents/ui/room-settings/RoomStickerPacksPage.qml
--- a/src/contents/ui/room-settings/RoomStickerPacksPage.qml
+++ b/src/contents/ui/room-settings/RoomStickerPacksPage.qml
@@ -47,17 +47,11 @@
property var addStickerPack: Kazv.AsyncHandler {
id: addStickerPack
trigger: () => {
- const type = Helpers.roomImagePackEventType;
- const stateKey = stickerPackStateKey.text;
- const state = room.state(type, stateKey);
- const content = state.content;
- content.pack = content.pack || {};
- content.pack.display_name = stickerPackName.text;
- return roomStickerPacksPage.room.sendStateEvent({
- type,
- state_key: stateKey,
- content,
- });
+ return matrixSession.addRoomStickerPack(
+ room.roomId,
+ stickerPackStateKey.text,
+ stickerPackName.text,
+ );
}
onResolved: (success, data) => {
diff --git a/src/js/matrix-helpers.js b/src/js/matrix-helpers.js
--- a/src/js/matrix-helpers.js
+++ b/src/js/matrix-helpers.js
@@ -125,5 +125,3 @@
}
const toolTipTimeout = 5000;
-const imagePackRoomsEventType = 'im.ponies.emote_rooms';
-const roomImagePackEventType = 'im.ponies.room_emotes';
diff --git a/src/matrix-session.hpp b/src/matrix-session.hpp
--- a/src/matrix-session.hpp
+++ b/src/matrix-session.hpp
@@ -233,6 +233,15 @@
*/
MatrixEvent *stickerRoomsEvent() const;
+ /**
+ * Update the sticker rooms for this account.
+ *
+ * @param content The content object for the sticker rooms account data event.
+ * @return A promise that resolves when the sticker rooms account data is updated,
+ * or when there is an error.
+ */
+ MatrixPromise *updateStickerRooms(const QJsonObject &content);
+
/**
* Update the sticker pack from source.
*
@@ -242,6 +251,17 @@
*/
MatrixPromise *updateStickerPack(MatrixStickerPackSource source);
+ /**
+ * Create a new sticker pack in a room.
+ *
+ * @param roomId The id of the room.
+ * @param stateKey The state key of the pack.
+ * @param displayName Thi display name of the pack.
+ * @return A promise that resolves when the sticker pack is added,
+ * or when there is an error.
+ */
+ MatrixPromise *addRoomStickerPack(const QString &roomId, const QString &stateKey, const QString &displayName);
+
MatrixUserGivenAttrsMap *userGivenNicknameMap() const;
MatrixPromise *sendAccountData(const QString &type, const QJsonObject &content);
diff --git a/src/matrix-session.cpp b/src/matrix-session.cpp
--- a/src/matrix-session.cpp
+++ b/src/matrix-session.cpp
@@ -447,7 +447,25 @@
MatrixEvent *MatrixSession::stickerRoomsEvent() const
{
- return new MatrixEvent(m_clientOnSecondaryRoot.accountData()[imagePackRoomsEventType][lager::lenses::or_default]);
+ return new MatrixEvent(m_clientOnSecondaryRoot.accountData().map(getCanonicalImagePackRoomsEvent));
+}
+
+MatrixPromise *MatrixSession::updateStickerRooms(const QJsonObject &content)
+{
+ auto promise = m_context.createResolvedPromise({});
+ for (const auto &type : imagePackRoomsEventTypes) {
+ auto event = Event(json{
+ {"type", type},
+ {"content", content},
+ });
+ promise = promise.then([client=m_clientOnSecondaryRoot.toEventLoop(), event, ctx=m_context](const auto &stat) {
+ if (stat.success()) {
+ return client.setAccountData(event);
+ }
+ return ctx.createResolvedPromise(stat);
+ });
+ }
+ return new MatrixPromise(promise);
}
MatrixPromise *MatrixSession::updateStickerPack(MatrixStickerPackSource source)
@@ -457,18 +475,49 @@
eventJson["type"] = source.eventType;
return sendAccountDataImpl(Event(std::move(eventJson)));
} else if (source.source == MatrixStickerPackSource::RoomState) {
- auto eventJson = std::move(source.event).raw().get();
- eventJson["type"] = source.eventType;
- eventJson["state_key"] = source.stateKey;
- return new MatrixPromise(
- m_clientOnSecondaryRoot
- .room(source.roomId)
- .sendStateEvent(Event(std::move(eventJson))));
+ auto room = m_clientOnSecondaryRoot
+ .room(source.roomId);
+ auto promise = m_context.createResolvedPromise({});
+ for (const auto &type : roomStateEventTypes) {
+ auto eventJson = std::move(source.event).raw().get();
+ eventJson["type"] = type;
+ eventJson["state_key"] = source.stateKey;
+ promise = promise.then([room=room.toEventLoop(), eventJson, ctx=m_context](const auto &stat) {
+ if (stat.success()) {
+ return room.sendStateEvent(Event(eventJson));
+ }
+ return ctx.createResolvedPromise(stat);
+ });
+ }
+
+ return new MatrixPromise(promise);
} else {
return 0;
}
}
+MatrixPromise *MatrixSession::addRoomStickerPack(const QString &roomId, const QString &stateKey, const QString &displayName)
+{
+ auto stateKeyStd = stateKey.toStdString();
+ auto roomIdStd = roomId.toStdString();
+ auto room = m_clientOnSecondaryRoot.room(roomIdStd);
+ auto eventJson = getCanonicalImagePackForRoom(room.stateEvents().make().get(), stateKeyStd).originalJson().get();
+ if (!eventJson.contains("content")) {
+ eventJson["content"] = json::object();
+ }
+ if (!eventJson["content"].contains("pack")) {
+ eventJson["content"]["pack"] = json::object();
+ }
+ eventJson["content"]["pack"]["display_name"] = displayName.toStdString();
+ return updateStickerPack(MatrixStickerPackSource{
+ MatrixStickerPackSource::RoomState,
+ roomStateEventTypes[0],
+ Event(eventJson),
+ roomIdStd,
+ stateKeyStd,
+ });
+}
+
MatrixUserGivenAttrsMap *MatrixSession::userGivenNicknameMap() const
{
return new MatrixUserGivenAttrsMap(
diff --git a/src/matrix-sticker-pack-list-p.hpp b/src/matrix-sticker-pack-list-p.hpp
--- a/src/matrix-sticker-pack-list-p.hpp
+++ b/src/matrix-sticker-pack-list-p.hpp
@@ -6,8 +6,24 @@
#pragma once
#include <kazv-defs.hpp>
+#include <event.hpp>
+#include <clientutil.hpp>
+#include <immer/array.hpp>
+#include <immer/map.hpp>
#include <string>
inline const std::string accountDataEventType = "im.ponies.user_emotes";
-inline const std::string roomStateEventType = "im.ponies.room_emotes";
-inline const std::string imagePackRoomsEventType = "im.ponies.emote_rooms";
+/// types for room state event image packs, primary then secondary
+inline const immer::array<std::string> roomStateEventTypes = {
+ "m.room.image_pack",
+ "im.ponies.room_emotes",
+};
+/// types for image pack rooms in account data, primary then secondary
+inline const immer::array<std::string> imagePackRoomsEventTypes = {
+ "m.image_pack.rooms",
+ "im.ponies.emote_rooms",
+};
+
+Kazv::Event getCanonicalImagePackRoomsEvent(immer::map<std::string, Kazv::Event> accountData);
+
+Kazv::Event getCanonicalImagePackForRoom(immer::map<Kazv::KeyOfState, Kazv::Event> state, const std::string &stateKey);
diff --git a/src/matrix-sticker-pack-list.cpp b/src/matrix-sticker-pack-list.cpp
--- a/src/matrix-sticker-pack-list.cpp
+++ b/src/matrix-sticker-pack-list.cpp
@@ -20,12 +20,45 @@
using ImagePackRoomMap = immer::map<std::string/* room id */, immer::map<std::string/* */, json>>;
+Event getCanonicalImagePackRoomsEvent(immer::map<std::string, Event> accountData)
+{
+ for (const auto &type: imagePackRoomsEventTypes) {
+ if (accountData.count(type)) {
+ return accountData[type];
+ }
+ }
+ return Event();
+}
+
+Event getCanonicalImagePackForRoom(immer::map<Kazv::KeyOfState, Kazv::Event> state, const std::string &stateKey)
+{
+ for (const auto &type: roomStateEventTypes) {
+ auto ks = KeyOfState{type, stateKey};
+ if (state.count(ks)) {
+ return state[ks];
+ }
+ }
+ return Event();
+}
+
+Event getCanonicalRoomPack(immer::map<KeyOfState, Event> evs, const std::string &stateKey)
+{
+ for (const auto &type: roomStateEventTypes) {
+ auto ks = KeyOfState{type, stateKey};
+ if (evs.count(ks)) {
+ return evs[ks];
+ }
+ }
+ return Event();
+}
+
lager::reader<immer::flex_vector<MatrixStickerPackSource>> getEventsFromClient(Client client)
{
lager::reader<Event> userEmotes = client.accountData()[accountDataEventType][lager::lenses::or_default];
return lager::with(
userEmotes,
- client.accountData()[imagePackRoomsEventType][lager::lenses::or_default]
+ client.accountData()
+ .map(getCanonicalImagePackRoomsEvent)
// The following jsonAtOr performs the validation for us:
// if the content does not conform to the string-to-string-to-anything map, return an empty one
.xform(eventContent | jsonAtOr("rooms", ImagePackRoomMap{})),
@@ -42,8 +75,8 @@
for (const auto &[stateKey, _] : stateKeyMap) {
res.push_back(MatrixStickerPackSource{
MatrixStickerPackSource::RoomState,
- roomStateEventType,
- rooms[roomId].stateEvents[KeyOfState{roomStateEventType, stateKey}],
+ roomStateEventTypes[0],
+ getCanonicalRoomPack(rooms[roomId].stateEvents, stateKey),
roomId,
stateKey,
});
@@ -60,13 +93,23 @@
.map([](const auto &roomId, const auto &state) {
return intoImmer(
immer::flex_vector<MatrixStickerPackSource>{},
- zug::filter([](const auto &pair) {
- return pair.first.type == roomStateEventType;
+ zug::filter([state](const auto &pair) {
+ auto it = std::find(roomStateEventTypes.begin(), roomStateEventTypes.end(), pair.first.type);
+ if (it == roomStateEventTypes.end()) {
+ return false;
+ }
+ // This is one of image pack types. Now check if it is the stable type
+ if (it == roomStateEventTypes.begin()) {
+ return true;
+ }
+ // Here, it is not a stable type.
+ // Only return true if there is no corresponding stable type for the same state key
+ return !state.count(KeyOfState{roomStateEventTypes[0], pair.first.stateKey});
})
| zug::map([roomId](const auto &pair) {
return MatrixStickerPackSource{
MatrixStickerPackSource::RoomState,
- roomStateEventType,
+ pair.first.type,
pair.second,
roomId,
pair.first.stateKey,
diff --git a/src/tests/matrix-sticker-pack-test.cpp b/src/tests/matrix-sticker-pack-test.cpp
--- a/src/tests/matrix-sticker-pack-test.cpp
+++ b/src/tests/matrix-sticker-pack-test.cpp
@@ -38,7 +38,9 @@
private Q_SLOTS:
void testStickerPack();
void testStickerPackList();
+ void testStickerPackListStable();
void testStickerPackListInRoom();
+ void testStickerPackListInRoomStable();
void testAddToPack();
void testRemoveFromPack();
};
@@ -82,7 +84,21 @@
"type": "im.ponies.emote_rooms"
})"_json);
-static Event getRoomStickersEvent(std::string stateKey, std::string name)
+static const auto imagePackRoomsEventStable = Event(R"({
+ "content": {
+ "rooms": {
+ "!someroom:example.org": {
+ "de.sorunome.mx-puppet-bridge.discord": {}
+ },
+ "!someotherroom:example.org": {
+ "": {}
+ }
+ }
+ },
+ "type": "im.ponies.emote_rooms"
+})"_json);
+
+static Event getRoomStickersEvent(std::string stateKey, std::string name, bool stable = false)
{
auto j = R"({
"content": {
@@ -105,6 +121,9 @@
},
"type": "im.ponies.room_emotes"
})"_json;
+ if (stable) {
+ j["type"] = "m.room.image_pack";
+ }
j["state_key"] = stateKey;
j["content"]["pack"]["display_name"] = name;
return Event(j);
@@ -212,7 +231,7 @@
{u"source"_s, MatrixStickerPackSource::RoomState},
{u"isAccountData"_s, false},
{u"isState"_s, true},
- {u"eventType"_s, u"im.ponies.room_emotes"_s},
+ {u"eventType"_s, u"m.room.image_pack"_s},
{u"roomId"_s, u"!someroom:example.org"_s},
{u"stateKey"_s, u""_s},
{u"packName"_s, u"Pack 1"_s},
@@ -221,7 +240,7 @@
{u"source"_s, MatrixStickerPackSource::RoomState},
{u"isAccountData"_s, false},
{u"isState"_s, true},
- {u"eventType"_s, u"im.ponies.room_emotes"_s},
+ {u"eventType"_s, u"m.room.image_pack"_s},
{u"roomId"_s, u"!someroom:example.org"_s},
{u"stateKey"_s, u"de.sorunome.mx-puppet-bridge.discord"_s},
{u"packName"_s, u"Pack 2"_s},
@@ -230,7 +249,7 @@
{u"source"_s, MatrixStickerPackSource::RoomState},
{u"isAccountData"_s, false},
{u"isState"_s, true},
- {u"eventType"_s, u"im.ponies.room_emotes"_s},
+ {u"eventType"_s, u"m.room.image_pack"_s},
{u"roomId"_s, u"!someotherroom:example.org"_s},
{u"stateKey"_s, u""_s},
{u"packName"_s, u"Pack 3"_s},
@@ -242,7 +261,7 @@
auto p1 = toUniquePtr(stickerPackList->packFor(QJsonObject{
{u"source"_s, MatrixStickerPackSource::RoomState},
- {u"eventType"_s, u"im.ponies.room_emotes"_s},
+ {u"eventType"_s, u"m.room.image_pack"_s},
{u"roomId"_s, u"!someroom:example.org"_s},
{u"stateKey"_s, u""_s},
}));
@@ -250,13 +269,47 @@
auto p2 = toUniquePtr(stickerPackList->packFor(QJsonObject{
{u"source"_s, MatrixStickerPackSource::RoomState},
- {u"eventType"_s, u"im.ponies.room_emotes"_s},
+ {u"eventType"_s, u"m.room.image_pack"_s},
{u"roomId"_s, u"!someotherroom:example.org"_s},
{u"stateKey"_s, u"somestatekey"_s},
}));
QVERIFY(p2->isAccountData());
}
+void MatrixStickerPackTest::testStickerPackListStable()
+{
+ auto model = makeClient(
+ withAccountData({stickerPackEvent, imagePackRoomsEvent, imagePackRoomsEventStable})
+ | withRoom(makeRoom(
+ withRoomId("!someroom:example.org")
+ | withRoomState({
+ getRoomStickersEvent("", "Pack 1"),
+ getRoomStickersEvent("de.sorunome.mx-puppet-bridge.discord", "Pack 2"),
+ getRoomStickersEvent("de.sorunome.mx-puppet-bridge.discord", "Pack 2 stable", /* stable = */ true),
+ })
+ ))
+ | withRoom(makeRoom(
+ withRoomId("!someotherroom:example.org")
+ | withRoomState({getRoomStickersEvent("", "Pack 3")})
+ ))
+ );
+ SessionSetup s(SdkModel{model});
+ auto stickerPackList = toUniquePtr(s.session.stickerPackList());
+
+ // stable types takes over unstable types
+ QCOMPARE(stickerPackList->rowCount(QModelIndex()), 3);
+ QCOMPARE(stickerPackList->count(), 3);
+
+ auto packs = std::array<std::unique_ptr<MatrixStickerPack>, 3>{
+ toUniquePtr(stickerPackList->at(0)),
+ toUniquePtr(stickerPackList->at(1)),
+ toUniquePtr(stickerPackList->at(2)),
+ };
+
+ QVERIFY(hasPack(packs, u"Pack 2 stable"_s));
+ QVERIFY(!hasPack(packs, u"Pack 2"_s));
+}
+
void MatrixStickerPackTest::testStickerPackListInRoom()
{
auto model = makeClient(
@@ -307,6 +360,34 @@
QCOMPARE(QSet<QJsonValue>(packsArr.begin(), packsArr.end()), expectedPacks);
}
+void MatrixStickerPackTest::testStickerPackListInRoomStable()
+{
+ auto model = makeClient(
+ withRoom(makeRoom(
+ withRoomId("!someroom:example.org")
+ | withRoomState({
+ getRoomStickersEvent("", "Pack 1"),
+ getRoomStickersEvent("de.sorunome.mx-puppet-bridge.discord", "Pack 2"),
+ getRoomStickersEvent("de.sorunome.mx-puppet-bridge.discord", "Pack 2 stable", /* stable = */ true),
+ })
+ ))
+ );
+ SessionSetup s(SdkModel{model});
+ auto roomList = toUniquePtr(s.session.roomList());
+ auto room = toUniquePtr(roomList->room(u"!someroom:example.org"_s));
+ auto stickerPackList = toUniquePtr(room->stickerPackList());
+ QCOMPARE(stickerPackList->count(), 2);
+
+ auto packs = std::array<std::unique_ptr<MatrixStickerPack>, 2>{
+ toUniquePtr(stickerPackList->at(0)),
+ toUniquePtr(stickerPackList->at(1)),
+ };
+
+ QVERIFY(hasPack(packs, u"Pack 1"_s));
+ QVERIFY(hasPack(packs, u"Pack 2 stable"_s));
+ QVERIFY(!hasPack(packs, u"Pack 2"_s));
+}
+
void MatrixStickerPackTest::testAddToPack()
{
using namespace nlohmann::literals;
diff --git a/src/tests/quick-tests/test-helpers/MatrixSessionMock.qml b/src/tests/quick-tests/test-helpers/MatrixSessionMock.qml
--- a/src/tests/quick-tests/test-helpers/MatrixSessionMock.qml
+++ b/src/tests/quick-tests/test-helpers/MatrixSessionMock.qml
@@ -25,6 +25,8 @@
])
property var joinRoom: mockHelper.promise()
property var sendAccountData: mockHelper.promise()
+ property var updateStickerRooms: mockHelper.promise()
+ property var addRoomStickerPack: mockHelper.promise()
property var login: mockHelper.noop()
property var ssoLoginStart: mockHelper.func((serverUrl) => serverUrl + '/_matrix/client/v3/login/sso/redirect?redirectUrl=http://127.0.0.1:7456/sso-redirect/random')
property var discoverAndGetLoginFlows: mockHelper.noop()
diff --git a/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml b/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml
--- a/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml
+++ b/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml
@@ -45,9 +45,9 @@
const usePackAction = findChild(packItem, 'usePackAction');
verify(!usePackAction.checked);
usePackAction.trigger();
- tryVerify(() => matrixSession.sendAccountData.calledTimes() === 1);
+ tryVerify(() => matrixSession.updateStickerRooms.calledTimes() === 1);
verify(JsHelpers.deepEqual(
- matrixSession.sendAccountData.lastArgs()[1],
+ matrixSession.updateStickerRooms.lastArgs()[0],
{
rooms: {
'!foo:example.com': {
@@ -72,9 +72,9 @@
const usePackAction = findChild(packItem, 'usePackAction');
verify(usePackAction.checked);
usePackAction.trigger();
- tryVerify(() => matrixSession.sendAccountData.calledTimes() === 1);
+ tryVerify(() => matrixSession.updateStickerRooms.calledTimes() === 1);
verify(JsHelpers.deepEqual(
- matrixSession.sendAccountData.lastArgs()[1],
+ matrixSession.updateStickerRooms.lastArgs()[0],
{
rooms: {
'!foo:example.com': {
diff --git a/src/tests/quick-tests/tst_RoomStickerPacksPage.qml b/src/tests/quick-tests/tst_RoomStickerPacksPage.qml
--- a/src/tests/quick-tests/tst_RoomStickerPacksPage.qml
+++ b/src/tests/quick-tests/tst_RoomStickerPacksPage.qml
@@ -55,42 +55,18 @@
{
succ: true,
stateKey: '',
- packContent: {
- pack: {
- display_name: 'some name',
- },
- },
},
{
succ: false,
stateKey: '',
- packContent: {
- pack: {
- display_name: 'some name',
- },
- },
},
{
succ: true,
stateKey: 'foo',
- packContent: {
- images: {
- 'mew': {},
- },
- pack: {
- display_name: 'some name',
- },
- },
},
{
succ: true,
stateKey: 'bar',
- packContent: {
- pack: {
- 'some': 'others',
- display_name: 'some name',
- },
- },
},
];
}
@@ -101,17 +77,17 @@
findChild(page, 'stickerPackName').text = 'some name';
findChild(page, 'stickerPackStateKey').text = data.stateKey;
page.addStickerPackPopup.accept();
- tryVerify(() => page.room.sendStateEvent.calledTimes() === 1);
+ tryVerify(() => matrixSession.addRoomStickerPack.calledTimes() === 1);
verify(JsHelpers.deepEqual(
- page.room.sendStateEvent.lastArgs(),
- [{
- type: MatrixHelpers.roomImagePackEventType,
- state_key: data.stateKey,
- content: data.packContent,
- }],
+ matrixSession.addRoomStickerPack.lastArgs(),
+ [
+ page.room.roomId,
+ data.stateKey,
+ 'some name',
+ ],
));
- page.room.sendStateEvent.lastRetVal().resolve(data.succ, {});
+ matrixSession.addRoomStickerPack.lastRetVal().resolve(data.succ, {});
compare(item.showPassiveNotification.calledTimes(), 1);
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Aug 7, 3:17 PM (18 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1723102
Default Alt Text
D341.1786141036.diff (21 KB)
Attached To
Mode
D341: Support stable image pack event types
Attached
Detach File
Event Timeline
Log In to Comment