Fix clear history

This commit is contained in:
Peter 2019-03-20 21:15:16 +04:00
parent 6696d6045c
commit 2a05628f97
8 changed files with 59 additions and 25 deletions

View File

@ -90,6 +90,7 @@ enum AccountStateMutationOperation {
case UpdateCall(Api.PhoneCall)
case UpdateLangPack(String, Api.LangPackDifference?)
case UpdateMinAvailableMessage(MessageId)
case UpdatePeerInclusionMinTimestamp(PeerId, Int32)
}
struct AccountMutableState {
@ -277,6 +278,10 @@ struct AccountMutableState {
self.addOperation(.UpdateMinAvailableMessage(id))
}
mutating func updatePeerInclusionMinTimestamp(peerId: PeerId, timestamp: Int32) {
self.addOperation(.UpdatePeerInclusionMinTimestamp(peerId, timestamp))
}
mutating func mergeUsers(_ users: [Api.User]) {
self.addOperation(.MergeApiUsers(users))
@ -347,7 +352,7 @@ struct AccountMutableState {
mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerInclusionMinTimestamp, .UpdatePeerChatUnreadMark, .UpdateIsContact:
break
case let .AddMessages(messages, location):
for message in messages {

View File

@ -829,6 +829,13 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
}
}
updatedState.editMessage(messageId, message: message)
for media in message.media {
if let media = media as? TelegramMediaAction {
if case .historyCleared = media.action {
updatedState.readInbox(messageId)
}
}
}
}
case let .updateNewChannelMessage(apiMessage, pts, ptsCount):
if let message = StoreMessage(apiMessage: apiMessage) {
@ -1885,7 +1892,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddMessages: OptimizeAddMessagesState?
for operation in operations {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerInclusionMinTimestamp, .UpdateIsContact:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
}
@ -2104,6 +2111,14 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids)
case let .UpdateMinAvailableMessage(id):
transaction.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id)
case let .UpdatePeerInclusionMinTimestamp(peerId, timestamp):
let inclusion = transaction.getPeerChatListInclusion(peerId)
switch inclusion {
case .ifHasMessages, .ifHasMessagesOrOneOf:
transaction.updatePeerChatListInclusion(peerId, inclusion: inclusion.withSetIfHasMessagesOrMaxMinTimestamp(timestamp))
default:
break
}
case let .EditMessage(id, message):
transaction.updateMessage(id, update: { previousMessage in
var updatedFlags = message.flags

View File

@ -86,15 +86,18 @@ final class CloudChatRemoveChatOperation: PostboxCoding {
final class CloudChatClearHistoryOperation: PostboxCoding {
let peerId: PeerId
let topMessageId: MessageId
let type: InteractiveMessagesDeletionType
init(peerId: PeerId, topMessageId: MessageId) {
init(peerId: PeerId, topMessageId: MessageId, type: InteractiveMessagesDeletionType) {
self.peerId = peerId
self.topMessageId = topMessageId
self.type = type
}
init(decoder: PostboxDecoder) {
self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0))
self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0))
self.type = InteractiveMessagesDeletionType(rawValue: decoder.decodeInt32ForKey("type", orElse: 0)) ?? .forLocalPeer
}
func encode(_ encoder: PostboxEncoder) {
@ -102,6 +105,7 @@ final class CloudChatClearHistoryOperation: PostboxCoding {
encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p")
encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n")
encoder.encodeInt32(self.topMessageId.id, forKey: "m.i")
encoder.encodeInt32(self.type.rawValue, forKey: "type")
}
}
@ -113,7 +117,7 @@ func cloudChatAddRemoveChatOperation(transaction: Transaction, peerId: PeerId, r
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveChatOperation(peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible, topMessageId: transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)))
}
func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?) {
func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, type: InteractiveMessagesDeletionType) {
let topMessageId: MessageId?
if let explicitTopMessageId = explicitTopMessageId {
topMessageId = explicitTopMessageId
@ -121,6 +125,6 @@ func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId,
topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)
}
if let topMessageId = topMessageId {
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId))
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, type: type))
}
}

View File

@ -9,9 +9,9 @@ import Foundation
import MtProtoKitDynamic
#endif
public enum InteractiveMessagesDeletionType {
case forLocalPeer
case forEveryone
public enum InteractiveMessagesDeletionType: Int32 {
case forLocalPeer = 0
case forEveryone = 1
}
public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId], type: InteractiveMessagesDeletionType) -> Signal<Void, NoError> {
@ -57,21 +57,25 @@ public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId
}
}
public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signal<Void, NoError> {
public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type: InteractiveMessagesDeletionType) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
var topTimestamp: Int32?
if let topIndex = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
topTimestamp = topIndex.timestamp
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, type: type)
var topIndex: MessageIndex?
if let topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud), let topMessage = transaction.getMessage(topMessageId) {
topIndex = MessageIndex(topMessage)
}
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil)
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId)
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference {
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1))
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1), type: type)
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId)
}
if let topTimestamp = topTimestamp {
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topTimestamp)
if let topIndex = topIndex {
if peerId.namespace == Namespaces.Peer.CloudUser {
let _ = transaction.addMessages([StoreMessage(id: topIndex.id, globallyUniqueId: nil, groupingKey: nil, timestamp: topIndex.timestamp, flags: StoreMessageFlags(), tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: nil, text: "", attributes: [], media: [TelegramMediaAction(action: .historyCleared)])], location: .Random)
} else {
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topIndex.timestamp)
}
}
} else if peerId.namespace == Namespaces.Peer.SecretChat {
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId)

View File

@ -6,6 +6,8 @@ import Foundation
#endif
public struct LimitsConfiguration: Equatable, PreferencesEntry {
public static let timeIntervalForever: Int32 = 0x7fffffff
public var maxGroupMemberCount: Int32
public var maxSupergroupMemberCount: Int32
public var maxMessageForwardBatchSize: Int32

View File

@ -261,7 +261,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
}
let deleteMessages: Signal<Void, NoError>
if let inputPeer = apiInputPeer(peer), let topMessageId = operation.topMessageId ?? transaction.getTopPeerMessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud) {
deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false)
deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
} else {
deleteMessages = .complete()
}
@ -285,7 +285,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
} else {
reportSignal = .complete()
}
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false)
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
|> then(reportSignal)
|> then(postbox.transaction { transaction -> Void in
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id)
@ -298,8 +298,15 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
}
}
private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool) -> Signal<Void, NoError> {
let signal = network.request(Api.functions.messages.deleteHistory(flags: justClear ? 1 : 0, peer: inputPeer, maxId: maxId))
private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool, type: InteractiveMessagesDeletionType) -> Signal<Void, NoError> {
var flags: Int32 = 0
if justClear {
flags |= 1 << 0
}
if case .forEveryone = type {
flags |= 1 << 1
}
let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: maxId))
|> map { result -> Api.messages.AffectedHistory? in
return result
}
@ -330,7 +337,7 @@ private func requestClearHistory(postbox: Postbox, network: Network, stateManage
private func clearHistory(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatClearHistoryOperation) -> Signal<Void, NoError> {
if peer.id.namespace == Namespaces.Peer.CloudGroup || peer.id.namespace == Namespaces.Peer.CloudUser {
if let inputPeer = apiInputPeer(peer) {
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true)
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, type: operation.type)
} else {
return .complete()
}

View File

@ -559,9 +559,6 @@ extension StoreMessage {
case .messageEmpty:
return nil
case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action):
if case .messageActionHistoryClear = action {
return nil
}
let peerId: PeerId
var authorId: PeerId?
switch toId {

View File

@ -240,7 +240,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return TelegramMediaAction(action: .channelMigratedFromGroup(title: title, groupId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)))
case let .messageActionChatAddUser(users):
return TelegramMediaAction(action: .addedMembers(peerIds: users.map({ PeerId(namespace: Namespaces.Peer.CloudUser, id: $0) })))
case let .messageActionChatCreate(title, userIds):
case let .messageActionChatCreate(title, _):
return TelegramMediaAction(action: .groupCreated(title: title))
case .messageActionChatDeletePhoto:
return TelegramMediaAction(action: .photoUpdated(image: nil))