Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add survey action and Privacy Pro attributes #2879

Merged
merged 9 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
12 changes: 6 additions & 6 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
4B6484F327FD1E350050A7A1 /* MenuControllerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6484E927FD1E340050A7A1 /* MenuControllerView.swift */; };
4B6ED9452B992FE4007F5CAA /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B6ED9442B992FE4007F5CAA /* vpn-dark-mode.json */; };
4B75EA9226A266CB00018634 /* PrintingUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B75EA9126A266CB00018634 /* PrintingUserScript.swift */; };
4B78074E2B183A1F009DB2CF /* SurveyURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B78074D2B183A1F009DB2CF /* SurveyURLBuilder.swift */; };
4B78074E2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B78074D2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift */; };
4B948E2629DCCDB9002531FA /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 4B948E2529DCCDB9002531FA /* Persistence */; };
4BB697A42B1D99C4003699B5 /* VPNWaitlistActivationDateStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B78074B2B1823C5009DB2CF /* VPNWaitlistActivationDateStore.swift */; };
4BB697A52B1D99C5003699B5 /* VPNWaitlistActivationDateStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B78074B2B1823C5009DB2CF /* VPNWaitlistActivationDateStore.swift */; };
Expand Down Expand Up @@ -1304,7 +1304,7 @@
4B6ED9442B992FE4007F5CAA /* vpn-dark-mode.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "vpn-dark-mode.json"; sourceTree = "<group>"; };
4B75EA9126A266CB00018634 /* PrintingUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrintingUserScript.swift; sourceTree = "<group>"; };
4B78074B2B1823C5009DB2CF /* VPNWaitlistActivationDateStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNWaitlistActivationDateStore.swift; sourceTree = "<group>"; };
4B78074D2B183A1F009DB2CF /* SurveyURLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyURLBuilder.swift; sourceTree = "<group>"; };
4B78074D2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteMessagingSurveyURLBuilder.swift; sourceTree = "<group>"; };
4BB7CBAF2AF59C310014A35F /* VPNWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNWidget.swift; sourceTree = "<group>"; };
4BBBBA892B031B4200D965DA /* VPNWaitlistDebugViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNWaitlistDebugViewController.swift; sourceTree = "<group>"; };
4BBBBA8A2B031B4200D965DA /* VPNWaitlistViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNWaitlistViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3326,7 +3326,6 @@
4BBBBA8A2B031B4200D965DA /* VPNWaitlistViewController.swift */,
4BCD146A2B05C4B5000B1E4C /* VPNWaitlistTermsAndConditionsViewController.swift */,
4B78074B2B1823C5009DB2CF /* VPNWaitlistActivationDateStore.swift */,
4B78074D2B183A1F009DB2CF /* SurveyURLBuilder.swift */,
BDFF031F2BA3D3AD00F324C9 /* Feature Visibility */,
);
name = VPN;
Expand Down Expand Up @@ -4319,6 +4318,7 @@
C1B7B52028941F2A0098FD6A /* RemoteMessageRequest.swift */,
C1B7B52128941F2A0098FD6A /* RemoteMessaging.swift */,
C1B7B51F28941F2A0098FD6A /* RemoteMessagingStore.swift */,
4B78074D2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift */,
);
name = RemoteMessaging;
sourceTree = "<group>";
Expand Down Expand Up @@ -6451,7 +6451,7 @@
F1386BA41E6846C40062FC3C /* TabDelegate.swift in Sources */,
37CF91602BB4737300BADCAE /* CrashCollectionOnboarding.swift in Sources */,
C1B924B72ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift in Sources */,
4B78074E2B183A1F009DB2CF /* SurveyURLBuilder.swift in Sources */,
4B78074E2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift in Sources */,
3132FA2A27A0788F00DD7A12 /* QuickLookPreviewHelper.swift in Sources */,
D670E5BB2BB6A75300941A42 /* SubscriptionNavigationCoordinator.swift in Sources */,
C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */,
Expand Down Expand Up @@ -9853,8 +9853,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 145.3.2;
branch = "sam/rmf-survey-updates";
kind = branch;
};
};
9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/DuckDuckGo/BrowserServicesKit",
"state" : {
"revision" : "1c692ce52ffd74edd1d1180e038a14a0cf1dd736",
"version" : "145.3.2"
"branch" : "sam/rmf-survey-updates",
"revision" : "0bb46a5c37b5741ed1eb8a806fb498755cad92bc"
}
},
{
Expand Down Expand Up @@ -185,8 +185,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/TrackerRadarKit.git",
"state" : {
"revision" : "6c84fd19139414fc0edbf9673ade06e532a564f0",
"version" : "2.0.0"
"revision" : "c01e6a59d000356b58ec77053e0a99d538be56a5",
"version" : "2.1.1"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/AutofillLoginSettingsListViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ final class AutofillLoginSettingsListViewController: UIViewController {
let messageView = PasswordsSurveyView(surveyButtonAction: { [weak self] in
let survey = "https://selfserve.decipherinc.com/survey/selfserve/32ab/240409"
if let surveyURL = URL(string: survey) {
let surveyURLBuilder = DefaultSurveyURLBuilder()
let surveyURLBuilder = DefaultRemoteMessagingSurveyURLBuilder()
let surveyURLWithParameters = surveyURLBuilder.addPasswordsCountSurveyParameter(to: surveyURL)
LaunchTabNotification.postLaunchTabNotification(urlString: surveyURLWithParameters.absoluteString)
} else {
Expand Down
13 changes: 1 addition & 12 deletions DuckDuckGo/HomeMessageViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,9 @@ struct HomeMessageViewModel {
LaunchTabNotification.postLaunchTabNotification(urlString: value)
onDidClose(buttonAction)
}
case .surveyURL(let value):
case .survey(let value):
return {
#if NETWORK_PROTECTION
if let surveyURL = URL(string: value) {
let surveyURLBuilder = DefaultSurveyURLBuilder()
let surveyURLWithParameters = surveyURLBuilder.addSurveyParameters(to: surveyURL)
LaunchTabNotification.postLaunchTabNotification(urlString: surveyURLWithParameters.absoluteString)
} else {
LaunchTabNotification.postLaunchTabNotification(urlString: value)
}
#else
LaunchTabNotification.postLaunchTabNotification(urlString: value)
#endif

onDidClose(buttonAction)
}
case .appStore:
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/HomeMessageViewModelBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ extension RemoteAction {
case .share(let value, let title):
return .share(value: value, title: title)

case .appStore, .url, .surveyURL:
case .appStore, .url, .survey:
if isSecondaryAction {
return .cancel
}
Expand Down
23 changes: 7 additions & 16 deletions DuckDuckGo/RemoteMessaging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Persistence
import Bookmarks
import RemoteMessaging
import NetworkProtection
import Subscription

struct RemoteMessaging {

Expand Down Expand Up @@ -153,21 +154,9 @@ struct RemoteMessaging {
case .success(let statusResponse):
os_log("Successfully fetched remote messages", log: .remoteMessaging, type: .debug)

let isNetworkProtectionWaitlistUser: Bool
let daysSinceNetworkProtectionEnabled: Int

#if NETWORK_PROTECTION
let vpnAccess = NetworkProtectionAccessController()
let accessType = vpnAccess.networkProtectionAccessType()
let isVPNActivated = NetworkProtectionKeychainTokenStore().isFeatureActivated
let activationDateStore = DefaultVPNWaitlistActivationDateStore()

isNetworkProtectionWaitlistUser = (accessType == .waitlistInvited) && isVPNActivated
daysSinceNetworkProtectionEnabled = activationDateStore.daysSinceActivation() ?? -1
#else
isNetworkProtectionWaitlistUser = false
daysSinceNetworkProtectionEnabled = -1
#endif
let daysSinceNetworkProtectionEnabled = activationDateStore.daysSinceActivation() ?? -1
let surveyActionMapper = DefaultRemoteMessagingSurveyURLBuilder(statisticsStore: statisticsStore)

let remoteMessagingConfigMatcher = RemoteMessagingConfigMatcher(
appAttributeMatcher: AppAttributeMatcher(statisticsStore: statisticsStore,
Expand All @@ -179,9 +168,11 @@ struct RemoteMessaging {
favoritesCount: favoritesCount,
appTheme: AppUserDefaults().currentThemeName.rawValue,
isWidgetInstalled: isWidgetInstalled,
isNetPWaitlistUser: isNetworkProtectionWaitlistUser,
daysSinceNetPEnabled: daysSinceNetworkProtectionEnabled),
daysSinceNetPEnabled: daysSinceNetworkProtectionEnabled,
isPrivacyProEligibleUser: SubscriptionPurchaseEnvironment.canPurchase,
isPrivacyProSubscriber: AccountManager().isUserAuthenticated),
percentileStore: RemoteMessagingPercentileUserDefaultsStore(userDefaults: .standard),
surveyActionMapper: surveyActionMapper,
dismissedMessageIds: remoteMessagingStore.fetchDismissedRemoteMessageIds()
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// SurveyURLBuilder.swift
// RemoteMessagingSurveyURLBuilder.swift
// DuckDuckGo
//
// Copyright © 2023 DuckDuckGo. All rights reserved.
Expand All @@ -17,18 +17,13 @@
// limitations under the License.
//

#if NETWORK_PROTECTION

import Foundation
import BrowserServicesKit
import RemoteMessaging
import Core
import Common

protocol SurveyURLBuilder {
func addSurveyParameters(to url: URL) -> URL
}

struct DefaultSurveyURLBuilder: SurveyURLBuilder {
struct DefaultRemoteMessagingSurveyURLBuilder: RemoteMessagingSurveyActionMapping {

enum SurveyURLParameters: String, CaseIterable {
samsymons marked this conversation as resolved.
Show resolved Hide resolved
case atb = "atb"
Expand All @@ -50,15 +45,15 @@ struct DefaultSurveyURLBuilder: SurveyURLBuilder {
}

// swiftlint:disable:next cyclomatic_complexity
func addSurveyParameters(to surveyURL: URL) -> URL {
func add(parameters: [RemoteMessagingSurveyActionParameter], to surveyURL: URL) -> URL {
guard var components = URLComponents(string: surveyURL.absoluteString) else {
assertionFailure("Could not build URL components from survey URL")
return surveyURL
}

var queryItems = components.queryItems ?? []

for parameter in SurveyURLParameters.allCases {
for parameter in parameters {
switch parameter {
case .atb:
if let atb = statisticsStore.atb {
Expand All @@ -68,11 +63,7 @@ struct DefaultSurveyURLBuilder: SurveyURLBuilder {
if let variant = statisticsStore.variant {
queryItems.append(URLQueryItem(name: parameter.rawValue, value: variant))
}
case .daysSinceActivated:
if let daysSinceActivated = activationDateStore.daysSinceActivation() {
queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: daysSinceActivated)))
}
case .iosVersion:
case .osVersion:
queryItems.append(URLQueryItem(name: parameter.rawValue, value: AppVersion.shared.osVersion))
case .appVersion:
queryItems.append(URLQueryItem(name: parameter.rawValue, value: AppVersion.shared.versionAndBuildNumber))
Expand All @@ -83,6 +74,8 @@ struct DefaultSurveyURLBuilder: SurveyURLBuilder {
if let daysSinceLastActive = activationDateStore.daysSinceLastActive() {
queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: daysSinceLastActive)))
}
case .daysInstalled:
break // TODO
samsymons marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -92,7 +85,7 @@ struct DefaultSurveyURLBuilder: SurveyURLBuilder {
}

func addPasswordsCountSurveyParameter(to surveyURL: URL) -> URL {
let surveyURLWithParameters = addSurveyParameters(to: surveyURL)
let surveyURLWithParameters = add(parameters: RemoteMessagingSurveyActionParameter.allCases, to: surveyURL)

guard var components = URLComponents(string: surveyURLWithParameters.absoluteString), let bucket = passwordsCountBucket() else {
return surveyURLWithParameters
Expand Down Expand Up @@ -129,5 +122,3 @@ struct DefaultSurveyURLBuilder: SurveyURLBuilder {
}

}

#endif
14 changes: 12 additions & 2 deletions DuckDuckGoTests/RemoteMessagingStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,11 @@ class RemoteMessagingStoreTests: XCTestCase {
favoritesCount: 0,
appTheme: "light",
isWidgetInstalled: false,
isNetPWaitlistUser: false,
daysSinceNetPEnabled: -1),
daysSinceNetPEnabled: -1,
isPrivacyProEligibleUser: false,
isPrivacyProSubscriber: false),
percentileStore: RemoteMessagingPercentileUserDefaultsStore(userDefaults: self.defaults),
surveyActionMapper: MockRemoteMessagingSurveyActionMapper(),
dismissedMessageIds: []
)

Expand All @@ -160,3 +162,11 @@ class RemoteMessagingStoreTests: XCTestCase {
}
}
}

private final class MockRemoteMessagingSurveyActionMapper: RemoteMessagingSurveyActionMapping {

func add(parameters: [RemoteMessagingSurveyActionParameter], to url: URL) -> URL {
return url
}

}
Loading