diff --git a/CHANGELOG.md b/CHANGELOG.md index f52906c0..b909a522 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ _None._ ### Breaking Changes -_None._ +- Refactor the logic to fetch metadata of VideoPress videos [#581] ### New Features diff --git a/WordPressKit.podspec b/WordPressKit.podspec index 7c9921b5..1de625f6 100644 --- a/WordPressKit.podspec +++ b/WordPressKit.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |s| s.name = 'WordPressKit' - s.version = '6.3.0' + s.version = '7.0.0-beta.1' s.summary = 'WordPressKit offers a clean and simple WordPress.com and WordPress.org API.' s.description = <<-DESC diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index fd57471e..790ceb6d 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -19,6 +19,12 @@ 17CE77F420C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CE77F320C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift */; }; 17D936252475D8AB008B2205 /* RemoteHomepageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D936242475D8AB008B2205 /* RemoteHomepageType.swift */; }; 1A4F98672279A87D00D86E8E /* WPKit-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4F98662279A87D00D86E8E /* WPKit-Swift.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 1DAC3D2629AF4F250068FE13 /* RemoteVideoPressVideo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DAC3D2529AF4F250068FE13 /* RemoteVideoPressVideo.swift */; }; + 1DC837C229B9F04F009DCD4B /* RemoteVideoPressVideoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC837C129B9F04F009DCD4B /* RemoteVideoPressVideoTests.swift */; }; + 1DF972BA29B0DF8C007A72BC /* videopress-token.json in Resources */ = {isa = PBXBuildFile; fileRef = 1DF972B729B0DF8C007A72BC /* videopress-token.json */; }; + 1DF972BF29B107E7007A72BC /* videopress-private-video.json in Resources */ = {isa = PBXBuildFile; fileRef = 1DF972BC29B107E7007A72BC /* videopress-private-video.json */; }; + 1DF972C029B107E7007A72BC /* videopress-public-video.json in Resources */ = {isa = PBXBuildFile; fileRef = 1DF972BD29B107E7007A72BC /* videopress-public-video.json */; }; + 1DF972C129B107E7007A72BC /* videopress-site-default-video.json in Resources */ = {isa = PBXBuildFile; fileRef = 1DF972BE29B107E7007A72BC /* videopress-site-default-video.json */; }; 240315B0A1D6C2B981572B5B /* Pods_WordPressKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */; }; 24ADA24E24F9B32D001B5DAE /* FeatureFlagSerializationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24ADA24D24F9B32D001B5DAE /* FeatureFlagSerializationTest.swift */; }; 3236F77824AE34B40088E8F3 /* ReaderTopicServiceRemote+Interests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3236F77724AE34B40088E8F3 /* ReaderTopicServiceRemote+Interests.swift */; }; @@ -677,6 +683,12 @@ 17CE77F320C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderSiteSearchServiceRemoteTests.swift; sourceTree = ""; }; 17D936242475D8AB008B2205 /* RemoteHomepageType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteHomepageType.swift; sourceTree = ""; }; 1A4F98662279A87D00D86E8E /* WPKit-Swift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WPKit-Swift.h"; sourceTree = ""; }; + 1DAC3D2529AF4F250068FE13 /* RemoteVideoPressVideo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteVideoPressVideo.swift; sourceTree = ""; }; + 1DC837C129B9F04F009DCD4B /* RemoteVideoPressVideoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteVideoPressVideoTests.swift; sourceTree = ""; }; + 1DF972B729B0DF8C007A72BC /* videopress-token.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "videopress-token.json"; sourceTree = ""; }; + 1DF972BC29B107E7007A72BC /* videopress-private-video.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "videopress-private-video.json"; sourceTree = ""; }; + 1DF972BD29B107E7007A72BC /* videopress-public-video.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "videopress-public-video.json"; sourceTree = ""; }; + 1DF972BE29B107E7007A72BC /* videopress-site-default-video.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "videopress-site-default-video.json"; sourceTree = ""; }; 24ADA24D24F9B32D001B5DAE /* FeatureFlagSerializationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagSerializationTest.swift; sourceTree = ""; }; 264F5C834541BBF2018F4964 /* Pods-WordPressKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.debug.xcconfig"; sourceTree = ""; }; 3236F77724AE34B40088E8F3 /* ReaderTopicServiceRemote+Interests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReaderTopicServiceRemote+Interests.swift"; sourceTree = ""; }; @@ -1992,6 +2004,7 @@ FEE4EF56272FDD4B003CDA3C /* RemoteCommentV2.swift */, FEF7419C28085D89002C4203 /* RemoteBloggingPrompt.swift */, FE20A6A3282A96C00025E975 /* RemoteBloggingPromptsSettings.swift */, + 1DAC3D2529AF4F250068FE13 /* RemoteVideoPressVideo.swift */, ); name = Models; sourceTree = ""; @@ -2250,6 +2263,10 @@ E1787DAF200E564B004CB3AF /* timezones.json */, 436D5642211B7F9B00CEAA33 /* validate-domain-contact-information-response-fail.json */, 436D5644211B801000CEAA33 /* validate-domain-contact-information-response-success.json */, + 1DF972BC29B107E7007A72BC /* videopress-private-video.json */, + 1DF972BD29B107E7007A72BC /* videopress-public-video.json */, + 1DF972BE29B107E7007A72BC /* videopress-site-default-video.json */, + 1DF972B729B0DF8C007A72BC /* videopress-token.json */, FFE247A920C891E5002DF3A2 /* WordPressComAuthenticateWithIDToken2FANeededSuccess.json */, FFE247AB20C891E5002DF3A2 /* WordPressComAuthenticateWithIDTokenBearerTokenSuccess.json */, FFE247AE20C891E6002DF3A2 /* WordPressComAuthenticateWithIDTokenExistingUserNeedsConnection.json */, @@ -2455,6 +2472,7 @@ children = ( F3FF8A1B279C86E000E5C90F /* Stats */, F3FF8A20279C8EE200E5C90F /* RemotePersonTests.swift */, + 1DC837C129B9F04F009DCD4B /* RemoteVideoPressVideoTests.swift */, ); path = Models; sourceTree = ""; @@ -2695,6 +2713,7 @@ 74C473B51EF320CC009918F2 /* site-delete-bad-json-failure.json in Resources */, 740B23E21F17FB4200067A2A /* xmlrpc-metaweblog-editpost-change-format-failure.xml in Resources */, FFE247BD20C9C88B002DF3A2 /* empty.json in Resources */, + 1DF972BA29B0DF8C007A72BC /* videopress-token.json in Resources */, BA8EA71324A056C300D5CC9F /* plugin-service-remote-featured-malformed.json in Resources */, 436D5643211B7F9B00CEAA33 /* validate-domain-contact-information-response-fail.json in Resources */, AB49D09725D1AC0A0084905B /* post-likes-success.json in Resources */, @@ -2787,6 +2806,7 @@ 740B23EE1F17FB7E00067A2A /* xmlrpc-malformed-request-xml-error.xml in Resources */, 826016F91F9FAF6300533B6C /* activity-log-success-3.json in Resources */, FE20A6A8282BC83A0025E975 /* blogging-prompts-settings-update-with-response.json in Resources */, + 1DF972BF29B107E7007A72BC /* videopress-private-video.json in Resources */, 8B749E8A25AF819700023F03 /* jetpack-capabilities-malformed.json in Resources */, 93BD27551EE73442002BB00B /* auth-send-login-email-invalid-client-failure.json in Resources */, 826016FD1F9FAF6300533B6C /* activity-log-bad-json-failure.json in Resources */, @@ -2850,6 +2870,7 @@ 93BD27631EE73442002BB00B /* me-sites-visibility-bad-json-failure.json in Resources */, 17BF9A7220C7E18200BF57D2 /* reader-site-search-success-hasmore.json in Resources */, 9AB6D64B21872A0D0008F274 /* post-revisions-success.json in Resources */, + 1DF972C029B107E7007A72BC /* videopress-public-video.json in Resources */, C92EFF6925E7403F00E0308D /* common-starter-site-designs-success.json in Resources */, 7433BC131EFC45C7002D9E92 /* site-plans-bad-json-failure.json in Resources */, 74B335DE1F06F5A50053A184 /* WordPressComRestApiFailInvalidJSON.json in Resources */, @@ -2884,6 +2905,7 @@ 9A881750223C01E400A3AB20 /* jetpack-service-error-install-failure.json in Resources */, 74FC6F431F191C1D00112505 /* notifications-load-all.json in Resources */, 74C473C11EF32C74009918F2 /* site-export-missing-status-failure.json in Resources */, + 1DF972C129B107E7007A72BC /* videopress-site-default-video.json in Resources */, 828A2400201B671F004F6859 /* activity-restore-success.json in Resources */, 826016FC1F9FAF6300533B6C /* activity-log-success-2.json in Resources */, C738CAF928622BB1001BE107 /* qrlogin-authenticate-failed-400.json in Resources */, @@ -3107,6 +3129,7 @@ 74E2295C1F1E77290085F7F2 /* KeyringConnectionExternalUser.swift in Sources */, E1BD95151FD5A2B800CD5CE3 /* PluginDirectoryServiceRemote.swift in Sources */, 7430C9D71F1933210051B8E6 /* RemoteReaderCrossPostMeta.swift in Sources */, + 1DAC3D2629AF4F250068FE13 /* RemoteVideoPressVideo.swift in Sources */, FA68CD152993C6CD00FA4C29 /* BlazeServiceRemote.swift in Sources */, 4081976F221DDE9B00A298E4 /* StatsTopPostsTimeIntervalData.swift in Sources */, 9311A68B1F22625A00704AC9 /* TaxonomyServiceRemoteXMLRPC.m in Sources */, @@ -3273,6 +3296,7 @@ BAFA775624ADAB3C000F0D3A /* MockPluginDirectoryEntryProvider.swift in Sources */, 9AB6D64A218727D60008F274 /* PostServiceRemoteRESTRevisionsTest.swift in Sources */, 7430C9BD1F192C0F0051B8E6 /* ReaderPostServiceRemoteTests.m in Sources */, + 1DC837C229B9F04F009DCD4B /* RemoteVideoPressVideoTests.swift in Sources */, FAD1345125909DEA00A8FEB1 /* JetpackBackupServiceRemoteTests.swift in Sources */, 8B2F4BE924ABC9DC0056C08A /* ReaderPostServiceRemote+CardsTests.swift in Sources */, 40F9880C221ACEEE00B7B369 /* StatsRemoteV2Tests.swift in Sources */, diff --git a/WordPressKit/MediaServiceRemote.h b/WordPressKit/MediaServiceRemote.h index 50054ca0..dd5640e7 100644 --- a/WordPressKit/MediaServiceRemote.h +++ b/WordPressKit/MediaServiceRemote.h @@ -1,6 +1,7 @@ #import @class RemoteMedia; +@class RemoteVideoPressVideo; @protocol MediaServiceRemote @@ -59,15 +60,31 @@ failure:(void (^)(NSError *))failure; /** - Retrieves the VideoPress URL for the request videoPressID - - @param videoPressID the videoPressID to search for - @param success a block to be executed if the the video is found on VideoPress and the URL is valid - @param failure a block to be executed if the video is not found on VideoPress. + * Retrieves the metadata of a VideoPress video. + * + * The metadata parameters can be found in the API reference: + * https://developer.wordpress.com/docs/api/1.1/get/videos/%24guid/ + * + * @param videoPressID ID of the video in VideoPress. + * @param isSitePrivate true if the site is private, this will be used to determine the fetch of the VideoPress token. + * @param success a block to be executed when the metadata is fetched successfully. + * @param failure a block to be executed when the metadata can't be fetched. */ --(void)getVideoURLFromVideoPressID:(NSString *)videoPressID - success:(void (^)(NSURL *videoURL, NSURL *posterURL))success +-(void)getMetadataFromVideoPressID:(NSString *)videoPressID + isSitePrivate:(BOOL)isSitePrivate + success:(void (^)(RemoteVideoPressVideo *metadata))success failure:(void (^)(NSError *))failure; +/** + Retrieves the VideoPress token for the request videoPressID. + The token is required to play private VideoPress videos. + + @param videoPressID the videoPressID to search for. + @param success a block to be executed if the the token is fetched successfully for the VideoPress video. + @param failure a block to be executed if the token can't be fetched for the VideoPress video. + */ +-(void)getVideoPressToken:(NSString *)videoPressID + success:(void (^)(NSString *token))success + failure:(void (^)(NSError *))failure; @end diff --git a/WordPressKit/MediaServiceRemoteREST.m b/WordPressKit/MediaServiceRemoteREST.m index c5e6f50e..f95cc962 100644 --- a/WordPressKit/MediaServiceRemoteREST.m +++ b/WordPressKit/MediaServiceRemoteREST.m @@ -309,25 +309,63 @@ - (void)deleteMedia:(RemoteMedia *)media }]; } --(void)getVideoURLFromVideoPressID:(NSString *)videoPressID - success:(void (^)(NSURL *videoURL, NSURL *posterURL))success +-(void)getMetadataFromVideoPressID:(NSString *)videoPressID + isSitePrivate:(BOOL)isSitePrivate + success:(void (^)(RemoteVideoPressVideo *metadata))success failure:(void (^)(NSError *))failure { NSString *path = [NSString stringWithFormat:@"videos/%@", videoPressID]; NSString *requestUrl = [self pathForEndpoint:path withVersion:ServiceRemoteWordPressComRESTApiVersion_1_1]; - + [self.wordPressComRestApi GET:requestUrl + parameters:nil + success:^(id responseObject, NSHTTPURLResponse *httpResponse) { + NSDictionary *response = (NSDictionary *)responseObject; + RemoteVideoPressVideo *video = [[RemoteVideoPressVideo alloc] initWithDictionary:response id:videoPressID]; + + BOOL needsToken = video.privacySetting == VideoPressPrivacySettingIsPrivate || (video.privacySetting == VideoPressPrivacySettingSiteDefault && isSitePrivate); + if(needsToken) { + [self getVideoPressToken:videoPressID success:^(NSString *token) { + video.token = token; + if (success) { + success(video); + } + } failure:^(NSError * error) { + if (failure) { + failure(error); + } + }]; + } + else { + if (success) { + success(video); + } + } + } failure:^(NSError *error, NSHTTPURLResponse *response) { + if (failure) { + failure(error); + } + }]; +} + +-(void)getVideoPressToken:(NSString *)videoPressID + success:(void (^)(NSString *token))success + failure:(void (^)(NSError *))failure +{ + + NSString *path = [NSString stringWithFormat:@"sites/%@/media/videopress-playback-jwt/%@", self.siteID, videoPressID]; + NSString *requestUrl = [self pathForEndpoint:path + withVersion:ServiceRemoteWordPressComRESTApiVersion_2_0]; + + [self.wordPressComRestApi POST:requestUrl parameters:nil success:^(id responseObject, NSHTTPURLResponse *httpResponse) { NSDictionary *response = (NSDictionary *)responseObject; - NSString *urlString = [response stringForKey:@"original"]; - NSString *posterURLString = [response stringForKey:@"poster"]; - NSURL *videoURL = [NSURL URLWithString:urlString]; - NSURL *posterURL = [NSURL URLWithString:posterURLString]; - if (videoURL) { + NSString *token = [response stringForKey:@"metadata_token"]; + if (token) { if (success) { - success(videoURL, posterURL); + success(token); } } else { if (failure) { diff --git a/WordPressKit/MediaServiceRemoteXMLRPC.m b/WordPressKit/MediaServiceRemoteXMLRPC.m index 7558ba81..88df1774 100644 --- a/WordPressKit/MediaServiceRemoteXMLRPC.m +++ b/WordPressKit/MediaServiceRemoteXMLRPC.m @@ -233,11 +233,25 @@ - (void)deleteMedia:(RemoteMedia *)media }]; } --(void)getVideoURLFromVideoPressID:(NSString *)videoPressID - success:(void (^)(NSURL *videoURL, NSURL *posterURL))success +-(void)getMetadataFromVideoPressID:(NSString *)videoPressID + isSitePrivate:(BOOL)includeToken + success:(void (^)(RemoteVideoPressVideo *video))success failure:(void (^)(NSError *))failure { - //Sergio Estevao: 2017-04-12 this option doens't exist on XML-RPC so we will always fail the request + // ⚠️ The endpoint used for fetching the metadata is not available in XML-RPC. + if (failure) { + NSError *error = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorUnsupportedURL + userInfo:nil]; + failure(error); + } +} + +-(void)getVideoPressToken:(NSString *)videoPressID + success:(void (^)(NSString *token))success + failure:(void (^)(NSError *))failure +{ + // The endpoint `wpcom/v2/sites//media/videopress-playback-jwt/` is not available in XML-RPC. if (failure) { NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnsupportedURL diff --git a/WordPressKit/RemoteVideoPressVideo.swift b/WordPressKit/RemoteVideoPressVideo.swift new file mode 100644 index 00000000..7613136a --- /dev/null +++ b/WordPressKit/RemoteVideoPressVideo.swift @@ -0,0 +1,100 @@ +import Foundation + +/// This enum matches the privacy setting constants defined in Jetpack: +/// https://github.com/Automattic/jetpack/blob/a2ccfb7978184e306211292a66ed49dcf38a517f/projects/packages/videopress/src/utility-functions.php#L13-L17 +@objc public enum VideoPressPrivacySetting: Int, Encodable { + case isPublic = 0 + case isPrivate = 1 + case siteDefault = 2 +} + +@objcMembers public class RemoteVideoPressVideo: NSObject, Encodable { + + /// The following properties match the response parameters from the `videos` endpoint: + /// https://developer.wordpress.com/docs/api/1.1/get/videos/%24guid/ + /// + /// However, it's missing the following parameters that could be added in the future if needed: + /// - files + /// - file_url_base + /// - upload_date + /// - files_status + /// - subtitles + public var id: String + public var title: String? + public var videoDescription: String? + public var width: Int? + public var height: Int? + public var duration: Int? + public var displayEmbed: Bool? + public var allowDownload: Bool? + public var rating: String? + public var privacySetting: VideoPressPrivacySetting = .siteDefault + public var posterURL: URL? + public var originalURL: URL? + public var watermarkURL: URL? + public var bgColor: String? + public var blogId: Int? + public var postId: Int? + public var finished: Bool? + + public var token: String? + + enum CodingKeys: String, CodingKey { + case id, title, videoDescription = "description", width, height, duration, displayEmbed, allowDownload, rating, privacySetting, posterURL, originalURL, watermarkURL, bgColor, blogId, postId, finished, token + } + + public init(dictionary metadataDict: NSDictionary, id: String) { + self.id = id + + title = metadataDict.string(forKey: "title") + videoDescription = metadataDict.string(forKey: "description") + width = metadataDict.number(forKey: "width")?.intValue + height = metadataDict.number(forKey: "height")?.intValue + duration = metadataDict.number(forKey: "duration")?.intValue + displayEmbed = metadataDict.object(forKey: "display_embed") as? Bool + allowDownload = metadataDict.object(forKey: "allow_download") as? Bool + rating = metadataDict.string(forKey: "rating") + if let privacySettingValue = metadataDict.number(forKey: "privacy_setting")?.intValue, let privacySettingEnum = VideoPressPrivacySetting.init(rawValue: privacySettingValue) { + privacySetting = privacySettingEnum + } + if let poster = metadataDict.string(forKey: "poster") { + posterURL = URL(string: poster) + } + if let original = metadataDict.string(forKey: "original") { + originalURL = URL(string: original) + } + if let watermark = metadataDict.string(forKey: "watermark") { + watermarkURL = URL(string: watermark) + } + bgColor = metadataDict.string(forKey: "bg_color") + blogId = metadataDict.number(forKey: "blog_id")?.intValue + postId = metadataDict.number(forKey: "post_id")?.intValue + finished = metadataDict.object(forKey: "finished") as? Bool + } + + /// Returns the specified URL adding the token as a query parameter, which is required to play private videos. + /// - Parameters: + /// - url: URL to include the token. + /// + /// - Returns: The specified URL with the token as a query parameter. It will return `nil` if the token is not present. + @objc(getURLWithToken:) + public func getURLWithToken(url: URL) -> URL? { + guard let token, var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) else { + return nil + } + let metadataTokenParam = URLQueryItem(name: "metadata_token", value: token) + urlComponents.queryItems = (urlComponents.queryItems ?? []) + [metadataTokenParam] + return urlComponents.url + } + + public func asDictionary() -> [String: Any] { + guard + let data = try? JSONEncoder().encode(self), + let dictionary = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] + else { + assertionFailure("Encoding of RemoteVideoPressVideo failed") + return [String: Any]() + } + return dictionary + } +} diff --git a/WordPressKitTests/MediaServiceRemoteRESTTests.swift b/WordPressKitTests/MediaServiceRemoteRESTTests.swift index f96283fb..ec891176 100644 --- a/WordPressKitTests/MediaServiceRemoteRESTTests.swift +++ b/WordPressKitTests/MediaServiceRemoteRESTTests.swift @@ -1,7 +1,7 @@ import XCTest @testable import WordPressKit -class MediaServiceRemoteRESTTests: XCTestCase { +class MediaServiceRemoteRESTTests: RemoteTestCase, RESTTestable { let mockRemoteApi = MockWordPressComRestApi() var mediaServiceRemote: MediaServiceRemoteREST! @@ -347,4 +347,84 @@ class MediaServiceRemoteRESTTests: XCTestCase { XCTAssertEqual(remoteMediaArray[1].height?.intValue, height) XCTAssertEqual(remoteMediaArray[1].width?.intValue, width) } + + func testGetMetadataFromVideoPressIDPath() { + let id = "AbCDeF" + let expectedPath = mediaServiceRemote.path(forEndpoint: "videos/\(id)", withVersion: ._1_1) + mediaServiceRemote.getMetadataFromVideoPressID(id, isSitePrivate: false, success: nil, failure: nil) + XCTAssertTrue(mockRemoteApi.getMethodCalled, "Wrong method, expected GET got \(mockRemoteApi.methodCalled())") + XCTAssertEqual(mockRemoteApi.URLStringPassedIn, expectedPath, "Wrong path") + } + + func testGetMetadataFromPublicVideoPressIDPath() { + let id = "AbCDeF" + // Mock VideoPress metadata response. + stubRemoteResponse("/videos", filename: "videopress-public-video.json", contentType: .ApplicationHTML) + let expect = self.expectation(description: "VideoPress metadata is fetched for a public video in a private site") + let mediaServiceRemote = MediaServiceRemoteREST(wordPressComRestApi: getRestApi(), siteID: NSNumber(value: siteID)) + mediaServiceRemote.getMetadataFromVideoPressID(id, isSitePrivate: true, success: { metadata in + expect.fulfill() + XCTAssertNotNil(metadata) + XCTAssertEqual(metadata?.id, id) + XCTAssertNil(metadata?.token) + }, failure: { _ in + expect.fulfill() + XCTFail("This call should be successfull") + }) + self.waitForExpectations(timeout: 2, handler: nil) + } + + func testGetMetadataFromPrivateVideoPressIDPath() { + let id = "AbCDeF" + let token = "videopress-token" + stubRemoteResponse("/videos", filename: "videopress-private-video.json", contentType: .ApplicationHTML) + stubRemoteResponse("/media/videopress-playback-jwt", filename: "videopress-token.json", contentType: .ApplicationHTML) + let expect = self.expectation(description: "VideoPress metadata is fetched for a private video in public site") + let mediaServiceRemote = MediaServiceRemoteREST(wordPressComRestApi: getRestApi(), siteID: NSNumber(value: siteID)) + mediaServiceRemote.getMetadataFromVideoPressID(id, isSitePrivate: false, success: { metadata in + expect.fulfill() + XCTAssertNotNil(metadata) + XCTAssertEqual(metadata?.id, id) + XCTAssertEqual(metadata?.token, token) + }, failure: { _ in + expect.fulfill() + XCTFail("This call should be successfull") + }) + self.waitForExpectations(timeout: 2, handler: nil) + } + + func testGetMetadataFromSiteDefaultVideoPressIDPath() { + let id = "AbCDeF" + let token = "videopress-token" + stubRemoteResponse("/videos", filename: "videopress-site-default-video.json", contentType: .ApplicationHTML) + stubRemoteResponse("/media/videopress-playback-jwt", filename: "videopress-token.json", contentType: .ApplicationHTML) + let expect = self.expectation(description: "VideoPress metadata is fetched for a site default video in a private site") + let mediaServiceRemote = MediaServiceRemoteREST(wordPressComRestApi: getRestApi(), siteID: NSNumber(value: siteID)) + mediaServiceRemote.getMetadataFromVideoPressID(id, isSitePrivate: true, success: { metadata in + expect.fulfill() + XCTAssertNotNil(metadata) + XCTAssertEqual(metadata?.id, id) + XCTAssertEqual(metadata?.token, token) + }, failure: { _ in + expect.fulfill() + XCTFail("This call should be successfull") + }) + self.waitForExpectations(timeout: 2, handler: nil) + } + + func testGetVideoPressToken() { + let id = "AbCDeF" + let token = "videopress-token" + stubRemoteResponse("/media/videopress-playback-jwt", filename: "videopress-token.json", contentType: .ApplicationHTML) + let expect = self.expectation(description: "VideoPress token is fetched for a video") + let mediaServiceRemote = MediaServiceRemoteREST(wordPressComRestApi: getRestApi(), siteID: NSNumber(value: siteID)) + mediaServiceRemote.getVideoPressToken(id, success: { result in + expect.fulfill() + XCTAssertEqual(result, token) + }, failure: { _ in + expect.fulfill() + XCTFail("This call should be successfull") + }) + self.waitForExpectations(timeout: 2, handler: nil) + } } diff --git a/WordPressKitTests/Mock Data/videopress-private-video.json b/WordPressKitTests/Mock Data/videopress-private-video.json new file mode 100644 index 00000000..f0ad2bcf --- /dev/null +++ b/WordPressKitTests/Mock Data/videopress-private-video.json @@ -0,0 +1,19 @@ +{ + "guid": "OO4thna8", + "title": "VideoPress demo", + "description": "", + "width": 1280, + "height": 720, + "duration": 143700, + "display_embed": true, + "allow_download": false, + "rating": "G", + "poster": "https://videos.files.wordpress.com/OO4thna8/videopress2-web2_hd.original.jpg", + "original": "https://videos.files.wordpress.com/OO4thna8/videopress2-web2.mov", + "watermark": "https://wptv.files.wordpress.com/2010/07/wptv.png", + "bg_color": "", + "blog_id": 9999, + "post_id": 1913, + "privacy_setting": 1, + "finished": true +} diff --git a/WordPressKitTests/Mock Data/videopress-public-video.json b/WordPressKitTests/Mock Data/videopress-public-video.json new file mode 100644 index 00000000..361a507f --- /dev/null +++ b/WordPressKitTests/Mock Data/videopress-public-video.json @@ -0,0 +1,19 @@ +{ + "guid": "OO4thna8", + "title": "VideoPress demo", + "description": "", + "width": 1280, + "height": 720, + "duration": 143700, + "display_embed": true, + "allow_download": false, + "rating": "G", + "poster": "https://videos.files.wordpress.com/OO4thna8/videopress2-web2_hd.original.jpg", + "original": "https://videos.files.wordpress.com/OO4thna8/videopress2-web2.mov", + "watermark": "https://wptv.files.wordpress.com/2010/07/wptv.png", + "bg_color": "", + "blog_id": 9999, + "post_id": 1913, + "privacy_setting": 0, + "finished": true +} diff --git a/WordPressKitTests/Mock Data/videopress-site-default-video.json b/WordPressKitTests/Mock Data/videopress-site-default-video.json new file mode 100644 index 00000000..7a3ac06c --- /dev/null +++ b/WordPressKitTests/Mock Data/videopress-site-default-video.json @@ -0,0 +1,19 @@ +{ + "guid": "OO4thna8", + "title": "VideoPress demo", + "description": "", + "width": 1280, + "height": 720, + "duration": 143700, + "display_embed": true, + "allow_download": false, + "rating": "G", + "poster": "https://videos.files.wordpress.com/OO4thna8/videopress2-web2_hd.original.jpg", + "original": "https://videos.files.wordpress.com/OO4thna8/videopress2-web2.mov", + "watermark": "https://wptv.files.wordpress.com/2010/07/wptv.png", + "bg_color": "", + "blog_id": 9999, + "post_id": 1913, + "privacy_setting": 2, + "finished": true +} diff --git a/WordPressKitTests/Mock Data/videopress-token.json b/WordPressKitTests/Mock Data/videopress-token.json new file mode 100644 index 00000000..39600bc2 --- /dev/null +++ b/WordPressKitTests/Mock Data/videopress-token.json @@ -0,0 +1,3 @@ +{ + "metadata_token": "videopress-token" +} \ No newline at end of file diff --git a/WordPressKitTests/Models/RemoteVideoPressVideoTests.swift b/WordPressKitTests/Models/RemoteVideoPressVideoTests.swift new file mode 100644 index 00000000..229bb8bc --- /dev/null +++ b/WordPressKitTests/Models/RemoteVideoPressVideoTests.swift @@ -0,0 +1,82 @@ +import XCTest +@testable import WordPressKit + +class RemoteVideoPressVideoTests: XCTestCase { + + func mockVideoPressMetadata(_ id: String) -> NSDictionary { + return [ + "title": "VideoPress demo", + "description": "asd", + "width": 1280, + "height": 720, + "duration": 143700, + "display_embed": true, + "allow_download": false, + "rating": "G", + "poster": "https://videos.files.wordpress.com/\(id)/videopress2-web2_hd.original.jpg", + "original": "https://videos.files.wordpress.com/\(id)/videopress2-web2.mov", + "watermark": "https://wptv.files.wordpress.com/2010/07/wptv.png", + "bg_color": "", + "blog_id": 5089392, + "post_id": 1913, + "finished": true + ] + } + + func testInit() { + let id = "AbCdE" + let metadata = mockVideoPressMetadata(id) + let video = RemoteVideoPressVideo(dictionary: metadata, id: id) + XCTAssertEqual(video.title, metadata["title"] as? String) + XCTAssertEqual(video.videoDescription, metadata["description"] as? String) + XCTAssertEqual(video.width, metadata["width"] as? Int) + XCTAssertEqual(video.height, metadata["height"] as? Int) + XCTAssertEqual(video.duration, metadata["duration"] as? Int) + XCTAssertEqual(video.displayEmbed, metadata["display_embed"] as? Bool) + XCTAssertEqual(video.allowDownload, metadata["allow_download"] as? Bool) + XCTAssertEqual(video.rating, metadata["rating"] as? String) + XCTAssertEqual(video.posterURL, URL(string: metadata["poster"] as! String)) + XCTAssertEqual(video.originalURL, URL(string: metadata["original"] as! String)) + XCTAssertEqual(video.watermarkURL, URL(string: metadata["watermark"] as! String)) + XCTAssertEqual(video.bgColor, metadata["bg_color"] as? String) + XCTAssertEqual(video.blogId, metadata["blog_id"] as? Int) + XCTAssertEqual(video.postId, metadata["post_id"] as? Int) + XCTAssertEqual(video.finished, metadata["finished"] as? Bool) + } + + func testGetURLWithToken() { + let id = "AbCdE" + let metadata = mockVideoPressMetadata(id) + let token = "videopress-token" + let video = RemoteVideoPressVideo(dictionary: metadata, id: id) + let originalURL = video.originalURL! + + video.token = token + XCTAssertEqual(video.getURLWithToken(url: originalURL), URL(string: "\(originalURL.absoluteString)?metadata_token=\(token)")) + + video.token = nil + XCTAssertNil(video.getURLWithToken(url: originalURL)) + } + + func testAsDictionary() throws { + let id = "AbCdE" + let metadata = mockVideoPressMetadata(id) + let video = RemoteVideoPressVideo(dictionary: metadata, id: id) + let dict = video.asDictionary() + XCTAssertEqual(video.title, dict["title"] as? String) + XCTAssertEqual(video.videoDescription, dict["description"] as? String) + XCTAssertEqual(video.width, dict["width"] as? Int) + XCTAssertEqual(video.height, dict["height"] as? Int) + XCTAssertEqual(video.duration, dict["duration"] as? Int) + XCTAssertEqual(video.displayEmbed, dict["displayEmbed"] as? Bool) + XCTAssertEqual(video.allowDownload, dict["allowDownload"] as? Bool) + XCTAssertEqual(video.rating, dict["rating"] as? String) + XCTAssertEqual(video.posterURL?.absoluteString, dict["posterURL"] as? String) + XCTAssertEqual(video.originalURL?.absoluteString, dict["originalURL"] as? String) + XCTAssertEqual(video.watermarkURL?.absoluteString, dict["watermarkURL"] as? String) + XCTAssertEqual(video.bgColor, dict["bgColor"] as? String) + XCTAssertEqual(video.blogId, dict["blogId"] as? Int) + XCTAssertEqual(video.postId, dict["postId"] as? Int) + XCTAssertEqual(video.finished, dict["finished"] as? Bool) + } +}