Room Settings Parents

Add the ability to manage parent rooms from a child, this includes:
- viewing parents
- adding a new parent
- removing an existing one

Follows the rules from the matrix spec https://spec.matrix.org/v1.7/client-server-api/#mspaceparent-relationships
This commit is contained in:
James Graham
2023-10-02 18:41:17 +00:00
parent 17bc08270d
commit 7180fa022b
3 changed files with 310 additions and 0 deletions

View File

@@ -117,6 +117,7 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
});
connect(this, &Room::changed, this, [this] {
Q_EMIT canEncryptRoomChanged();
Q_EMIT parentIdsChanged();
});
connect(connection, &Connection::capabilitiesLoaded, this, &NeoChatRoom::maxRoomVersionChanged);
connect(this, &Room::changed, this, [this]() {
@@ -1099,6 +1100,80 @@ void NeoChatRoom::clearInvitationNotification()
NotificationsManager::instance().clearInvitationNotification(id());
}
bool NeoChatRoom::hasParent() const
{
return currentState().eventsOfType("m.space.parent"_ls).size() > 0;
}
QVector<QString> NeoChatRoom::parentIds() const
{
auto parentEvents = currentState().eventsOfType("m.space.parent"_ls);
QVector<QString> parentIds;
for (const auto &parentEvent : parentEvents) {
if (parentEvent->contentJson().contains("via"_ls) && !parentEvent->contentPart<QJsonArray>("via"_ls).isEmpty()) {
parentIds += parentEvent->stateKey();
}
}
return parentIds;
}
bool NeoChatRoom::isCanonicalParent(const QString &parentId) const
{
if (auto parentEvent = currentState().get("m.space.parent"_ls, parentId)) {
return parentEvent->contentPart<bool>("canonical"_ls);
}
return false;
}
bool NeoChatRoom::canModifyParent(const QString &parentId) const
{
if (!canSendState("m.space.parent"_ls)) {
return false;
}
// If we can't peek the parent we assume that we neither have permission nor is
// there an existing space child event for this room.
if (auto parent = static_cast<NeoChatRoom *>(connection()->room(parentId))) {
if (!parent->isSpace()) {
return false;
}
// If the user is allowed to set space child events in the parent they are
// allowed to set the space as a parent (even if a space child event doesn't
// exist).
if (parent->canSendState("m.space.child"_ls)) {
return true;
}
// If the parent has a space child event the user can set as a parent (even
// if they don't have permission to set space child events in that parent).
if (parent->currentState().contains("m.space.child"_ls, id())) {
return true;
}
}
return false;
}
void NeoChatRoom::addParent(const QString &parentId)
{
if (!canModifyParent(parentId)) {
return;
}
if (auto parent = static_cast<NeoChatRoom *>(connection()->room(parentId))) {
setState("m.space.parent"_ls, parentId, QJsonObject{{"canonical"_ls, true}, {"via"_ls, QJsonArray{connection()->domain()}}});
}
}
void NeoChatRoom::removeParent(const QString &parentId)
{
if (!canModifyParent(parentId)) {
return;
}
if (!currentState().contains("m.space.parent"_ls, parentId)) {
return;
}
if (auto parent = static_cast<NeoChatRoom *>(connection()->room(parentId))) {
setState("m.space.parent"_ls, parentId, {});
}
}
bool NeoChatRoom::isSpace()
{
const auto creationEvent = this->creation();