Skip to content

Commit

Permalink
Update the Privacy Pro status attribute to use an array. (#878)
Browse files Browse the repository at this point in the history
Required:

Task/Issue URL: https://app.asana.com/0/1199333091098016/1207731341550989/f
iOS PR: duckduckgo/iOS#3033
macOS PR: duckduckgo/macos-browser#2940
What kind of version bump will this require?: Patch (technically the public API has not changed)

Description:

This PR updates the Privacy Pro status attribute to match an array instead of a string.
  • Loading branch information
samsymons authored Jul 4, 2024
1 parent a9a41a0 commit 6834243
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 23 deletions.
18 changes: 9 additions & 9 deletions Sources/RemoteMessaging/Matchers/UserAttributeMatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,19 +160,19 @@ public struct UserAttributeMatcher: AttributeMatcher {
case let matchingAttribute as PrivacyProPurchasePlatformMatchingAttribute:
return StringArrayMatchingAttribute(matchingAttribute.value).matches(value: privacyProPurchasePlatform ?? "")
case let matchingAttribute as PrivacyProSubscriptionStatusMatchingAttribute:
guard let value = matchingAttribute.value else {
return .fail
let mappedStatuses = matchingAttribute.value.compactMap { status in
return PrivacyProSubscriptionStatus(rawValue: status)
}

guard let status = PrivacyProSubscriptionStatus(rawValue: value) else {
return .fail
for status in mappedStatuses {
switch status {
case .active: if isPrivacyProSubscriptionActive { return .match }
case .expiring: if isPrivacyProSubscriptionExpiring { return .match }
case .expired: if isPrivacyProSubscriptionExpired { return .match }
}
}

switch status {
case .active: return isPrivacyProSubscriptionActive ? .match : .fail
case .expiring: return isPrivacyProSubscriptionExpiring ? .match : .fail
case .expired: return isPrivacyProSubscriptionExpired ? .match : .fail
}
return .fail
case let matchingAttribute as InteractedWithMessageMatchingAttribute:
if dismissedMessageIds.contains(where: { messageId in
StringArrayMatchingAttribute(matchingAttribute.value).matches(value: messageId) == .match
Expand Down
11 changes: 6 additions & 5 deletions Sources/RemoteMessaging/Model/MatchingAttributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -799,21 +799,22 @@ struct PrivacyProPurchasePlatformMatchingAttribute: MatchingAttribute, Equatable
}

struct PrivacyProSubscriptionStatusMatchingAttribute: MatchingAttribute, Equatable {
var value: String?
var value: [String] = []
var fallback: Bool?

init(jsonMatchingAttribute: AnyDecodable) {
guard let jsonMatchingAttribute = jsonMatchingAttribute.value as? [String: Any] else { return }

if let value = jsonMatchingAttribute[RuleAttributes.value] as? String {
guard let jsonMatchingAttribute = jsonMatchingAttribute.value as? [String: Any] else {
return
}
if let value = jsonMatchingAttribute[RuleAttributes.value] as? [String] {
self.value = value
}
if let fallback = jsonMatchingAttribute[RuleAttributes.fallback] as? Bool {
self.fallback = fallback
}
}

init(value: String?, fallback: Bool?) {
init(value: [String], fallback: Bool?) {
self.value = value
self.fallback = fallback
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class JsonToRemoteConfigModelMapperTests: XCTestCase {

attribs = rule8?.attributes.filter { $0 is PrivacyProSubscriptionStatusMatchingAttribute }
XCTAssertEqual(attribs?.first as? PrivacyProSubscriptionStatusMatchingAttribute, PrivacyProSubscriptionStatusMatchingAttribute(
value: "active", fallback: nil
value: ["active", "expiring"], fallback: nil
))

let rule9 = config.rules.filter { $0.id == 9 }.first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,35 +250,47 @@ class UserAttributeMatcherTests: XCTestCase {

func testWhenPrivacyProSubscriptionStatusMatchesThenReturnMatch() throws {
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: PrivacyProSubscriptionStatusMatchingAttribute(value: "active", fallback: nil)
matchingAttribute: PrivacyProSubscriptionStatusMatchingAttribute(value: ["active"], fallback: nil)
), .match)
}

func testWhenPrivacyProSubscriptionStatusHasMultipleAttributesAndOneMatchesThenReturnMatch() throws {
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: PrivacyProSubscriptionStatusMatchingAttribute(value: ["active", "expiring", "expired"], fallback: nil)
), .match)
}

func testWhenPrivacyProSubscriptionStatusDoesNotMatchThenReturnFail() throws {
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: PrivacyProSubscriptionStatusMatchingAttribute(value: "expiring", fallback: nil)
matchingAttribute: PrivacyProSubscriptionStatusMatchingAttribute(value: ["expiring"], fallback: nil)
), .fail)
}

func testWhenPrivacyProSubscriptionStatusHasUnsupportedStatusThenReturnFail() throws {
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: PrivacyProSubscriptionStatusMatchingAttribute(value: "unsupported_status", fallback: nil)
matchingAttribute: PrivacyProSubscriptionStatusMatchingAttribute(value: ["unsupported_status"], fallback: nil)
), .fail)
}

func testWhenOneDismissedMessageIdMatchesThenReturnMatch() throws {
setUpUserAttributeMatcher(dismissedMessageIds: ["1"])
XCTAssertEqual(userAttributeMatcher.evaluate(matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["1", "2", "3"], fallback: nil)), .match)
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["1", "2", "3"], fallback: nil)
), .match)
}

func testWhenAllDismissedMessageIdsMatchThenReturnMatch() throws {
setUpUserAttributeMatcher(dismissedMessageIds: ["1", "2", "3"])
XCTAssertEqual(userAttributeMatcher.evaluate(matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["1", "2", "3"], fallback: nil)), .match)
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["1", "2", "3"], fallback: nil)
), .match)
}

func testWhenNoDismissedMessageIdsMatchThenReturnFail() throws {
setUpUserAttributeMatcher(dismissedMessageIds: ["1", "2", "3"])
XCTAssertEqual(userAttributeMatcher.evaluate(matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["4", "5"], fallback: nil)), .fail)
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["4", "5"], fallback: nil)
), .fail)
}

func testWhenHaveDismissedMessageIdsAndMatchAttributeIsEmptyThenReturnFail() throws {
Expand All @@ -288,7 +300,9 @@ class UserAttributeMatcherTests: XCTestCase {

func testWhenHaveNoDismissedMessageIdsAndMatchAttributeIsNotEmptyThenReturnFail() throws {
setUpUserAttributeMatcher(dismissedMessageIds: [])
XCTAssertEqual(userAttributeMatcher.evaluate(matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["1", "2"], fallback: nil)), .fail)
XCTAssertEqual(userAttributeMatcher.evaluate(
matchingAttribute: InteractedWithMessageMatchingAttribute(value: ["1", "2"], fallback: nil)
), .fail)
}

private func setUpUserAttributeMatcher(dismissedMessageIds: [String] = []) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@
"value": ["apple", "stripe"]
},
"pproSubscriptionStatus": {
"value": "active"
"value": ["active", "expiring"]
},
"pproDaysSinceSubscribed": {
"min": 5,
Expand Down

0 comments on commit 6834243

Please sign in to comment.