// SPDX-FileCopyrightText: 2024 James Graham // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL #include "permissionsmodel.h" #include "powerlevel.h" #include #include static const QStringList defaultPermissions = { QStringLiteral("users_default"), QStringLiteral("state_default"), QStringLiteral("events_default"), QStringLiteral("invite"), QStringLiteral("kick"), QStringLiteral("ban"), QStringLiteral("redact"), QStringLiteral("m.reaction"), QStringLiteral("m.room.redaction"), QStringLiteral("m.room.power_levels"), QStringLiteral("m.room.name"), QStringLiteral("m.room.avatar"), QStringLiteral("m.room.canonical_alias"), QStringLiteral("m.room.topic"), QStringLiteral("m.room.encryption"), QStringLiteral("m.room.history_visibility"), QStringLiteral("m.room.pinned_events"), QStringLiteral("m.room.tombstone"), QStringLiteral("m.room.server_acl"), QStringLiteral("m.space.child"), QStringLiteral("m.space.parent"), }; // Alternate name text for default permissions. static const QHash defaultPermissionNames = { {QStringLiteral("users_default"), kli18nc("Room permission type", "Default user power level")}, {QStringLiteral("state_default"), kli18nc("Room permission type", "Default power level to set the room state")}, {QStringLiteral("events_default"), kli18nc("Room permission type", "Default power level to send messages")}, {QStringLiteral("invite"), kli18nc("Room permission type", "Invite users")}, {QStringLiteral("kick"), kli18nc("Room permission type", "Kick users")}, {QStringLiteral("ban"), kli18nc("Room permission type", "Ban users")}, {QStringLiteral("redact"), kli18nc("Room permission type", "Remove messages sent by other users")}, {QStringLiteral("m.reaction"), kli18nc("Room permission type", "Send reactions")}, {QStringLiteral("m.room.redaction"), kli18nc("Room permission type", "Remove their own messages")}, {QStringLiteral("m.room.power_levels"), kli18nc("Room permission type", "Change user permissions")}, {QStringLiteral("m.room.name"), kli18nc("Room permission type", "Change the room name")}, {QStringLiteral("m.room.avatar"), kli18nc("Room permission type", "Change the room avatar")}, {QStringLiteral("m.room.canonical_alias"), kli18nc("Room permission type", "Change the room canonical alias")}, {QStringLiteral("m.room.topic"), kli18nc("Room permission type", "Change the room topic")}, {QStringLiteral("m.room.encryption"), kli18nc("Room permission type", "Enable encryption for the room")}, {QStringLiteral("m.room.history_visibility"), kli18nc("Room permission type", "Change the room history visibility")}, {QStringLiteral("m.room.pinned_events"), kli18nc("Room permission type", "Set pinned events")}, {QStringLiteral("m.room.tombstone"), kli18nc("Room permission type", "Upgrade the room")}, {QStringLiteral("m.room.server_acl"), kli18nc("Room permission type", "Set the room server access control list (ACL)")}, {QStringLiteral("m.space.child"), kli18nc("Room permission type", "Set the children of this space")}, {QStringLiteral("m.space.parent"), kli18nc("Room permission type", "Set the parent space of this room")}, }; // Subtitles for the default values. static const QHash defaultSubtitles = { {QStringLiteral("users_default"), kli18nc("Room permission type", "This is the power level for all new users when joining the room")}, {QStringLiteral("state_default"), kli18nc("Room permission type", "This is used for all state events that do not have their own entry here")}, {QStringLiteral("events_default"), kli18nc("Room permission type", "This is used for all message events that do not have their own entry here")}, }; // Permissions that should use the event default. static const QStringList eventPermissions = { QStringLiteral("m.room.message"), QStringLiteral("m.reaction"), QStringLiteral("m.room.redaction"), }; PermissionsModel::PermissionsModel(QObject *parent) : QAbstractListModel(parent) { } NeoChatRoom *PermissionsModel::room() const { return m_room; } void PermissionsModel::setRoom(NeoChatRoom *room) { if (room == m_room) { return; } m_room = room; Q_EMIT roomChanged(); initializeModel(); } void PermissionsModel::initializeModel() { beginResetModel(); m_permissions.clear(); if (m_room == nullptr) { endResetModel(); return; } const auto currentPowerLevelEvent = m_room->currentState().get(); if (currentPowerLevelEvent == nullptr) { return; } m_permissions.append(defaultPermissions); for (const auto &event : currentPowerLevelEvent->events().keys()) { if (!m_permissions.contains(event)) { m_permissions += event; } } endResetModel(); } QVariant PermissionsModel::data(const QModelIndex &index, int role) const { if (m_room == nullptr || !index.isValid()) { return {}; } if (index.row() >= rowCount()) { qDebug() << "PushRuleModel, something's wrong: index.row() >= m_rules.count()"; return {}; } const auto permission = m_permissions.value(index.row()); if (role == NameRole) { if (defaultPermissionNames.keys().contains(permission)) { return defaultPermissionNames.value(permission).toString(); } return permission; } if (role == SubtitleRole) { if (permission.startsWith(QLatin1String("m.")) && defaultPermissionNames.keys().contains(permission)) { return permission; } if (defaultSubtitles.contains(permission)) { return defaultSubtitles.value(permission).toString(); } return QString(); } if (role == TypeRole) { return permission; } if (role == LevelRole) { const auto level = powerLevel(permission); if (level.has_value()) { return *level; } return {}; } if (role == LevelNameRole) { const auto level = powerLevel(permission); if (level.has_value()) { return i18nc("%1 is the name of the power level, e.g. admin and %2 is the value that represents.", "%1 (%2)", PowerLevel::nameForLevel(PowerLevel::levelForValue(*level)), *level); } return QString(); } if (role == IsDefaultValueRole) { return permission.contains(QLatin1String("default")); } if (role == IsBasicPermissionRole) { return permission == QStringLiteral("invite") || permission == QStringLiteral("kick") || permission == QStringLiteral("ban") || permission == QStringLiteral("redact"); } return {}; } int PermissionsModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_permissions.count(); } QHash PermissionsModel::roleNames() const { QHash roles = QAbstractItemModel::roleNames(); roles[NameRole] = "name"; roles[SubtitleRole] = "subtitle"; roles[TypeRole] = "type"; roles[LevelRole] = "level"; roles[LevelNameRole] = "levelName"; roles[IsDefaultValueRole] = "isDefaultValue"; roles[IsBasicPermissionRole] = "isBasicPermission"; return roles; } std::optional PermissionsModel::powerLevel(const QString &permission) const { if (m_room == nullptr) { return std::nullopt; } if (const auto currentPowerLevelEvent = m_room->currentState().get()) { if (permission == QStringLiteral("ban")) { return currentPowerLevelEvent->ban(); } else if (permission == QStringLiteral("kick")) { return currentPowerLevelEvent->kick(); } else if (permission == QStringLiteral("invite")) { return currentPowerLevelEvent->invite(); } else if (permission == QStringLiteral("redact")) { return currentPowerLevelEvent->redact(); } else if (permission == QStringLiteral("users_default")) { return currentPowerLevelEvent->usersDefault(); } else if (permission == QStringLiteral("state_default")) { return currentPowerLevelEvent->stateDefault(); } else if (permission == QStringLiteral("events_default")) { return currentPowerLevelEvent->eventsDefault(); } else if (eventPermissions.contains(permission)) { return currentPowerLevelEvent->powerLevelForEvent(permission); } else { return currentPowerLevelEvent->powerLevelForState(permission); } } return std::nullopt; } void PermissionsModel::setPowerLevel(const QString &permission, const int &newPowerLevel) { if (m_room == nullptr) { return; } int clampPowerLevel = std::clamp(newPowerLevel, -1, 100); const auto currentPowerLevel = powerLevel(permission); if (!currentPowerLevel.has_value() || currentPowerLevel == clampPowerLevel) { return; } if (auto currentPowerLevelEvent = m_room->currentState().get()) { auto powerLevelContent = currentPowerLevelEvent->contentJson(); if (powerLevelContent.contains(permission)) { powerLevelContent[permission] = clampPowerLevel; } else { auto eventPowerLevels = powerLevelContent[QLatin1String("events")].toObject(); eventPowerLevels[permission] = clampPowerLevel; powerLevelContent[QLatin1String("events")] = eventPowerLevels; } m_room->setState(powerLevelContent); } } #include "moc_permissionsmodel.cpp"