Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F112136
D34.1732272036.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D34.1732272036.diff
View Options
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@
matrix-event-reader.cpp
matrix-event-reader-list-model.cpp
matrix-event.cpp
+ matrix-link.cpp
meta-types.cpp
l10n-provider.cpp
qt-rand-adapter.cpp
diff --git a/src/matrix-link.hpp b/src/matrix-link.hpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-link.hpp
@@ -0,0 +1,52 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <libkazv-config.hpp>
+
+#include <immer/config.hpp> // https://github.com/arximboldi/immer/issues/168
+
+#include <tuple>
+#include <vector>
+#include <QObject>
+#include <QStringList>
+
+class QUrl;
+
+/**
+ * A link that represents a Matrix object.
+ */
+class MatrixLink
+{
+ Q_GADGET
+ Q_PROPERTY(bool isUser READ isUser CONSTANT)
+ Q_PROPERTY(bool isRoom READ isRoom CONSTANT)
+ Q_PROPERTY(bool isEvent READ isEvent CONSTANT)
+ Q_PROPERTY(QStringList identifiers READ identifiers CONSTANT)
+ Q_PROPERTY(QStringList routingServers READ routingServers CONSTANT)
+
+public:
+ enum Type {
+ None,
+ User,
+ RoomId,
+ RoomAlias,
+ Event,
+ };
+
+ MatrixLink(const QUrl &url);
+
+ bool isValid() const;
+ bool isUser() const;
+ bool isRoom() const;
+ bool isEvent() const;
+ QStringList identifiers() const;
+ QStringList routingServers() const;
+
+private:
+ std::vector<std::pair<Type, QString>> m_identifiers;
+ QStringList m_routingServers;
+};
diff --git a/src/matrix-link.cpp b/src/matrix-link.cpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-link.cpp
@@ -0,0 +1,102 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libkazv-config.hpp>
+
+#include <immer/config.hpp> // https://github.com/arximboldi/immer/issues/168
+
+#include <QUrl>
+#include <QUrlQuery>
+#include <QDebug>
+
+#include "matrix-link.hpp"
+
+std::pair<MatrixLink::Type, QString> parseMatrixToComp(QString comp)
+{
+ comp = QUrl("foo:#" + comp).fragment(QUrl::FullyDecoded);
+ if (comp.startsWith('@')) {
+ return {MatrixLink::User, comp};
+ } else if (comp.startsWith('#')) {
+ return {MatrixLink::RoomAlias, comp};
+ } else if (comp.startsWith('!')) {
+ return {MatrixLink::RoomId, comp};
+ } else if (comp.startsWith('$')) {
+ return {MatrixLink::Event, comp};
+ } else {
+ return {MatrixLink::None, comp};
+ }
+}
+
+QStringList parseMatrixToQuery(QString query)
+{
+ auto q = QUrlQuery(query);
+ return q.allQueryItemValues("via");
+}
+
+MatrixLink::MatrixLink(const QUrl &url)
+{
+ // matrix.to link
+ if (url.scheme() == "https"
+ && url.host() == "matrix.to") {
+ auto frag = url.fragment();
+ auto parts = frag.split('?');
+ QString ids = parts[0];
+ QString query = parts.size() > 1 ? parts[1] : "";
+
+ auto comps = ids.split('/');
+ if (comps.empty() || comps[0] != "") {
+ return;
+ }
+ comps.pop_front();
+ for (auto comp : comps) {
+ m_identifiers.push_back(parseMatrixToComp(comp));
+ }
+
+ m_routingServers = parseMatrixToQuery(query);
+ }
+}
+
+bool MatrixLink::isValid() const
+{
+ return !m_identifiers.empty()
+ && m_identifiers[0].first != None
+ && m_identifiers[0].first != Event
+ && (m_identifiers.size() == 1 || (
+ m_identifiers[1].first == Event
+ && (m_identifiers[0].first == RoomId
+ || m_identifiers[0].first == RoomAlias)));
+}
+
+bool MatrixLink::isUser() const
+{
+ return isValid() && m_identifiers[0].first == User;
+}
+
+bool MatrixLink::isRoom() const
+{
+ return isValid() && (
+ m_identifiers[0].first == RoomId
+ || m_identifiers[0].first == RoomAlias);
+}
+
+bool MatrixLink::isEvent() const
+{
+ return isValid() && m_identifiers.size() == 2;
+}
+
+QStringList MatrixLink::identifiers() const
+{
+ QStringList ret;
+ for (auto [_, id] : m_identifiers) {
+ ret.push_back(id);
+ }
+ return ret;
+}
+
+QStringList MatrixLink::routingServers() const
+{
+ return m_routingServers;
+}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -18,6 +18,7 @@
matrix-room-list-test.cpp
kazv-markdown-test.cpp
matrix-sticker-pack-test.cpp
+ matrix-link-test.cpp
LINK_LIBRARIES Qt5::Test kazvtestlib
)
diff --git a/src/tests/matrix-link-test.cpp b/src/tests/matrix-link-test.cpp
new file mode 100644
--- /dev/null
+++ b/src/tests/matrix-link-test.cpp
@@ -0,0 +1,106 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libkazv-config.hpp>
+#include <immer/config.hpp> // https://github.com/arximboldi/immer/issues/168
+
+#include <vector>
+#include <QtTest>
+
+#include "matrix-link.hpp"
+
+class MatrixLinkTest : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testInvalidLink();
+ void testUserLink();
+ void testRoomLink();
+ void testEventLink();
+ void testRoutingServers();
+};
+
+void MatrixLinkTest::testInvalidLink()
+{
+ std::vector<QUrl> links = {
+ QUrl("https://matrix.to/#"),
+ QUrl("https://matrix.to/#/"),
+ QUrl("https://matrix.to/#//"),
+ QUrl("https://matrix.to/#///"),
+ QUrl("http://matrix.to/#/%40alice%3Aexample.org"),
+ QUrl("https://lol.lol/#/%40alice%3Aexample.org"),
+ QUrl("https://matrix.to/#%40alice%3Aexample.org"),
+ };
+ for (auto link : links) {
+ MatrixLink ml(link);
+ QVERIFY(!ml.isValid());
+ }
+}
+
+void MatrixLinkTest::testUserLink()
+{
+ std::vector<QUrl> links = {
+ QUrl("https://matrix.to/#/%40alice%3Aexample.org"),
+ QUrl("https://matrix.to/#/@alice%3Aexample.org"),
+ QUrl("https://matrix.to/#/%40alice:example.org"),
+ QUrl("https://matrix.to/#/@alice:example.org"),
+ };
+ for (auto link : links) {
+ MatrixLink ml(link);
+ QVERIFY(ml.isUser());
+ QCOMPARE(ml.identifiers(), QStringList{"@alice:example.org"});
+ }
+}
+
+void MatrixLinkTest::testRoomLink()
+{
+ std::vector<std::tuple<QUrl, QString>> links = {
+ {QUrl("https://matrix.to/#/%23somewhere%3Aexample.org"), "#somewhere:example.org"},
+ {QUrl("https://matrix.to/#/%23somewhere:example.org"), "#somewhere:example.org"},
+ {QUrl("https://matrix.to/#/#somewhere%3Aexample.org"), "#somewhere:example.org"},
+ {QUrl("https://matrix.to/#/#somewhere:example.org"), "#somewhere:example.org"},
+ {QUrl("https://matrix.to/#/!somewhere%3Aexample.org?via=elsewhere.ca"), "!somewhere:example.org"},
+ {QUrl("https://matrix.to/#/!somewhere:example.org?via=elsewhere.ca"), "!somewhere:example.org"},
+ {QUrl("https://matrix.to/#/!somewhere%3Aexample.org"), "!somewhere:example.org"},
+ {QUrl("https://matrix.to/#/!somewhere:example.org"), "!somewhere:example.org"},
+ };
+ for (auto [link, pointed] : links) {
+ MatrixLink ml(link);
+ QVERIFY(ml.isRoom());
+ QCOMPARE(ml.identifiers(), QStringList{pointed});
+ }
+}
+
+void MatrixLinkTest::testEventLink()
+{
+ std::vector<std::tuple<QUrl, QString>> links = {
+ {QUrl("https://matrix.to/#/%23somewhere%3Aexample.org/%24event%3Aexample.org"), "#somewhere:example.org"},
+ {QUrl("https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org"), "#somewhere:example.org"},
+ {QUrl("https://matrix.to/#/!somewhere%3Aexample.org/%24event%3Aexample.org?via=elsewhere.ca"), "!somewhere:example.org"},
+ {QUrl("https://matrix.to/#/!somewhere%3Aexample.org/$event:example.org?via=elsewhere.ca"), "!somewhere:example.org"},
+ };
+ for (auto [link, pointed] : links) {
+ MatrixLink ml(link);
+ QVERIFY(ml.isRoom());
+ QCOMPARE(ml.identifiers(), (QStringList{pointed, "$event:example.org"}));
+ }
+}
+
+void MatrixLinkTest::testRoutingServers()
+{
+ QCOMPARE(MatrixLink(QUrl("https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org")).routingServers(), (QStringList{}));
+
+ QCOMPARE(MatrixLink(QUrl("https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org?via=a.org")).routingServers(), (QStringList{"a.org"}));
+
+ QCOMPARE(MatrixLink(QUrl("https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org?via=a.org&via=b.org")).routingServers(), (QStringList{"a.org", "b.org"}));
+
+ QCOMPARE(MatrixLink(QUrl("https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org?foo=bar&via=a.org&via=b.org")).routingServers(), (QStringList{"a.org", "b.org"}));
+}
+
+QTEST_MAIN(MatrixLinkTest)
+
+#include "matrix-link-test.moc"
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 22, 2:40 AM (12 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38792
Default Alt Text
D34.1732272036.diff (8 KB)
Attached To
Mode
D34: Add functionality to parse matrix.to links
Attached
Detach File
Event Timeline
Log In to Comment