mirror of
https://github.com/bitwarden/android.git
synced 2026-06-08 08:06:32 -05:00
BIT-1078: Save login items (Networking) (#272)
This commit is contained in:
committed by
Álison Fernandes
parent
1f337e94f0
commit
d36601fa3a
@@ -16,7 +16,7 @@ class LocalDateTimeSerializer : KSerializer<LocalDateTime> {
|
||||
private val dateTimeFormatterDeserialization = DateTimeFormatter
|
||||
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.[SSSSSSS][SSSSSS][SSSSS][SSSS][SSS][SS][S]'Z'")
|
||||
private val dateTimeFormatterSerialization =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'")
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = PrimitiveSerialDescriptor(serialName = "LocalDateTime", kind = PrimitiveKind.STRING)
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.x8bit.bitwarden.data.vault.datasource.network.api
|
||||
|
||||
import CipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
|
||||
/**
|
||||
* Defines raw calls under the /ciphers API with authentication applied.
|
||||
*/
|
||||
interface CiphersApi {
|
||||
|
||||
/**
|
||||
* Create a cipher.
|
||||
*/
|
||||
@POST("ciphers")
|
||||
suspend fun createCipher(@Body body: CipherJsonRequest): Result<SyncResponseJson.Cipher>
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.x8bit.bitwarden.data.vault.datasource.network.di
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.SyncService
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.SyncServiceImpl
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.retrofit.Retrofits
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersService
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersServiceImpl
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@@ -17,6 +19,14 @@ import javax.inject.Singleton
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object VaultNetworkModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCiphersService(
|
||||
retrofits: Retrofits,
|
||||
): CiphersService = CiphersServiceImpl(
|
||||
ciphersApi = retrofits.authenticatedApiRetrofit.create(),
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSyncService(
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.CipherRepromptTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.CipherTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.time.LocalDateTime
|
||||
|
||||
/**
|
||||
* Represents a cipher request.
|
||||
*
|
||||
* @property notes The notes of the cipher (nullable).
|
||||
* @property reprompt The reprompt of the cipher.
|
||||
* @property passwordHistory A list of password history objects
|
||||
* associated with the cipher (nullable).
|
||||
* @property type The type of cipher.
|
||||
* @property login The login of the cipher.
|
||||
* @property secureNote The secure note of the cipher.
|
||||
* @property folderId The folder ID of the cipher (nullable).
|
||||
* @property organizationId The organization ID of the cipher (nullable).
|
||||
* @property identity The identity of the cipher.
|
||||
* @property name The name of the cipher (nullable).
|
||||
* @property fields A list of fields associated with the cipher (nullable).
|
||||
* @property isFavorite If the cipher is a favorite.
|
||||
* @property card The card of the cipher.
|
||||
*/
|
||||
@Serializable
|
||||
data class CipherJsonRequest(
|
||||
@SerialName("notes")
|
||||
val notes: String?,
|
||||
|
||||
@SerialName("reprompt")
|
||||
val reprompt: CipherRepromptTypeJson,
|
||||
|
||||
@SerialName("passwordHistory")
|
||||
val passwordHistory: List<SyncResponseJson.Cipher.PasswordHistory>?,
|
||||
|
||||
@SerialName("lastKnownRevisionDate")
|
||||
@Contextual
|
||||
val lastKnownRevisionDate: LocalDateTime?,
|
||||
|
||||
@SerialName("type")
|
||||
val type: CipherTypeJson,
|
||||
|
||||
@SerialName("login")
|
||||
val login: SyncResponseJson.Cipher.Login?,
|
||||
|
||||
@SerialName("secureNote")
|
||||
val secureNote: SyncResponseJson.Cipher.SecureNote?,
|
||||
|
||||
@SerialName("folderId")
|
||||
val folderId: String?,
|
||||
|
||||
@SerialName("organizationId")
|
||||
val organizationId: String?,
|
||||
|
||||
@SerialName("identity")
|
||||
val identity: SyncResponseJson.Cipher.Identity?,
|
||||
|
||||
@SerialName("name")
|
||||
val name: String?,
|
||||
|
||||
@SerialName("fields")
|
||||
val fields: List<SyncResponseJson.Cipher.Field>?,
|
||||
|
||||
@SerialName("favorite")
|
||||
val isFavorite: Boolean,
|
||||
|
||||
@SerialName("card")
|
||||
val card: SyncResponseJson.Cipher.Card?,
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.x8bit.bitwarden.data.vault.datasource.network.service
|
||||
|
||||
import CipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
|
||||
/**
|
||||
* Provides an API for querying ciphers endpoints.
|
||||
*/
|
||||
interface CiphersService {
|
||||
/**
|
||||
* Attempt to create a cipher.
|
||||
*/
|
||||
suspend fun createCipher(body: CipherJsonRequest): Result<SyncResponseJson.Cipher>
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.x8bit.bitwarden.data.vault.datasource.network.service
|
||||
|
||||
import CipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.api.CiphersApi
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
|
||||
class CiphersServiceImpl constructor(
|
||||
private val ciphersApi: CiphersApi,
|
||||
) : CiphersService {
|
||||
override suspend fun createCipher(body: CipherJsonRequest): Result<SyncResponseJson.Cipher> =
|
||||
ciphersApi.createCipher(body = body)
|
||||
}
|
||||
@@ -10,21 +10,22 @@ import com.x8bit.bitwarden.ui.vault.feature.vault.VaultState
|
||||
* Transforms a [CipherView] into a [VaultState.ViewState.VaultItem].
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
private fun CipherView.toVaultItem(): VaultState.ViewState.VaultItem =
|
||||
when (type) {
|
||||
private fun CipherView.toVaultItemOrNull(): VaultState.ViewState.VaultItem? {
|
||||
val id = this.id ?: return null
|
||||
return when (type) {
|
||||
CipherType.LOGIN -> VaultState.ViewState.VaultItem.Login(
|
||||
id = id.toString(),
|
||||
id = id,
|
||||
name = name.asText(),
|
||||
username = login?.username?.asText(),
|
||||
)
|
||||
|
||||
CipherType.SECURE_NOTE -> VaultState.ViewState.VaultItem.SecureNote(
|
||||
id = id.toString(),
|
||||
id = id,
|
||||
name = name.asText(),
|
||||
)
|
||||
|
||||
CipherType.CARD -> VaultState.ViewState.VaultItem.Card(
|
||||
id = id.toString(),
|
||||
id = id,
|
||||
name = name.asText(),
|
||||
brand = card?.brand?.asText(),
|
||||
lastFourDigits = card?.number
|
||||
@@ -33,11 +34,12 @@ private fun CipherView.toVaultItem(): VaultState.ViewState.VaultItem =
|
||||
)
|
||||
|
||||
CipherType.IDENTITY -> VaultState.ViewState.VaultItem.Identity(
|
||||
id = id.toString(),
|
||||
id = id,
|
||||
name = name.asText(),
|
||||
firstName = identity?.firstName?.asText(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms [VaultData] into [VaultState.ViewState].
|
||||
@@ -46,24 +48,28 @@ fun VaultData.toViewState(): VaultState.ViewState =
|
||||
if (cipherViewList.isEmpty() && folderViewList.isEmpty()) {
|
||||
VaultState.ViewState.NoItems
|
||||
} else {
|
||||
// Filter out any items with invalid IDs in the unlikely case they exist
|
||||
val filteredCipherViewList = cipherViewList.filterNot { it.id.isNullOrBlank() }
|
||||
VaultState.ViewState.Content(
|
||||
loginItemsCount = cipherViewList.count { it.type == CipherType.LOGIN },
|
||||
cardItemsCount = cipherViewList.count { it.type == CipherType.CARD },
|
||||
identityItemsCount = cipherViewList.count { it.type == CipherType.IDENTITY },
|
||||
secureNoteItemsCount = cipherViewList.count { it.type == CipherType.SECURE_NOTE },
|
||||
loginItemsCount = filteredCipherViewList.count { it.type == CipherType.LOGIN },
|
||||
cardItemsCount = filteredCipherViewList.count { it.type == CipherType.CARD },
|
||||
identityItemsCount = filteredCipherViewList.count { it.type == CipherType.IDENTITY },
|
||||
secureNoteItemsCount = filteredCipherViewList
|
||||
.count { it.type == CipherType.SECURE_NOTE },
|
||||
favoriteItems = cipherViewList
|
||||
.filter { it.favorite }
|
||||
.map { it.toVaultItem() },
|
||||
.mapNotNull { it.toVaultItemOrNull() },
|
||||
folderItems = folderViewList.map { folderView ->
|
||||
VaultState.ViewState.FolderItem(
|
||||
id = folderView.id,
|
||||
name = folderView.name.asText(),
|
||||
itemCount = cipherViewList.count { folderView.id == it.folderId },
|
||||
itemCount = cipherViewList
|
||||
.count { !it.id.isNullOrBlank() && folderView.id == it.folderId },
|
||||
)
|
||||
},
|
||||
noFolderItems = cipherViewList
|
||||
.filter { it.folderId.isNullOrBlank() }
|
||||
.map { it.toVaultItem() },
|
||||
.mapNotNull { it.toVaultItemOrNull() },
|
||||
// TODO need to populate trash item count in BIT-969
|
||||
trashItemsCount = 0,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user