This repository was archived by the owner on Sep 15, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
[Site creation] Implementation of segments service #71
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
4a1e147
Bump pod version to beta 5
ctarda 6c92a6a
Scaffold service. Now we can start working on the app side of the pro…
ctarda da00f5f
Push the implementation of the segments service down to WordPressKit
ctarda 777f163
Declare some properties as public
ctarda 7d1a564
Declare extension to WordPressComServiceRemote as public
ctarda 5bbdf0e
Make initialisers public
ctarda 78c5700
Add end to end test for the segments service
ctarda fa3267a
Remove SiteSegmentsRequest
ctarda facf460
Merge branch 'develop' into feature/site-segments-service
ctarda c20602b
Add unit tests for SiteSegment
ctarda 29767cb
Update minor version instead of patch version
ctarda File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
WordPressKit/WordPressComServiceRemote+SiteSegments.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| /// Models a type of site. | ||
| public struct SiteSegment { | ||
| public let identifier: Int64 // we use a numeric ID for segments; see p9wMUP-bH-612-p2 for discussion | ||
| public let title: String | ||
| public let subtitle: String | ||
| public let icon: URL? | ||
| public let iconColor: String? | ||
| public let mobile: Bool | ||
|
|
||
| public init(identifier: Int64, title: String, subtitle: String, icon: URL?, iconColor: String?, mobile: Bool) { | ||
| self.identifier = identifier | ||
| self.title = title | ||
| self.subtitle = subtitle | ||
| self.icon = icon | ||
| self.iconColor = iconColor | ||
| self.mobile = mobile | ||
| } | ||
| } | ||
|
|
||
| extension SiteSegment { | ||
| public static let blogSegmentIdentifier = Int64(1) | ||
| } | ||
|
|
||
| extension SiteSegment: Equatable { | ||
| public static func ==(lhs: SiteSegment, rhs: SiteSegment) -> Bool { | ||
| return lhs.identifier == rhs.identifier | ||
| } | ||
| } | ||
|
|
||
| extension SiteSegment: Decodable { | ||
| enum CodingKeys: String, CodingKey { | ||
| case segmentId = "id" | ||
| case segmentTypeTitle = "segment_type_title" | ||
| case segmentTypeSubtitle = "segment_type_subtitle" | ||
| case iconURL = "icon_URL" | ||
| case iconColor = "icon_color" | ||
| case mobile = "mobile" | ||
| } | ||
|
|
||
| public init(from decoder: Decoder) throws { | ||
| let values = try decoder.container(keyedBy: CodingKeys.self) | ||
| identifier = try values.decode(Int64.self, forKey: .segmentId) | ||
| title = try values.decode(String.self, forKey: .segmentTypeTitle) | ||
| subtitle = try values.decode(String.self, forKey: .segmentTypeSubtitle) | ||
| if let iconString = try values.decodeIfPresent(String.self, forKey: .iconURL) { | ||
| icon = URL(string: iconString) | ||
| } else { | ||
| icon = nil | ||
| } | ||
|
|
||
| if let iconColorString = try values.decodeIfPresent(String.self, forKey: .iconColor) { | ||
| var cleanIconColorString = iconColorString | ||
| if iconColorString.hasPrefix("#") { | ||
| cleanIconColorString = String(iconColorString.dropFirst(1)) | ||
| } | ||
|
|
||
| iconColor = cleanIconColorString | ||
| } else { | ||
| iconColor = nil | ||
| } | ||
|
|
||
| mobile = try values.decode(Bool.self, forKey: .mobile) | ||
|
|
||
| } | ||
| } | ||
|
|
||
| // MARK: - WordPressComServiceRemote (Site Segments) | ||
|
|
||
| /// Describes the errors that could arise when searching for site verticals. | ||
| /// | ||
| /// - requestEncodingFailure: unable to encode the request parameters. | ||
| /// - responseDecodingFailure: unable to decode the server response. | ||
| /// - serviceFailure: the service returned an unexpected error. | ||
| /// | ||
| public enum SiteSegmentsError: Error { | ||
| case requestEncodingFailure | ||
| case responseDecodingFailure | ||
| case serviceFailure | ||
| } | ||
|
|
||
| /// Advises the caller of results related to requests for site segments. | ||
| /// | ||
| /// - success: the site segments request succeeded with the accompanying result. | ||
| /// - failure: the site segments request failed due to the accompanying error. | ||
| /// | ||
| public enum SiteSegmentsResult { | ||
| case success([SiteSegment]) | ||
| case failure(SiteSegmentsError) | ||
| } | ||
|
|
||
| public typealias SiteSegmentsServiceCompletion = (SiteSegmentsResult) -> Void | ||
|
|
||
| /// Site segments service, exclusive to WordPress.com. | ||
| /// | ||
| public extension WordPressComServiceRemote { | ||
| func retrieveSegments(completion: @escaping SiteSegmentsServiceCompletion) { | ||
| let endpoint = "segments" | ||
| let remotePath = path(forEndpoint: endpoint, withVersion: ._2_0) | ||
|
|
||
| wordPressComRestApi.GET( | ||
| remotePath, | ||
| parameters: nil, | ||
| success: { [weak self] responseObject, httpResponse in | ||
| DDLogInfo("\(responseObject) | \(String(describing: httpResponse))") | ||
|
|
||
| guard let self = self else { | ||
| return | ||
| } | ||
|
|
||
| do { | ||
| let response = try self.decodeResponse(responseObject: responseObject) | ||
| let validContent = self.validSegments(response) | ||
| completion(.success(validContent)) | ||
| } catch { | ||
| DDLogError("Failed to decode \([SiteVertical].self) : \(error.localizedDescription)") | ||
| completion(.failure(SiteSegmentsError.responseDecodingFailure)) | ||
| } | ||
| }, | ||
| failure: { error, httpResponse in | ||
| DDLogError("\(error) | \(String(describing: httpResponse))") | ||
| completion(.failure(SiteSegmentsError.serviceFailure)) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Serialization support | ||
|
|
||
| private extension WordPressComServiceRemote { | ||
| private func decodeResponse(responseObject: AnyObject) throws -> [SiteSegment] { | ||
| let decoder = JSONDecoder() | ||
| let data = try JSONSerialization.data(withJSONObject: responseObject, options: []) | ||
| let response = try decoder.decode([SiteSegment].self, from: data) | ||
|
|
||
| return response | ||
| } | ||
|
|
||
| private func validSegments(_ allSegments: [SiteSegment]) -> [SiteSegment] { | ||
| return allSegments.filter { | ||
| return $0.mobile == true | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| [ | ||
| { | ||
| "icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_blogger.png", | ||
| "icon_color" : "#0087be", | ||
| "id" : 1, | ||
| "mobile" : true, | ||
| "segment_type_subtitle" : "Share and discuss ideas, updates, or creations.", | ||
| "segment_type_title" : "Blog", | ||
| "slug" : "blog" | ||
| }, | ||
| { | ||
| "icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_business.png", | ||
| "icon_color" : "#f0b849", | ||
| "id" : 2, | ||
| "mobile" : true, | ||
| "segment_type_subtitle" : "Promote products and services.", | ||
| "segment_type_title" : "Business", | ||
| "slug" : "business" | ||
| }, | ||
| { | ||
| "icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_professional.png", | ||
| "icon_color" : "#f0b849", | ||
| "id" : 3, | ||
| "mobile" : true, | ||
| "segment_type_subtitle" : "Showcase your portfolio, skills or work.", | ||
| "segment_type_title" : "Professional", | ||
| "slug" : "professional" | ||
| }, | ||
| { | ||
| "icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_educator.png", | ||
| "icon_color" : "#d94f4f", | ||
| "id" : 4, | ||
| "mobile" : true, | ||
| "segment_type_subtitle" : "Share school projects and class info.", | ||
| "segment_type_title" : "Education", | ||
| "slug" : "education" | ||
| }, | ||
| { | ||
| "icon_URL" : "", | ||
| "icon_color" : "", | ||
| "id" : 5, | ||
| "mobile" : false, | ||
| "segment_type_subtitle" : "Sell your collection of products online.", | ||
| "segment_type_title" : "Online store", | ||
| "slug" : "online-store" | ||
| }, | ||
| { | ||
| "icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_blank_canvas.png", | ||
| "icon_color" : "#87a6bc", | ||
| "id" : 6, | ||
| "mobile" : true, | ||
| "segment_type_subtitle" : "Start with a blank site.", | ||
| "segment_type_title" : "Blank Canvas", | ||
| "slug" : "blank-canvas" | ||
| } | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
This conversation was marked as resolved.
Show resolved
Hide resolved
|
||
| "icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_blogger.png", | ||
| "icon_color" : "#0087be", | ||
| "id" : 1, | ||
| "mobile" : true, | ||
| "segment_type_subtitle" : "Share and discuss ideas, updates, or creations.", | ||
| "segment_type_title" : "Blog", | ||
| "slug" : "blog" | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import XCTest | ||
| @testable import WordPressKit | ||
|
|
||
| final class SiteCreationSegmentsTests: RemoteTestCase, RESTTestable { | ||
|
|
||
| func testSiteSegmentsRequest_Succeeds() { | ||
| // Given | ||
| let endpoint = "segments" | ||
| let fileName = "site-segments-multiple.json" | ||
| stubRemoteResponse(endpoint, filename: fileName, contentType: .ApplicationJSON) | ||
|
|
||
| let expectedSegmentsCount = 5 | ||
|
|
||
| // When, Then | ||
| let segmentsExpectation = expectation(description: "Initiate site segments request") | ||
| let remote = WordPressComServiceRemote(wordPressComRestApi: getRestApi()) | ||
| remote.retrieveSegments(completion: { result in | ||
| segmentsExpectation.fulfill() | ||
| switch result { | ||
| case .success(let segments): | ||
| XCTAssertNotNil(segments) | ||
|
|
||
| let mobileSegmentsCount = segments.count | ||
| XCTAssertEqual(mobileSegmentsCount, expectedSegmentsCount) | ||
|
|
||
| case .failure(_): | ||
| XCTFail() | ||
| } | ||
| }) | ||
|
|
||
| waitForExpectations(timeout: timeout) | ||
| } | ||
|
|
||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should be updating the patch version in this case. It seems like we should be updating the minor version, yes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated!