// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import Foundation import GRDB import SessionUtilitiesKit public extension VisibleMessage { struct VMQuote: Codable { public let timestamp: UInt64? public let publicKey: String? public let text: String? public let attachmentId: String? public var isValid: Bool { timestamp != nil && publicKey != nil } // MARK: - Initialization internal init(timestamp: UInt64, publicKey: String, text: String?, attachmentId: String?) { self.timestamp = timestamp self.publicKey = publicKey self.text = text self.attachmentId = attachmentId } // MARK: - Proto Conversion public static func fromProto(_ proto: SNProtoDataMessageQuote) -> VMQuote? { return VMQuote( timestamp: proto.id, publicKey: proto.author, text: proto.text, attachmentId: nil ) } public func toProto() -> SNProtoDataMessageQuote? { preconditionFailure("Use toProto(_:) instead.") } public func toProto(_ db: Database) -> SNProtoDataMessageQuote? { guard let timestamp = timestamp, let publicKey = publicKey else { SNLog("Couldn't construct quote proto from: \(self).") return nil } let quoteProto = SNProtoDataMessageQuote.builder(id: timestamp, author: publicKey) if let text = text { quoteProto.setText(text) } addAttachmentsIfNeeded(db, to: quoteProto) do { return try quoteProto.build() } catch { SNLog("Couldn't construct quote proto from: \(self).") return nil } } private func addAttachmentsIfNeeded(_ db: Database, to quoteProto: SNProtoDataMessageQuote.SNProtoDataMessageQuoteBuilder) { guard let attachmentId = attachmentId else { return } guard let attachment: Attachment = try? Attachment.fetchOne(db, id: attachmentId), attachment.state == .uploaded else { #if DEBUG preconditionFailure("Sending a message before all associated attachments have been uploaded.") #else return #endif } let quotedAttachmentProto = SNProtoDataMessageQuoteQuotedAttachment.builder() quotedAttachmentProto.setContentType(attachment.contentType) if let fileName = attachment.sourceFilename { quotedAttachmentProto.setFileName(fileName) } guard let attachmentProto = attachment.buildProto() else { return SNLog("Ignoring invalid attachment for quoted message.") } quotedAttachmentProto.setThumbnail(attachmentProto) do { try quoteProto.addAttachments(quotedAttachmentProto.build()) } catch { SNLog("Couldn't construct quoted attachment proto from: \(self).") } } // MARK: - Description public var description: String { """ Quote( timestamp: \(timestamp?.description ?? "null"), publicKey: \(publicKey ?? "null"), text: \(text ?? "null"), attachmentId: \(attachmentId ?? "null") ) """ } } } // MARK: - Database Type Conversion public extension VisibleMessage.VMQuote { static func from(_ db: Database, quote: Quote) -> VisibleMessage.VMQuote { return VisibleMessage.VMQuote( timestamp: UInt64(quote.timestampMs), publicKey: quote.authorId, text: quote.body, attachmentId: quote.attachmentId ) } }