Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Experiments/Experiments/DefaultFeatureFlagService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
case .storeCreationMVP:
return true
case .justInTimeMessagesOnDashboard:
return buildConfig == .localDeveloper || buildConfig == .alpha
return true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this meant to go in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's intentional, this is the last bit required for the release of i1. I've checked that it works correctly on a release build.

Should have called it out in the description, sorry!

case .productsOnboarding:
return buildConfig == .localDeveloper || buildConfig == .alpha
case .performanceMonitoring,
Expand Down
1 change: 1 addition & 0 deletions Hardware/Hardware.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,7 @@
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = ALPHA;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
Expand Down
5 changes: 1 addition & 4 deletions Networking/Networking.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@
09EA564B27C75FCE00407D40 /* ProductVariationsBulkUpdateMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EA564A27C75FCE00407D40 /* ProductVariationsBulkUpdateMapper.swift */; };
21DB5B99C4107CF69C0A57EC /* Pods_NetworkingTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69314EDE650855CAF927057E /* Pods_NetworkingTests.framework */; };
24F98C522502E79800F49B68 /* FeatureFlagsRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F98C512502E79800F49B68 /* FeatureFlagsRemote.swift */; };
24F98C542502E8DD00F49B68 /* Bundle+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F98C532502E8DD00F49B68 /* Bundle+Woo.swift */; };
24F98C562502EA4800F49B68 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F98C552502EA4800F49B68 /* FeatureFlag.swift */; };
24F98C582502EA8800F49B68 /* FeatureFlagMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F98C572502EA8800F49B68 /* FeatureFlagMapper.swift */; };
24F98C5E2502EDCF00F49B68 /* BundleWooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F98C5D2502EDCF00F49B68 /* BundleWooTests.swift */; };
Expand Down Expand Up @@ -865,7 +864,6 @@
09885C7F27C3FFD200910A62 /* product-variations-bulk-update.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "product-variations-bulk-update.json"; sourceTree = "<group>"; };
09EA564A27C75FCE00407D40 /* ProductVariationsBulkUpdateMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductVariationsBulkUpdateMapper.swift; sourceTree = "<group>"; };
24F98C512502E79800F49B68 /* FeatureFlagsRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagsRemote.swift; sourceTree = "<group>"; };
24F98C532502E8DD00F49B68 /* Bundle+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Woo.swift"; sourceTree = "<group>"; };
24F98C552502EA4800F49B68 /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = "<group>"; };
24F98C572502EA8800F49B68 /* FeatureFlagMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagMapper.swift; sourceTree = "<group>"; };
24F98C5D2502EDCF00F49B68 /* BundleWooTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleWooTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2346,7 +2344,6 @@
021C7BF623863D1800A3BCBD /* Encodable+Serialization.swift */,
02BDB83423EA98C800BCC63E /* String+HTML.swift */,
57E8FED2246616AC0057CD68 /* Result+Extensions.swift */,
24F98C532502E8DD00F49B68 /* Bundle+Woo.swift */,
265EFBDB285257950033BD33 /* Order+Fallbacks.swift */,
);
path = Extensions;
Expand Down Expand Up @@ -3011,7 +3008,6 @@
D88E229025AC990A0023F3B1 /* OrderFeeLine.swift in Sources */,
74046E1F217A6B70007DD7BF /* SiteSettingsMapper.swift in Sources */,
26B2F74524C5573F0065CCC8 /* LeaderboardListMapper.swift in Sources */,
24F98C542502E8DD00F49B68 /* Bundle+Woo.swift in Sources */,
31D27C812602889C002EDB1D /* SitePluginsRemote.swift in Sources */,
02BE0A7B274B695F001176D2 /* WordPressMediaMapper.swift in Sources */,
45150A9A268340D2006922EA /* Country.swift in Sources */,
Expand Down Expand Up @@ -3484,6 +3480,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.woo.Networking;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = ALPHA;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALID_ARCHS = "$(inherited)";
Expand Down
50 changes: 47 additions & 3 deletions Networking/Networking/Remote/JustInTimeMessagesRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import Foundation

public protocol JustInTimeMessagesRemoteProtocol {
func loadAllJustInTimeMessages(for siteID: Int64,
messagePath: JustInTimeMessagesRemote.MessagePath) async -> Result<[JustInTimeMessage], Error>
messagePath: JustInTimeMessagesRemote.MessagePath,
query: [String: String?]?,
locale: String?) async -> Result<[JustInTimeMessage], Error>
func dismissJustInTimeMessage(for siteID: Int64,
messageID: String,
featureClass: String) async -> Result<Bool, Error>
Expand All @@ -18,16 +20,22 @@ public final class JustInTimeMessagesRemote: Remote, JustInTimeMessagesRemotePro
/// - Parameters:
/// - siteID: The site for which we'll fetch JustInTimeMessages.
/// - messagePath: The location for JITMs to be displayed
/// - query: A dictionary of "query parameters" to include in the JITM request payload
/// - locale: the locale identifier (language and region only, e.g. en_US) for the current device.
/// - Returns:
/// Async result with an array of `[JustInTimeMessage]` (usually contains one element) or an error
///
public func loadAllJustInTimeMessages(for siteID: Int64,
messagePath: JustInTimeMessagesRemote.MessagePath) async -> Result<[JustInTimeMessage], Error> {
messagePath: JustInTimeMessagesRemote.MessagePath,
query: [String: String?]?,
locale: String?) async -> Result<[JustInTimeMessage], Error> {
let request = JetpackRequest(wooApiVersion: .none,
method: .get,
siteID: siteID,
locale: locale,
path: Path.jitm,
parameters: [ParameterKey.messagePath: messagePath.requestValue])
parameters: getParameters(messagePath: messagePath,
query: query))

let mapper = JustInTimeMessageListMapper(siteID: siteID)

Expand All @@ -39,6 +47,41 @@ public final class JustInTimeMessagesRemote: Remote, JustInTimeMessagesRemotePro
}
}

private func getParameters(messagePath: JustInTimeMessagesRemote.MessagePath,
query: [String: String?]?) -> [String: String] {
var parameters = [ParameterKey.messagePath: messagePath.requestValue]
if let query = query,
let queryString = justInTimeMessageQuery(from: query) {
parameters[ParameterKey.query] = queryString
}
return parameters
}

private func justInTimeMessageQuery(from parameters: [String: String?]) -> String? {
let queryItems = parameters.map { (key: String, value: String?) in
URLQueryItem(name: key, value: value)
}
var components = URLComponents()
/// This is a workaround for a backend bug where only the first param can be used for targeting JITMs.
/// `build_type` is the most important, but absent in release builds. In release builds, `platform` is the most important
/// This can be removed when the backend bug is fixed, order should not matter here.
components.queryItems = queryItems.sorted(by: { lhs, rhs in
switch (lhs.name, rhs.name) {
case (_, "build_type"):
return false
case ("build_type", "platform"):
return true
case (_, "platform"):
return false
case ("platform", _):
return true
default:
return lhs.name < rhs.name
}
})
return components.query
}

/// Dismisses a `JustInTimeMessage` using the API.
///
/// - Parameters:
Expand Down Expand Up @@ -81,6 +124,7 @@ public extension JustInTimeMessagesRemote {
static let messagePath = "message_path"
static let featureClass = "feature_class"
static let messageID = "id"
static let query = "query"
}

/// Message Path parameter
Expand Down
11 changes: 10 additions & 1 deletion Networking/Networking/Requests/JetpackRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ struct JetpackRequest: URLRequestConvertible {
///
let siteID: Int64

/// Locale identifier, simplified as `language_Region` e.g. `en_US`
///
let locale: String?

/// Jetpack-Tunneled RPC
///
let path: String
Expand All @@ -40,13 +44,14 @@ struct JetpackRequest: URLRequestConvertible {
/// - path: RPC that should be called.
/// - parameters: Collection of Key/Value parameters, to be forwarded to the Jetpack Connected site.
///
init(wooApiVersion: WooAPIVersion, method: HTTPMethod, siteID: Int64, path: String, parameters: [String: Any]? = nil) {
init(wooApiVersion: WooAPIVersion, method: HTTPMethod, siteID: Int64, locale: String? = nil, path: String, parameters: [String: Any]? = nil) {
if [.mark1, .mark2].contains(wooApiVersion) {
DDLogWarn("⚠️ You are using an older version of the Woo REST API: \(wooApiVersion.rawValue), for path: \(path)")
}
self.wooApiVersion = wooApiVersion
self.method = method
self.siteID = siteID
self.locale = locale
self.path = path
self.parameters = parameters ?? [:]
}
Expand Down Expand Up @@ -102,6 +107,10 @@ private extension JetpackRequest {
"path": jetpackPath + "&_method=" + method.rawValue.lowercased()
]

if let locale = locale {
output["locale"] = locale
}

if let jetpackQueryParams = jetpackQueryParams {
output["query"] = jetpackQueryParams
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ final class JustInTimeMessagesRemoteTests: XCTestCase {
network = MockNetwork()
}

override func tearDown() {
network = nil
super.tearDown()
}

// MARK: - Load all Just In Time Messages tests

/// Verifies that loadAllJustInTimeMessages properly parses the `just-in-time-message-list` sample response.
Expand All @@ -37,7 +32,9 @@ final class JustInTimeMessagesRemoteTests: XCTestCase {
messagePath: JustInTimeMessagesRemote.MessagePath(
app: .wooMobile,
screen: "my_store",
hook: .adminNotices))
hook: .adminNotices),
query: nil,
locale: "en_US")

// Then
XCTAssert(result.isSuccess)
Expand All @@ -57,7 +54,9 @@ final class JustInTimeMessagesRemoteTests: XCTestCase {
messagePath: JustInTimeMessagesRemote.MessagePath(
app: .wooMobile,
screen: "my_store",
hook: .adminNotices))
hook: .adminNotices),
query: nil,
locale: "en_US")

// Then
let request = try XCTUnwrap(network.requestsForResponseData.first as? JetpackRequest)
Expand All @@ -78,7 +77,9 @@ final class JustInTimeMessagesRemoteTests: XCTestCase {
messagePath: JustInTimeMessagesRemote.MessagePath(
app: .wooMobile,
screen: "my_store",
hook: .adminNotices))
hook: .adminNotices),
query: nil,
locale: "en_US")

// Then
let justInTimeMessages = try result.get()
Expand All @@ -97,7 +98,9 @@ final class JustInTimeMessagesRemoteTests: XCTestCase {
messagePath: JustInTimeMessagesRemote.MessagePath(
app: .wooMobile,
screen: "my_store",
hook: .adminNotices))
hook: .adminNotices),
query: nil,
locale: "en_US")

// Then
let request = try XCTUnwrap(network.requestsForResponseData.first as? JetpackRequest)
Expand All @@ -122,11 +125,65 @@ final class JustInTimeMessagesRemoteTests: XCTestCase {
messagePath: JustInTimeMessagesRemote.MessagePath(
app: .wooMobile,
screen: "my_store",
hook: .adminNotices))
hook: .adminNotices),
query: nil,
locale: "en_US")

// Then
XCTAssertTrue(result.isFailure)
let resultError = try XCTUnwrap(result.failure as? NetworkError)
assertEqual(error, resultError)
}

func test_test_loadAllJustInTimeMessages_uses_passed_locale_for_request() async throws {
// Given
let remote = JustInTimeMessagesRemote(network: network)

// When
_ = await remote.loadAllJustInTimeMessages(
for: self.sampleSiteID,
messagePath: JustInTimeMessagesRemote.MessagePath(
app: .wooMobile,
screen: "my_store",
hook: .adminNotices),
query: nil,
locale: "en_US")

// Then
let request = try XCTUnwrap(network.requestsForResponseData.first as? JetpackRequest)
let url = try XCTUnwrap(request.urlRequest?.url)
let queryItems = try XCTUnwrap(URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems)
let locale = try XCTUnwrap(queryItems.first { $0.name == "locale" }?.value)
assertEqual("en_US", locale)
}

func test_test_loadAllJustInTimeMessages_uses_passed_query_for_request() async throws {
// Given
let remote = JustInTimeMessagesRemote(network: network)

// When
_ = await remote.loadAllJustInTimeMessages(
for: self.sampleSiteID,
messagePath: JustInTimeMessagesRemote.MessagePath(
app: .wooMobile,
screen: "my_store",
hook: .adminNotices),
query: [
"platform": "ios",
"version": "11.1"
],
locale: "en_US")

// Then
let request = try XCTUnwrap(network.requestsForResponseData.first as? JetpackRequest)
let url = try XCTUnwrap(request.urlRequest?.url)
let queryItems = try XCTUnwrap(URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems)
let queryJson = try XCTUnwrap(queryItems.first { $0.name == "query" }?.value)
assertThat(queryJson, contains: "\"query\":")
let parameters = request.parameters
let jitmQuery = try XCTUnwrap(request.parameters["query"] as? String)
// Individually check query items because dictionaries aren't ordered
assertThat(jitmQuery, contains: "platform=ios") // platform=ios
assertThat(jitmQuery, contains: "version=11.1") // version=11.1
}
}
14 changes: 14 additions & 0 deletions Networking/NetworkingTests/Requests/JetpackRequestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ final class JetpackRequestTests: XCTestCase {
XCTAssertEqual(output.httpMethod?.uppercased(), "POST")
XCTAssertTrue(generatedBody.contains("%26_method%3Dput"))
}

/// Verifies that a JetpackRequest with `locale` encodes `&locale=fr_FR` query string parameter.
///
func test_request_with_locale_includes_locale_parameter() {
let request = JetpackRequest(wooApiVersion: .mark3,
method: .get,
siteID: sampleSiteID,
locale: "fr_FR",
path: sampleRPC,
parameters: sampleParameters)

let output = try! request.asURLRequest()
XCTAssertTrue((output.url?.absoluteString.contains("locale=fr_FR"))!)
}
}


Expand Down
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [**] You can now search customers when creating or editing an order. [https://github.com/woocommerce/woocommerce-ios/issues/7741]
- [internal] Store creation is available from the login prologue, login email error screen, and store picker. [https://github.com/woocommerce/woocommerce-ios/pull/8023]
- [internal] The login flow is simplified with only the option to log in with WordPress.com. This flow is presented in parallel with the existing flow in an A/B test experiment. [https://github.com/woocommerce/woocommerce-ios/pull/7996]
- [**] Relevant Just In Time Messages will be displayed on the My Store screen [https://github.com/woocommerce/woocommerce-ios/issues/7853]

11.0
-----
Expand Down
1 change: 1 addition & 0 deletions Storage/Storage.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.woo.Storage;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = ALPHA;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALID_ARCHS = "$(inherited)";
Expand Down
Loading