From 95f734dfa2d19fb97a189611a33202eac886cebf Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 13 Jul 2023 19:24:41 +0200 Subject: [PATCH] basic implementation --- .../Mocks/Generated/GeneratedMocks.swift | 26 +++++++++++++++++++ .../RoomScreen/RoomScreenViewModel.swift | 21 ++++++++++++--- .../Sources/Services/Room/RoomProxy.swift | 13 ++++++++++ .../Services/Room/RoomProxyProtocol.swift | 4 +++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index bc4844e698..b0d578cfe5 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -451,6 +451,11 @@ class RoomProxyMock: RoomProxyProtocol { set(value) { underlyingHasUnreadNotifications = value } } var underlyingHasUnreadNotifications: Bool! + var currentUserID: String { + get { return underlyingCurrentUserID } + set(value) { underlyingCurrentUserID = value } + } + var underlyingCurrentUserID: String! var name: String? var displayName: String? var topic: String? @@ -1093,6 +1098,27 @@ class RoomProxyMock: RoomProxyProtocol { return uploadAvatarMediaReturnValue } } + //MARK: - canUserRedact + + var canUserRedactUserIDCallsCount = 0 + var canUserRedactUserIDCalled: Bool { + return canUserRedactUserIDCallsCount > 0 + } + var canUserRedactUserIDReceivedUserID: String? + var canUserRedactUserIDReceivedInvocations: [String] = [] + var canUserRedactUserIDReturnValue: Result! + var canUserRedactUserIDClosure: ((String) async -> Result)? + + func canUserRedact(userID: String) async -> Result { + canUserRedactUserIDCallsCount += 1 + canUserRedactUserIDReceivedUserID = userID + canUserRedactUserIDReceivedInvocations.append(userID) + if let canUserRedactUserIDClosure = canUserRedactUserIDClosure { + return await canUserRedactUserIDClosure(userID) + } else { + return canUserRedactUserIDReturnValue + } + } } class RoomTimelineProviderMock: RoomTimelineProviderProtocol { var updatePublisher: AnyPublisher { diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 820eb6173a..063ab14616 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -34,6 +34,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol private let analytics: AnalyticsService private unowned let userIndicatorController: UserIndicatorControllerProtocol private let notificationCenterProtocol: NotificationCenterProtocol + + private var canCurrentUserRedact = false init(timelineController: RoomTimelineControllerProtocol, mediaProvider: MediaProviderProtocol, @@ -104,7 +106,14 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol case .markRoomAsRead: Task { await markRoomAsRead() } case .timelineItemMenu(let itemID): - showTimelineItemActionMenu(for: itemID) + Task { + if case let .success(value) = await roomProxy.canUserRedact(userID: roomProxy.currentUserID) { + canCurrentUserRedact = value + } else { + canCurrentUserRedact = false + } + showTimelineItemActionMenu(for: itemID) + } case .timelineItemMenuAction(let itemID, let action): processTimelineItemMenuAction(action, itemID: itemID) case .displayCameraPicker: @@ -408,9 +417,11 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol actions.append(.copyPermalink) - if item.isOutgoing { + if canRedactItem(item) { actions.append(.redact) - } else { + } + + if !item.isOutgoing { actions.append(.report) } @@ -424,6 +435,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol return .init(actions: actions, debugActions: debugActions) } + + private func canRedactItem(_ item: EventBasedTimelineItemProtocol) -> Bool { + item.isOutgoing || (canCurrentUserRedact && !roomProxy.isDirect) + } // swiftlint:disable:next cyclomatic_complexity function_body_length private func processTimelineItemMenuAction(_ action: TimelineItemMenuAction, itemID: TimelineItemIdentifier) { diff --git a/ElementX/Sources/Services/Room/RoomProxy.swift b/ElementX/Sources/Services/Room/RoomProxy.swift index 88f3810b9c..09de1ca363 100644 --- a/ElementX/Sources/Services/Room/RoomProxy.swift +++ b/ElementX/Sources/Services/Room/RoomProxy.swift @@ -55,6 +55,10 @@ class RoomProxy: RoomProxyProtocol { innerTimelineProvider } + var currentUserID: String { + room.currentUserId() + } + deinit { roomTimelineObservationToken?.cancel() backPaginationStateObservationToken?.cancel() @@ -647,6 +651,15 @@ class RoomProxy: RoomProxyProtocol { } } + func canUserRedact(userID: String) async -> Result { + do { + return try await .success(room.canUserRedact(userId: userID)) + } catch { + MXLog.error("Failed checking if the user can redact with error: \(error)") + return .failure(.failedCheckingPermission) + } + } + // MARK: - Private /// Force the timeline to load member details so it can populate sender profiles whenever we add a timeline listener diff --git a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift index b33dbab6ab..fb2dc05d03 100644 --- a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift @@ -41,6 +41,7 @@ enum RoomProxyError: Error, Equatable { case failedSettingRoomTopic case failedRemovingAvatar case failedUploadingAvatar + case failedCheckingPermission } // sourcery: AutoMockable @@ -54,6 +55,7 @@ protocol RoomProxyProtocol { var canonicalAlias: String? { get } var alternativeAliases: [String] { get } var hasUnreadNotifications: Bool { get } + var currentUserID: String { get } var name: String? { get } var displayName: String? { get } @@ -159,6 +161,8 @@ protocol RoomProxyProtocol { func removeAvatar() async -> Result func uploadAvatar(media: MediaInfo) async -> Result + + func canUserRedact(userID: String) async -> Result } extension RoomProxyProtocol {