From 736d19cdfbaa9dab4391c6b6b240d3e20a4eebe0 Mon Sep 17 00:00:00 2001 From: Matt Bumgardner Date: Thu, 26 Jul 2018 16:14:48 -0500 Subject: [PATCH 1/4] Integrated Tracks with AuthenticationManager --- .../Classes/Analytics/WooAnalytics.swift | 6 - .../Classes/Analytics/WooAnalyticsStat.swift | 123 ++++++++++++++++++ .../AuthenticationManager.swift | 15 ++- .../WooCommerce.xcodeproj/project.pbxproj | 4 + 4 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 WooCommerce/Classes/Analytics/WooAnalyticsStat.swift diff --git a/WooCommerce/Classes/Analytics/WooAnalytics.swift b/WooCommerce/Classes/Analytics/WooAnalytics.swift index 9a7d7276d28..ae1576d6d31 100644 --- a/WooCommerce/Classes/Analytics/WooAnalytics.swift +++ b/WooCommerce/Classes/Analytics/WooAnalytics.swift @@ -1,12 +1,6 @@ import Foundation -public enum WooAnalyticsStat: String { - case applicationOpened = "application_opened" - case applicationClosed = "application_closed" -} - - public class WooAnalytics { // MARK: - Properties diff --git a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift new file mode 100644 index 00000000000..35459f5ee3e --- /dev/null +++ b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift @@ -0,0 +1,123 @@ +import WordPressShared + + +/// This enum contains all of the events we track in the app. +/// +public enum WooAnalyticsStat: String { + case applicationOpened = "application_opened" + case applicationClosed = "application_closed" + + case signedIn = "signed_in" + case logout = "account_logout" + case openedLogin = "login_accessed" + case loginFailed = "login_failed_to_login" + case loginAutoFillCredentialsFilled = "login_autofill_credentials_filled" + case loginAutoFillCredentialsUpdated = "login_autofill_credentials_updated" + case loginProloguePaged = "login_prologue_paged" + case loginPrologueViewed = "login_prologue_viewed" + case loginEmailFormViewed = "login_email_form_viewed" + case loginMagicLinkOpenEmailClientViewed = "login_magic_link_open_email_client_viewed" + case loginMagicLinkRequestFormViewed = "login_magic_link_request_form_viewed" + case loginPasswordFormViewed = "login_password_form_viewed" + case loginURLFormViewed = "login_url_form_viewed" + case loginURLHelpScreenViewed = "login_url_help_screen_viewed" + case loginUsernamePasswordFormViewed = "login_username_password_form_viewed" + case loginTwoFactorFormViewed = "login_two_factor_form_viewed" + case loginEpilogueViewed = "login_epilogue_viewed" + case loginForgotPasswordClicked = "login_forgot_password_clicked" + case loginSocialButtonClick = "login_social_button_click" + case loginSocialButtonFailure = "login_social_button_failure" + case loginSocialConnectSuccess = "login_social_connect_success" + case loginSocialConnectFailure = "login_social_connect_failure" + case loginSocialSuccess = "login_social_login_success" + case loginSocialFailure = "login_social_login_failure" + case loginSocial2faNeeded = "login_social_2fa_needed" + case loginSocialAccountsNeedConnecting = "login_social_accounts_need_connecting" + case loginSocialErrorUnknownUser = "login_social_error_unknown_user" + case onePasswordFailed = "one_password_failed" + case onePasswordLogin = "one_password_login" + case onePasswordSignup = "one_password_signup" +} + +public extension WooAnalyticsStat { + + /// Converts the provided WPAnalyticsStat into a WooAnalyticsStat. + /// This whole process kinda stinks, but we need this for the `WordPressAuthenticatorDelegate` + /// implementation. ☹️ Feel free to refactor later on! + /// + /// - Parameter stat: The WPAnalyticsStat to convert + /// - Returns: The corresponding WooAnalyticsStat or nil if it cannot be converted + /// + static func valueOf(stat: WPAnalyticsStat) -> WooAnalyticsStat? { + var wooEvent: WooAnalyticsStat? = nil + + switch stat { + case .signedIn: + wooEvent = WooAnalyticsStat.signedIn + case .signedInToJetpack: + wooEvent = WooAnalyticsStat.signedIn + case .logout: + wooEvent = WooAnalyticsStat.logout + case .openedLogin: + wooEvent = WooAnalyticsStat.openedLogin + case .loginFailed: + wooEvent = WooAnalyticsStat.loginFailed + case .loginAutoFillCredentialsFilled: + wooEvent = WooAnalyticsStat.loginAutoFillCredentialsFilled + case .loginAutoFillCredentialsUpdated: + wooEvent = WooAnalyticsStat.loginAutoFillCredentialsUpdated + case .loginProloguePaged: + wooEvent = WooAnalyticsStat.loginProloguePaged + case .loginPrologueViewed: + wooEvent = WooAnalyticsStat.loginPrologueViewed + case .loginEmailFormViewed: + wooEvent = WooAnalyticsStat.loginEmailFormViewed + case .loginMagicLinkOpenEmailClientViewed: + wooEvent = WooAnalyticsStat.loginMagicLinkOpenEmailClientViewed + case .loginMagicLinkRequestFormViewed: + wooEvent = WooAnalyticsStat.loginMagicLinkRequestFormViewed + case .loginPasswordFormViewed: + wooEvent = WooAnalyticsStat.loginPasswordFormViewed + case .loginURLFormViewed: + wooEvent = WooAnalyticsStat.loginURLFormViewed + case .loginURLHelpScreenViewed: + wooEvent = WooAnalyticsStat.loginURLHelpScreenViewed + case .loginUsernamePasswordFormViewed: + wooEvent = WooAnalyticsStat.loginUsernamePasswordFormViewed + case .loginTwoFactorFormViewed: + wooEvent = WooAnalyticsStat.loginTwoFactorFormViewed + case .loginEpilogueViewed: + wooEvent = WooAnalyticsStat.loginEpilogueViewed + case .loginForgotPasswordClicked: + wooEvent = WooAnalyticsStat.loginForgotPasswordClicked + case .loginSocialButtonClick: + wooEvent = WooAnalyticsStat.loginSocialButtonClick + case .loginSocialButtonFailure: + wooEvent = WooAnalyticsStat.loginSocialButtonFailure + case .loginSocialConnectSuccess: + wooEvent = WooAnalyticsStat.loginSocialConnectSuccess + case .loginSocialConnectFailure: + wooEvent = WooAnalyticsStat.loginSocialConnectFailure + case .loginSocialSuccess: + wooEvent = WooAnalyticsStat.loginSocialSuccess + case .loginSocialFailure: + wooEvent = WooAnalyticsStat.loginSocialFailure + case .loginSocial2faNeeded: + wooEvent = WooAnalyticsStat.loginSocial2faNeeded + case .loginSocialAccountsNeedConnecting: + wooEvent = WooAnalyticsStat.loginSocialAccountsNeedConnecting + case .loginSocialErrorUnknownUser: + wooEvent = WooAnalyticsStat.loginSocialErrorUnknownUser + case .onePasswordFailed: + wooEvent = WooAnalyticsStat.onePasswordFailed + case .onePasswordLogin: + wooEvent = WooAnalyticsStat.onePasswordLogin + case .onePasswordSignup: + wooEvent = WooAnalyticsStat.onePasswordSignup + default: + wooEvent = nil + } + + return wooEvent + } +} diff --git a/WooCommerce/Classes/Authentication/AuthenticationManager.swift b/WooCommerce/Classes/Authentication/AuthenticationManager.swift index 74514c2f243..3fd6f6f0d8b 100644 --- a/WooCommerce/Classes/Authentication/AuthenticationManager.swift +++ b/WooCommerce/Classes/Authentication/AuthenticationManager.swift @@ -190,18 +190,27 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate { /// Tracks a given Analytics Event. /// func track(event: WPAnalyticsStat) { - // TODO: Integrate Tracks + guard let wooEvent = WooAnalyticsStat.valueOf(stat: event) else { + return + } + WooAnalytics.shared.track(wooEvent) } /// Tracks a given Analytics Event, with the specified properties. /// func track(event: WPAnalyticsStat, properties: [AnyHashable: Any]) { - // TODO: Integrate Tracks + guard let wooEvent = WooAnalyticsStat.valueOf(stat: event) else { + return + } + WooAnalytics.shared.track(wooEvent, withProperties: properties) } /// Tracks a given Analytics Event, with the specified error. /// func track(event: WPAnalyticsStat, error: Error) { - // TODO: Integrate Tracks + guard let wooEvent = WooAnalyticsStat.valueOf(stat: event) else { + return + } + WooAnalytics.shared.track(wooEvent, withError: error) } } diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 03e234c359d..5fe617ac5cb 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ /* Begin PBXBuildFile section */ 7403F7E220EC04070097198F /* OrderStatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7403F7E120EC04070097198F /* OrderStatusViewModel.swift */; }; + 7421344A210A323C00C13890 /* WooAnalyticsStat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74213449210A323C00C13890 /* WooAnalyticsStat.swift */; }; 746791632108D7C0007CF1DC /* WooAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 746791622108D7C0007CF1DC /* WooAnalyticsTests.swift */; }; 746791662108D87B007CF1DC /* MockupAnalyticsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 746791652108D87B007CF1DC /* MockupAnalyticsProvider.swift */; }; 747AA0892107CEC60047A89B /* AnalyticsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 747AA0882107CEC60047A89B /* AnalyticsProvider.swift */; }; @@ -174,6 +175,7 @@ /* Begin PBXFileReference section */ 33035144757869DE5E4DC88A /* Pods-WooCommerce.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WooCommerce.release.xcconfig"; path = "../Pods/Target Support Files/Pods-WooCommerce/Pods-WooCommerce.release.xcconfig"; sourceTree = ""; }; 7403F7E120EC04070097198F /* OrderStatusViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderStatusViewModel.swift; sourceTree = ""; }; + 74213449210A323C00C13890 /* WooAnalyticsStat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooAnalyticsStat.swift; sourceTree = ""; }; 746791622108D7C0007CF1DC /* WooAnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooAnalyticsTests.swift; sourceTree = ""; }; 746791652108D87B007CF1DC /* MockupAnalyticsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockupAnalyticsProvider.swift; sourceTree = ""; }; 747AA0882107CEC60047A89B /* AnalyticsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsProvider.swift; sourceTree = ""; }; @@ -332,6 +334,7 @@ isa = PBXGroup; children = ( CEA16F3920FD0C8C0061B4E1 /* WooAnalytics.swift */, + 74213449210A323C00C13890 /* WooAnalyticsStat.swift */, 747AA0882107CEC60047A89B /* AnalyticsProvider.swift */, 747AA08A2107CF8D0047A89B /* TracksProvider.swift */, ); @@ -996,6 +999,7 @@ B56DB3CA2049BFAA00D4AA8E /* AppDelegate.swift in Sources */, B5A82EE7210263460053ADC8 /* UIViewController+Helpers.swift in Sources */, CE1F512B206985DF00C6C810 /* PaddedLabel.swift in Sources */, + 7421344A210A323C00C13890 /* WooAnalyticsStat.swift in Sources */, CE1EC8D120B6FE39009762BF /* FootnoteView.swift in Sources */, B557DA1520979904005962F4 /* CustomerNoteTableViewCell.swift in Sources */, CE855366209BA6A700938BDC /* CustomerInfoTableViewCell.swift in Sources */, From 118afe781e53da02733324188f30e70800fe643c Mon Sep 17 00:00:00 2001 From: Matt Bumgardner Date: Thu, 26 Jul 2018 18:01:00 -0500 Subject: [PATCH 2/4] Added tracking for logout --- .../ViewRelated/Dashboard/Settings/SettingsViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/SettingsViewController.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/SettingsViewController.swift index 6d1346e6072..0adc1f066c1 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/SettingsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/SettingsViewController.swift @@ -76,6 +76,7 @@ extension SettingsViewController: UITableViewDataSource { if cell is LogOutTableViewCell { let logoutCell = cell as! LogOutTableViewCell logoutCell.didSelectLogout = { [weak self] in + WooAnalytics.shared.track(.logout) StoresManager.shared.deauthenticate() self?.navigationController?.popToRootViewController(animated: true) } From 0b20213e1a78245315e0ac69834f11bb163029d8 Mon Sep 17 00:00:00 2001 From: Matt Bumgardner Date: Thu, 26 Jul 2018 18:18:07 -0500 Subject: [PATCH 3/4] Added WordPressShared to the Podfile; added two factor events --- Podfile | 1 + Podfile.lock | 3 ++- WooCommerce/Classes/Analytics/WooAnalyticsStat.swift | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Podfile b/Podfile index f40e3eb8f36..512c2601b49 100644 --- a/Podfile +++ b/Podfile @@ -19,6 +19,7 @@ target 'WooCommerce' do pod 'Automattic-Tracks-iOS', :git => 'https://github.com/Automattic/Automattic-Tracks-iOS.git', :tag => '0.2.3' pod 'Gridicons', '0.15' pod 'WordPressAuthenticator', '1.0.4' + pod 'WordPressShared', '1.0.8' # External Libraries diff --git a/Podfile.lock b/Podfile.lock index c453a0365ec..581dc1c680a 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -73,6 +73,7 @@ DEPENDENCIES: - Gridicons (= 0.15) - KeychainAccess (~> 3.1) - WordPressAuthenticator (= 1.0.4) + - WordPressShared (= 1.0.8) SPEC REPOS: https://github.com/cocoapods/specs.git: @@ -132,6 +133,6 @@ SPEC CHECKSUMS: WordPressUI: af141587ec444f9af753a00605bd0d3f14d8d8a3 wpxmlrpc: bfc572f62ce7ee897f6f38b098d2ba08732ecef4 -PODFILE CHECKSUM: bca741aeec025b018771a1e5d22cbc71dfd15f55 +PODFILE CHECKSUM: c627b723e165dabc83c6716871f3199190464f2c COCOAPODS: 1.5.3 diff --git a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift index 35459f5ee3e..f4e8ce975ec 100644 --- a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift +++ b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift @@ -37,6 +37,8 @@ public enum WooAnalyticsStat: String { case onePasswordFailed = "one_password_failed" case onePasswordLogin = "one_password_login" case onePasswordSignup = "one_password_signup" + case twoFactorCodeRequested = "two_factor_code_requested" + case twoFactorSentSMS = "two_factor_sent_sms" } public extension WooAnalyticsStat { @@ -114,6 +116,10 @@ public extension WooAnalyticsStat { wooEvent = WooAnalyticsStat.onePasswordLogin case .onePasswordSignup: wooEvent = WooAnalyticsStat.onePasswordSignup + case .twoFactorCodeRequested: + wooEvent = WooAnalyticsStat.twoFactorCodeRequested + case .twoFactorSentSMS: + wooEvent = WooAnalyticsStat.twoFactorSentSMS default: wooEvent = nil } From 7026acb0fa72ba82936776bc5460bc311b58ca7e Mon Sep 17 00:00:00 2001 From: Matt Bumgardner Date: Thu, 26 Jul 2018 20:55:40 -0500 Subject: [PATCH 4/4] Added some missing tracks events for magic links --- .../Classes/Analytics/WooAnalyticsStat.swift | 20 +++++++++++++++++++ .../AuthenticationManager.swift | 3 +++ 2 files changed, 23 insertions(+) diff --git a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift index f4e8ce975ec..806b791c7df 100644 --- a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift +++ b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift @@ -4,9 +4,14 @@ import WordPressShared /// This enum contains all of the events we track in the app. /// public enum WooAnalyticsStat: String { + + // Application Events + // case applicationOpened = "application_opened" case applicationClosed = "application_closed" + // Authentication Events + // case signedIn = "signed_in" case logout = "account_logout" case openedLogin = "login_accessed" @@ -18,6 +23,11 @@ public enum WooAnalyticsStat: String { case loginEmailFormViewed = "login_email_form_viewed" case loginMagicLinkOpenEmailClientViewed = "login_magic_link_open_email_client_viewed" case loginMagicLinkRequestFormViewed = "login_magic_link_request_form_viewed" + case loginMagicLinkExited = "login_magic_link_exited" + case loginMagicLinkFailed = "login_magic_link_failed" + case loginMagicLinkOpened = "login_magic_link_opened" + case loginMagicLinkRequested = "login_magic_link_requested" + case loginMagicLinkSucceeded = "login_magic_link_succeeded" case loginPasswordFormViewed = "login_password_form_viewed" case loginURLFormViewed = "login_url_form_viewed" case loginURLHelpScreenViewed = "login_url_help_screen_viewed" @@ -78,6 +88,16 @@ public extension WooAnalyticsStat { wooEvent = WooAnalyticsStat.loginMagicLinkOpenEmailClientViewed case .loginMagicLinkRequestFormViewed: wooEvent = WooAnalyticsStat.loginMagicLinkRequestFormViewed + case .loginMagicLinkExited: + wooEvent = WooAnalyticsStat.loginMagicLinkExited + case .loginMagicLinkFailed: + wooEvent = WooAnalyticsStat.loginMagicLinkFailed + case .loginMagicLinkOpened: + wooEvent = WooAnalyticsStat.loginMagicLinkOpened + case .loginMagicLinkRequested: + wooEvent = WooAnalyticsStat.loginMagicLinkRequested + case .loginMagicLinkSucceeded: + wooEvent = WooAnalyticsStat.loginMagicLinkSucceeded case .loginPasswordFormViewed: wooEvent = WooAnalyticsStat.loginPasswordFormViewed case .loginURLFormViewed: diff --git a/WooCommerce/Classes/Authentication/AuthenticationManager.swift b/WooCommerce/Classes/Authentication/AuthenticationManager.swift index 3fd6f6f0d8b..bb1f5d39033 100644 --- a/WooCommerce/Classes/Authentication/AuthenticationManager.swift +++ b/WooCommerce/Classes/Authentication/AuthenticationManager.swift @@ -191,6 +191,7 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate { /// func track(event: WPAnalyticsStat) { guard let wooEvent = WooAnalyticsStat.valueOf(stat: event) else { + DDLogWarn("⚠️ Could not convert WPAnalyticsStat with value: \(event.rawValue)") return } WooAnalytics.shared.track(wooEvent) @@ -200,6 +201,7 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate { /// func track(event: WPAnalyticsStat, properties: [AnyHashable: Any]) { guard let wooEvent = WooAnalyticsStat.valueOf(stat: event) else { + DDLogWarn("⚠️ Could not convert WPAnalyticsStat with value: \(event.rawValue)") return } WooAnalytics.shared.track(wooEvent, withProperties: properties) @@ -209,6 +211,7 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate { /// func track(event: WPAnalyticsStat, error: Error) { guard let wooEvent = WooAnalyticsStat.valueOf(stat: event) else { + DDLogWarn("⚠️ Could not convert WPAnalyticsStat with value: \(event.rawValue)") return } WooAnalytics.shared.track(wooEvent, withError: error)