diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/api/SendsApi.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/api/SendsApi.kt index eed47da82..102ff6a5e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/api/SendsApi.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/api/SendsApi.kt @@ -1,7 +1,7 @@ package com.x8bit.bitwarden.data.vault.datasource.network.api import androidx.annotation.Keep -import com.x8bit.bitwarden.data.vault.datasource.network.model.SendFileResponseJson +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.SendJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson import okhttp3.MultipartBody @@ -28,7 +28,7 @@ interface SendsApi { * Create a file send. */ @POST("sends/file/v2") - suspend fun createFileSend(@Body body: SendJsonRequest): Result + suspend fun createFileSend(@Body body: SendJsonRequest): Result /** * Updates a send. diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateFileSendResponse.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateFileSendResponse.kt new file mode 100644 index 000000000..e37b4c1be --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateFileSendResponse.kt @@ -0,0 +1,36 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Represents a response from create file send. + */ +sealed class CreateFileSendResponse { + + /** + * Represents the response from a successful create file send request. + * + * @property createFileJsonResponse Response JSON received from create file send request. + */ + data class Success( + val createFileJsonResponse: CreateFileSendResponseJson, + ) : CreateFileSendResponse() + + /** + * Represents the json body of an invalid create request. + * + * @property message A general, user-displayable error message. + * @property validationErrors a map where each value is a list of error messages for each + * key. The values in the array should be used for display to the user, since the keys tend + * to come back as nonsense. (eg: empty string key) + */ + @Serializable + data class Invalid( + @SerialName("message") + override val message: String, + + @SerialName("validationErrors") + override val validationErrors: Map>?, + ) : CreateFileSendResponse(), InvalidJsonResponse +} diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SendFileResponseJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateFileSendResponseJson.kt similarity index 91% rename from app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SendFileResponseJson.kt rename to app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateFileSendResponseJson.kt index 0d6f1d90c..2baa66602 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SendFileResponseJson.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateFileSendResponseJson.kt @@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable * Represents the JSON response from creating a new file send. */ @Serializable -data class SendFileResponseJson( +data class CreateFileSendResponseJson( @SerialName("url") val url: String, diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateSendJsonResponse.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateSendJsonResponse.kt new file mode 100644 index 000000000..b686967e9 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CreateSendJsonResponse.kt @@ -0,0 +1,34 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Models a response from either "create text send" or "create file send" requests. + */ +sealed class CreateSendJsonResponse { + /** + * Represents a successful response from either "create text send" or "create file send" + * request. + * + * @property send The created send object. + */ + data class Success(val send: SyncResponseJson.Send) : CreateSendJsonResponse() + + /** + * Represents the json body of an invalid create request. + * + * @property message A general, user-displayable error message. + * @property validationErrors a map where each value is a list of error messages for each + * key. The values in the array should be used for display to the user, since the keys tend + * to come back as nonsense. (eg: empty string key) + */ + @Serializable + data class Invalid( + @SerialName("message") + override val message: String, + + @SerialName("validationErrors") + override val validationErrors: Map>?, + ) : CreateSendJsonResponse(), InvalidJsonResponse +} diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/InvalidJsonResponse.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/InvalidJsonResponse.kt new file mode 100644 index 000000000..61451923e --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/InvalidJsonResponse.kt @@ -0,0 +1,28 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +/** + * Represents the json body of an invalid send json request. + */ +sealed interface InvalidJsonResponse { + + /** + * A general, user-displayable error message. + */ + val message: String + + /** + * a map where each value is a list of error messages for each key. + * The values in the array should be used for display to the user, since the keys tend to come + * back as nonsense. (eg: empty string key) + */ + val validationErrors: Map>? + + /** + * Returns the first error message found in [validationErrors], or [message] if there are no + * [validationErrors] present. + */ + val firstValidationErrorMessage: String? + get() = validationErrors + ?.flatMap { it.value } + ?.first() +} diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsService.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsService.kt index 7382d5ea3..990217308 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsService.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsService.kt @@ -1,6 +1,8 @@ package com.x8bit.bitwarden.data.vault.datasource.network.service -import com.x8bit.bitwarden.data.vault.datasource.network.model.SendFileResponseJson +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponse +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponseJson +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateSendJsonResponse import com.x8bit.bitwarden.data.vault.datasource.network.model.SendJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateSendResponseJson @@ -14,20 +16,20 @@ interface SendsService { */ suspend fun createTextSend( body: SendJsonRequest, - ): Result + ): Result /** * Attempt to create a file send. */ suspend fun createFileSend( body: SendJsonRequest, - ): Result + ): Result /** * Attempt to upload the given [encryptedFile] associated with the [sendFileResponse]. */ suspend fun uploadFile( - sendFileResponse: SendFileResponseJson, + sendFileResponse: CreateFileSendResponseJson, encryptedFile: ByteArray, ): Result diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceImpl.kt index 2a6b97ec4..5e6091b15 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceImpl.kt @@ -5,8 +5,10 @@ import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenErr import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull import com.x8bit.bitwarden.data.vault.datasource.network.api.AzureApi import com.x8bit.bitwarden.data.vault.datasource.network.api.SendsApi +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponse +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponseJson +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateSendJsonResponse import com.x8bit.bitwarden.data.vault.datasource.network.model.FileUploadType -import com.x8bit.bitwarden.data.vault.datasource.network.model.SendFileResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.SendJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateSendResponseJson @@ -28,11 +30,33 @@ class SendsServiceImpl( private val clock: Clock, private val json: Json, ) : SendsService { - override suspend fun createTextSend(body: SendJsonRequest): Result = + override suspend fun createTextSend( + body: SendJsonRequest, + ): Result = sendsApi.createTextSend(body = body) + .map { CreateSendJsonResponse.Success(send = it) } + .recoverCatching { throwable -> + throwable.toBitwardenError() + .parseErrorBodyOrNull( + code = 400, + json = json, + ) + ?: throw throwable + } - override suspend fun createFileSend(body: SendJsonRequest): Result = + override suspend fun createFileSend( + body: SendJsonRequest, + ): Result = sendsApi.createFileSend(body = body) + .map { CreateFileSendResponse.Success(it) } + .recoverCatching { throwable -> + throwable.toBitwardenError() + .parseErrorBodyOrNull( + code = 400, + json = json, + ) + ?: throw throwable + } override suspend fun updateSend( sendId: String, @@ -55,7 +79,7 @@ class SendsServiceImpl( } override suspend fun uploadFile( - sendFileResponse: SendFileResponseJson, + sendFileResponse: CreateFileSendResponseJson, encryptedFile: ByteArray, ): Result { val send = sendFileResponse.sendResponse diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index 76d9a352a..360a8e89b 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -10,6 +10,7 @@ import com.bitwarden.core.ExportFormat import com.bitwarden.core.FolderView import com.bitwarden.core.InitOrgCryptoRequest import com.bitwarden.core.InitUserCryptoMethod +import com.bitwarden.core.Send import com.bitwarden.core.SendType import com.bitwarden.core.SendView import com.bitwarden.crypto.Kdf @@ -35,10 +36,13 @@ import com.x8bit.bitwarden.data.platform.repository.util.map import com.x8bit.bitwarden.data.platform.repository.util.observeWhenSubscribedAndLoggedIn import com.x8bit.bitwarden.data.platform.repository.util.updateToPendingOrLoading import com.x8bit.bitwarden.data.platform.util.asFailure +import com.x8bit.bitwarden.data.platform.util.asSuccess import com.x8bit.bitwarden.data.platform.util.flatMap import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateCipherInOrganizationJsonRequest +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponse +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateSendJsonResponse import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateCipherCollectionsJsonRequest @@ -980,11 +984,12 @@ class VaultRepositoryImpl( ) } + @Suppress("ReturnCount") override suspend fun createSend( sendView: SendView, fileUri: Uri?, ): CreateSendResult { - val userId = activeUserId ?: return CreateSendResult.Error + val userId = activeUserId ?: return CreateSendResult.Error(message = null) return vaultSdkSource .encryptSend( userId = userId, @@ -992,54 +997,33 @@ class VaultRepositoryImpl( ) .flatMap { send -> when (send.type) { - SendType.TEXT -> { - sendsService.createTextSend(body = send.toEncryptedNetworkSend()) + SendType.TEXT -> sendsService.createTextSend(send.toEncryptedNetworkSend()) + SendType.FILE -> createFileSend(fileUri, userId, send) + } + } + .map { createSendResponse -> + when (createSendResponse) { + is CreateSendJsonResponse.Invalid -> { + return CreateSendResult.Error( + message = createSendResponse.firstValidationErrorMessage, + ) } - SendType.FILE -> { - val uri = fileUri ?: return@flatMap IllegalArgumentException( - "File URI must be present to create a File Send.", - ) - .asFailure() - - fileManager - .uriToByteArray(fileUri = uri) - .flatMap { - vaultSdkSource.encryptBuffer( - userId = userId, - send = send, - fileBuffer = it, - ) - } - .flatMap { encryptedFile -> - sendsService - .createFileSend( - body = send.toEncryptedNetworkSend( - fileLength = encryptedFile.size, - ), - ) - .flatMap { sendFileResponse -> - sendsService.uploadFile( - sendFileResponse = sendFileResponse, - encryptedFile = encryptedFile, - ) - } - } + is CreateSendJsonResponse.Success -> { + // Save the send immediately, regardless of whether the decrypt succeeds + vaultDiskSource.saveSend(userId = userId, send = createSendResponse.send) + createSendResponse } } } - .onSuccess { - // Save the send immediately, regardless of whether the decrypt succeeds - vaultDiskSource.saveSend(userId = userId, send = it) - } - .flatMap { + .flatMap { createSendSuccessResponse -> vaultSdkSource.decryptSend( userId = userId, - send = it.toEncryptedSdkSend(), + send = createSendSuccessResponse.send.toEncryptedSdkSend(), ) } .fold( - onFailure = { CreateSendResult.Error }, + onFailure = { CreateSendResult.Error(message = null) }, onSuccess = { CreateSendResult.Success(it) }, ) } @@ -1594,6 +1578,56 @@ class VaultRepositoryImpl( ) } + private suspend fun createFileSend( + uri: Uri?, + userId: String, + send: Send, + ): Result { + uri ?: return IllegalArgumentException( + "File URI must be present to create a File Send.", + ) + .asFailure() + + return fileManager + .uriToByteArray(fileUri = uri) + .flatMap { + vaultSdkSource.encryptBuffer( + userId = userId, + send = send, + fileBuffer = it, + ) + } + .flatMap { encryptedFile -> + sendsService + .createFileSend( + body = send.toEncryptedNetworkSend( + fileLength = encryptedFile.size, + ), + ) + .flatMap { sendFileResponse -> + when (sendFileResponse) { + is CreateFileSendResponse.Invalid -> { + CreateSendJsonResponse + .Invalid( + message = sendFileResponse.message, + validationErrors = sendFileResponse.validationErrors, + ) + .asSuccess() + } + + is CreateFileSendResponse.Success -> { + sendsService + .uploadFile( + sendFileResponse = sendFileResponse.createFileJsonResponse, + encryptedFile = encryptedFile, + ) + .map { CreateSendJsonResponse.Success(it) } + } + } + } + } + } + /** * Deletes the send specified by [syncSendDeleteData] from disk. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt index b7f604827..d1ccb9b45 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt @@ -15,5 +15,5 @@ sealed class CreateSendResult { /** * Generic error while creating a send. */ - data object Error : CreateSendResult() + data class Error(val message: String?) : CreateSendResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt index adf1da50c..43c26a792 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt @@ -184,12 +184,13 @@ class AddSendViewModel @Inject constructor( action: AddSendAction.Internal.CreateSendResultReceive, ) { when (val result = action.result) { - CreateSendResult.Error -> { + is CreateSendResult.Error -> { mutableStateFlow.update { it.copy( dialogState = AddSendState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), - message = R.string.generic_error_message.asText(), + message = result.message?.asText() + ?: R.string.generic_error_message.asText(), ), ) } diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseSendUtil.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseSendUtil.kt index 5cec0df8a..eb529c39a 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseSendUtil.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseSendUtil.kt @@ -2,6 +2,13 @@ package com.x8bit.bitwarden.data.vault.datasource.network.model import java.time.ZonedDateTime +fun createMockFileSendResponseJson(number: Int, type: SendTypeJson = SendTypeJson.FILE) = + CreateFileSendResponseJson( + url = "www.test.com", + fileUploadType = FileUploadType.AZURE, + sendResponse = createMockSend(number = number, type = type), + ) + fun createMockSend( number: Int, type: SendTypeJson = SendTypeJson.FILE, diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceTest.kt index e20306624..3fdd73e51 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/SendsServiceTest.kt @@ -4,10 +4,11 @@ import android.net.Uri import com.x8bit.bitwarden.data.platform.base.BaseServiceTest import com.x8bit.bitwarden.data.vault.datasource.network.api.AzureApi import com.x8bit.bitwarden.data.vault.datasource.network.api.SendsApi -import com.x8bit.bitwarden.data.vault.datasource.network.model.FileUploadType -import com.x8bit.bitwarden.data.vault.datasource.network.model.SendFileResponseJson +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponse +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateSendJsonResponse import com.x8bit.bitwarden.data.vault.datasource.network.model.SendTypeJson import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateSendResponseJson +import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockFileSendResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockSend import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockSendJsonRequest import io.mockk.every @@ -52,16 +53,18 @@ class SendsServiceTest : BaseServiceTest() { @Test fun `createFileSend should return the correct response`() = runTest { - val response = SendFileResponseJson( - url = "www.test.com", - fileUploadType = FileUploadType.AZURE, - sendResponse = createMockSend(number = 1, type = SendTypeJson.FILE), + val sendFileResponse = CreateFileSendResponse.Success( + createFileJsonResponse = createMockFileSendResponseJson(number = 1), ) server.enqueue(MockResponse().setBody(CREATE_FILE_SEND_SUCCESS_JSON)) val result = sendsService.createFileSend( body = createMockSendJsonRequest(number = 1, type = SendTypeJson.FILE), ) - assertEquals(response, result.getOrThrow()) + + assertEquals( + sendFileResponse, + result.getOrThrow(), + ) } @Test @@ -71,7 +74,7 @@ class SendsServiceTest : BaseServiceTest() { body = createMockSendJsonRequest(number = 1, type = SendTypeJson.TEXT), ) assertEquals( - createMockSend(number = 1), + CreateSendJsonResponse.Success(createMockSend(number = 1)), result.getOrThrow(), ) } @@ -113,13 +116,9 @@ class SendsServiceTest : BaseServiceTest() { fun `uploadFile with Azure uploadFile success should return send`() = runTest { val url = "www.test.com" setupMockUri(url = url, queryParams = mapOf("sv" to "2024-04-03")) - val mockSend = createMockSend(number = 1, type = SendTypeJson.FILE) - val sendFileResponse = SendFileResponseJson( - url = url, - fileUploadType = FileUploadType.AZURE, - sendResponse = mockSend, - ) + val sendFileResponse = createMockFileSendResponseJson(number = 1) val encryptedFile = byteArrayOf() + server.enqueue(MockResponse().setResponseCode(201)) val result = sendsService.uploadFile( @@ -127,17 +126,14 @@ class SendsServiceTest : BaseServiceTest() { encryptedFile = encryptedFile, ) - assertEquals(mockSend, result.getOrThrow()) + assertEquals(sendFileResponse.sendResponse, result.getOrThrow()) } @Test fun `uploadFile with Direct uploadFile success should return send`() = runTest { - val mockSend = createMockSend(number = 1, type = SendTypeJson.FILE) - val sendFileResponse = SendFileResponseJson( - url = "www.test.com", - fileUploadType = FileUploadType.DIRECT, - sendResponse = mockSend, - ) + val url = "www.test.com" + setupMockUri(url = url, queryParams = mapOf("sv" to "2024-04-03")) + val sendFileResponse = createMockFileSendResponseJson(number = 1) val encryptedFile = byteArrayOf() server.enqueue(MockResponse().setResponseCode(201)) @@ -146,7 +142,7 @@ class SendsServiceTest : BaseServiceTest() { encryptedFile = encryptedFile, ) - assertEquals(mockSend, result.getOrThrow()) + assertEquals(sendFileResponse.sendResponse, result.getOrThrow()) } @Test diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt index 847df88c1..31ea74484 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt @@ -39,9 +39,9 @@ import com.x8bit.bitwarden.data.platform.util.asSuccess import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateCipherInOrganizationJsonRequest -import com.x8bit.bitwarden.data.vault.datasource.network.model.FileUploadType +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateFileSendResponse +import com.x8bit.bitwarden.data.vault.datasource.network.model.CreateSendJsonResponse import com.x8bit.bitwarden.data.vault.datasource.network.model.FolderJsonRequest -import com.x8bit.bitwarden.data.vault.datasource.network.model.SendFileResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.SendTypeJson import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson @@ -55,6 +55,7 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipher import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipherJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCollection import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockDomains +import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockFileSendResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockFolder import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganizationKeys @@ -2430,7 +2431,7 @@ class VaultRepositoryTest { ) assertEquals( - CreateSendResult.Error, + CreateSendResult.Error(message = null), result, ) } @@ -2447,7 +2448,7 @@ class VaultRepositoryTest { val result = vaultRepository.createSend(sendView = mockSendView, fileUri = null) - assertEquals(CreateSendResult.Error, result) + assertEquals(CreateSendResult.Error(message = null), result) } @Test @@ -2469,7 +2470,7 @@ class VaultRepositoryTest { val result = vaultRepository.createSend(sendView = mockSendView, fileUri = null) - assertEquals(CreateSendResult.Error, result) + assertEquals(CreateSendResult.Error(IllegalStateException().message), result) } @Suppress("MaxLineLength") @@ -2482,6 +2483,7 @@ class VaultRepositoryTest { val mockSdkSend = createMockSdkSend(number = 1, type = SendType.TEXT) val mockSend = createMockSend(number = 1, type = SendTypeJson.TEXT) val mockSendViewResult = createMockSendView(number = 2) + val sendTextResponse = CreateSendJsonResponse.Success(send = mockSend) coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() @@ -2490,7 +2492,7 @@ class VaultRepositoryTest { body = createMockSendJsonRequest(number = 1, type = SendTypeJson.TEXT) .copy(fileLength = null), ) - } returns mockSend.asSuccess() + } returns sendTextResponse.asSuccess() coEvery { vaultDiskSource.saveSend(userId, mockSend) } just runs coEvery { vaultSdkSource.decryptSend(userId, mockSdkSend) @@ -2529,7 +2531,7 @@ class VaultRepositoryTest { val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri) - assertEquals(CreateSendResult.Error, result) + assertEquals(CreateSendResult.Error(IllegalStateException().message), result) } @Test @@ -2544,14 +2546,18 @@ class VaultRepositoryTest { val mockSdkSend = createMockSdkSend(number = 1) val byteArray = byteArrayOf(1) val encryptedByteArray = byteArrayOf(2) - val sendFileResponse = SendFileResponseJson( - url = url, - fileUploadType = FileUploadType.AZURE, - sendResponse = createMockSend(number = 1, type = SendTypeJson.FILE), + val sendFileResponse = CreateFileSendResponse.Success( + createMockFileSendResponseJson( + number = 1, + type = SendTypeJson.FILE, + ), ) coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() + coEvery { + vaultSdkSource.decryptSend(userId, mockSdkSend) + } returns mockSendView.asSuccess() coEvery { fileManager.uriToByteArray(any()) } returns byteArray.asSuccess() coEvery { vaultSdkSource.encryptBuffer( @@ -2560,19 +2566,25 @@ class VaultRepositoryTest { fileBuffer = byteArray, ) } returns encryptedByteArray.asSuccess() + coEvery { + vaultDiskSource.saveSend( + userId, + sendFileResponse.createFileJsonResponse.sendResponse, + ) + } just runs coEvery { sendsService.createFileSend(body = createMockSendJsonRequest(number = 1)) } returns sendFileResponse.asSuccess() coEvery { sendsService.uploadFile( - sendFileResponse = sendFileResponse, + sendFileResponse = sendFileResponse.createFileJsonResponse, encryptedFile = encryptedByteArray, ) - } returns Throwable("Fail").asFailure() + } returns Throwable().asFailure() val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri) - assertEquals(CreateSendResult.Error, result) + assertEquals(CreateSendResult.Error(null), result) } @Test @@ -2588,11 +2600,11 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() - coEvery { fileManager.uriToByteArray(any()) } returns Throwable("Fail").asFailure() + coEvery { fileManager.uriToByteArray(any()) } returns Throwable().asFailure() val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri) - assertEquals(CreateSendResult.Error, result) + assertEquals(CreateSendResult.Error(message = null), result) } @Test @@ -2607,11 +2619,8 @@ class VaultRepositoryTest { val mockSdkSend = createMockSdkSend(number = 1) val byteArray = byteArrayOf(1) val encryptedByteArray = byteArrayOf(2) - val sendResponse = createMockSend(number = 1) - val sendFileResponse = SendFileResponseJson( - url = url, - fileUploadType = FileUploadType.AZURE, - sendResponse = sendResponse, + val sendFileResponse = CreateFileSendResponse.Success( + createMockFileSendResponseJson(number = 1), ) val mockSendViewResult = createMockSendView(number = 1) coEvery { @@ -2630,11 +2639,16 @@ class VaultRepositoryTest { } returns sendFileResponse.asSuccess() coEvery { sendsService.uploadFile( - sendFileResponse = sendFileResponse, + sendFileResponse = sendFileResponse.createFileJsonResponse, encryptedFile = encryptedByteArray, ) - } returns sendResponse.asSuccess() - coEvery { vaultDiskSource.saveSend(userId, sendResponse) } just runs + } returns sendFileResponse.createFileJsonResponse.sendResponse.asSuccess() + coEvery { + vaultDiskSource.saveSend( + userId, + sendFileResponse.createFileJsonResponse.sendResponse, + ) + } just runs coEvery { vaultSdkSource.decryptSend(userId, mockSdkSend) } returns mockSendViewResult.asSuccess() diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt index 43d8ce96d..2a60c67c1 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt @@ -259,7 +259,7 @@ class AddSendViewModelTest : BaseViewModelTest() { every { viewState.toSendView(clock) } returns mockSendView coEvery { vaultRepository.createSend(sendView = mockSendView, fileUri = null) - } returns CreateSendResult.Error + } returns CreateSendResult.Error("Fail") val viewModel = createViewModel(initialState) viewModel.stateFlow.test { @@ -277,7 +277,7 @@ class AddSendViewModelTest : BaseViewModelTest() { initialState.copy( dialogState = AddSendState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), - message = R.string.generic_error_message.asText(), + message = "Fail".asText(), ), ), awaitItem(),