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

Freemium PIR: Rename all PIR references to DBP #3249

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
98 changes: 48 additions & 50 deletions DuckDuckGo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions DuckDuckGo/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
public let subscriptionUIHandler: SubscriptionUIHandling

// MARK: - Freemium DBP
private var freemiumPIRScanResultPolling: FreemiumPIRScanResultPolling?
private var freemiumDBPScanResultPolling: FreemiumDBPScanResultPolling?

// MARK: - VPN

Expand Down Expand Up @@ -383,10 +383,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate {

dataBrokerProtectionSubscriptionEventHandler.registerForSubscriptionAccountManagerEvents()

let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let freemiumDBPUserStateManager = DefaultFreemiumDBPUserStateManager(userDefaults: .dbp)
let pirGatekeeper = DefaultDataBrokerProtectionFeatureGatekeeper(accountManager:
subscriptionManager.accountManager,
freemiumPIRUserStateManager: freemiumPIRUserStateManager)
freemiumDBPUserStateManager: freemiumDBPUserStateManager)

DataBrokerProtectionAppEvents(featureGatekeeper: pirGatekeeper).applicationDidFinishLaunching()

Expand All @@ -411,8 +411,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
didCrashDuringCrashHandlersSetUp = false
}

freemiumPIRScanResultPolling = DefaultFreemiumPIRScanResultPolling(dataManager: DataBrokerProtectionManager.shared.dataManager, freemiumPIRUserStateManager: freemiumPIRUserStateManager)
freemiumPIRScanResultPolling?.startPollingOrObserving()
freemiumDBPScanResultPolling = DefaultFreemiumDBPScanResultPolling(dataManager: DataBrokerProtectionManager.shared.dataManager, freemiumDBPUserStateManager: freemiumDBPUserStateManager)
freemiumDBPScanResultPolling?.startPollingOrObserving()
}

private func fireFailedCompilationsPixelIfNeeded() {
Expand All @@ -438,10 +438,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate {

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

let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let freemiumDBPUserStateManager = DefaultFreemiumDBPUserStateManager(userDefaults: .dbp)
let pirGatekeeper = DefaultDataBrokerProtectionFeatureGatekeeper(accountManager:
subscriptionManager.accountManager,
freemiumPIRUserStateManager: freemiumPIRUserStateManager)
freemiumDBPUserStateManager: freemiumDBPUserStateManager)

DataBrokerProtectionAppEvents(featureGatekeeper: pirGatekeeper).applicationDidBecomeActive()

Expand Down
58 changes: 29 additions & 29 deletions DuckDuckGo/Common/Localizables/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1298,55 +1298,55 @@ struct UserText {
// Comment: "Progress view title when completing the purchase"
static let completingPurchaseTitle = "Completing purchase..."

// Key: "freemium.pir.menu.item"
// Key: "freemium.dbp.menu.item"
// Comment: "Title for Freemium Personal Information Removal (Scan-Only) item in the options menu"
static let freemiumPIROptionsMenuItem = "Personal Information Scan"
static let freemiumDBPOptionsMenuItem = "Personal Information Scan"

// Key: "home.page.promotion.freemium.pir.subtitle"
// Comment: "Subtitle for the Freemium PIR Home Page Promotion"
static let homePagePromotionFreemiumPIRSubtitle = "Find your personal info on sites that sell it."
// Key: "home.page.promotion.freemium.dbp.subtitle"
// Comment: "Subtitle for the Freemium DBP Home Page Promotion"
static let homePagePromotionFreemiumDBPSubtitle = "Find your personal info on sites that sell it."

// Key: "home.page.promotion.freemium.pir.button.title"
// Comment: "Title for the Freemium PIR Home Page Promotion Button"
static let homePagePromotionFreemiumPIRButtonTitle = "Free Scan"
// Key: "home.page.promotion.freemium.dbp.button.title"
// Comment: "Title for the Freemium DBP Home Page Promotion Button"
static let homePagePromotionFreemiumDBPButtonTitle = "Free Scan"

// Key: "home.page.promotion.freemium.pir.post.scan.engagement.results.title"
// Comment: "Title for the Freemium PIR Home Page Post Scan Engagement Promotion When There Are Results"
static let homePagePromotionFreemiumPIRPostScanEngagementResultsTitle = "We found your personal info"
// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.results.title"
// Comment: "Title for the Freemium DBP Home Page Post Scan Engagement Promotion When There Are Results"
static let homePagePromotionFreemiumDBPPostScanEngagementResultsTitle = "We found your personal info"

// Key: "home.page.promotion.freemium.pir.post.scan.engagement.result.single.match.subtitle"
// Comment: "Subtitle for the Freemium PIR Home Page Post Scan Engagement Promotion When Only One Record is Found"
static let homePagePromotionFreemiumPIRPostScanEngagementResultSingleMatchSubtitle = "1 record has been found on 1 site"
// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.single.match.subtitle"
// Comment: "Subtitle for the Freemium DBP Home Page Post Scan Engagement Promotion When Only One Record is Found"
static let homePagePromotionFreemiumDBPPostScanEngagementResultSingleMatchSubtitle = "1 record has been found on 1 site"

/// Generates a subtitle for the Freemium PIR Home Page Post Scan Engagement Promotion when records are found on a single broker site.
/// Key: "home.page.promotion.freemium.pir.post.scan.engagement.result.single.broker.subtitle"
/// Generates a subtitle for the Freemium DBP Home Page Post Scan Engagement Promotion when records are found on a single broker site.
/// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.single.broker.subtitle"
///
/// - Parameter resultCount: The number of records found.
/// - Returns: A formatted string indicating the number of records found on 1 site.
static func homePagePromotionFreemiumPIRPostScanEngagementResultSingleBrokerSubtitle(resultCount: Int) -> String {
static func homePagePromotionFreemiumDBPPostScanEngagementResultSingleBrokerSubtitle(resultCount: Int) -> String {
String(format: "%d records have been found on 1 site", resultCount)
}

/// Generates a subtitle for the Freemium PIR Home Page Post Scan Engagement Promotion when records are found on multiple broker sites.
/// Key: "home.page.promotion.freemium.pir.post.scan.engagement.result.plural.subtitle"
/// Generates a subtitle for the Freemium DBP Home Page Post Scan Engagement Promotion when records are found on multiple broker sites.
/// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.plural.subtitle"
///
/// - Parameters:
/// - resultCount: The number of records found.
/// - brokerCount: The number of broker sites where records were found.
/// - Returns: A formatted string indicating the number of records found on multiple sites.
static func homePagePromotionFreemiumPIRPostScanEngagementResultPluralSubtitle(resultCount: Int, brokerCount: Int) -> String {
static func homePagePromotionFreemiumDBPPostScanEngagementResultPluralSubtitle(resultCount: Int, brokerCount: Int) -> String {
String(format: "%d records have been found on %d sites", resultCount, brokerCount)
}

// Key: "home.page.promotion.freemium.pir.post.scan.engagement.no.results.title"
// Comment: "Title for the Freemium PIR Home Page Post Scan Engagement Promotion When There Are No Results"
static let homePagePromotionFreemiumPIRPostScanEngagementNoResultsTitle = "Good news, we didn't find your info"
// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.no.results.title"
// Comment: "Title for the Freemium DBP Home Page Post Scan Engagement Promotion When There Are No Results"
static let homePagePromotionFreemiumDBPPostScanEngagementNoResultsTitle = "Good news, we didn't find your info"

// Key: "home.page.promotion.freemium.pir.post.scan.engagement.no.results.subtitle"
// Comment: "Subtitle for the Freemium PIR Home Page Post Scan Engagement Promotion When There Are No Results"
static let homePagePromotionFreemiumPIRPostScanEngagementNoResultsSubtitle = "We’ll keep checking and let you know if we find something"
// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.no.results.subtitle"
// Comment: "Subtitle for the Freemium DBP Home Page Post Scan Engagement Promotion When There Are No Results"
static let homePagePromotionFreemiumDBPPostScanEngagementNoResultsSubtitle = "We’ll keep checking and let you know if we find something"

// Key: "home.page.promotion.freemium.pir.post.scan.engagement.button.title"
// Comment: "Title for the Freemium PIR Home Page Post Scan Engagement Promotion Button"
static let homePagePromotionFreemiumPIRPostScanEngagementButtonTitle = "View Details"
// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.button.title"
// Comment: "Title for the Freemium DBP Home Page Post Scan Engagement Promotion Button"
static let homePagePromotionFreemiumDBPPostScanEngagementButtonTitle = "View Details"
}
8 changes: 4 additions & 4 deletions DuckDuckGo/DBP/DBPHomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class DBPHomeViewController: NSViewController {
private let pixelHandler: EventMapping<DataBrokerProtectionPixels> = DataBrokerProtectionPixelsHandler()
private var currentChildViewController: NSViewController?
private var observer: NSObjectProtocol?
private var freemiumPIRFeature: FreemiumPIRFeature
private var freemiumDBPFeature: FreemiumDBPFeature

private let prerequisiteVerifier: DataBrokerPrerequisitesStatusVerifier
private lazy var errorViewController: DataBrokerProtectionErrorViewController = {
Expand Down Expand Up @@ -73,10 +73,10 @@ final class DBPHomeViewController: NSViewController {

init(dataBrokerProtectionManager: DataBrokerProtectionManager,
prerequisiteVerifier: DataBrokerPrerequisitesStatusVerifier = DefaultDataBrokerPrerequisitesStatusVerifier(),
freemiumPIRFeature: FreemiumPIRFeature) {
freemiumDBPFeature: FreemiumDBPFeature) {
self.dataBrokerProtectionManager = dataBrokerProtectionManager
self.prerequisiteVerifier = prerequisiteVerifier
self.freemiumPIRFeature = freemiumPIRFeature
self.freemiumDBPFeature = freemiumDBPFeature
super.init(nibName: nil, bundle: nil)
}

Expand All @@ -98,7 +98,7 @@ final class DBPHomeViewController: NSViewController {
override func viewDidAppear() {
super.viewDidAppear()

if !dataBrokerProtectionManager.isUserAuthenticated() && !freemiumPIRFeature.isAvailable {
if !dataBrokerProtectionManager.isUserAuthenticated() && !freemiumDBPFeature.isAvailable {
assertionFailure("This UI should never be presented if the user is not authenticated")
closeUI()
}
Expand Down
10 changes: 5 additions & 5 deletions DuckDuckGo/DBP/DataBrokerProtectionFeatureGatekeeper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ struct DefaultDataBrokerProtectionFeatureGatekeeper: DataBrokerProtectionFeature
private let userDefaults: UserDefaults
private let subscriptionAvailability: SubscriptionFeatureAvailability
private let accountManager: AccountManager
private let freemiumPIRUserStateManager: FreemiumPIRUserStateManager
private let freemiumDBPUserStateManager: FreemiumDBPUserStateManager

init(privacyConfigurationManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager,
featureDisabler: DataBrokerProtectionFeatureDisabling = DataBrokerProtectionFeatureDisabler(),
pixelHandler: EventMapping<DataBrokerProtectionPixels> = DataBrokerProtectionPixelsHandler(),
userDefaults: UserDefaults = .standard,
subscriptionAvailability: SubscriptionFeatureAvailability = DefaultSubscriptionFeatureAvailability(),
accountManager: AccountManager,
freemiumPIRUserStateManager: FreemiumPIRUserStateManager) {
freemiumDBPUserStateManager: FreemiumDBPUserStateManager) {
self.privacyConfigurationManager = privacyConfigurationManager
self.featureDisabler = featureDisabler
self.pixelHandler = pixelHandler
self.userDefaults = userDefaults
self.subscriptionAvailability = subscriptionAvailability
self.accountManager = accountManager
self.freemiumPIRUserStateManager = freemiumPIRUserStateManager
self.freemiumDBPUserStateManager = freemiumDBPUserStateManager
}

var isUserLocaleAllowed: Bool {
Expand All @@ -78,7 +78,7 @@ struct DefaultDataBrokerProtectionFeatureGatekeeper: DataBrokerProtectionFeature
Logger.dataBrokerProtection.debug("Disabling and removing DBP for all users")
}

/// Checks PIR prerequisites
/// Checks DBP prerequisites
///
/// Prerequisites are satisified if either:
/// 1. The user is an active freemium user (e.g has onboarded to freemium and is not authenticated)
Expand All @@ -88,7 +88,7 @@ struct DefaultDataBrokerProtectionFeatureGatekeeper: DataBrokerProtectionFeature
func arePrerequisitesSatisfied() async -> Bool {

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

let entitlements = await accountManager.hasEntitlement(forProductName: .dataBrokerProtection,
cachePolicy: .reloadIgnoringLocalCacheData)
Expand Down
4 changes: 2 additions & 2 deletions DuckDuckGo/DBP/DataBrokerProtectionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public final class DataBrokerProtectionManager {
private let fakeBrokerFlag: DataBrokerDebugFlag = DataBrokerDebugFlagFakeBroker()

private lazy var freemiumDBPFirstProfileSavedNotifier: FreemiumDBPFirstProfileSavedNotifier = {
let freemiumPIRUserStateManager = DefaultFreemiumPIRUserStateManager(userDefaults: .dbp)
let freemiumDBPUserStateManager = DefaultFreemiumDBPUserStateManager(userDefaults: .dbp)
let accountManager = Application.appDelegate.subscriptionManager.accountManager
let freemiumDBPFirstProfileSavedNotifier = FreemiumDBPFirstProfileSavedNotifier(freemiumPIRUserStateManager: freemiumPIRUserStateManager,
let freemiumDBPFirstProfileSavedNotifier = FreemiumDBPFirstProfileSavedNotifier(freemiumDBPUserStateManager: freemiumDBPUserStateManager,
accountManager: accountManager)
return freemiumDBPFirstProfileSavedNotifier
}()
Expand Down
4 changes: 2 additions & 2 deletions DuckDuckGo/FeatureFlagging/Model/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public enum FeatureFlag: String {
case deduplicateLoginsOnImport

// https://app.asana.com/0/1206488453854252/1207136666798700/f
case freemiumPIR
case freemiumDBP

case highlightsOnboarding

Expand All @@ -54,7 +54,7 @@ extension FeatureFlag: FeatureFlagSourceProviding {
return .remoteReleasable(.subfeature(AutofillSubfeature.deduplicateLoginsOnImport))
case .unknownUsernameCategorization:
return .remoteReleasable(.subfeature(AutofillSubfeature.unknownUsernameCategorization))
case .freemiumPIR:
case .freemiumDBP:
return .remoteDevelopment(.subfeature(DBPSubfeature.freemium))
case .phishingDetectionErrorPage:
return .remoteReleasable(.subfeature(PhishingDetectionSubfeature.allowErrorPage))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// FreemiumPIRFeature.swift
// FreemiumDBPFeature.swift
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
Expand All @@ -21,49 +21,49 @@
import Subscription
import Freemium

/// Conforming types encapsulate logic relating to the Freemium PIR Feature (e.g Feature Availability etc.)
protocol FreemiumPIRFeature {
/// Conforming types encapsulate logic relating to the Freemium DBP Feature (e.g Feature Availability etc.)
protocol FreemiumDBPFeature {
var isAvailable: Bool { get }
}

/// Default implementation of `FreemiumPIRFeature`
final class DefaultFreemiumPIRFeature: FreemiumPIRFeature {
/// Default implementation of `FreemiumDBPFeature`
final class DefaultFreemiumDBPFeature: FreemiumDBPFeature {

private let featureFlagger: FeatureFlagger
private let subscriptionManager: SubscriptionManager
private let accountManager: AccountManager
private var freemiumPIRUserStateManager: FreemiumPIRUserStateManager
private var freemiumDBPUserStateManager: FreemiumDBPUserStateManager
private let featureDisabler: DataBrokerProtectionFeatureDisabling

var isAvailable: Bool {
/* Freemium PIR availability criteria:
/* Freemium DBP availability criteria:
1. Feature Flag enabled
2. Privacy Pro Available
3. Not a current Privacy Pro subscriber
4. (Temp) In experiment cohort
*/
featureFlagger.isFeatureOn(.freemiumPIR) // #1
featureFlagger.isFeatureOn(.freemiumDBP) // #1
&& isPotentialPrivacyProSubscriber // #2 & #3
// TODO: - Also check experiment cohort here

Check failure on line 47 in DuckDuckGo/Freemium/DBP/FreemiumDBPFeature.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

TODOs should be resolved (- Also check experiment cohort...) (todo)
}

init(featureFlagger: FeatureFlagger = NSApp.delegateTyped.featureFlagger,
subscriptionManager: SubscriptionManager,
accountManager: AccountManager,
freemiumPIRUserStateManager: FreemiumPIRUserStateManager,
freemiumDBPUserStateManager: FreemiumDBPUserStateManager,
featureDisabler: DataBrokerProtectionFeatureDisabling = DataBrokerProtectionFeatureDisabler()) {

self.featureFlagger = featureFlagger
self.subscriptionManager = subscriptionManager
self.accountManager = accountManager
self.freemiumPIRUserStateManager = freemiumPIRUserStateManager
self.freemiumDBPUserStateManager = freemiumDBPUserStateManager
self.featureDisabler = featureDisabler

offBoardIfNecessary()
}
}

private extension DefaultFreemiumPIRFeature {
private extension DefaultFreemiumDBPFeature {

/// Returns true if a user is a "potential" Privacy Pro subscriber. This means:
///
Expand All @@ -76,24 +76,24 @@

/// Returns true IFF:
///
/// 1. The user did onboard to Freemium PIR
/// 1. The user did onboard to Freemium DBP
/// 2. The feature flag is disabled
/// 3. The user `isPotentialPrivacyProSubscriber` (see definition)
var shouldDisableAndDelete: Bool {
guard freemiumPIRUserStateManager.didOnboard else { return false }
guard freemiumDBPUserStateManager.didOnboard else { return false }

return !featureFlagger.isFeatureOn(.freemiumPIR)
return !featureFlagger.isFeatureOn(.freemiumDBP)
&& isPotentialPrivacyProSubscriber
}

/// This method offboards a Freemium user if the feature flag was disabled
///
/// Offboarding involves:
/// - Resettting `FreemiumPIRUserStateManager`state
/// - Disabling and deleting PIR data
/// - Resettting `FreemiumDBPUserStateManager`state
/// - Disabling and deleting DBP data
func offBoardIfNecessary() {
if shouldDisableAndDelete {
freemiumPIRUserStateManager.didOnboard = false
freemiumDBPUserStateManager.didOnboard = false
featureDisabler.disableAndDelete()
}
}
Expand Down
Loading
Loading