From ab0baf5d9eb3319f8d3da15bd966ab8ab2810fce Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 2 May 2021 18:01:18 +0200 Subject: Only show actions, when you have permissions to do them --- src/timeline/Permissions.cpp | 63 ++++++++++++++++++++++ src/timeline/Permissions.h | 33 ++++++++++++ src/timeline/TimelineModel.cpp | 119 ++++++++++++++++++++++++++++++++++++++++- src/timeline/TimelineModel.h | 7 +++ 4 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 src/timeline/Permissions.cpp create mode 100644 src/timeline/Permissions.h (limited to 'src/timeline') diff --git a/src/timeline/Permissions.cpp b/src/timeline/Permissions.cpp new file mode 100644 index 00000000..1eaab468 --- /dev/null +++ b/src/timeline/Permissions.cpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "Permissions.h" + +#include "Cache_p.h" +#include "MatrixClient.h" +#include "TimelineModel.h" + +Permissions::Permissions(TimelineModel *parent) + : QObject(parent) + , room(parent) +{ + invalidate(); +} + +void +Permissions::invalidate() +{ + pl = cache::client() + ->getStateEvent(room->roomId().toStdString()) + .value_or(mtx::events::StateEvent{}) + .content; +} + +bool +Permissions::canInvite() +{ + return pl.user_level(http::client()->user_id().to_string()) >= pl.invite; +} + +bool +Permissions::canBan() +{ + return pl.user_level(http::client()->user_id().to_string()) >= pl.ban; +} + +bool +Permissions::canKick() +{ + return pl.user_level(http::client()->user_id().to_string()) >= pl.kick; +} + +bool +Permissions::canRedact() +{ + return pl.user_level(http::client()->user_id().to_string()) >= pl.redact; +} +bool +Permissions::canChange(int eventType) +{ + return pl.user_level(http::client()->user_id().to_string()) >= + pl.state_level(to_string(qml_mtx_events::fromRoomEventType( + static_cast(eventType)))); +} +bool +Permissions::canSend(int eventType) +{ + return pl.user_level(http::client()->user_id().to_string()) >= + pl.event_level(to_string(qml_mtx_events::fromRoomEventType( + static_cast(eventType)))); +} diff --git a/src/timeline/Permissions.h b/src/timeline/Permissions.h new file mode 100644 index 00000000..f7e6f389 --- /dev/null +++ b/src/timeline/Permissions.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include + +class TimelineModel; + +class Permissions : public QObject +{ + Q_OBJECT + +public: + Permissions(TimelineModel *parent); + + Q_INVOKABLE bool canInvite(); + Q_INVOKABLE bool canBan(); + Q_INVOKABLE bool canKick(); + + Q_INVOKABLE bool canRedact(); + Q_INVOKABLE bool canChange(int eventType); + Q_INVOKABLE bool canSend(int eventType); + + void invalidate(); + +private: + TimelineModel *room; + mtx::events::state::PowerLevels pl; +}; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index c472ab33..a1e9ac0c 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -207,6 +207,111 @@ toRoomEventTypeString(const mtx::events::collections::TimelineEvents &event) event); } +mtx::events::EventType +qml_mtx_events::fromRoomEventType(qml_mtx_events::EventType t) +{ + switch (t) { + // Unsupported event + case qml_mtx_events::Unsupported: + return mtx::events::EventType::Unsupported; + + /// m.room_key_request + case qml_mtx_events::KeyRequest: + return mtx::events::EventType::RoomKeyRequest; + /// m.reaction: + case qml_mtx_events::Reaction: + return mtx::events::EventType::Reaction; + /// m.room.aliases + case qml_mtx_events::Aliases: + return mtx::events::EventType::RoomAliases; + /// m.room.avatar + case qml_mtx_events::Avatar: + return mtx::events::EventType::RoomAvatar; + /// m.call.invite + case qml_mtx_events::CallInvite: + return mtx::events::EventType::CallInvite; + /// m.call.answer + case qml_mtx_events::CallAnswer: + return mtx::events::EventType::CallAnswer; + /// m.call.hangup + case qml_mtx_events::CallHangUp: + return mtx::events::EventType::CallHangUp; + /// m.call.candidates + case qml_mtx_events::CallCandidates: + return mtx::events::EventType::CallCandidates; + /// m.room.canonical_alias + case qml_mtx_events::CanonicalAlias: + return mtx::events::EventType::RoomCanonicalAlias; + /// m.room.create + case qml_mtx_events::RoomCreate: + return mtx::events::EventType::RoomCreate; + /// m.room.encrypted. + case qml_mtx_events::Encrypted: + return mtx::events::EventType::RoomEncrypted; + /// m.room.encryption. + case qml_mtx_events::Encryption: + return mtx::events::EventType::RoomEncryption; + /// m.room.guest_access + case qml_mtx_events::RoomGuestAccess: + return mtx::events::EventType::RoomGuestAccess; + /// m.room.history_visibility + case qml_mtx_events::RoomHistoryVisibility: + return mtx::events::EventType::RoomHistoryVisibility; + /// m.room.join_rules + case qml_mtx_events::RoomJoinRules: + return mtx::events::EventType::RoomJoinRules; + /// m.room.member + case qml_mtx_events::Member: + return mtx::events::EventType::RoomMember; + /// m.room.name + case qml_mtx_events::Name: + return mtx::events::EventType::RoomName; + /// m.room.power_levels + case qml_mtx_events::PowerLevels: + return mtx::events::EventType::RoomPowerLevels; + /// m.room.tombstone + case qml_mtx_events::Tombstone: + return mtx::events::EventType::RoomTombstone; + /// m.room.topic + case qml_mtx_events::Topic: + return mtx::events::EventType::RoomTopic; + /// m.room.redaction + case qml_mtx_events::Redaction: + return mtx::events::EventType::RoomRedaction; + /// m.room.pinned_events + case qml_mtx_events::PinnedEvents: + return mtx::events::EventType::RoomPinnedEvents; + // m.sticker + case qml_mtx_events::Sticker: + return mtx::events::EventType::Sticker; + // m.tag + case qml_mtx_events::Tag: + return mtx::events::EventType::Tag; + /// m.room.message + case qml_mtx_events::AudioMessage: + case qml_mtx_events::EmoteMessage: + case qml_mtx_events::FileMessage: + case qml_mtx_events::ImageMessage: + case qml_mtx_events::LocationMessage: + case qml_mtx_events::NoticeMessage: + case qml_mtx_events::TextMessage: + case qml_mtx_events::VideoMessage: + case qml_mtx_events::Redacted: + case qml_mtx_events::UnknownMessage: + case qml_mtx_events::KeyVerificationRequest: + case qml_mtx_events::KeyVerificationStart: + case qml_mtx_events::KeyVerificationMac: + case qml_mtx_events::KeyVerificationAccept: + case qml_mtx_events::KeyVerificationCancel: + case qml_mtx_events::KeyVerificationKey: + case qml_mtx_events::KeyVerificationDone: + case qml_mtx_events::KeyVerificationReady: + return mtx::events::EventType::RoomMessage; + default: + return mtx::events::EventType::Unsupported; + }; +} + TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObject *parent) : QAbstractListModel(parent) , events(room_id.toStdString(), this) @@ -282,6 +387,7 @@ TimelineModel::roleNames() const {Body, "body"}, {FormattedBody, "formattedBody"}, {PreviousMessageUserId, "previousMessageUserId"}, + {IsSender, "isSender"}, {UserId, "userId"}, {UserName, "userName"}, {PreviousMessageDay, "previousMessageDay"}, @@ -333,6 +439,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r namespace acc = mtx::accessors; switch (role) { + case IsSender: + return QVariant(acc::sender(event) == http::client()->user_id().to_string()); case UserId: return QVariant(QString::fromStdString(acc::sender(event))); case UserName: @@ -497,6 +605,7 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r m.insert(names[IsOnlyEmoji], data(event, static_cast(IsOnlyEmoji))); m.insert(names[Body], data(event, static_cast(Body))); m.insert(names[FormattedBody], data(event, static_cast(FormattedBody))); + m.insert(names[IsSender], data(event, static_cast(IsSender))); m.insert(names[UserId], data(event, static_cast(UserId))); m.insert(names[UserName], data(event, static_cast(UserName))); m.insert(names[Day], data(event, static_cast(Day))); @@ -608,7 +717,10 @@ TimelineModel::syncState(const mtx::responses::State &s) emit roomNameChanged(); else if (std::holds_alternative>(e)) emit roomTopicChanged(); - else if (std::holds_alternative>(e)) { + else if (std::holds_alternative>(e)) { + permissions_.invalidate(); + emit permissionsChanged(); + } else if (std::holds_alternative>(e)) { emit roomAvatarUrlChanged(); emit roomNameChanged(); } @@ -661,7 +773,10 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline) emit roomNameChanged(); else if (std::holds_alternative>(e)) emit roomTopicChanged(); - else if (std::holds_alternative>(e)) { + else if (std::holds_alternative>(e)) { + permissions_.invalidate(); + emit permissionsChanged(); + } else if (std::holds_alternative>(e)) { emit roomAvatarUrlChanged(); emit roomNameChanged(); } diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 33e77f53..caeb25cf 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -16,6 +16,7 @@ #include "CacheCryptoStructs.h" #include "EventStore.h" #include "InputBar.h" +#include "Permissions.h" #include "ui/RoomSettings.h" #include "ui/UserProfile.h" @@ -105,6 +106,7 @@ enum EventType KeyVerificationReady }; Q_ENUM_NS(EventType) +mtx::events::EventType fromRoomEventType(qml_mtx_events::EventType); enum EventState { @@ -159,6 +161,7 @@ class TimelineModel : public QAbstractListModel Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged) Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged) Q_PROPERTY(InputBar *input READ input CONSTANT) + Q_PROPERTY(Permissions *permissions READ permissions NOTIFY permissionsChanged) public: explicit TimelineModel(TimelineViewManager *manager, @@ -173,6 +176,7 @@ public: Body, FormattedBody, PreviousMessageUserId, + IsSender, UserId, UserName, PreviousMessageDay, @@ -300,6 +304,7 @@ public slots: QString roomName() const; QString roomTopic() const; InputBar *input() { return &input_; } + Permissions *permissions() { return &permissions_; } QString roomAvatarUrl() const; QString roomId() const { return room_id_; } @@ -331,6 +336,7 @@ signals: void roomNameChanged(); void roomTopicChanged(); void roomAvatarUrlChanged(); + void permissionsChanged(); void forwardToRoom(mtx::events::collections::TimelineEvents *e, QString roomId); void scrollTargetChanged(); @@ -359,6 +365,7 @@ private: TimelineViewManager *manager_; InputBar input_{this}; + Permissions permissions_{this}; QTimer showEventTimer{this}; QString eventIdToShow; -- cgit 1.5.1