Skip to content

Commit

Permalink
[Media] Migrate WPCom media upload to /wp/v2 endpoints (#14537)
Browse files Browse the repository at this point in the history
  • Loading branch information
selanthiraiyan authored Nov 29, 2024
2 parents 3c5694c + 3e96abc commit ef049cb
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 382 deletions.
12 changes: 4 additions & 8 deletions Networking/Networking.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
020D07BC23D856BF00FD9580 /* MediaRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020D07BB23D856BF00FD9580 /* MediaRemote.swift */; };
020D07BE23D8570800FD9580 /* MediaListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020D07BD23D8570800FD9580 /* MediaListMapper.swift */; };
020D07C023D8587700FD9580 /* MediaRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020D07BF23D8587700FD9580 /* MediaRemoteTests.swift */; };
020D07C223D858BB00FD9580 /* media-upload.json in Resources */ = {isa = PBXBuildFile; fileRef = 020D07C123D858BB00FD9580 /* media-upload.json */; };
020D0C03291504DE00BB3DCE /* UnauthenticatedRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020D0C02291504DE00BB3DCE /* UnauthenticatedRequestTests.swift */; };
020EF5E92A8BC957009D2169 /* ProductsTotalMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020EF5E82A8BC957009D2169 /* ProductsTotalMapper.swift */; };
020EF5ED2A8C8F4F009D2169 /* products-total.json in Resources */ = {isa = PBXBuildFile; fileRef = 020EF5EC2A8C8F4F009D2169 /* products-total.json */; };
Expand Down Expand Up @@ -95,7 +94,6 @@
02AED9DC2AA04716006DC460 /* KeyedDecodingContainer+WooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02AED9DB2AA04716006DC460 /* KeyedDecodingContainer+WooTests.swift */; };
02AF07EA27492DBC00B2D81E /* WordPressMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02AF07E927492DBC00B2D81E /* WordPressMedia.swift */; };
02AF07EC27492FDD00B2D81E /* media-library-from-wordpress-site.json in Resources */ = {isa = PBXBuildFile; fileRef = 02AF07EB27492FDD00B2D81E /* media-library-from-wordpress-site.json */; };
02AF07EE27493AE700B2D81E /* media-upload-to-wordpress-site.json in Resources */ = {isa = PBXBuildFile; fileRef = 02AF07ED27493AE700B2D81E /* media-upload-to-wordpress-site.json */; };
02B41A90296BC85800FE3311 /* site-domains.json in Resources */ = {isa = PBXBuildFile; fileRef = 02B41A8F296BC85800FE3311 /* site-domains.json */; };
02B41A92296BEB3000FE3311 /* load-site-current-plan-success.json in Resources */ = {isa = PBXBuildFile; fileRef = 02B41A91296BEB3000FE3311 /* load-site-current-plan-success.json */; };
02B41A94296C04BC00FE3311 /* load-site-plans-no-current-plan.json in Resources */ = {isa = PBXBuildFile; fileRef = 02B41A93296C04BC00FE3311 /* load-site-plans-no-current-plan.json */; };
Expand Down Expand Up @@ -1249,6 +1247,7 @@
EECB7EE8286555180028C888 /* media-update-product-id.json in Resources */ = {isa = PBXBuildFile; fileRef = EECB7EE7286555180028C888 /* media-update-product-id.json */; };
EECDBEDE296845F400293C4E /* RESTRequestConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECDBEDD296845F400293C4E /* RESTRequestConvertible.swift */; };
EECDBEE029684AC500293C4E /* WordPressAPIVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECDBEDF29684AC500293C4E /* WordPressAPIVersionTests.swift */; };
EED25B1D2CF74B9800503657 /* media-upload.json in Resources */ = {isa = PBXBuildFile; fileRef = EED25B1C2CF74B9800503657 /* media-upload.json */; };
EEDADD282B7C6A5E00F7302B /* media.json in Resources */ = {isa = PBXBuildFile; fileRef = EEDADD272B7C6A5E00F7302B /* media.json */; };
EEE846A22A54745F005239B6 /* identify-language-success.json in Resources */ = {isa = PBXBuildFile; fileRef = EEE846A02A54745F005239B6 /* identify-language-success.json */; };
EEE846A32A54745F005239B6 /* identify-language-failure.json in Resources */ = {isa = PBXBuildFile; fileRef = EEE846A12A54745F005239B6 /* identify-language-failure.json */; };
Expand Down Expand Up @@ -1306,7 +1305,6 @@
020D07BB23D856BF00FD9580 /* MediaRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaRemote.swift; sourceTree = "<group>"; };
020D07BD23D8570800FD9580 /* MediaListMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaListMapper.swift; sourceTree = "<group>"; };
020D07BF23D8587700FD9580 /* MediaRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaRemoteTests.swift; sourceTree = "<group>"; };
020D07C123D858BB00FD9580 /* media-upload.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "media-upload.json"; sourceTree = "<group>"; };
020D0C02291504DE00BB3DCE /* UnauthenticatedRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnauthenticatedRequestTests.swift; sourceTree = "<group>"; };
020EF5E82A8BC957009D2169 /* ProductsTotalMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsTotalMapper.swift; sourceTree = "<group>"; };
020EF5EC2A8C8F4F009D2169 /* products-total.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "products-total.json"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1382,7 +1380,6 @@
02AED9DB2AA04716006DC460 /* KeyedDecodingContainer+WooTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyedDecodingContainer+WooTests.swift"; sourceTree = "<group>"; };
02AF07E927492DBC00B2D81E /* WordPressMedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordPressMedia.swift; sourceTree = "<group>"; };
02AF07EB27492FDD00B2D81E /* media-library-from-wordpress-site.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "media-library-from-wordpress-site.json"; sourceTree = "<group>"; };
02AF07ED27493AE700B2D81E /* media-upload-to-wordpress-site.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "media-upload-to-wordpress-site.json"; sourceTree = "<group>"; };
02B41A8F296BC85800FE3311 /* site-domains.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-domains.json"; sourceTree = "<group>"; };
02B41A91296BEB3000FE3311 /* load-site-current-plan-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "load-site-current-plan-success.json"; sourceTree = "<group>"; };
02B41A93296C04BC00FE3311 /* load-site-plans-no-current-plan.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "load-site-plans-no-current-plan.json"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2437,6 +2434,7 @@
EECB7EE7286555180028C888 /* media-update-product-id.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "media-update-product-id.json"; sourceTree = "<group>"; };
EECDBEDD296845F400293C4E /* RESTRequestConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTRequestConvertible.swift; sourceTree = "<group>"; };
EECDBEDF29684AC500293C4E /* WordPressAPIVersionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordPressAPIVersionTests.swift; sourceTree = "<group>"; };
EED25B1C2CF74B9800503657 /* media-upload.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "media-upload.json"; sourceTree = "<group>"; };
EEDADD272B7C6A5E00F7302B /* media.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = media.json; sourceTree = "<group>"; };
EEE846A02A54745F005239B6 /* identify-language-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "identify-language-success.json"; sourceTree = "<group>"; };
EEE846A12A54745F005239B6 /* identify-language-failure.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "identify-language-failure.json"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3086,6 +3084,7 @@
B559EBA820A0B5B100836CD4 /* Responses */ = {
isa = PBXGroup;
children = (
EED25B1C2CF74B9800503657 /* media-upload.json */,
EE6C6B6F2C6A190500632BDA /* systemStatus-inconsistent-page-id-data-type.json */,
DEB3878E2C2D71A10025256E /* gla-campaign-list-with-data-envelope.json */,
DEB3878D2C2D71A10025256E /* gla-campaign-list-without-data-envelope.json */,
Expand Down Expand Up @@ -3268,8 +3267,6 @@
02F096C12406691100C0C1D5 /* media-library.json */,
02AF07EB27492FDD00B2D81E /* media-library-from-wordpress-site.json */,
EECB7EE7286555180028C888 /* media-update-product-id.json */,
020D07C123D858BB00FD9580 /* media-upload.json */,
02AF07ED27493AE700B2D81E /* media-upload-to-wordpress-site.json */,
B58D10C92114D22E00107ED4 /* new-order-note.json */,
022902D322E2436400059692 /* no_stats_permission_error.json */,
B5A24178217F98F600595DEF /* notifications-load-all.json */,
Expand Down Expand Up @@ -4285,7 +4282,6 @@
EE57C137297F98DB00BC31E7 /* product-variations-load-all-without-data.json in Resources */,
09885C8027C3FFD200910A62 /* product-variations-bulk-update.json in Resources */,
31054734262E36AB00C5C02B /* wcpay-payment-intent-error.json in Resources */,
02AF07EE27493AE700B2D81E /* media-upload-to-wordpress-site.json in Resources */,
CCE5F38F29EFFE3800087332 /* subscription-list.json in Resources */,
DE4F2A4029750EF400B0701C /* inbox-note-without-data.json in Resources */,
45ED4F12239E8C57004F1BE3 /* taxes-classes.json in Resources */,
Expand Down Expand Up @@ -4622,6 +4618,7 @@
02E7FFCF25621C7900C53030 /* shipping-label-print.json in Resources */,
CE12AE9529F29F4F0056DD17 /* order-with-subscription-renewal.json in Resources */,
CEE9188129F7DC23004B23FF /* order-with-gift-cards.json in Resources */,
EED25B1D2CF74B9800503657 /* media-upload.json in Resources */,
74ABA1CB213F19FE00FFAD30 /* top-performers-week.json in Resources */,
B9CA4F332AB213DF00285AB9 /* tax.json in Resources */,
456930AD2652AF00009ED69D /* shipping-label-carriers-and-rates-success.json in Resources */,
Expand Down Expand Up @@ -4696,7 +4693,6 @@
0359EA2127AAE58C0048DE2D /* wcpay-charge-card-present.json in Resources */,
451274A625276C82009911FF /* product-variation.json in Resources */,
CC80E3F92948C8BC00D5FF45 /* site-visits-quarter.json in Resources */,
020D07C223D858BB00FD9580 /* media-upload.json in Resources */,
CE71E23B2A4C666A00DB5376 /* reports-products-alt.json in Resources */,
31A451D127863A2E00FE81AA /* stripe-account-rejected-other.json in Resources */,
DEF13C5029629EEA0024A02B /* user-complete-without-data.json in Resources */,
Expand Down
59 changes: 7 additions & 52 deletions Networking/Networking/Remote/MediaRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@ public protocol MediaRemoteProtocol {
pageNumber: Int,
pageSize: Int,
completion: @escaping (Result<[WordPressMedia], Error>) -> Void)
func uploadMedia(for siteID: Int64,
func uploadMedia(siteID: Int64,
productID: Int64,
mediaItems: [UploadableMedia],
completion: @escaping (Result<[Media], Error>) -> Void)
func uploadMediaToWordPressSite(siteID: Int64,
productID: Int64,
mediaItem: UploadableMedia,
completion: @escaping (Result<WordPressMedia, Error>) -> Void)
mediaItem: UploadableMedia,
completion: @escaping (Result<WordPressMedia, Error>) -> Void)
func updateProductID(siteID: Int64,
productID: Int64,
mediaID: Int64,
Expand Down Expand Up @@ -145,47 +141,6 @@ public class MediaRemote: Remote, MediaRemoteProtocol {
}
}

/// Uploads an array of media in the local file system.
/// API reference: https://developer.wordpress.com/docs/api/1.1/post/sites/%24site/media/new/
///
/// - Parameters:
/// - siteID: Site for which we'll upload the media to.
/// - productID: Product for which the media items are first added to.
/// - context: Display or edit. Scope under which the request is made;
/// determines fields present in response. Default is Display.
/// - mediaItems: An array of uploadable media items.
/// - completion: Closure to be executed upon completion.
///
public func uploadMedia(for siteID: Int64,
productID: Int64,
mediaItems: [UploadableMedia],
completion: @escaping (Result<[Media], Error>) -> Void) {

let formParameters: [String: String] = [Int](0..<mediaItems.count).reduce(into: [:]) { (parentIDsByKey, index) in
parentIDsByKey["attrs[\(index)][parent_id]"] = "\(productID)"
parentIDsByKey["attrs[\(index)][\(ParameterKey.altText)]"] = mediaItems[index].altText
}

let path = "sites/\(siteID)/media/new"
let request = DotcomRequest(wordpressApiVersion: .mark1_1,
method: .post,
path: path)
let mapper = MediaListMapper()

enqueueMultipartFormDataUpload(request, mapper: mapper, multipartFormData: { multipartFormData in
formParameters.forEach { (key, value) in
multipartFormData.append(Data(value.utf8), withName: key)
}

mediaItems.forEach { mediaItem in
multipartFormData.append(mediaItem.localURL,
withName: "media[]",
fileName: mediaItem.filename,
mimeType: mediaItem.mimeType)
}
}, completion: completion)
}

/// Uploads a media item in the local file system to the WordPress site via WordPress site API.
/// The API does not support multiple media items unlike the WPCOM version in `uploadMedia`.
/// API reference: https://developer.wordpress.org/rest-api/reference/media/#create-a-media-item
Expand All @@ -195,10 +150,10 @@ public class MediaRemote: Remote, MediaRemoteProtocol {
/// - productID: Product for which the media items are first added to.
/// - mediaItem: The media item to upload.
/// - completion: Closure to be executed upon completion.
public func uploadMediaToWordPressSite(siteID: Int64,
productID: Int64,
mediaItem: UploadableMedia,
completion: @escaping (Result<WordPressMedia, Error>) -> Void) {
public func uploadMedia(siteID: Int64,
productID: Int64,
mediaItem: UploadableMedia,
completion: @escaping (Result<WordPressMedia, Error>) -> Void) {
let formParameters: [String: String] = [
ParameterKey.wordPressMediaPostID: "\(productID)",
ParameterKey.fieldsWordPressSite: ParameterValue.wordPressMediaFields,
Expand Down
69 changes: 8 additions & 61 deletions Networking/NetworkingTests/Remote/MediaRemoteTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ final class MediaRemoteTests: XCTestCase {
let remote = MediaRemote(network: network)

// When
remote.uploadMedia(for: self.sampleSiteID, productID: sampleProductID, mediaItems: [], completion: { _ in })
remote.uploadMedia(siteID: sampleSiteID, productID: sampleProductID, mediaItem: .fake(), completion: { _ in })

// Then
let request = try XCTUnwrap(network.requestsForResponseData.last as? DotcomRequest)
Expand All @@ -222,69 +222,16 @@ final class MediaRemoteTests: XCTestCase {
/// Verifies that `uploadMedia` properly parses the `media-upload` sample response.
///
func test_uploadMedia_properly_returns_parsed_media() throws {
// Given
let remote = MediaRemote(network: network)
let path = "sites/\(sampleSiteID)/media/new"
network.simulateResponse(requestUrlSuffix: path, filename: "media-upload")

// When
let result = waitFor { promise in
remote.uploadMedia(for: self.sampleSiteID,
productID: self.sampleProductID,
mediaItems: []) { result in
promise(result)
}
}

// Then
let mediaItems = try XCTUnwrap(result.get())
XCTAssertEqual(mediaItems.count, 1)
}

/// Verifies that `uploadMedia` properly relays Networking Layer errors.
///
func test_uploadMedia_properly_relays_networking_errors() {
// Given
let remote = MediaRemote(network: network)

// When
let result = waitFor { promise in
remote.uploadMedia(for: self.sampleSiteID,
productID: self.sampleProductID,
mediaItems: []) { result in
promise(result)
}
}

// Then
XCTAssertTrue(result.isFailure)
}

func test_uploadMediaToWordPressSite_does_not_send_data_in_request_body() throws {
// Given
let remote = MediaRemote(network: network)

// When
remote.uploadMediaToWordPressSite(siteID: sampleSiteID, productID: sampleProductID, mediaItem: .fake(), completion: { _ in })

// Then
let request = try XCTUnwrap(network.requestsForResponseData.last as? DotcomRequest)
XCTAssertNil(try request.asURLRequest().httpBody)
}

/// Verifies that `uploadMediaToWordPressSite` properly parses the `media-upload-to-wordpress-site` sample response.
///
func test_uploadMediaToWordPressSite_properly_returns_parsed_media() throws {
// Given
let remote = MediaRemote(network: network)
let path = "sites/\(sampleSiteID)/media"
network.simulateResponse(requestUrlSuffix: path, filename: "media-upload-to-wordpress-site")
network.simulateResponse(requestUrlSuffix: path, filename: "media-upload")

// When
let result = waitFor { promise in
remote.uploadMediaToWordPressSite(siteID: self.sampleSiteID,
productID: self.sampleProductID,
mediaItem: .fake()) { result in
remote.uploadMedia(siteID: self.sampleSiteID,
productID: self.sampleProductID,
mediaItem: .fake()) { result in
promise(result)
}
}
Expand Down Expand Up @@ -316,9 +263,9 @@ final class MediaRemoteTests: XCTestCase {

// When
let result = waitFor { promise in
remote.uploadMediaToWordPressSite(siteID: self.sampleSiteID,
productID: self.sampleProductID,
mediaItem: .fake()) { result in
remote.uploadMedia(siteID: self.sampleSiteID,
productID: self.sampleProductID,
mediaItem: .fake()) { result in
promise(result)
}
}
Expand Down
Loading

0 comments on commit ef049cb

Please sign in to comment.