Restore quoted reply thumbnail attachments from backup
This commit is contained in:
parent
07baa170f7
commit
4d320fd384
@ -86,6 +86,45 @@ internal class MessageBackupMessageAttachmentArchiver: MessageBackupProtoArchive
|
||||
)
|
||||
}
|
||||
|
||||
public func restoreQuotedReplyThumbnailAttachment(
|
||||
_ attachment: BackupProto_MessageAttachment,
|
||||
chatItemId: MessageBackup.ChatItemId,
|
||||
messageRowId: Int64,
|
||||
message: TSMessage,
|
||||
thread: MessageBackup.ChatThread,
|
||||
tx: DBWriteTransaction
|
||||
) -> MessageBackup.RestoreInteractionResult<Void> {
|
||||
let clientUUID: UUID?
|
||||
if attachment.hasClientUuid {
|
||||
guard let uuid = UUID(data: attachment.clientUuid) else {
|
||||
return .messageFailure([.restoreFrameError(
|
||||
.invalidProtoData(.invalidAttachmentClientUUID),
|
||||
chatItemId
|
||||
)])
|
||||
}
|
||||
clientUUID = uuid
|
||||
} else {
|
||||
clientUUID = nil
|
||||
}
|
||||
|
||||
let ownedAttachment = OwnedAttachmentBackupPointerProto(
|
||||
proto: attachment.pointer,
|
||||
renderingFlag: attachment.flag.asAttachmentFlag,
|
||||
clientUUID: clientUUID,
|
||||
owner: .quotedReplyAttachment(.init(
|
||||
messageRowId: messageRowId,
|
||||
receivedAtTimestamp: message.receivedAtTimestamp,
|
||||
threadRowId: thread.threadRowId
|
||||
))
|
||||
)
|
||||
|
||||
return restoreAttachments(
|
||||
[ownedAttachment],
|
||||
chatItemId: chatItemId,
|
||||
tx: tx
|
||||
)
|
||||
}
|
||||
|
||||
private func restoreAttachments(
|
||||
_ attachments: [OwnedAttachmentBackupPointerProto],
|
||||
chatItemId: MessageBackup.ChatItemId,
|
||||
|
||||
@ -30,6 +30,7 @@ extension MessageBackup {
|
||||
|
||||
fileprivate let reactions: [BackupProto_Reaction]
|
||||
fileprivate let bodyAttachments: [BackupProto_MessageAttachment]
|
||||
fileprivate let quotedMessageThumbnail: BackupProto_MessageAttachment?
|
||||
}
|
||||
|
||||
struct Payment {
|
||||
@ -395,39 +396,47 @@ class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchiver {
|
||||
)])
|
||||
}
|
||||
|
||||
let restoreInteractionResult: RestoreInteractionResult<Void>
|
||||
let restoreBodyAttachmentsResult: RestoreInteractionResult<Void>
|
||||
var downstreamObjectResults = [RestoreInteractionResult<Void>]()
|
||||
switch restoredContents {
|
||||
case .text(let text):
|
||||
restoreInteractionResult = reactionArchiver.restoreReactions(
|
||||
downstreamObjectResults.append(reactionArchiver.restoreReactions(
|
||||
text.reactions,
|
||||
chatItemId: chatItemId,
|
||||
message: message,
|
||||
context: context.recipientContext,
|
||||
tx: tx
|
||||
)
|
||||
restoreBodyAttachmentsResult = attachmentsArchiver.restoreBodyAttachments(
|
||||
))
|
||||
downstreamObjectResults.append(attachmentsArchiver.restoreBodyAttachments(
|
||||
text.bodyAttachments,
|
||||
chatItemId: chatItemId,
|
||||
messageRowId: messageRowId,
|
||||
message: message,
|
||||
thread: thread,
|
||||
tx: tx
|
||||
)
|
||||
))
|
||||
if let quotedMessageThumbnail = text.quotedMessageThumbnail {
|
||||
downstreamObjectResults.append(attachmentsArchiver.restoreQuotedReplyThumbnailAttachment(
|
||||
quotedMessageThumbnail,
|
||||
chatItemId: chatItemId,
|
||||
messageRowId: messageRowId,
|
||||
message: message,
|
||||
thread: thread,
|
||||
tx: tx
|
||||
))
|
||||
}
|
||||
case .archivedPayment(let archivedPayment):
|
||||
restoreInteractionResult = restoreArchivedPaymentContents(
|
||||
downstreamObjectResults.append(restoreArchivedPaymentContents(
|
||||
archivedPayment,
|
||||
chatItemId: chatItemId,
|
||||
thread: thread,
|
||||
message: message,
|
||||
tx: tx
|
||||
)
|
||||
// No body attachments to restore
|
||||
restoreBodyAttachmentsResult = .success(())
|
||||
))
|
||||
}
|
||||
|
||||
return restoreInteractionResult
|
||||
.combine(restoreBodyAttachmentsResult)
|
||||
return downstreamObjectResults.reduce(.success(()), {
|
||||
$0.combine($1)
|
||||
})
|
||||
}
|
||||
|
||||
// MARK: Helpers
|
||||
@ -524,6 +533,7 @@ class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchiver {
|
||||
var partialErrors = [RestoreFrameError]()
|
||||
|
||||
let quotedMessage: TSQuotedMessage?
|
||||
let quotedMessageThumbnail: BackupProto_MessageAttachment?
|
||||
if standardMessage.hasQuote {
|
||||
guard
|
||||
let quoteResult = restoreQuote(
|
||||
@ -536,9 +546,10 @@ class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchiver {
|
||||
else {
|
||||
return .messageFailure(partialErrors)
|
||||
}
|
||||
quotedMessage = quoteResult
|
||||
(quotedMessage, quotedMessageThumbnail) = quoteResult
|
||||
} else {
|
||||
quotedMessage = nil
|
||||
quotedMessageThumbnail = nil
|
||||
}
|
||||
|
||||
guard standardMessage.hasText else {
|
||||
@ -554,7 +565,8 @@ class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchiver {
|
||||
body: body,
|
||||
quotedMessage: quotedMessage,
|
||||
reactions: standardMessage.reactions,
|
||||
bodyAttachments: standardMessage.attachments
|
||||
bodyAttachments: standardMessage.attachments,
|
||||
quotedMessageThumbnail: quotedMessageThumbnail
|
||||
)))
|
||||
case .partialRestore(let body, let partialErrors):
|
||||
return .partialRestore(
|
||||
@ -562,7 +574,8 @@ class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchiver {
|
||||
body: body,
|
||||
quotedMessage: quotedMessage,
|
||||
reactions: standardMessage.reactions,
|
||||
bodyAttachments: standardMessage.attachments
|
||||
bodyAttachments: standardMessage.attachments,
|
||||
quotedMessageThumbnail: quotedMessageThumbnail
|
||||
)),
|
||||
partialErrors
|
||||
)
|
||||
@ -655,7 +668,7 @@ class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchiver {
|
||||
thread: MessageBackup.ChatThread,
|
||||
context: MessageBackup.ChatRestoringContext,
|
||||
tx: DBReadTransaction
|
||||
) -> RestoreInteractionResult<TSQuotedMessage> {
|
||||
) -> RestoreInteractionResult<(TSQuotedMessage, BackupProto_MessageAttachment?)> {
|
||||
let authorAddress: MessageBackup.InteropAddress
|
||||
switch context.recipientContext[quote.authorRecipientId] {
|
||||
case .none:
|
||||
@ -735,26 +748,48 @@ class MessageBackupTSMessageContentsArchiver: MessageBackupProtoArchiver {
|
||||
isGiftBadge = true
|
||||
}
|
||||
|
||||
guard let quoteBody else {
|
||||
// Non-text not supported yet.
|
||||
return .messageFailure([.restoreFrameError(.unimplemented, chatItemId)])
|
||||
let quotedAttachmentInfo: OWSAttachmentInfo?
|
||||
let quotedAttachmentThumbnail: BackupProto_MessageAttachment?
|
||||
if let quotedAttachmentProto = quote.attachments.first {
|
||||
if quotedAttachmentProto.hasThumbnail {
|
||||
quotedAttachmentInfo = .init(forV2ThumbnailReference: ())
|
||||
quotedAttachmentThumbnail = quotedAttachmentProto.thumbnail
|
||||
} else {
|
||||
let mimeType = quotedAttachmentProto.contentType.nilIfEmpty
|
||||
?? MimeType.applicationOctetStream.rawValue
|
||||
let sourceFilename = quotedAttachmentProto.fileName.nilIfEmpty
|
||||
quotedAttachmentInfo = .init(
|
||||
stubWithMimeType: mimeType,
|
||||
sourceFilename: sourceFilename
|
||||
)
|
||||
quotedAttachmentThumbnail = nil
|
||||
}
|
||||
} else {
|
||||
quotedAttachmentInfo = nil
|
||||
quotedAttachmentThumbnail = nil
|
||||
}
|
||||
|
||||
// TODO: [Backups] Support attachments
|
||||
guard quoteBody != nil || quotedAttachmentThumbnail != nil || isGiftBadge else {
|
||||
return .messageFailure([.restoreFrameError(
|
||||
.invalidProtoData(.quotedMessageEmptyContent),
|
||||
chatItemId
|
||||
)])
|
||||
}
|
||||
|
||||
let quotedMessage = TSQuotedMessage(
|
||||
targetMessageTimestamp: targetMessageTimestamp,
|
||||
authorAddress: authorAddress,
|
||||
body: quoteBody.text,
|
||||
bodyRanges: quoteBody.ranges,
|
||||
body: quoteBody?.text,
|
||||
bodyRanges: quoteBody?.ranges,
|
||||
bodySource: bodySource,
|
||||
quotedAttachmentInfo: quotedAttachmentInfo,
|
||||
isGiftBadge: isGiftBadge
|
||||
)
|
||||
|
||||
if partialErrors.isEmpty {
|
||||
return .success(quotedMessage)
|
||||
return .success((quotedMessage, quotedAttachmentThumbnail))
|
||||
} else {
|
||||
return .partialRestore(quotedMessage, partialErrors)
|
||||
return .partialRestore((quotedMessage, quotedAttachmentThumbnail), partialErrors)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -364,6 +364,10 @@ extension MessageBackup {
|
||||
/// A `BackupProto_BodyRange` with a missing or unrecognized style.
|
||||
case unrecognizedBodyRangeStyle
|
||||
|
||||
/// A quoted message had no body, attachment, gift badge, or other
|
||||
/// content in its representation of the original being quoted.
|
||||
case quotedMessageEmptyContent
|
||||
|
||||
/// A `BackupProto_Group's` gv2 master key could not be parsed by libsignal.
|
||||
case invalidGV2MasterKey
|
||||
/// A `BackupProto_Group` was missing its group snapshot.
|
||||
@ -594,6 +598,7 @@ extension MessageBackup {
|
||||
.unrecognizedMessageSendStatus,
|
||||
.reactionNotFromAciOrE164,
|
||||
.unrecognizedBodyRangeStyle,
|
||||
.quotedMessageEmptyContent,
|
||||
.invalidGV2MasterKey,
|
||||
.missingGV2GroupSnapshot,
|
||||
.unrecognizedGV2MemberRole,
|
||||
|
||||
@ -740,6 +740,7 @@ public class QuotedReplyManagerImpl: QuotedReplyManager {
|
||||
),
|
||||
bodyRanges: nil,
|
||||
bodySource: .remote,
|
||||
quotedAttachmentInfo: nil,
|
||||
isGiftBadge: false
|
||||
))
|
||||
}
|
||||
|
||||
@ -119,12 +119,12 @@ typedef NS_ENUM(NSUInteger, OWSAttachmentInfoReference) {
|
||||
isGiftBadge:(BOOL)isGiftBadge;
|
||||
|
||||
// used when restoring quoted messages from backups
|
||||
// TODO: attachments should be here too, once they are body can be made nullable.
|
||||
+ (instancetype)quotedMessageWithTargetMessageTimestamp:(nullable NSNumber *)timestamp
|
||||
authorAddress:(SignalServiceAddress *)authorAddress
|
||||
body:(NSString *)body
|
||||
body:(nullable NSString *)body
|
||||
bodyRanges:(nullable MessageBodyRanges *)bodyRanges
|
||||
bodySource:(TSQuotedMessageContentSource)bodySource
|
||||
quotedAttachmentInfo:(nullable OWSAttachmentInfo *)attachmentInfo
|
||||
isGiftBadge:(BOOL)isGiftBadge;
|
||||
|
||||
@end
|
||||
|
||||
@ -210,11 +210,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (instancetype)quotedMessageWithTargetMessageTimestamp:(nullable NSNumber *)timestamp
|
||||
authorAddress:(SignalServiceAddress *)authorAddress
|
||||
body:(NSString *)body
|
||||
body:(nullable NSString *)body
|
||||
bodyRanges:(nullable MessageBodyRanges *)bodyRanges
|
||||
bodySource:(TSQuotedMessageContentSource)bodySource
|
||||
quotedAttachmentInfo:(nullable OWSAttachmentInfo *)attachmentInfo
|
||||
isGiftBadge:(BOOL)isGiftBadge
|
||||
{
|
||||
OWSAssertDebug(body != nil || attachmentInfo != nil);
|
||||
OWSAssertDebug(authorAddress.isValid);
|
||||
|
||||
uint64_t rawTimestamp;
|
||||
@ -230,7 +232,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
body:body
|
||||
bodyRanges:bodyRanges
|
||||
bodySource:bodySource
|
||||
receivedQuotedAttachmentInfo:nil
|
||||
receivedQuotedAttachmentInfo:attachmentInfo
|
||||
isGiftBadge:isGiftBadge];
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user