Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85831688
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
12 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/contents/ui/EventSourceView.qml b/src/contents/ui/EventSourceView.qml
index 6e9236d..a172179 100644
--- a/src/contents/ui/EventSourceView.qml
+++ b/src/contents/ui/EventSourceView.qml
@@ -1,45 +1,45 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
ColumnLayout {
property var event
Label {
text: l10n.get('event-source-decrypted')
- visible: event.decrypted
+ visible: event.encrypted
}
TextArea {
objectName: 'decryptedSourceView'
text: stringify(event.decryptedSource)
readOnly: true
font.family: 'monospace'
- visible: event.decrypted
+ visible: event.encrypted
Layout.fillWidth: true
wrapMode: TextEdit.Wrap
}
Label {
text: l10n.get('event-source-original')
}
TextArea {
objectName: 'originalSourceView'
text: stringify(event.originalSource)
readOnly: true
font.family: 'monospace'
Layout.fillWidth: true
wrapMode: TextEdit.Wrap
}
function stringify(json) {
return JSON.stringify(json, null, 2);
}
}
diff --git a/src/matrix-event.cpp b/src/matrix-event.cpp
index 4d44636..a469513 100644
--- a/src/matrix-event.cpp
+++ b/src/matrix-event.cpp
@@ -1,213 +1,213 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <kazv-defs.hpp>
#include "matrix-event.hpp"
#include "matrix-event-reader-list-model.hpp"
#include "matrix-event-list.hpp"
#include "helper.hpp"
#include "kazv-log.hpp"
using namespace Kazv;
static std::optional<LocalEchoDesc> getLocalEcho(std::variant<Event, LocalEchoDesc> event)
{
if (std::holds_alternative<LocalEchoDesc>(event)) {
return std::get<LocalEchoDesc>(event);
} else {
return std::nullopt;
}
}
static Event getEvent(std::variant<Event, LocalEchoDesc> event)
{
if (std::holds_alternative<LocalEchoDesc>(event)) {
return std::get<LocalEchoDesc>(event).event;
} else {
return std::get<Event>(event);
}
}
MatrixEvent::MatrixEvent(lager::reader<std::variant<Event, LocalEchoDesc>> event, std::optional<Room> room, QObject *parent)
: QObject(parent)
, m_localEcho(event.map(getLocalEcho))
, m_event(event.map(getEvent))
, m_room(room)
, m_eventIdStd(m_event.map(&Event::id))
, m_senderStd(m_event.map(&Event::sender))
, m_originalContent(m_event.map([](Event e) { return e.content().get().get<QJsonObject>(); }))
, m_edits(m_room.has_value() ? lager::reader<EventList>(lager::with(
m_event,
m_room->relatedEvents(m_eventIdStd, "m.replace")
).map([](const Event &origEvent, const EventList &edits) -> EventList {
// https://spec.matrix.org/v1.10/client-server-api/#event-replacements
if (!(
// (3) no state key
!origEvent.isState()
// (4) original event is not an edit
&& origEvent.relationship().first != "m.replace"
)) {
return EventList{};
}
auto origType = origEvent.type();
auto origSender = origEvent.sender();
return intoImmer(
EventList{},
zug::filter([&origType, &origSender](const Event &ev) {
return
// (0) same room id requirement is implicit.
// (1) same sender
origSender == ev.sender()
// (2) same type
&& origType == ev.type()
// (3) no state key
&& !ev.isState()
// (4) original event is not an edit is checked above
// (5) replaced event content has `m.new_content`
&& ev.content().get().contains("m.new_content");
}),
edits
);
})) : lager::make_constant(EventList{}))
, LAGER_QT(eventId)(m_eventIdStd.xform(strToQt))
, LAGER_QT(sender)(m_senderStd.xform(strToQt))
, LAGER_QT(type)(m_event.xform(zug::map([](Event e) { return e.type(); }) | strToQt))
, LAGER_QT(stateKey)(m_event.xform(zug::map([](Event e) { return e.stateKey(); }) | strToQt))
, LAGER_QT(content)(lager::with(m_originalContent, m_edits).map([](const QJsonObject &origContent, const EventList &edits) {
if (edits.empty()) {
return origContent;
} else {
return edits.at(edits.size() - 1).content().get().at("m.new_content").get<QJsonObject>();
}
}))
, LAGER_QT(encrypted)(m_event.xform(zug::map([](Event e) { return e.encrypted(); })))
, LAGER_QT(decrypted)(m_event.map([](Event e) { return e.decrypted(); }))
, LAGER_QT(isState)(m_event.map([](Event e) { return e.isState(); }))
, LAGER_QT(unsignedData)(m_event.map([](Event e) {
auto j = e.raw();
if (j.get().contains("unsigned")) {
return j.get()["unsigned"].template get<QJsonObject>();
} else {
return QJsonObject();
}
}))
, LAGER_QT(isLocalEcho)(m_localEcho.map([](const auto &maybe) { return maybe.has_value(); }))
, LAGER_QT(isSending)(m_localEcho.map([](const auto &maybe) {
return maybe.has_value() && maybe.value().status == LocalEchoDesc::Sending;
}))
, LAGER_QT(isFailed)(m_localEcho.map([](const auto &maybe) {
return maybe.has_value() && maybe.value().status == LocalEchoDesc::Failed;
}))
, LAGER_QT(txnId)(m_localEcho.map([](const auto &maybe) {
return maybe.has_value() ? QString::fromStdString(maybe.value().txnId) : QStringLiteral("");
}))
, LAGER_QT(redacted)(m_event.map([](const auto &e) {
return e.redacted();
}))
, LAGER_QT(originalSource)(m_event.map([](Event e) {
return e.originalJson().get().template get<QJsonObject>();
}))
, LAGER_QT(decryptedSource)(m_event.map([](Event e) {
- return e.decrypted() ? e.raw().get().template get<QJsonObject>() : QJsonObject();
+ return e.encrypted() ? e.decryptedJson().get().template get<QJsonObject>() : QJsonObject();
}))
, LAGER_QT(replyingToEventId)(m_event.map([](Event e) {
return e.replyingTo();
}).xform(strToQt))
, LAGER_QT(relationType)(m_event.map([](Event e) {
return e.relationship().first;
}).xform(strToQt))
, LAGER_QT(relatedEventId)(m_event.map([](Event e) {
return e.relationship().second;
}).xform(strToQt))
, LAGER_QT(formattedTime)(m_event
.map(&Event::originServerTs)
.map([](Timestamp ts) {
auto locale = QLocale::system();
return locale.toString(
QDateTime::fromMSecsSinceEpoch(ts).time(),
QLocale::ShortFormat
);
}))
, LAGER_QT(formattedDateTime)(m_event
.map(&Event::originServerTs)
.map([](Timestamp ts) {
auto locale = QLocale::system();
return locale.toString(
QDateTime::fromMSecsSinceEpoch(ts),
QLocale::ShortFormat
);
}))
, LAGER_QT(isEdited)(m_edits.map([](const auto &edits) { return !edits.empty(); }))
{
}
MatrixEvent::MatrixEvent(lager::reader<Event> event, std::optional<Kazv::Room> room, QObject *parent)
: MatrixEvent(event.map([](const auto &e) -> std::variant<Kazv::Event, Kazv::LocalEchoDesc> { return e; }), room, parent)
{
}
MatrixEvent::~MatrixEvent() = default;
MatrixEventReaderListModel *MatrixEvent::readers() const
{
if (!m_room.has_value()) {
qCDebug(kazvLog) << "readers(): no room!";
return new MatrixEventReaderListModel(lager::make_constant(immer::flex_vector<std::tuple<Kazv::Event, Kazv::Timestamp>>{}));
}
auto eventReaders = lager::with(
m_room.value().eventReaders(m_event.map(&Event::id)),
m_room.value().stateEvents()
).map([](const auto &eventReaders, const auto &states) {
return intoImmer(
immer::flex_vector<std::tuple<Kazv::Event, Kazv::Timestamp>>{},
zug::map([states](const auto &item) -> std::tuple<Kazv::Event, Kazv::Timestamp> {
auto [userId, ts] = item;
qCDebug(kazvLog) << "readers(): read by" << QString::fromStdString(userId);
auto memberEvent = states.count({"m.room.member", userId})
? states[{"m.room.member", userId}]
: Event{json{
{"content", json::object()},
{"state_key", userId},
{"type", "m.room.member"},
}};
return {memberEvent, ts};
}),
eventReaders
);
}).make();
return new MatrixEventReaderListModel(eventReaders);
}
Kazv::Event MatrixEvent::underlyingEvent() const
{
return m_event.get();
}
MatrixEventList *MatrixEvent::history() const
{
return new MatrixEventList(lager::with(m_event, m_edits)
.map([](const auto &event, const auto &edits) {
return intoImmer(
EventList{event},
zug::map([event](const auto &e) {
auto j = event.originalJson().get();
auto ret = j;
ret["type"] = e.type();
ret["content"] = e.content().get().at("m.new_content");
ret["event_id"] = e.id();
ret["origin_server_ts"] = e.originServerTs();
if (j.contains("/content/m.relates_to"_json_pointer)) {
ret["content"]["m.relates_to"] = j["content"]["m.relates_to"];
}
return Event(ret);
}),
edits
);
}));
}
diff --git a/src/tests/quick-tests/tst_EventSourceView.qml b/src/tests/quick-tests/tst_EventSourceView.qml
index 1215100..898d2f0 100644
--- a/src/tests/quick-tests/tst_EventSourceView.qml
+++ b/src/tests/quick-tests/tst_EventSourceView.qml
@@ -1,90 +1,90 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.3
import QtQuick.Layouts 1.15
import QtTest 1.0
import '../../contents/ui' as Kazv
import 'test-helpers.js' as Helpers
import 'test-helpers' as TestHelpers
Item {
id: item
width: 800
height: 600
property var l10n: Helpers.fluentMock
property var unencryptedEvent: ({
encrypted: false,
decrypted: false,
originalSource: {
event_id: '$foo',
content: {},
},
})
property var encryptedEvent: ({
encrypted: true,
decrypted: false,
originalSource: {
event_id: '$foo',
content: {},
},
})
property var decryptedEvent: ({
encrypted: true,
decrypted: true,
originalSource: {
event_id: '$foo',
content: {},
},
decryptedSource: {
content: {
msgtype: 'm.text',
body: 'foo',
},
},
})
ColumnLayout {
Kazv.EventSourceView {
id: evUnencrypted
event: unencryptedEvent
}
Kazv.EventSourceView {
id: evEncrypted
event: encryptedEvent
}
Kazv.EventSourceView {
id: evDecrypted
event: decryptedEvent
}
}
TestCase {
id: eventSourceViewTest
name: 'EventSourceViewTest'
when: windowShown
function test_unencrypted() {
verify(!findChild(evUnencrypted, 'decryptedSourceView').visible);
verify(findChild(evUnencrypted, 'originalSourceView').visible);
}
function test_encrypted() {
- verify(!findChild(evEncrypted, 'decryptedSourceView').visible);
+ verify(findChild(evEncrypted, 'decryptedSourceView').visible);
verify(findChild(evEncrypted, 'originalSourceView').visible);
}
function test_decrypted() {
verify(findChild(evDecrypted, 'decryptedSourceView').visible);
verify(findChild(evDecrypted, 'originalSourceView').visible);
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Nov 1, 8:10 PM (12 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1803304
Default Alt Text
(12 KB)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline