Skip to content

Commit 43c8c2a

Browse files
authored
Merge pull request #2141 from woocommerce/issue/1988-image-uplad-product-id
Image upload: attach the product ID to an image uploaded from edit product
2 parents d7328be + a461854 commit 43c8c2a

File tree

8 files changed

+43
-8
lines changed

8 files changed

+43
-8
lines changed

Networking/Networking/Network/Network.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ import Alamofire
44
/// Constructs `multipart/form-data` for uploads within an HTTP or HTTPS body.
55
///
66
public protocol MultipartFormData {
7+
/// Appends a file with file URL for a name to form data.
8+
///
79
func append(_ fileURL: URL, withName name: String, fileName: String, mimeType: String)
10+
11+
/// Appends data for a name to form data.
12+
///
13+
func append(_ data: Data, withName name: String)
814
}
915

1016
/// Defines all of the Network Operations we'll be performing. This allows us to swap the actual Wrapper in our

Networking/Networking/Remote/MediaRemote.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,25 @@ public class MediaRemote: Remote {
4040
///
4141
/// - Parameters:
4242
/// - siteID: Site for which we'll upload the media to.
43+
/// - productID: Product for which the media items are first added to.
4344
/// - context: Display or edit. Scope under which the request is made;
4445
/// determines fields present in response. Default is Display.
4546
/// - mediaItems: An array of uploadable media items.
4647
/// - completion: Closure to be executed upon completion.
4748
///
4849
public func uploadMedia(for siteID: Int64,
50+
productID: Int64,
4951
context: String? = Default.context,
5052
mediaItems: [UploadableMedia],
5153
completion: @escaping ([Media]?, Error?) -> Void) {
5254
let parameters = [
5355
ParameterKey.contextKey: context ?? Default.context,
5456
]
5557

58+
let formParameters: [String: String] = [Int](0..<mediaItems.count).reduce(into: [:]) { (parentIDsByKey, index) in
59+
parentIDsByKey["attrs[\(index)][parent_id]"] = "\(productID)"
60+
}
61+
5662
let path = "sites/\(siteID)/media/new"
5763
let request = DotcomRequest(wordpressApiVersion: .mark1_1,
5864
method: .post,
@@ -61,6 +67,10 @@ public class MediaRemote: Remote {
6167
let mapper = MediaListMapper()
6268

6369
enqueueMultipartFormDataUpload(request, mapper: mapper, multipartFormData: { multipartFormData in
70+
formParameters.forEach { (key, value) in
71+
multipartFormData.append(Data(value.utf8), withName: key)
72+
}
73+
6474
mediaItems.forEach { mediaItem in
6575
multipartFormData.append(mediaItem.localURL,
6676
withName: "media[]",

Networking/NetworkingTests/Remote/MediaRemoteTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ final class MediaRemoteTests: XCTestCase {
1010
///
1111
let sampleSiteID: Int64 = 1234
1212

13+
/// Dummy Product ID
14+
///
15+
private let sampleProductID: Int64 = 586
16+
1317
/// Repeat always!
1418
///
1519
override func setUp() {
@@ -64,6 +68,7 @@ final class MediaRemoteTests: XCTestCase {
6468
network.simulateResponse(requestUrlSuffix: path, filename: "media-upload")
6569

6670
remote.uploadMedia(for: sampleSiteID,
71+
productID: sampleProductID,
6772
mediaItems: []) { mediaItems, error in
6873
XCTAssertNil(error)
6974
XCTAssertNotNil(mediaItems)
@@ -81,6 +86,7 @@ final class MediaRemoteTests: XCTestCase {
8186
let expectation = self.expectation(description: "Upload one media item")
8287

8388
remote.uploadMedia(for: sampleSiteID,
89+
productID: sampleProductID,
8490
mediaItems: []) { mediaItems, error in
8591
XCTAssertNil(mediaItems)
8692
XCTAssertNotNil(error)

WooCommerce/Classes/ViewRelated/Products/Media/ProductImageActionHandler.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ final class ProductImageActionHandler {
99
typealias OnAssetUpload = (PHAsset, ProductImage) -> Void
1010

1111
private let siteID: Int64
12+
private let productID: Int64
1213

1314
/// The queue where internal states like `allStatuses` and `observations` are updated on to maintain thread safety.
1415
private let queue: DispatchQueue
@@ -41,6 +42,7 @@ final class ProductImageActionHandler {
4142
/// - queue: the queue where the update callbacks are called on. Default to be the main queue.
4243
init(siteID: Int64, product: Product, queue: DispatchQueue = .main) {
4344
self.siteID = siteID
45+
self.productID = product.productID
4446
self.queue = queue
4547
self.allStatuses = (productImageStatuses: product.imageStatuses, error: nil)
4648
}
@@ -170,11 +172,11 @@ final class ProductImageActionHandler {
170172

171173
private func uploadMediaAssetToSiteMediaLibrary(asset: PHAsset, onCompletion: @escaping (_ uploadedMedia: Media?, _ error: Error?) -> Void) {
172174
DispatchQueue.main.async { [weak self] in
173-
guard let siteID = self?.siteID else {
175+
guard let siteID = self?.siteID, let productID = self?.productID else {
174176
return
175177
}
176178

177-
let action = MediaAction.uploadMedia(siteID: siteID, mediaAsset: asset, onCompletion: onCompletion)
179+
let action = MediaAction.uploadMedia(siteID: siteID, productID: productID, mediaAsset: asset, onCompletion: onCompletion)
178180
ServiceLocator.stores.dispatch(action)
179181
}
180182
}

WooCommerce/WooCommerceTests/Mockups/MockMediaStoresManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ final class MockMediaStoresManager: DefaultStoresManager {
2626

2727
private func onMediaAction(action: MediaAction) {
2828
switch action {
29-
case .uploadMedia(_, _, let onCompletion):
29+
case .uploadMedia(_, _, _, let onCompletion):
3030
onCompletion(media, nil)
3131
case .retrieveMediaLibrary(_, _, _, let onCompletion):
3232
guard let media = media else {

Yosemite/Yosemite/Actions/MediaAction.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@ public enum MediaAction: Action {
1818

1919
/// Uploads an exportable media asset to the site's WP Media Library.
2020
///
21-
case uploadMedia(siteID: Int64, mediaAsset: ExportableAsset, onCompletion: (_ uploadedMedia: Media?, _ error: Error?) -> Void)
21+
case uploadMedia(siteID: Int64,
22+
productID: Int64,
23+
mediaAsset: ExportableAsset,
24+
onCompletion: (_ uploadedMedia: Media?, _ error: Error?) -> Void)
2225
}

Yosemite/Yosemite/Stores/MediaStore.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public final class MediaStore: Store {
3636
switch action {
3737
case .retrieveMediaLibrary(let siteID, let pageNumber, let pageSize, let onCompletion):
3838
retrieveMediaLibrary(siteID: siteID, pageNumber: pageNumber, pageSize: pageSize, onCompletion: onCompletion)
39-
case .uploadMedia(let siteID, let mediaAsset, let onCompletion):
40-
uploadMedia(siteID: siteID, mediaAsset: mediaAsset, onCompletion: onCompletion)
39+
case .uploadMedia(let siteID, let productID, let mediaAsset, let onCompletion):
40+
uploadMedia(siteID: siteID, productID: productID, mediaAsset: mediaAsset, onCompletion: onCompletion)
4141
}
4242
}
4343
}
@@ -60,6 +60,7 @@ private extension MediaStore {
6060
/// 2) Uploads the exported media file to the server
6161
///
6262
func uploadMedia(siteID: Int64,
63+
productID: Int64,
6364
mediaAsset: ExportableAsset,
6465
onCompletion: @escaping (_ uploadedMedia: Media?, _ error: Error?) -> Void) {
6566
mediaExportService.export(mediaAsset,
@@ -69,16 +70,19 @@ private extension MediaStore {
6970
return
7071
}
7172
self?.uploadMedia(siteID: siteID,
73+
productID: productID,
7274
uploadableMedia: uploadableMedia,
7375
onCompletion: onCompletion)
7476
})
7577
}
7678

7779
func uploadMedia(siteID: Int64,
80+
productID: Int64,
7881
uploadableMedia media: UploadableMedia,
7982
onCompletion: @escaping (_ uploadedMedia: Media?, _ error: Error?) -> Void) {
8083
let remote = MediaRemote(network: network)
8184
remote.uploadMedia(for: siteID,
85+
productID: productID,
8286
mediaItems: [media]) { (uploadedMediaItems, error) in
8387
// Removes local media after the upload API request.
8488
do {

Yosemite/YosemiteTests/Stores/MediaStoreTests.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ final class MediaStoreTests: XCTestCase {
2020
///
2121
private let sampleSiteID: Int64 = 123
2222

23+
/// Testing Product ID
24+
///
25+
private let sampleProductID: Int64 = 586
26+
2327
// MARK: - Overridden Methods
2428

2529
override func setUp() {
@@ -140,7 +144,7 @@ final class MediaStoreTests: XCTestCase {
140144
network.simulateResponse(requestUrlSuffix: path, filename: "media-upload")
141145

142146
let asset = PHAsset()
143-
let action = MediaAction.uploadMedia(siteID: sampleSiteID, mediaAsset: asset) { (uploadedMedia, error) in
147+
let action = MediaAction.uploadMedia(siteID: sampleSiteID, productID: sampleProductID, mediaAsset: asset) { (uploadedMedia, error) in
144148
XCTAssertNotNil(uploadedMedia)
145149
XCTAssertNil(error)
146150

@@ -184,7 +188,7 @@ final class MediaStoreTests: XCTestCase {
184188
network.simulateResponse(requestUrlSuffix: path, filename: "generic_error")
185189

186190
let asset = PHAsset()
187-
let action = MediaAction.uploadMedia(siteID: sampleSiteID, mediaAsset: asset) { (uploadedMedia, error) in
191+
let action = MediaAction.uploadMedia(siteID: sampleSiteID, productID: sampleProductID, mediaAsset: asset) { (uploadedMedia, error) in
188192
XCTAssertNil(uploadedMedia)
189193
XCTAssertNotNil(error)
190194

0 commit comments

Comments
 (0)