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..0dded932f 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -288,6 +288,21 @@ 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 user's current server. + //! + //! 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 user's current 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..7b5f86227 100644 --- a/lib/room.h +++ b/lib/room.h @@ -836,10 +836,25 @@ 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 user's current server. + //! + //! 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 - void setLocalAliases(const QStringList& aliases); + /// \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); /// You shouldn't normally call this method; it's here for debugging