Skip to content

Commit

Permalink
Freemium PIR: Refactor Freemium PIR State to Remove Dependency on Acc…
Browse files Browse the repository at this point in the history
…ountManager (#3197)

Task/Issue URL:
https://app.asana.com/0/1201621853593513/1208197280287450/f
CC: @miasma13

**Description**: As an outcome of
[this](#3178 (comment))
discussion, I have refactored `FreemiumPIRUserStateManager` to remove
it’s dependency on `AccountManager`. This includes the removal of the
`isActiveUser` computed property.
  • Loading branch information
aataraxiaa committed Sep 10, 2024
1 parent 16428c6 commit b2a7f38
Show file tree
Hide file tree
Showing 16 changed files with 94 additions and 137 deletions.
4 changes: 2 additions & 2 deletions DuckDuckGo/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {

dataBrokerProtectionSubscriptionEventHandler.registerForSubscriptionAccountManagerEvents()

let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: subscriptionManager.accountManager)
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let pirGatekeeper = DefaultDataBrokerProtectionFeatureGatekeeper(accountManager:
subscriptionManager.accountManager,
freemiumPIRUserStateManager: freemiumPIRUserStateManager)
Expand Down Expand Up @@ -432,7 +432,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {

NetworkProtectionAppEvents(featureGatekeeper: DefaultVPNFeatureGatekeeper(subscriptionManager: subscriptionManager)).applicationDidBecomeActive()

let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: subscriptionManager.accountManager)
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let pirGatekeeper = DefaultDataBrokerProtectionFeatureGatekeeper(accountManager:
subscriptionManager.accountManager,
freemiumPIRUserStateManager: freemiumPIRUserStateManager)
Expand Down
7 changes: 3 additions & 4 deletions DuckDuckGo/DBP/DataBrokerProtectionFeatureGatekeeper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ struct DefaultDataBrokerProtectionFeatureGatekeeper: DataBrokerProtectionFeature
/// Checks PIR prerequisites
///
/// Prerequisites are satisified if either:
/// 1. The user is an active freemium user
/// 1. The user is an active freemium user (e.g has onboarded to freemium and is not authenticated)
/// 2. The user has a subscription with valid entitlements
///
/// - Returns: Bool indicating prerequisites are satisfied
func arePrerequisitesSatisfied() async -> Bool {

if freemiumPIRUserStateManager.isActiveUser { return true }
let isAuthenticated = accountManager.isUserAuthenticated
if !isAuthenticated && freemiumPIRUserStateManager.didOnboard { return true }

let entitlements = await accountManager.hasEntitlement(forProductName: .dataBrokerProtection,
cachePolicy: .reloadIgnoringLocalCacheData)
Expand All @@ -99,8 +100,6 @@ struct DefaultDataBrokerProtectionFeatureGatekeeper: DataBrokerProtectionFeature
hasEntitlements = false
}

let isAuthenticated = accountManager.accessToken != nil

firePrerequisitePixelsAndLogIfNecessary(hasEntitlements: hasEntitlements, isAuthenticatedResult: isAuthenticated)

return hasEntitlements && isAuthenticated
Expand Down
4 changes: 2 additions & 2 deletions DuckDuckGo/Freemium/FreemiumDebugMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ final class FreemiumDebugMenu: NSMenuItem {

@objc
func setFreemiumPIROnboardStateEnabled() {
DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: Application.appDelegate.subscriptionManager.accountManager).didOnboard = true
DefaultFreemiumPIRUserStateManager(userDefaults: .dbp).didOnboard = true
}

@objc
func setFreemiumPIROnboardStateDisabled() {
DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: Application.appDelegate.subscriptionManager.accountManager).didOnboard = false
DefaultFreemiumPIRUserStateManager(userDefaults: .dbp).didOnboard = false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ final class NavigationBarViewController: NSViewController {

@IBAction func optionsButtonAction(_ sender: NSButton) {
let internalUserDecider = NSApp.delegateTyped.internalUserDecider
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: subscriptionManager.accountManager)
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let freemiumPIRFeature = DefaultFreemiumPIRFeature(subscriptionManager: subscriptionManager, accountManager: subscriptionManager.accountManager)
let menu = MoreOptionsMenu(tabCollectionViewModel: tabCollectionViewModel,
passwordManagerCoordinator: PasswordManagerCoordinator.shared,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ final class RemoteMessagingConfigMatcherProvider: RemoteMessagingConfigMatcherPr

let deprecatedRemoteMessageStorage = DefaultSurveyRemoteMessagingStorage.surveys()

let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: subscriptionManager.accountManager)
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let isCurrentFreemiumPIRUser = !subscriptionManager.accountManager.isUserAuthenticated && freemiumPIRUserStateManager.didOnboard

return RemoteMessagingConfigMatcher(
appAttributeMatcher: AppAttributeMatcher(statisticsStore: statisticsStore,
Expand All @@ -164,7 +165,7 @@ final class RemoteMessagingConfigMatcherProvider: RemoteMessagingConfigMatcherPr
hasCustomHomePage: startupPreferencesPersistor().launchToCustomHomePage,
isDuckPlayerOnboarded: duckPlayerPreferencesPersistor.youtubeOverlayAnyButtonPressed,
isDuckPlayerEnabled: duckPlayerPreferencesPersistor.duckPlayerModeBool != false,
isCurrentFreemiumPIRUser: freemiumPIRUserStateManager.isActiveUser,
isCurrentFreemiumPIRUser: isCurrentFreemiumPIRUser,
dismissedDeprecatedMacRemoteMessageIds: deprecatedRemoteMessageStorage.dismissedMessageIDs()
),
percentileStore: RemoteMessagingPercentileUserDefaultsStore(keyValueStore: UserDefaults.standard),
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/Tab/View/BrowserTabViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ final class BrowserTabViewController: NSViewController {
return homePageViewController ?? {
let subscriptionManager = Application.appDelegate.subscriptionManager
let freemiumPIRFeature = DefaultFreemiumPIRFeature(subscriptionManager: subscriptionManager, accountManager: subscriptionManager.accountManager)
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: subscriptionManager.accountManager)
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let homePageViewController = HomePageViewController(tabCollectionViewModel: tabCollectionViewModel, bookmarkManager: bookmarkManager,
freemiumPIRFeature: freemiumPIRFeature,
freemiumPIRUserStateManager: freemiumPIRUserStateManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public class DataBrokerProtectionAgentManagerProvider {
emailService: emailService,
captchaService: captchaService)

let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp, accountManager: accountManager)
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)

let agentstopper = DefaultDataBrokerProtectionAgentStopper(dataManager: dataManager,
entitlementMonitor: DataBrokerProtectionEntitlementMonitor(),
Expand All @@ -102,6 +102,7 @@ public class DataBrokerProtectionAgentManagerProvider {
operationDependencies: operationDependencies,
pixelHandler: pixelHandler,
agentStopper: agentstopper,
authenticationManager: authenticationManager,
freemiumPIRUserStateManager: freemiumPIRUserStateManager)
}
}
Expand All @@ -116,6 +117,7 @@ public final class DataBrokerProtectionAgentManager {
private let operationDependencies: DataBrokerOperationDependencies
private let pixelHandler: EventMapping<DataBrokerProtectionPixels>
private let agentStopper: DataBrokerProtectionAgentStopper
private let authenticationManager: DataBrokerProtectionAuthenticationManaging
private let freemiumPIRUserStateManager: FreemiumPIRUserStateManager

// Used for debug functions only, so not injected
Expand All @@ -131,6 +133,7 @@ public final class DataBrokerProtectionAgentManager {
operationDependencies: DataBrokerOperationDependencies,
pixelHandler: EventMapping<DataBrokerProtectionPixels>,
agentStopper: DataBrokerProtectionAgentStopper,
authenticationManager: DataBrokerProtectionAuthenticationManaging,
freemiumPIRUserStateManager: FreemiumPIRUserStateManager
) {
self.userNotificationService = userNotificationService
Expand All @@ -141,6 +144,7 @@ public final class DataBrokerProtectionAgentManager {
self.operationDependencies = operationDependencies
self.pixelHandler = pixelHandler
self.agentStopper = agentStopper
self.authenticationManager = authenticationManager
self.freemiumPIRUserStateManager = freemiumPIRUserStateManager

self.activityScheduler.delegate = self
Expand Down Expand Up @@ -191,18 +195,18 @@ extension DataBrokerProtectionAgentManager {

private extension DataBrokerProtectionAgentManager {

/// Starts either Freemium (scan-only) or Subscription (scan and opt-out) scheduled operations
/// Starts either Subscription (scan and opt-out) or Freemium (scan-only) scheduled operations
/// - Parameters:
/// - showWebView: Whether to show the web view or not
/// - operationDependencies: Operation dependencies
/// - completion: Completion handler
func startFreemiumOrSubscriptionScheduledOperations(showWebView: Bool,
operationDependencies: DataBrokerOperationDependencies,
completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)?) {
if freemiumPIRUserStateManager.isActiveUser {
queueManager.startScheduledScanOperationsIfPermitted(showWebView: showWebView, operationDependencies: operationDependencies, completion: completion)
} else {
if authenticationManager.isUserAuthenticated {
queueManager.startScheduledAllOperationsIfPermitted(showWebView: showWebView, operationDependencies: operationDependencies, completion: completion)
} else {
queueManager.startScheduledScanOperationsIfPermitted(showWebView: showWebView, operationDependencies: operationDependencies, completion: completion)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,15 @@ struct DefaultDataBrokerProtectionAgentStopper: DataBrokerProtectionAgentStopper
do {
let hasProfile = try dataManager.fetchProfile() != nil
let isAuthenticated = authenticationManager.isUserAuthenticated
let isFreemium = freemiumPIRUserStateManager.isActiveUser
let didOnboardToFreemium = freemiumPIRUserStateManager.didOnboard

if !hasProfile || (!isAuthenticated && !isFreemium) {
if !hasProfile || (!isAuthenticated && !didOnboardToFreemium) {
Logger.dataBrokerProtection.debug("Prerequisites are invalid")
stopAgent()
return
}


if !isAuthenticated && isFreemium {
if satisfiesFreemiumPrerequisites() {
Logger.dataBrokerProtection.debug("User is Freemium")
return
}
Expand All @@ -88,11 +87,18 @@ struct DefaultDataBrokerProtectionAgentStopper: DataBrokerProtectionAgentStopper
public func monitorEntitlementAndStopAgentIfEntitlementIsInvalidAndUserIsNotFreemium(interval: TimeInterval) {
entitlementMonitor.start(checkEntitlementFunction: authenticationManager.hasValidEntitlement,
interval: interval) { result in
guard !self.freemiumPIRUserStateManager.isActiveUser else { return }

if satisfiesFreemiumPrerequisites() { return }
stopAgentBasedOnEntitlementCheckResult(result)
}
}

private func satisfiesFreemiumPrerequisites() -> Bool {
let isAuthenticated = authenticationManager.isUserAuthenticated
let didOnboardToFreemium = freemiumPIRUserStateManager.didOnboard
return !isAuthenticated && didOnboardToFreemium
}

private func stopAgent() {
stopAction.stopAgent()
}
Expand Down
Loading

0 comments on commit b2a7f38

Please sign in to comment.