From 6bd628c3462abee3db8661be12fc93be820a475a Mon Sep 17 00:00:00 2001 From: David Perez Date: Mon, 24 Jun 2024 11:09:01 -0500 Subject: [PATCH] Create sealed class for Organization Events (#3345) --- .../manager/event/OrganizationEventManager.kt | 4 +- .../event/OrganizationEventManagerImpl.kt | 10 +- .../manager/model/OrganizationEvent.kt | 106 ++++++++++++++++++ .../event/OrganizationEventManagerTest.kt | 27 +++-- 4 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/OrganizationEvent.kt diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManager.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManager.kt index 91fa9d8e4..914801fe9 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManager.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManager.kt @@ -1,6 +1,6 @@ package com.x8bit.bitwarden.data.platform.manager.event -import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEventType +import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent /** * A manager for tracking events. @@ -9,5 +9,5 @@ interface OrganizationEventManager { /** * Tracks a specific event to be uploaded at a different time. */ - fun trackEvent(eventType: OrganizationEventType, cipherId: String? = null) + fun trackEvent(event: OrganizationEvent) } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerImpl.kt index 6d90ee8f4..5c831b39a 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerImpl.kt @@ -9,7 +9,7 @@ import com.x8bit.bitwarden.data.platform.datasource.disk.EventDiskSource import com.x8bit.bitwarden.data.platform.datasource.network.model.OrganizationEventJson import com.x8bit.bitwarden.data.platform.datasource.network.service.EventService import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager -import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEventType +import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent import com.x8bit.bitwarden.data.vault.repository.VaultRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -58,14 +58,14 @@ class OrganizationEventManagerImpl( } @Suppress("ReturnCount") - override fun trackEvent(eventType: OrganizationEventType, cipherId: String?) { + override fun trackEvent(event: OrganizationEvent) { val userId = authRepository.activeUserId ?: return if (authRepository.authStateFlow.value !is AuthState.Authenticated) return val organizations = authRepository.organizations.filter { it.shouldUseEvents } if (organizations.none()) return ioScope.launch { - cipherId?.let { id -> + event.cipherId?.let { id -> val cipherOrganizationId = vaultRepository .getVaultItemStateFlow(itemId = id) .first { it.data != null } @@ -77,8 +77,8 @@ class OrganizationEventManagerImpl( eventDiskSource.addOrganizationEvent( userId = userId, event = OrganizationEventJson( - type = eventType, - cipherId = cipherId, + type = event.type, + cipherId = event.cipherId, date = ZonedDateTime.now(clock), ), ) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/OrganizationEvent.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/OrganizationEvent.kt new file mode 100644 index 000000000..73cb76b8d --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/OrganizationEvent.kt @@ -0,0 +1,106 @@ +package com.x8bit.bitwarden.data.platform.manager.model + +/** + * A representation of events used for organization tracking. + */ +sealed class OrganizationEvent { + /** + * The type of event this model represents. + */ + abstract val type: OrganizationEventType + + /** + * The optional cipher ID. + */ + abstract val cipherId: String? + + /** + * Tracks when a value is successfully auto-filled + */ + data class CipherClientAutoFilled( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_AUTO_FILLED + } + + /** + * Tracks when a card code is copied. + */ + data class CipherClientCopiedCardCode( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_COPIED_CARD_CODE + } + + /** + * Tracks when a hidden field is copied. + */ + data class CipherClientCopiedHiddenField( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_COPIED_HIDDEN_FIELD + } + + /** + * Tracks when a password is copied. + */ + data class CipherClientCopiedPassword( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_COPIED_PASSWORD + } + + /** + * Tracks when a card code is made visible. + */ + data class CipherClientToggledCardCodeVisible( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_TOGGLED_CARD_CODE_VISIBLE + } + + /** + * Tracks when a card number is made visible. + */ + data class CipherClientToggledCardNumberVisible( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_TOGGLED_CARD_NUMBER_VISIBLE + } + + /** + * Tracks when a hidden field is made visible. + */ + data class CipherClientToggledHiddenFieldVisible( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_TOGGLED_HIDDEN_FIELD_VISIBLE + } + + /** + * Tracks when a password is made visible. + */ + data class CipherClientToggledPasswordVisible( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_TOGGLED_PASSWORD_VISIBLE + } + + /** + * Tracks when a cipher is viewed. + */ + data class CipherClientViewed( + override val cipherId: String, + ) : OrganizationEvent() { + override val type: OrganizationEventType + get() = OrganizationEventType.CIPHER_CLIENT_VIEWED + } +} diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerTest.kt index 13f0a9276..809bb0178 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/event/OrganizationEventManagerTest.kt @@ -7,6 +7,7 @@ import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager import com.x8bit.bitwarden.data.platform.datasource.disk.EventDiskSource import com.x8bit.bitwarden.data.platform.datasource.network.model.OrganizationEventJson import com.x8bit.bitwarden.data.platform.datasource.network.service.EventService +import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEventType import com.x8bit.bitwarden.data.platform.repository.model.DataState import com.x8bit.bitwarden.data.platform.util.asSuccess @@ -125,8 +126,9 @@ class OrganizationEventManagerTest { every { authRepository.activeUserId } returns null organizationEventManager.trackEvent( - eventType = OrganizationEventType.CIPHER_UPDATED, - cipherId = CIPHER_ID, + event = OrganizationEvent.CipherClientAutoFilled( + cipherId = CIPHER_ID, + ), ) coVerify(exactly = 0) { @@ -137,8 +139,9 @@ class OrganizationEventManagerTest { @Test fun `trackEvent should do nothing if the active user is not authenticated`() { organizationEventManager.trackEvent( - eventType = OrganizationEventType.CIPHER_UPDATED, - cipherId = CIPHER_ID, + event = OrganizationEvent.CipherClientAutoFilled( + cipherId = CIPHER_ID, + ), ) coVerify(exactly = 0) { @@ -153,8 +156,9 @@ class OrganizationEventManagerTest { every { authRepository.organizations } returns listOf(organization) organizationEventManager.trackEvent( - eventType = OrganizationEventType.CIPHER_UPDATED, - cipherId = CIPHER_ID, + event = OrganizationEvent.CipherClientAutoFilled( + cipherId = CIPHER_ID, + ), ) coVerify(exactly = 0) { @@ -172,8 +176,9 @@ class OrganizationEventManagerTest { mutableVaultItemStateFlow.value = DataState.Loaded(data = cipherView) organizationEventManager.trackEvent( - eventType = OrganizationEventType.CIPHER_UPDATED, - cipherId = CIPHER_ID, + event = OrganizationEvent.CipherClientAutoFilled( + cipherId = CIPHER_ID, + ), ) coVerify(exactly = 0) { @@ -191,11 +196,9 @@ class OrganizationEventManagerTest { every { authRepository.organizations } returns listOf(organization) val cipherView = createMockCipherView(number = 1) mutableVaultItemStateFlow.value = DataState.Loaded(data = cipherView) - val eventType = OrganizationEventType.CIPHER_UPDATED organizationEventManager.trackEvent( - eventType = eventType, - cipherId = CIPHER_ID, + event = OrganizationEvent.CipherClientAutoFilled(cipherId = CIPHER_ID), ) dispatcher.scheduler.runCurrent() @@ -203,7 +206,7 @@ class OrganizationEventManagerTest { eventDiskSource.addOrganizationEvent( userId = USER_ID, event = OrganizationEventJson( - type = eventType, + type = OrganizationEventType.CIPHER_CLIENT_AUTO_FILLED, cipherId = CIPHER_ID, date = ZonedDateTime.now(fixedClock), ),