Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
594eea9
adjust api to append SendableImage
johnxnguyen Oct 6, 2025
ad70d1f
use new api
johnxnguyen Oct 7, 2025
1da1e82
set default name
johnxnguyen Oct 7, 2025
e06d337
groom
johnxnguyen Oct 7, 2025
d629338
change default file name
johnxnguyen Oct 7, 2025
dd3c001
add name to protobuf asset
johnxnguyen Oct 7, 2025
bf9813f
include extra metadata
johnxnguyen Oct 7, 2025
bf54c2b
Merge branch 'release/cycle-4.8' into feat/asset-audit-log-metadata-w…
johnxnguyen Oct 8, 2025
f8647fd
delete dead code
johnxnguyen Oct 8, 2025
3dc5798
include metadata for profile image uploads
johnxnguyen Oct 8, 2025
286e0ad
include metadata for link previews
johnxnguyen Oct 8, 2025
75455fe
Merge branch 'release/cycle-4.8' into feat/asset-audit-log-metadata-w…
johnxnguyen Oct 8, 2025
7dfd1b1
Merge branch 'feat/asset-audit-log-metadata-wpb-20714' of github.com:…
johnxnguyen Oct 8, 2025
d1b9dd7
format
johnxnguyen Oct 9, 2025
d4c8583
use feature flag
johnxnguyen Oct 9, 2025
2e09c95
format
johnxnguyen Oct 9, 2025
552000e
fix data model tests
johnxnguyen Oct 9, 2025
6b68f29
fix request strategy tests
johnxnguyen Oct 9, 2025
936ceba
fix sync engine tests
johnxnguyen Oct 9, 2025
6f9dd8e
fix ui tests
johnxnguyen Oct 9, 2025
fe65c29
format
johnxnguyen Oct 9, 2025
c2f20a6
Merge branch 'release/cycle-4.8' into feat/asset-audit-log-metadata-w…
johnxnguyen Oct 9, 2025
d6c0661
move type to own file
johnxnguyen Oct 10, 2025
ca0114b
Merge branch 'release/cycle-4.8' into feat/asset-audit-log-metadata-w…
johnxnguyen Oct 10, 2025
ab0c634
factor out cloud detection
johnxnguyen Oct 13, 2025
0b35a1e
Merge branch 'feat/asset-audit-log-metadata-wpb-20714' of github.com:…
johnxnguyen Oct 13, 2025
91a4ce7
read feature from db at time of need
johnxnguyen Oct 13, 2025
07ac421
preserve forwarded image name
johnxnguyen Oct 13, 2025
a8176ae
add comment
johnxnguyen Oct 13, 2025
54d40f6
remove debug description
johnxnguyen Oct 13, 2025
5da81d4
format
johnxnguyen Oct 13, 2025
db94634
update comment
johnxnguyen Oct 13, 2025
53c3872
Merge branch 'release/cycle-4.8' into feat/asset-audit-log-metadata-w…
johnxnguyen Oct 13, 2025
dbe251d
fix test
johnxnguyen Oct 13, 2025
8ad6fcd
fix tests
johnxnguyen Oct 13, 2025
4200031
fix test
johnxnguyen Oct 14, 2025
2eeef72
fix multithread violation
johnxnguyen Oct 14, 2025
04e4835
fix tests
johnxnguyen Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,23 @@ public struct BackendEnvironment2: Sendable, Equatable, Hashable {
}

}

public extension BackendEnvironment2 {

var isCloudEnvironment: Bool {
config.endpoints.restAPIURL.host() == "prod-nginz-https.wire.com"
}

static func isCloudDomain(_ domain: String) -> Bool {
domain == "wire.com"
}

var isStagingEnvironment: Bool {
config.endpoints.restAPIURL.host() == "staging-nginz-https.zinfra.io"
}

static func isStagingDomain(_ domain: String) -> Bool {
domain == "staging.zinfra.io"
}

}
61 changes: 61 additions & 0 deletions wire-ios-data-model/Source/Model/Conversation/SendableImage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import UniformTypeIdentifiers

public struct SendableImage {

public let name: String
public let utType: UTType?
public let data: Data

public init(
name: String?,
utType: UTType?,
data: Data
) {
if let utType {
self.utType = utType
} else {
self.utType = Self.determineUTType(from: data)
}

if let name {
self.name = name
} else if let fileExtension = self.utType?.preferredFilenameExtension {
self.name = "picture.\(fileExtension)"
} else {
self.name = "picture"
}

self.data = data
}

private static func determineUTType(from data: Data) -> UTType? {
guard
!data.isEmpty,
let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
let uti = CGImageSourceGetType(imageSource) as String?
else {
return nil
}

return UTType(uti)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ public extension ZMConversation {
/// Append an image message.
///
/// - Parameters:
/// - url: A url locating some image data.
/// - image: The image to append.
/// - nonce: The nonce of the message.
///
/// - Throws:
Expand All @@ -268,55 +268,42 @@ public extension ZMConversation {
/// The appended message.

@discardableResult
func appendImage(at URL: URL, nonce: UUID = UUID()) throws -> ZMConversationMessage {
guard
URL.isFileURL,
ZMImagePreprocessor.sizeOfPrerotatedImage(at: URL) != .zero,
let imageData = try? Data(contentsOf: URL, options: [])
else {
throw AppendMessageError.invalidImageUrl
}

return try appendImage(from: imageData)
}

/// Append an image message.
///
/// - Parameters:
/// - imageData: Data representing an image.
/// - nonce: The nonce of the message.
///
/// - Throws:
/// - `AppendMessageError` if the message couldn't be appended.
///
/// - Returns:
/// The appended message.

@discardableResult
func appendImage(from imageData: Data, nonce: UUID = UUID()) throws -> ZMConversationMessage {
func appendImage(
_ image: SendableImage,
nonce: UUID
) throws -> ZMConversationMessage {
guard let moc = managedObjectContext else {
throw AppendMessageError.missingManagedObjectContext
}

guard let imageData = try? imageData.wr_removingImageMetadata() else {
guard let imageData = try? image.data.wr_removingImageMetadata() else {
throw AppendMessageError.failedToRemoveImageMetadata
}

// mimeType is assigned first, to make sure UI can handle animated GIF file correctly.
let mimeType = imageData.mimeType ?? ""
let mimeType = image.utType?.preferredMIMEType

// We update the size again when the the preprocessing is done.
let imageSize = ZMImagePreprocessor.sizeOfPrerotatedImage(with: imageData)

let asset = GenericMessageProtocol.Asset(
name: image.name,
mimeType: mimeType ?? "",
imageSize: imageSize,
mimeType: mimeType,
size: UInt64(imageData.count)
)

return try append(asset: asset, nonce: nonce, expires: true, prepareMessage: { message in
moc.zm_fileAssetCache.storeOriginalImage(data: imageData, for: message)
})
return try append(
asset: asset,
nonce: nonce,
expires: true,
prepareMessage: { message in
moc.zm_fileAssetCache.storeOriginalImage(
data: imageData,
for: message
)
}
)
}

/// Append a file message.
Expand Down Expand Up @@ -563,21 +550,6 @@ public extension ZMConversation {
try? appendLocation(with: locationData)
}

@discardableResult @objc(appendMessageWithImageData:)
func _appendImage(from imageData: Data) -> ZMConversationMessage? {
try? appendImage(from: imageData)
}

@discardableResult @objc(appendImageFromData:nonce:)
func _appendImage(from imageData: Data, nonce: UUID) -> ZMConversationMessage? {
try? appendImage(from: imageData, nonce: nonce)
}

@discardableResult @objc(appendImageAtURL:nonce:)
func _appendImage(at URL: URL, nonce: UUID) -> ZMConversationMessage? {
try? appendImage(at: URL, nonce: nonce)
}

@discardableResult @objc(appendMessageWithFileMetadata:)
func _appendFile(with fileMetadata: ZMFileMetadata) -> ZMConversationMessage? {
try? appendFile(with: fileMetadata)
Expand Down
11 changes: 11 additions & 0 deletions wire-ios-data-model/Source/Model/Message/V2Asset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ import MobileCoreServices
@objcMembers
public class V2Asset: NSObject, ZMImageMessageData {

public var name: String? {
guard
let message = assetClientMessage.underlyingMessage,
let original = message.assetData?.original
else {
return nil
}

return original.name
}

public var isDownloaded: Bool {
hasDownloadedFile
}
Expand Down
11 changes: 11 additions & 0 deletions wire-ios-data-model/Source/Model/Message/V3Asset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ public class V3Asset: NSObject, ZMImageMessageData {
}
}

public var name: String? {
guard
let message = assetClientMessage.underlyingMessage,
let original = message.assetData?.original
else {
return nil
}

return original.name
}

public var isDownloaded: Bool {
hasDownloadedFile
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ open class ZMFileMetadata: NSObject {
} else {
nil
}
let endName = name ?? (fileURL.lastPathComponent.isEmpty ? "unnamed" : fileURL.lastPathComponent)

let endName: String = if let name {
name
} else if !fileURL.lastPathComponent.isEmpty {
fileURL.lastPathComponent
} else {
"file"
}

self.filename = endName.removingExtremeCombiningCharacters
super.init()
Expand Down
1 change: 1 addition & 0 deletions wire-ios-data-model/Source/Public/ZMMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

@protocol ZMImageMessageData <NSObject>

@property (nonatomic, readonly, nullable) NSString *name;
@property (nonatomic, readonly, nullable) NSData *imageData; ///< This will either returns the mediumData or the original image data. Useful only for newly inserted messages.
@property (nonatomic, readonly, nullable) NSString *imageDataIdentifier; /// This can be used as a cache key for @c -imageData

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public protocol LegacyFeatureRepositoryInterface {
func storeConsumableNotifications(_ consumableNotifications: Feature.ConsumableNotifications)
func fetchChatBubblesSimple() -> Feature.ChatBubblesSimple
func storeChatBubblesSimple(_ chatBubblesSimple: Feature.ChatBubblesSimple)
func fetchAssetAuditLog() -> Feature.AssetAuditLog
}

/// **Do not use it for new code, use FeatureConfigRepository instead**
Expand Down Expand Up @@ -536,6 +537,16 @@ public class LegacyFeatureRepository: LegacyFeatureRepositoryInterface {
}
}

// MARK: - Asset audit log

public func fetchAssetAuditLog() -> Feature.AssetAuditLog {
guard let feature = Feature.fetch(name: .assetAuditLog, context: context) else {
return .init()
}

return .init(status: feature.status)
}

// MARK: - Methods

func createDefaultConfigsIfNeeded() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,17 @@ public extension GenericMessageProtocol.Asset {
}
}

init(imageSize: CGSize, mimeType: String, size: UInt64) {
init(
name: String,
mimeType: String,
imageSize: CGSize,
size: UInt64
) {
self = GenericMessageProtocol.Asset.with {
$0.original = GenericMessageProtocol.Asset.Original.with {
$0.size = size
$0.name = name
$0.mimeType = mimeType
$0.size = size
$0.image = GenericMessageProtocol.Asset.ImageMetaData.with {
$0.width = Int32(imageSize.width)
$0.height = Int32(imageSize.height)
Expand Down Expand Up @@ -228,12 +234,14 @@ public extension GenericMessageProtocol.Asset.RemoteData {

extension GenericMessage {
mutating func updateAssetOriginal(withImageProperties imageProperties: ZMIImageProperties) {
let asset = GenericMessageProtocol.Asset(
imageSize: imageProperties.size,
mimeType: imageProperties.mimeType,
size: UInt64(imageProperties.length)
)
update(asset: asset)
updateAsset { existingAsset in
existingAsset.original.mimeType = imageProperties.mimeType
existingAsset.original.size = UInt64(imageProperties.length)
existingAsset.original.image = GenericMessageProtocol.Asset.ImageMetaData.with {
$0.width = Int32(imageProperties.size.width)
$0.height = Int32(imageProperties.size.height)
}
}
}

mutating func updateAssetPreview(withUploadedOTRKey otrKey: Data, sha256: Data) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@
return self
}
do {
let data = try serializedData()

Check warning on line 549 in wire-ios-data-model/Source/Utilis/Protos/GenericMessage+Helper.swift

View workflow job for this annotation

GitHub Actions / Test Results

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

Check warning on line 549 in wire-ios-data-model/Source/Utilis/Protos/GenericMessage+Helper.swift

View workflow job for this annotation

GitHub Actions / Test Results

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'
var updatedText = try Text(serializedData: data)
updatedText.linkPreview = text.linkPreview
return updatedText
Expand Down Expand Up @@ -774,8 +774,9 @@
$0.summary = articleMetadata.summary ?? ""
if let imageData = articleMetadata.imageData.first {
$0.image = GenericMessageProtocol.Asset(
imageSize: CGSize(width: 0, height: 0),
name: "picture.jpeg",
mimeType: "image/jpeg",
imageSize: CGSize(width: 0, height: 0),
size: UInt64(imageData.count)
)
}
Expand All @@ -791,8 +792,9 @@
$0.title = twitterMetadata.message ?? ""
if let imageData = twitterMetadata.imageData.first {
$0.image = GenericMessageProtocol.Asset(
imageSize: CGSize(width: 0, height: 0),
name: "picture.jpeg",
mimeType: "image/jpeg",
imageSize: CGSize(width: 0, height: 0),
size: UInt64(imageData.count)
)
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading