From e66763f82bdfb7f691d981d6883675817d3c4600 Mon Sep 17 00:00:00 2001 From: James Graham Date: Fri, 10 Feb 2023 19:41:23 +0000 Subject: [PATCH 1/2] Improve alias management as follows: - modify setCanonicalAlias and setLocalAliases to prevent the same alias being the canonical and an alt alias (the server doesn't prevent this) - add functions to connection to map and unmap aliases on the server - add function to map an alias to the current room on the server --- lib/connection.cpp | 18 ++++++++++++++++++ lib/connection.h | 9 +++++++++ lib/room.cpp | 29 +++++++++++++++++++++++++++-- lib/room.h | 11 +++++++++-- 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/lib/connection.cpp b/lib/connection.cpp index ea85ee1ae..61e28181c 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -18,6 +18,7 @@ #include "csapi/account-data.h" #include "csapi/capabilities.h" +#include "csapi/directory.h" #include "csapi/joining.h" #include "csapi/leaving.h" #include "csapi/logout.h" @@ -1492,6 +1493,23 @@ Room* Connection::roomByAlias(const QString& roomAlias, JoinStates states) const return nullptr; } +void Connection::mapAlias(const QString& roomId, const QString& alias) +{ + auto getRoomIdByAliasJob = callApi(alias); + connect(getRoomIdByAliasJob, &BaseJob::success, this, [this, getRoomIdByAliasJob, alias, roomId] { + if (!getRoomIdByAliasJob->roomId().isEmpty()) { + qWarning(MAIN) << "Alias" << alias << "is already mapped to" << getRoomIdByAliasJob->roomId(); + } else { + callApi(alias, roomId); + } + }); +} + +void Connection::unmapAlias(const QString& alias) +{ + callApi(alias); +} + void Connection::updateRoomAliases(const QString& roomId, const QStringList& previousRoomAliases, const QStringList& roomAliases) diff --git a/lib/connection.h b/lib/connection.h index 66b3d7151..9e463f9a1 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -288,6 +288,15 @@ class QUOTIENT_API Connection : public QObject { Q_INVOKABLE Quotient::Room* roomByAlias( const QString& roomAlias, Quotient::JoinStates states = JoinState::Invite | JoinState::Join) const; + + //! \brief Map an alias to a room ID on the server. + //! + //! \note This is different to Room::setLocalAliases as that can only + //! get the room to publish an alias that is already mapped. + //! \sa Room::setLocalAliases + Q_INVOKABLE void mapAlias(const QString& roomId, const QString& alias); + //! Unmap an alias from a room ID on the server. + Q_INVOKABLE void unmapAlias(const QString& alias); //! \brief Update the internal map of room aliases to IDs //! //! This is used to maintain the internal index of room aliases. diff --git a/lib/room.cpp b/lib/room.cpp index 159d81629..e0ebd9154 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2306,9 +2306,27 @@ void Room::setName(const QString& newName) setState(newName); } +void Room::mapAlias(const QString& alias) const +{ + connection()->mapAlias(id(), alias); +} + void Room::setCanonicalAlias(const QString& newAlias) { - setState(newAlias, altAliases()); + QString oldCanonicalAlias = canonicalAlias(); + QStringList newAltAliases = altAliases(); + // Set the old canonical alias as an alt alias. + if (!oldCanonicalAlias.isEmpty()) { + newAltAliases.append(oldCanonicalAlias); + } + // If the new canonical alias is already a published alt alias remove it + // otherwise it will be in both lists. The server doesn't prevent this so we + // need to handle it. + if (newAltAliases.contains(newAlias)) { + newAltAliases.removeAll(newAlias); + } + + setState(newAlias, newAltAliases); } void Room::setPinnedEvents(const QStringList& events) @@ -2317,7 +2335,14 @@ void Room::setPinnedEvents(const QStringList& events) } void Room::setLocalAliases(const QStringList& aliases) { - setState(canonicalAlias(), aliases); + // If one of the new alt aliases is the current canonical alias set it to "" + // otherwise it will be in both lists. The server doesn't prevent this so we + // need to handle it. + QString currentCanonicalAlias = canonicalAlias(); + if (aliases.contains(currentCanonicalAlias)) { + currentCanonicalAlias = ""; + } + setState(currentCanonicalAlias, aliases); } void Room::setTopic(const QString& newTopic) diff --git a/lib/room.h b/lib/room.h index e2d6b869a..18c389fa1 100644 --- a/lib/room.h +++ b/lib/room.h @@ -836,10 +836,17 @@ public Q_SLOTS: const QString& stateKey, const QJsonObject& contentJson); void setName(const QString& newName); - void setCanonicalAlias(const QString& newAlias); + + //! \brief Map an alias to this room on the server. + //! + //! \note This is different to setLocalAliases as that can only + //! get the room to publish an alias that is already mapped. + //! \sa setLocalAliases + Q_INVOKABLE void mapAlias(const QString& alias) const; + Q_INVOKABLE void setCanonicalAlias(const QString& newAlias); void setPinnedEvents(const QStringList& events); /// Set room aliases on the user's current server - void setLocalAliases(const QStringList& aliases); + Q_INVOKABLE void setLocalAliases(const QStringList& aliases); void setTopic(const QString& newTopic); /// You shouldn't normally call this method; it's here for debugging From 084ca4c73b1ea428c470d961563ba9a5fa920fe0 Mon Sep 17 00:00:00 2001 From: James Graham Date: Sat, 11 Feb 2023 10:10:33 +0000 Subject: [PATCH 2/2] Improve documentation --- lib/connection.h | 16 +++++++++++----- lib/room.h | 18 +++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/connection.h b/lib/connection.h index 9e463f9a1..0dded932f 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -289,13 +289,19 @@ class QUOTIENT_API Connection : public QObject { const QString& roomAlias, Quotient::JoinStates states = JoinState::Invite | JoinState::Join) const; - //! \brief Map an alias to a room ID on the server. + //! \brief Map an alias to a room ID on the user's current server. //! - //! \note This is different to Room::setLocalAliases as that can only - //! get the room to publish an alias that is already mapped. - //! \sa Room::setLocalAliases + //! This uses the room alias endpoint from the matrix specification + //! https://spec.matrix.org/v1.5/client-server-api/#room-aliases + //! + //! \note This is different to Room::setLocalAliases and + //! Room::setCanonicalAlias as they can only get the room to publish + //! an alias that is already mapped. + //! i.e. Use this function first to map an alias then Room::setLocalAliases + //! or Room::setCanonicalAlias to publish the alias officially. + //! \sa Room::setLocalAliases, Room::setCanonicalAlias Q_INVOKABLE void mapAlias(const QString& roomId, const QString& alias); - //! Unmap an alias from a room ID on the server. + //! Unmap an alias from a room ID on the user's current server. Q_INVOKABLE void unmapAlias(const QString& alias); //! \brief Update the internal map of room aliases to IDs //! diff --git a/lib/room.h b/lib/room.h index 18c389fa1..7b5f86227 100644 --- a/lib/room.h +++ b/lib/room.h @@ -837,15 +837,23 @@ public Q_SLOTS: const QJsonObject& contentJson); void setName(const QString& newName); - //! \brief Map an alias to this room on the server. + //! \brief Map an alias to this room on the user's current server. //! - //! \note This is different to setLocalAliases as that can only - //! get the room to publish an alias that is already mapped. - //! \sa setLocalAliases + //! Convenience function to call Connection::mapAlias with this room's ID + //! \sa Connection::mapAlias Q_INVOKABLE void mapAlias(const QString& alias) const; + //! \brief Publish the given alias as the room's canonical alias. + //! + //! The alias that is published must already have been mapped to the room + //! on the server. + //! \sa Room::mapAlias Q_INVOKABLE void setCanonicalAlias(const QString& newAlias); void setPinnedEvents(const QStringList& events); - /// Set room aliases on the user's current server + /// \brief Publish list of alt aliases for the room on the user's current server. + //! + //! The aliases that are published must already have been mapped to the room + //! on the server. + //! \sa Room::mapAlias Q_INVOKABLE void setLocalAliases(const QStringList& aliases); void setTopic(const QString& newTopic);