diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 423027e33c..29bfae48b3 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -498,6 +498,7 @@ 802C895C21639B8900C6B9B2 /* MessagesViewControllerBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 802C895B21639B8900C6B9B2 /* MessagesViewControllerBanner.swift */; }; 802C895E2165393600C6B9B2 /* MessagesViewControllerEditing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 802C895D2165393600C6B9B2 /* MessagesViewControllerEditing.swift */; }; 802C896121658F3400C6B9B2 /* EmojiViewSetEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = 802C896021658F3400C6B9B2 /* EmojiViewSetEmoji.swift */; }; + 802D25AB224E2EE00043B40B /* RoomDeletedMessagesRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 802D25AA224E2EE00043B40B /* RoomDeletedMessagesRequest.swift */; }; 80307E3C1FD75BE1006AD9EF /* VOTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80307E3B1FD75BE1006AD9EF /* VOTextField.swift */; }; 80307E3E1FD75CB1006AD9EF /* VOLocalized.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80307E3D1FD75CB1006AD9EF /* VOLocalized.swift */; }; 80307E411FD75DC0006AD9EF /* VoiceOver.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80307E431FD75DC0006AD9EF /* VoiceOver.strings */; }; @@ -1487,6 +1488,7 @@ 802C895B21639B8900C6B9B2 /* MessagesViewControllerBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewControllerBanner.swift; sourceTree = ""; }; 802C895D2165393600C6B9B2 /* MessagesViewControllerEditing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewControllerEditing.swift; sourceTree = ""; }; 802C896021658F3400C6B9B2 /* EmojiViewSetEmoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiViewSetEmoji.swift; sourceTree = ""; }; + 802D25AA224E2EE00043B40B /* RoomDeletedMessagesRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomDeletedMessagesRequest.swift; sourceTree = ""; }; 80307E3B1FD75BE1006AD9EF /* VOTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VOTextField.swift; sourceTree = ""; }; 80307E3D1FD75CB1006AD9EF /* VOLocalized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VOLocalized.swift; sourceTree = ""; }; 80307E421FD75DC0006AD9EF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/VoiceOver.strings; sourceTree = ""; }; @@ -3285,6 +3287,7 @@ 8039441020AF1334002F317A /* RoomKickRequest.swift */, 8039442420B330B2002F317A /* RoomInviteRequest.swift */, 80BFF60221D40EDF00D99771 /* RoomHistoryRequest.swift */, + 802D25AA224E2EE00043B40B /* RoomDeletedMessagesRequest.swift */, ); path = Room; sourceTree = ""; @@ -4930,6 +4933,7 @@ 0B9AB2C120444ECD00ABEA05 /* LanguageViewController.swift in Sources */, 806728FD200789F4009FE94D /* PreferencesNavigationController.swift in Sources */, 413996171F3B44500075F96E /* UploadHelper.swift in Sources */, + 802D25AB224E2EE00043B40B /* RoomDeletedMessagesRequest.swift in Sources */, 7798B4151F852B720074B2F4 /* SelectField.swift in Sources */, 9977D859217E94C400FE5EC6 /* MessageActionsCell.swift in Sources */, 805DEC351FFC03380033151B /* CustomEmojiManager.swift in Sources */, diff --git a/Rocket.Chat/API/Clients/SubscriptionsClient.swift b/Rocket.Chat/API/Clients/SubscriptionsClient.swift index 54900d56d5..1a5f7b903f 100644 --- a/Rocket.Chat/API/Clients/SubscriptionsClient.swift +++ b/Rocket.Chat/API/Clients/SubscriptionsClient.swift @@ -277,16 +277,41 @@ extension SubscriptionsClient { api.fetch(request) { response in switch response { case .resource(let resource): - realm?.execute({ realm in - let messages = resource.messages(realm: realm) ?? [] - realm.add(messages, update: true) - lastMessageDate = messages.last?.createdAt - }, completion: { - completion(lastMessageDate) + self.loadDeletedMessages(subscription: subscription, completion: { (idsMessageDeleted) in + realm?.execute({ realm in + let messages = resource.messages(realm: realm) ?? [] + let messagesToDelete = realm.objects(Message.self).filter("identifier IN %@", idsMessageDeleted) + realm.delete(messagesToDelete) + realm.add(messages, update: true) + lastMessageDate = messages.last?.createdAt + }, completion: { + completion(lastMessageDate) + }) }) case .error: completion(lastMessageDate) } } } + + private func loadDeletedMessages(subscription: Subscription, completion: (([String]) -> Void)? = nil) { + + // TODO: Save latest date? Older messages may have been deleted so we probably should always check up to the oldest + // cached message. + let request = RoomDeletedMessagesRequest(roomId: subscription.rid, since: Date(timeIntervalSince1970: 0)) + API.current()?.fetch(request, completion: {response in + switch response { + case .resource(let resource): + let idsDeleted = resource.messages?.compactMap { $0 } + completion?(idsDeleted ?? []) + case .error(let error): + switch error { + case .version(available: _, required: _): + completion?([]) + default: + Alert.defaultError.present() + } + } + }) + } } diff --git a/Rocket.Chat/API/Requests/Room/RoomDeletedMessagesRequest.swift b/Rocket.Chat/API/Requests/Room/RoomDeletedMessagesRequest.swift new file mode 100644 index 0000000000..0bacb93fa8 --- /dev/null +++ b/Rocket.Chat/API/Requests/Room/RoomDeletedMessagesRequest.swift @@ -0,0 +1,57 @@ +// +// RoomDeletedMessagesRequest.swift +// Rocket.Chat +// +// Created by Luís Machado on 29/03/2019. +// Copyright © 2019 Rocket.Chat. All rights reserved. +// + +import SwiftyJSON +import Foundation + +struct RoomDeletedMessagesRequest: APIRequest { + typealias APIResourceType = DeletedMessagesResource + + let path = "/api/v1/chat.getDeletedMessages" + let requiredVersion = Version(0, 73, 0) + + var query: String? + let roomId: String? + let since: Date? + + // How to improve this default date? We only want deleted messages as far as the older message we have on cache! (older ones won't be returned) + init(roomId: String, since: Date = Date(timeIntervalSince1970: 0)) { + self.roomId = roomId + self.since = since + + let dateFormatter = ISO8601DateFormatter() + let dateString = dateFormatter.string(from: since) + + if let encodedString = dateString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) { + self.query = "roomId=\(roomId)&since=\(encodedString)" + } + } +} + +final class DeletedMessagesResource: APIResource { + var messages: [String?]? { + return raw?["messages"].arrayValue.map { + if let removedMsg = $0.dictionaryObject, let msgId = removedMsg["_id"] as? String { + return msgId + } + return nil + } + } + + var count: Int? { + return raw?["count"].int + } + + var offset: Int? { + return raw?["offset"].int + } + + var total: Int? { + return raw?["total"].int + } +}