Merge pull request #327 from mpretty-cyro/fix/input-not-reappearing

Fixed some issues with message deletion and the input field
pull/1053/head
Morgan Pretty 5 months ago committed by GitHub
commit 1439b1b033
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -2121,6 +2121,7 @@ extension ConversationVC:
} }
// Delete the message from the open group // Delete the message from the open group
self.hideInputAccessoryView()
deleteRemotely( deleteRemotely(
from: self, from: self,
request: Storage.shared request: Storage.shared
@ -2145,13 +2146,14 @@ extension ConversationVC:
userPublicKey : userPublicKey :
cellViewModel.threadId cellViewModel.threadId
) )
let serverHash: String? = Storage.shared.read { db -> String? in let serverHashes: Set<String> = Storage.shared
try Interaction .read { db -> Set<String> in
.select(.serverHash) try Interaction.serverHashesForDeletion(
.filter(id: cellViewModel.id) db,
.asRequest(of: String.self) interactionIds: [cellViewModel.id]
.fetchOne(db) )
} }
.defaulting(to: [])
let unsendRequest: UnsendRequest = UnsendRequest( let unsendRequest: UnsendRequest = UnsendRequest(
timestamp: UInt64(cellViewModel.timestampMs), timestamp: UInt64(cellViewModel.timestampMs),
author: (cellViewModel.variant == .standardOutgoing ? author: (cellViewModel.variant == .standardOutgoing ?
@ -2165,7 +2167,7 @@ extension ConversationVC:
) )
// For incoming interactions or interactions with no serverHash just delete them locally // For incoming interactions or interactions with no serverHash just delete them locally
guard cellViewModel.variant == .standardOutgoing, let serverHash: String = serverHash else { guard cellViewModel.variant == .standardOutgoing, !serverHashes.isEmpty else {
Storage.shared.writeAsync { db in Storage.shared.writeAsync { db in
_ = try Interaction _ = try Interaction
.filter(id: cellViewModel.id) .filter(id: cellViewModel.id)
@ -2173,7 +2175,7 @@ extension ConversationVC:
// No need to send the unsendRequest if there is no serverHash (ie. the message // No need to send the unsendRequest if there is no serverHash (ie. the message
// was outgoing but never got to the server) // was outgoing but never got to the server)
guard serverHash != nil else { return } guard !serverHashes.isEmpty else { return }
MessageSender MessageSender
.send( .send(
@ -2221,7 +2223,6 @@ extension ConversationVC:
actionSheet.addAction(UIAlertAction( actionSheet.addAction(UIAlertAction(
title: { title: {
switch (cellViewModel.threadVariant, cellViewModel.threadId) { switch (cellViewModel.threadVariant, cellViewModel.threadId) {
case (.legacyGroup, _), (.group, _): return "clearMessagesForEveryone".localized()
case (_, userPublicKey): return "deleteMessageDevicesAll".localized() case (_, userPublicKey): return "deleteMessageDevicesAll".localized()
default: return "deleteMessageEveryone".localized() default: return "deleteMessageEveryone".localized()
} }
@ -2231,6 +2232,10 @@ extension ConversationVC:
) { [weak self] _ in ) { [weak self] _ in
let completeServerDeletion = { let completeServerDeletion = {
Storage.shared.writeAsync { db in Storage.shared.writeAsync { db in
_ = try Interaction
.filter(id: cellViewModel.id)
.deleteAll(db)
try MessageSender try MessageSender
.send( .send(
db, db,
@ -2240,7 +2245,15 @@ extension ConversationVC:
threadVariant: cellViewModel.threadVariant, threadVariant: cellViewModel.threadVariant,
using: dependencies using: dependencies
) )
/// We should also remove the `SnodeReceivedMessageInfo` entries for the hashes (otherwise we
/// might try to poll for a hash which no longer exists, resulting in fetching the last 14 days of messages)
try SnodeReceivedMessageInfo.handlePotentialDeletedOrInvalidHash(
db,
potentiallyInvalidHashes: Array(serverHashes)
)
} }
self?.showInputAccessoryView()
} }
// We can only delete messages on the server for `contact` and `group` conversations // We can only delete messages on the server for `contact` and `group` conversations
@ -2253,7 +2266,7 @@ extension ConversationVC:
request: SnodeAPI request: SnodeAPI
.deleteMessages( .deleteMessages(
swarmPublicKey: targetPublicKey, swarmPublicKey: targetPublicKey,
serverHashes: [serverHash] serverHashes: Array(serverHashes)
) )
.map { _ in () } .map { _ in () }
.eraseToAnyPublisher() .eraseToAnyPublisher()

@ -799,32 +799,6 @@ public extension Interaction {
return "\(threadId)-\(id)" return "\(threadId)-\(id)"
} }
func markingAsDeleted() -> Interaction {
return Interaction(
id: id,
serverHash: nil,
messageUuid: messageUuid,
threadId: threadId,
authorId: authorId,
variant: .standardIncomingDeleted,
body: nil,
timestampMs: timestampMs,
receivedAtTimestampMs: receivedAtTimestampMs,
wasRead: true, // Never consider deleted messages unread
hasMention: false,
expiresInSeconds: expiresInSeconds,
expiresStartedAtMs: expiresStartedAtMs,
linkPreviewUrl: nil,
openGroupServerMessageId: openGroupServerMessageId,
openGroupWhisper: openGroupWhisper,
openGroupWhisperMods: openGroupWhisperMods,
openGroupWhisperTo: openGroupWhisperTo,
state: .deleted,
recipientReadTimestampMs: nil,
mostRecentFailureText: nil
)
}
static func isUserMentioned( static func isUserMentioned(
_ db: Database, _ db: Database,
threadId: String, threadId: String,
@ -1146,3 +1120,56 @@ public extension Interaction.State {
} }
} }
} }
// MARK: - Deletion
public extension Interaction {
/// When deleting a message we should also delete any reactions which were on the message, so fetch and
/// return those hashes as well
static func serverHashesForDeletion(
_ db: Database,
interactionIds: Set<Int64>,
additionalServerHashesToRemove: [String] = []
) throws -> Set<String> {
let messageHashes: [String] = try Interaction
.filter(ids: interactionIds)
.filter(Interaction.Columns.serverHash != nil)
.select(.serverHash)
.asRequest(of: String.self)
.fetchAll(db)
let reactionHashes: [String] = try Reaction
.filter(interactionIds.contains(Reaction.Columns.interactionId))
.filter(Reaction.Columns.serverHash != nil)
.select(.serverHash)
.asRequest(of: String.self)
.fetchAll(db)
return Set(messageHashes + reactionHashes + additionalServerHashesToRemove)
}
func markingAsDeleted() -> Interaction {
return Interaction(
id: id,
serverHash: nil,
messageUuid: messageUuid,
threadId: threadId,
authorId: authorId,
variant: .standardIncomingDeleted,
body: nil,
timestampMs: timestampMs,
receivedAtTimestampMs: receivedAtTimestampMs,
wasRead: true, // Never consider deleted messages unread
hasMention: false,
expiresInSeconds: expiresInSeconds,
expiresStartedAtMs: expiresStartedAtMs,
linkPreviewUrl: nil,
openGroupServerMessageId: openGroupServerMessageId,
openGroupWhisper: openGroupWhisper,
openGroupWhisperMods: openGroupWhisperMods,
openGroupWhisperTo: openGroupWhisperTo,
state: .deleted,
recipientReadTimestampMs: nil,
mostRecentFailureText: nil
)
}
}

@ -10,7 +10,8 @@ extension MessageReceiver {
_ db: Database, _ db: Database,
threadId: String, threadId: String,
threadVariant: SessionThread.Variant, threadVariant: SessionThread.Variant,
message: UnsendRequest message: UnsendRequest,
using dependencies: Dependencies
) throws { ) throws {
let userPublicKey: String = getUserHexEncodedPublicKey(db) let userPublicKey: String = getUserHexEncodedPublicKey(db)
@ -27,7 +28,7 @@ extension MessageReceiver {
let interaction: Interaction = maybeInteraction let interaction: Interaction = maybeInteraction
else { return } else { return }
// Mark incoming messages as read and remove any of their notifications /// Mark incoming messages as read and remove any of their notifications
if interaction.variant == .standardIncoming { if interaction.variant == .standardIncoming {
try Interaction.markAsRead( try Interaction.markAsRead(
db, db,
@ -42,15 +43,11 @@ extension MessageReceiver {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: interaction.notificationIdentifiers) UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: interaction.notificationIdentifiers)
} }
if author == message.sender, let serverHash: String = interaction.serverHash { /// Retrieve the hashes which should be deleted first (these will be removed by marking the message as deleted)
SnodeAPI let hashes: Set<String> = try Interaction.serverHashesForDeletion(
.deleteMessages( db,
swarmPublicKey: author, interactionIds: [interactionId]
serverHashes: [serverHash] )
)
.subscribe(on: DispatchQueue.global(qos: .background))
.sinkUntilComplete()
}
switch (interaction.variant, (author == message.sender)) { switch (interaction.variant, (author == message.sender)) {
case (.standardOutgoing, _), (_, false): case (.standardOutgoing, _), (_, false):
@ -71,5 +68,40 @@ extension MessageReceiver {
) )
} }
} }
/// Can't delete from the legacy group swarm so only bother for contact conversations
switch threadVariant {
case .legacyGroup, .group, .community: break
case .contact:
dependencies.storage
.readPublisher { db in
try SnodeAPI.preparedDeleteMessages(
db,
swarmPublicKey: userPublicKey,
serverHashes: Array(hashes),
requireSuccessfulDeletion: false,
using: dependencies
)
}
.flatMap { $0.send(using: dependencies) }
.subscribe(on: DispatchQueue.global(qos: .background), using: dependencies)
.sinkUntilComplete(
receiveCompletion: { result in
switch result {
case .failure: break
case .finished:
/// Since the server deletion was successful we should also remove the `SnodeReceivedMessageInfo`
/// entries for the hashes (otherwise we might try to poll for a hash which no longer exists, resulting in fetching
/// the last 14 days of messages)
dependencies.storage.writeAsync { db in
try SnodeReceivedMessageInfo.handlePotentialDeletedOrInvalidHash(
db,
potentiallyInvalidHashes: Array(hashes)
)
}
}
}
)
}
} }
} }

@ -335,7 +335,8 @@ public enum MessageReceiver {
db, db,
threadId: threadId, threadId: threadId,
threadVariant: threadVariant, threadVariant: threadVariant,
message: message message: message,
using: dependencies
) )
case let message as CallMessage: case let message as CallMessage:

Loading…
Cancel
Save