From 26b7d4b4dcf2b50b64a3979e6211094a7a5d63d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BBerko?= Date: Tue, 10 Dec 2024 11:34:56 +0100 Subject: [PATCH 1/8] feat: user folders [WPB-14442] (#3147) * feat: user folders * detekt fix * removed duplicated sq query * fix: favorite folder error handling, non paginatated conversations from folder * tests fix --- .../data/conversation/ConversationFilter.kt | 23 ++++++++-- .../data/conversation/ConversationFolder.kt | 9 ++-- .../data/conversation/ConversationMapper.kt | 17 +++---- .../conversation/ConversationRepository.kt | 4 +- .../ConversationRepositoryExtensions.kt | 2 +- .../folders/ConversationFolderRepository.kt | 10 +++- .../feature/conversation/ConversationScope.kt | 4 ++ ...rsationListDetailsWithEventsUseCaseImpl.kt | 24 +++++++--- .../ObserveConversationsFromFolderUseCase.kt | 10 ++-- .../folder/ObserveUserFoldersUseCase.kt | 46 +++++++++++++++++++ .../kalium/persistence/ConversationFolders.sq | 10 ++-- .../folder/ConversationFolderDAO.kt | 3 +- .../folder/ConversationFolderDAOImpl.kt | 20 +++++++- .../folder/ConversationFolderDAOTest.kt | 8 ++-- 14 files changed, 151 insertions(+), 39 deletions(-) create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveUserFoldersUseCase.kt diff --git a/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFilter.kt b/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFilter.kt index f1ca2a7bf39..a76fac75ca0 100644 --- a/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFilter.kt +++ b/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFilter.kt @@ -17,9 +17,22 @@ */ package com.wire.kalium.logic.data.conversation -enum class ConversationFilter { - ALL, - FAVORITES, - GROUPS, - ONE_ON_ONE +import kotlinx.serialization.Serializable + +@Serializable +sealed class ConversationFilter { + @Serializable + data object All : ConversationFilter() + + @Serializable + data object Favorites : ConversationFilter() + + @Serializable + data object Groups : ConversationFilter() + + @Serializable + data object OneOnOne : ConversationFilter() + + @Serializable + data class Folder(val folderName: String, val folderId: String) : ConversationFilter() } diff --git a/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFolder.kt b/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFolder.kt index 675e9f5794f..cf64352dd3d 100644 --- a/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFolder.kt +++ b/data/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationFolder.kt @@ -18,11 +18,14 @@ package com.wire.kalium.logic.data.conversation import com.wire.kalium.logic.data.id.QualifiedID +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +@Serializable data class ConversationFolder( - val id: String, - val name: String, - val type: FolderType + @SerialName("id") val id: String, + @SerialName("name") val name: String, + @SerialName("folder_type") val type: FolderType ) data class FolderWithConversations( diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapper.kt index cc2d9995a75..6382559ee23 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapper.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapper.kt @@ -676,15 +676,16 @@ internal fun ConversationEntity.VerificationStatus.toModel(): Conversation.Verif } internal fun ConversationFilter.toDao(): ConversationFilterEntity = when (this) { - ConversationFilter.ALL -> ConversationFilterEntity.ALL - ConversationFilter.FAVORITES -> ConversationFilterEntity.FAVORITES - ConversationFilter.GROUPS -> ConversationFilterEntity.GROUPS - ConversationFilter.ONE_ON_ONE -> ConversationFilterEntity.ONE_ON_ONE + ConversationFilter.All -> ConversationFilterEntity.ALL + ConversationFilter.Favorites -> ConversationFilterEntity.FAVORITES + ConversationFilter.Groups -> ConversationFilterEntity.GROUPS + ConversationFilter.OneOnOne -> ConversationFilterEntity.ONE_ON_ONE + is ConversationFilter.Folder -> ConversationFilterEntity.ALL // TODO think how to secure that } internal fun ConversationFilterEntity.toModel(): ConversationFilter = when (this) { - ConversationFilterEntity.ALL -> ConversationFilter.ALL - ConversationFilterEntity.FAVORITES -> ConversationFilter.FAVORITES - ConversationFilterEntity.GROUPS -> ConversationFilter.GROUPS - ConversationFilterEntity.ONE_ON_ONE -> ConversationFilter.ONE_ON_ONE + ConversationFilterEntity.ALL -> ConversationFilter.All + ConversationFilterEntity.FAVORITES -> ConversationFilter.Favorites + ConversationFilterEntity.GROUPS -> ConversationFilter.Groups + ConversationFilterEntity.ONE_ON_ONE -> ConversationFilter.OneOnOne } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt index f199fe862f7..2508b24762a 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt @@ -132,12 +132,12 @@ interface ConversationRepository { suspend fun observeConversationList(): Flow> suspend fun observeConversationListDetails( fromArchive: Boolean, - conversationFilter: ConversationFilter = ConversationFilter.ALL + conversationFilter: ConversationFilter = ConversationFilter.All ): Flow> suspend fun observeConversationListDetailsWithEvents( fromArchive: Boolean = false, - conversationFilter: ConversationFilter = ConversationFilter.ALL + conversationFilter: ConversationFilter = ConversationFilter.All ): Flow> suspend fun getConversationIds( diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryExtensions.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryExtensions.kt index aec18932a97..c41464ea225 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryExtensions.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryExtensions.kt @@ -73,5 +73,5 @@ data class ConversationQueryConfig( val fromArchive: Boolean = false, val onlyInteractionEnabled: Boolean = false, val newActivitiesOnTop: Boolean = false, - val conversationFilter: ConversationFilter = ConversationFilter.ALL, + val conversationFilter: ConversationFilter = ConversationFilter.All, ) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/folders/ConversationFolderRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/folders/ConversationFolderRepository.kt index 70ad373bdfa..5db72788cbd 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/folders/ConversationFolderRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/folders/ConversationFolderRepository.kt @@ -34,6 +34,7 @@ import com.wire.kalium.logic.functional.Either import com.wire.kalium.logic.functional.flatMap import com.wire.kalium.logic.functional.flatMapLeft import com.wire.kalium.logic.functional.map +import com.wire.kalium.logic.functional.mapRight import com.wire.kalium.logic.functional.onFailure import com.wire.kalium.logic.functional.onSuccess import com.wire.kalium.logic.kaliumLogger @@ -57,6 +58,7 @@ internal interface ConversationFolderRepository { suspend fun addConversationToFolder(conversationId: QualifiedID, folderId: String): Either suspend fun removeConversationFromFolder(conversationId: QualifiedID, folderId: String): Either suspend fun syncConversationFoldersFromLocal(): Either + suspend fun observeUserFolders(): Flow>> } internal class ConversationFolderDataSource internal constructor( @@ -72,7 +74,7 @@ internal class ConversationFolderDataSource internal constructor( } override suspend fun getFavoriteConversationFolder(): Either = wrapStorageRequest { - conversationFolderDAO.getFavoriteConversationFolder().toModel() + conversationFolderDAO.getFavoriteConversationFolder()?.toModel() } override suspend fun observeConversationsFromFolder(folderId: String): Flow> = @@ -152,4 +154,10 @@ internal class ConversationFolderDataSource internal constructor( } } } + + override suspend fun observeUserFolders(): Flow>> { + return conversationFolderDAO.observeUserFolders() + .wrapStorageRequest() + .mapRight { folderEntities -> folderEntities.map { it.toModel() } } + } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt index 0f3be756ff3..bc65552ad2d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt @@ -55,6 +55,8 @@ import com.wire.kalium.logic.feature.conversation.folder.GetFavoriteFolderUseCas import com.wire.kalium.logic.feature.conversation.folder.GetFavoriteFolderUseCaseImpl import com.wire.kalium.logic.feature.conversation.folder.ObserveConversationsFromFolderUseCase import com.wire.kalium.logic.feature.conversation.folder.ObserveConversationsFromFolderUseCaseImpl +import com.wire.kalium.logic.feature.conversation.folder.ObserveUserFoldersUseCase +import com.wire.kalium.logic.feature.conversation.folder.ObserveUserFoldersUseCaseImpl import com.wire.kalium.logic.feature.conversation.folder.RemoveConversationFromFavoritesUseCase import com.wire.kalium.logic.feature.conversation.folder.RemoveConversationFromFavoritesUseCaseImpl import com.wire.kalium.logic.feature.conversation.guestroomlink.CanCreatePasswordProtectedLinksUseCase @@ -361,4 +363,6 @@ class ConversationScope internal constructor( get() = AddConversationToFavoritesUseCaseImpl(conversationFolderRepository) val removeConversationFromFavorites: RemoveConversationFromFavoritesUseCase get() = RemoveConversationFromFavoritesUseCaseImpl(conversationFolderRepository) + val observeUserFolders: ObserveUserFoldersUseCase + get() = ObserveUserFoldersUseCaseImpl(conversationFolderRepository) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ObserveConversationListDetailsWithEventsUseCaseImpl.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ObserveConversationListDetailsWithEventsUseCaseImpl.kt index 4f7f9529f61..5a3b59405e8 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ObserveConversationListDetailsWithEventsUseCaseImpl.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ObserveConversationListDetailsWithEventsUseCaseImpl.kt @@ -45,16 +45,26 @@ internal class ObserveConversationListDetailsWithEventsUseCaseImpl( fromArchive: Boolean, conversationFilter: ConversationFilter ): Flow> { - return if (conversationFilter == ConversationFilter.FAVORITES) { - when (val result = getFavoriteFolder()) { - GetFavoriteFolderUseCase.Result.Failure -> { - flowOf(emptyList()) + return when (conversationFilter) { + ConversationFilter.Favorites -> { + when (val result = getFavoriteFolder()) { + GetFavoriteFolderUseCase.Result.Failure -> { + flowOf(emptyList()) + } + + is GetFavoriteFolderUseCase.Result.Success -> + conversationFolderRepository.observeConversationsFromFolder(result.folder.id) } + } - is GetFavoriteFolderUseCase.Result.Success -> conversationFolderRepository.observeConversationsFromFolder(result.folder.id) + is ConversationFilter.Folder -> { + conversationFolderRepository.observeConversationsFromFolder(conversationFilter.folderId) } - } else { - conversationRepository.observeConversationListDetailsWithEvents(fromArchive, conversationFilter) + + ConversationFilter.All, + ConversationFilter.Groups, + ConversationFilter.OneOnOne -> + conversationRepository.observeConversationListDetailsWithEvents(fromArchive, conversationFilter) } } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveConversationsFromFolderUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveConversationsFromFolderUseCase.kt index b0ffa60fa93..549b951c5fc 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveConversationsFromFolderUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveConversationsFromFolderUseCase.kt @@ -19,7 +19,10 @@ package com.wire.kalium.logic.feature.conversation.folder import com.wire.kalium.logic.data.conversation.ConversationDetailsWithEvents import com.wire.kalium.logic.data.conversation.folders.ConversationFolderRepository +import com.wire.kalium.util.KaliumDispatcher +import com.wire.kalium.util.KaliumDispatcherImpl import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn /** * This use case will observe and return the list of conversations from given folder. @@ -31,9 +34,10 @@ fun interface ObserveConversationsFromFolderUseCase { internal class ObserveConversationsFromFolderUseCaseImpl( private val conversationFolderRepository: ConversationFolderRepository, + private val dispatchers: KaliumDispatcher = KaliumDispatcherImpl ) : ObserveConversationsFromFolderUseCase { - override suspend operator fun invoke(folderId: String): Flow> { - return conversationFolderRepository.observeConversationsFromFolder(folderId) - } + override suspend operator fun invoke(folderId: String): Flow> = + conversationFolderRepository.observeConversationsFromFolder(folderId) + .flowOn(dispatchers.io) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveUserFoldersUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveUserFoldersUseCase.kt new file mode 100644 index 00000000000..3935cd2af28 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/ObserveUserFoldersUseCase.kt @@ -0,0 +1,46 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.conversation.folder + +import com.wire.kalium.logic.data.conversation.ConversationFolder +import com.wire.kalium.logic.data.conversation.folders.ConversationFolderRepository +import com.wire.kalium.logic.functional.mapToRightOr +import com.wire.kalium.util.KaliumDispatcher +import com.wire.kalium.util.KaliumDispatcherImpl +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn + +/** + * This use case will observe and return the list of all user folders. + * @see ConversationFolder + */ +fun interface ObserveUserFoldersUseCase { + suspend operator fun invoke(): Flow> +} + +internal class ObserveUserFoldersUseCaseImpl( + private val conversationFolderRepository: ConversationFolderRepository, + private val dispatchers: KaliumDispatcher = KaliumDispatcherImpl +) : ObserveUserFoldersUseCase { + + override suspend operator fun invoke(): Flow> { + return conversationFolderRepository.observeUserFolders() + .mapToRightOr(emptyList()) + .flowOn(dispatchers.io) + } +} diff --git a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationFolders.sq b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationFolders.sq index db44a482e77..38d2c6db4bf 100644 --- a/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationFolders.sq +++ b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationFolders.sq @@ -17,6 +17,10 @@ CREATE TABLE LabeledConversation ( PRIMARY KEY (folder_id, conversation_id) ); +getUserFolders: +SELECT * FROM ConversationFolder +WHERE folder_type != 'FAVORITE'; + getAllFoldersWithConversations: SELECT conversationFolder.id AS label_id, @@ -60,8 +64,8 @@ VALUES(?, ?); deleteLabeledConversation: DELETE FROM LabeledConversation WHERE conversation_id = ? AND folder_id = ?; -clearFolders: -DELETE FROM ConversationFolder; - clearLabeledConversations: DELETE FROM LabeledConversation; + +clearFolders: +DELETE FROM ConversationFolder; diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAO.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAO.kt index ed1ae82a9f8..0c201de5b8d 100644 --- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAO.kt +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAO.kt @@ -24,8 +24,9 @@ import kotlinx.coroutines.flow.Flow interface ConversationFolderDAO { suspend fun getFoldersWithConversations(): List suspend fun observeConversationListFromFolder(folderId: String): Flow> - suspend fun getFavoriteConversationFolder(): ConversationFolderEntity + suspend fun getFavoriteConversationFolder(): ConversationFolderEntity? suspend fun updateConversationFolders(folderWithConversationsList: List) suspend fun addConversationToFolder(conversationId: QualifiedIDEntity, folderId: String) suspend fun removeConversationFromFolder(conversationId: QualifiedIDEntity, folderId: String) + suspend fun observeUserFolders(): Flow> } diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOImpl.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOImpl.kt index 3316f030bd9..6e703b82419 100644 --- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOImpl.kt +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOImpl.kt @@ -18,6 +18,7 @@ package com.wire.kalium.persistence.dao.conversation.folder import app.cash.sqldelight.coroutines.asFlow +import com.wire.kalium.persistence.ConversationFolder import com.wire.kalium.persistence.ConversationFoldersQueries import com.wire.kalium.persistence.GetAllFoldersWithConversations import com.wire.kalium.persistence.dao.QualifiedIDEntity @@ -26,6 +27,7 @@ import com.wire.kalium.persistence.dao.conversation.ConversationDetailsWithEvent import com.wire.kalium.persistence.util.mapToList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext import kotlin.coroutines.CoroutineContext @@ -35,6 +37,14 @@ class ConversationFolderDAOImpl internal constructor( ) : ConversationFolderDAO { private val conversationDetailsWithEventsMapper = ConversationDetailsWithEventsMapper + override suspend fun observeUserFolders(): Flow> { + return conversationFoldersQueries.getUserFolders() + .asFlow() + .mapToList() + .map { it.map(::toEntity) } + .flowOn(coroutineContext) + } + override suspend fun getFoldersWithConversations(): List = withContext(coroutineContext) { val labeledConversationList = conversationFoldersQueries.getAllFoldersWithConversations().executeAsList().map(::toEntity) @@ -59,6 +69,12 @@ class ConversationFolderDAOImpl internal constructor( conversationId = row.conversation_id ) + private fun toEntity(row: ConversationFolder) = ConversationFolderEntity( + id = row.id, + name = row.name, + type = row.folder_type + ) + override suspend fun observeConversationListFromFolder(folderId: String): Flow> { return conversationFoldersQueries.getConversationsFromFolder( folderId, @@ -69,11 +85,11 @@ class ConversationFolderDAOImpl internal constructor( .flowOn(coroutineContext) } - override suspend fun getFavoriteConversationFolder(): ConversationFolderEntity { + override suspend fun getFavoriteConversationFolder(): ConversationFolderEntity? { return conversationFoldersQueries.getFavoriteFolder { id, name, folderType -> ConversationFolderEntity(id, name, folderType) } - .executeAsOne() + .executeAsOneOrNull() } override suspend fun updateConversationFolders(folderWithConversationsList: List) = diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOTest.kt b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOTest.kt index c55255dd733..d533ccc6dec 100644 --- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOTest.kt +++ b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/conversation/folder/ConversationFolderDAOTest.kt @@ -59,7 +59,8 @@ class ConversationFolderDAOTest : BaseDatabaseTest() { id = folderId, name = "folderName", type = ConversationFolderTypeEntity.USER, - conversationIdList = listOf(conversationEntity1.id)) + conversationIdList = listOf(conversationEntity1.id) + ) db.conversationFolderDAO.updateConversationFolders(listOf(conversationFolderEntity)) val result = db.conversationFolderDAO.observeConversationListFromFolder(folderId).first().first() @@ -79,12 +80,13 @@ class ConversationFolderDAOTest : BaseDatabaseTest() { id = folderId, name = "", type = ConversationFolderTypeEntity.FAVORITE, - conversationIdList = listOf(conversationEntity1.id)) + conversationIdList = listOf(conversationEntity1.id) + ) db.conversationFolderDAO.updateConversationFolders(listOf(conversationFolderEntity)) val result = db.conversationFolderDAO.getFavoriteConversationFolder() - assertEquals(folderId, result.id) + assertEquals(folderId, result?.id) } @Test From abcd037802987a6964464b7c0e96eac6e512bd4f Mon Sep 17 00:00:00 2001 From: Oussama Hassine Date: Wed, 11 Dec 2024 12:04:16 +0100 Subject: [PATCH 2/8] feat: add usecase to get team url (WPB-14872) (#3157) * feat: add usecase to get team url * feat:detekt * feat: detekt * feat: detekt --- .../server/ServerConfigRepository.kt | 3 ++ .../kalium/logic/feature/UserSessionScope.kt | 8 +++++ .../logic/feature/server/GetTeamUrlUseCase.kt | 31 +++++++++++++++++++ .../kalium/persistence/ServerConfiguration.sq | 3 ++ .../daokaliumdb/ServerConfigurationDAO.kt | 7 +++++ 5 files changed, 52 insertions(+) create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/GetTeamUrlUseCase.kt diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/ServerConfigRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/ServerConfigRepository.kt index 4fd77d402b4..a09c8241f17 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/ServerConfigRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/ServerConfigRepository.kt @@ -66,6 +66,7 @@ interface ServerConfigRepository { */ suspend fun configForUser(userId: UserId): Either suspend fun commonApiVersion(domain: String): Either + suspend fun getTeamUrlForUser(userId: UserId): String? } @Suppress("LongParameterList", "TooManyFunctions") @@ -165,4 +166,6 @@ internal class ServerConfigDataSource( is ApiVersionDTO.Valid -> Either.Right(it) } }.map { serverConfigMapper.fromDTO(it) } + + override suspend fun getTeamUrlForUser(userId: UserId): String? = dao.teamUrlForUser(userId.toDao()) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 543d5f9030c..3b40fb7cab4 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -291,6 +291,7 @@ import com.wire.kalium.logic.feature.selfDeletingMessages.ObserveSelfDeletionTim import com.wire.kalium.logic.feature.selfDeletingMessages.ObserveTeamSettingsSelfDeletingStatusUseCase import com.wire.kalium.logic.feature.selfDeletingMessages.ObserveTeamSettingsSelfDeletingStatusUseCaseImpl import com.wire.kalium.logic.feature.selfDeletingMessages.PersistNewSelfDeletionTimerUseCaseImpl +import com.wire.kalium.logic.feature.server.GetTeamUrlUseCase import com.wire.kalium.logic.feature.service.ServiceScope import com.wire.kalium.logic.feature.session.GetProxyCredentialsUseCase import com.wire.kalium.logic.feature.session.GetProxyCredentialsUseCaseImpl @@ -2144,6 +2145,13 @@ class UserSessionScope internal constructor( kaliumLogger = userScopedLogger, ) + val getTeamUrlUseCase: GetTeamUrlUseCase by lazy { + GetTeamUrlUseCase( + userId, + authenticationScope.serverConfigRepository, + ) + } + /** * This will start subscribers of observable work per user session, as long as the user is logged in. * When the user logs out, this work will be canceled. diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/GetTeamUrlUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/GetTeamUrlUseCase.kt new file mode 100644 index 00000000000..fc11e34b573 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/GetTeamUrlUseCase.kt @@ -0,0 +1,31 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.server + +import com.wire.kalium.logic.configuration.server.ServerConfigRepository +import com.wire.kalium.logic.data.user.UserId + +/** + * Use case to get the team url for the current user. + */ +class GetTeamUrlUseCase internal constructor( + private val selfUserId: UserId, + private val serverConfigRepository: ServerConfigRepository +) { + suspend operator fun invoke(): String = serverConfigRepository.getTeamUrlForUser(selfUserId) ?: "" +} diff --git a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq index 4fa81bcab28..dfcd7807ffd 100644 --- a/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq +++ b/persistence/src/commonMain/db_global/com/wire/kalium/persistence/ServerConfiguration.sq @@ -56,6 +56,9 @@ SELECT * FROM ServerConfiguration WHERE title = ? AND apiBaseUrl = ? AND webSock getByUser: SELECT * FROM ServerConfiguration WHERE id = (SELECT server_config_id FROM Accounts WHERE id = :userId); +getTeamUrlByUser: +SELECT teamsUrl FROM ServerConfiguration WHERE id = (SELECT server_config_id FROM Accounts WHERE id = :userId); + getServerConfigsWithAccIdWithLastCheckBeforeDate: SELECT sc.*, acc.id FROM Accounts AS acc LEFT JOIN ServerConfiguration AS sc ON acc.server_config_id == sc.id diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAO.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAO.kt index 04c83e96f77..00b56040372 100644 --- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAO.kt +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAO.kt @@ -118,6 +118,7 @@ internal object ServerConfigMapper { ) } +@Suppress("TooManyFunctions") interface ServerConfigurationDAO { suspend fun deleteById(id: String) suspend fun insert(insertData: InsertData) @@ -129,6 +130,7 @@ interface ServerConfigurationDAO { suspend fun updateServerMetaData(id: String, federation: Boolean, commonApiVersion: Int) suspend fun updateApiVersionAndDomain(id: String, domain: String, commonApiVersion: Int) suspend fun configForUser(userId: UserIDEntity): ServerConfigEntity? + suspend fun teamUrlForUser(userId: UserIDEntity): String? suspend fun setFederationToTrue(id: String) suspend fun getServerConfigsWithAccIdWithLastCheckBeforeDate(date: String): Flow> suspend fun updateBlackListCheckDate(configIds: Set, date: String) @@ -152,6 +154,7 @@ interface ServerConfigurationDAO { ) } +@Suppress("TooManyFunctions") internal class ServerConfigurationDAOImpl internal constructor( private val queries: ServerConfigurationQueries, private val queriesContext: CoroutineContext, @@ -240,4 +243,8 @@ internal class ServerConfigurationDAOImpl internal constructor( override suspend fun updateBlackListCheckDate(configIds: Set, date: String) = withContext(queriesContext) { queries.updateLastBlackListCheckByIds(date, configIds) } + + override suspend fun teamUrlForUser(userId: UserIDEntity): String? = withContext(queriesContext) { + queries.getTeamUrlByUser(userId).executeAsOneOrNull() + } } From 0667f9b780a8262768b0c37af3d49d4f83c55701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= <30429749+saleniuk@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:59:42 +0100 Subject: [PATCH 3/8] feat: use case to change cipher_profile [WPB-14826] (#3163) * feat: use case to change cipher_profile [WPB-14826] * change cipher_profile value to be platform specific * fix detekt --- .../kalium/logic/feature/UserSessionScope.kt | 1 + .../feature/debug/ChangeProfilingUseCase.kt | 32 +++++++++++++++++++ .../kalium/logic/feature/debug/DebugScope.kt | 4 +++ .../kalium/persistence/db/UserDatabase.kt | 9 +++++- .../persistence/db/UserDatabaseBuilder.kt | 23 ++++++++++++- 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 3b40fb7cab4..80a977d714e 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -1831,6 +1831,7 @@ class UserSessionScope internal constructor( legalHoldHandler, notificationTokenRepository, this, + userStorage, userScopedLogger, ) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt new file mode 100644 index 00000000000..83588fea472 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt @@ -0,0 +1,32 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.debug + +import com.wire.kalium.logic.di.UserStorage + +class ChangeProfilingUseCase( + private val userStorage: UserStorage, +) { + /** + * Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted + * @param enabled true to enable profiling, false to disable + */ + operator fun invoke(enabled: Boolean) { + userStorage.database.changeProfiling(enabled) + } +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/DebugScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/DebugScope.kt index 92d7176faaf..34b31cdf4b7 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/DebugScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/DebugScope.kt @@ -40,6 +40,7 @@ import com.wire.kalium.logic.data.prekey.PreKeyRepository import com.wire.kalium.logic.data.sync.SlowSyncRepository import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.data.user.UserRepository +import com.wire.kalium.logic.di.UserStorage import com.wire.kalium.logic.feature.message.MLSMessageCreator import com.wire.kalium.logic.feature.message.MLSMessageCreatorImpl import com.wire.kalium.logic.feature.message.MessageEnvelopeCreator @@ -92,6 +93,7 @@ class DebugScope internal constructor( private val legalHoldHandler: LegalHoldHandler, private val notificationTokenRepository: NotificationTokenRepository, private val scope: CoroutineScope, + userStorage: UserStorage, logger: KaliumLogger, internal val dispatcher: KaliumDispatcher = KaliumDispatcherImpl, ) { @@ -224,4 +226,6 @@ class DebugScope internal constructor( clientRepository, notificationTokenRepository, ) + + val changeProfiling: ChangeProfilingUseCase = ChangeProfilingUseCase(userStorage) } diff --git a/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt b/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt index 39f73fdb694..4491d1bf47c 100644 --- a/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt +++ b/persistence/src/androidMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt @@ -51,7 +51,14 @@ actual fun userDatabaseBuilder( ) { isWALEnabled = enableWAL } - return UserDatabaseBuilder(userId, driver, dispatcher, platformDatabaseData, isEncryptionEnabled) + return UserDatabaseBuilder( + userId = userId, + sqlDriver = driver, + dispatcher = dispatcher, + platformDatabaseData = platformDatabaseData, + isEncrypted = isEncryptionEnabled, + cipherProfile = "logcat", + ) } actual fun userDatabaseDriverByPath( diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt index 7c75ee447b6..fdf7c7bac9e 100644 --- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt @@ -112,13 +112,15 @@ internal expect fun userDatabaseDriverByPath( enableWAL: Boolean ): SqlDriver +@Suppress("LongParameterList") class UserDatabaseBuilder internal constructor( private val userId: UserIDEntity, internal val sqlDriver: SqlDriver, dispatcher: CoroutineDispatcher, private val platformDatabaseData: PlatformDatabaseData, private val isEncrypted: Boolean, - private val queriesContext: CoroutineContext = KaliumDispatcherImpl.io + private val queriesContext: CoroutineContext = KaliumDispatcherImpl.io, + private val cipherProfile: String? = null, ) { internal val database: UserDatabase = UserDatabase( @@ -316,6 +318,25 @@ class UserDatabaseBuilder internal constructor( */ fun dbFileLocation(): String? = getDatabaseAbsoluteFileLocation(platformDatabaseData, userId) + /** + * Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted + * @param enabled true to enable profiling, false to disable + */ + fun changeProfiling(enabled: Boolean) { + if (isEncrypted && cipherProfile != null) { + val cipherProfileValue = if (enabled) cipherProfile else "off" + sqlDriver.executeQuery( + identifier = null, + sql = "PRAGMA cipher_profile='$cipherProfileValue'", + mapper = { + it.next() + it.getLong(0).let { QueryResult.Value(it) } + }, + parameters = 0, + ) + } + } + /** * drops DB connection and delete the DB file */ From 5baff8ebe160a176b3871d2a059708a894a5f8c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 01:34:50 +0000 Subject: [PATCH 4/8] chore(deps): bump detekt from 1.23.6 to 1.23.7 (#3169) Bumps `detekt` from 1.23.6 to 1.23.7. Updates `io.gitlab.arturbosch.detekt:detekt-cli` from 1.23.6 to 1.23.7 - [Release notes](https://github.com/detekt/detekt/releases) - [Commits](https://github.com/detekt/detekt/compare/v1.23.6...v1.23.7) Updates `io.gitlab.arturbosch.detekt:detekt-api` from 1.23.6 to 1.23.7 - [Release notes](https://github.com/detekt/detekt/releases) - [Commits](https://github.com/detekt/detekt/compare/v1.23.6...v1.23.7) Updates `io.gitlab.arturbosch.detekt:detekt-test` from 1.23.6 to 1.23.7 - [Release notes](https://github.com/detekt/detekt/releases) - [Commits](https://github.com/detekt/detekt/compare/v1.23.6...v1.23.7) --- updated-dependencies: - dependency-name: io.gitlab.arturbosch.detekt:detekt-cli dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.gitlab.arturbosch.detekt:detekt-api dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.gitlab.arturbosch.detekt:detekt-test dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yamil Medina --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9060b93e117..b6746e68430 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,7 +44,7 @@ core-crypto-multiplatform = "0.6.0-rc.3-multiplatform-pre1" completeKotlin = "1.1.0" desugar-jdk = "2.0.4" kermit = "2.0.3" -detekt = "1.23.6" +detekt = "1.23.7" agp = "8.5.2" dokka = "1.8.20" carthage = "0.0.1" From 203d128ae4770543062035e46881ae4e9ceb4c95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:41:28 +0100 Subject: [PATCH 5/8] chore(deps): bump srvaroa/labeler from 1.8.2 to 1.12.0 (#3155) Bumps [srvaroa/labeler](https://github.com/srvaroa/labeler) from 1.8.2 to 1.12.0. - [Release notes](https://github.com/srvaroa/labeler/releases) - [Commits](https://github.com/srvaroa/labeler/compare/v1.8.2...v1.12.0) --- updated-dependencies: - dependency-name: srvaroa/labeler dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yamil Medina Co-authored-by: Vitor Hugo Schwaab --- .github/workflows/label-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml index 39c404a16ed..73ad05c39ab 100644 --- a/.github/workflows/label-pr.yml +++ b/.github/workflows/label-pr.yml @@ -9,6 +9,6 @@ jobs: name: Label PR based on title runs-on: ubuntu-latest steps: - - uses: srvaroa/labeler@v1.8.2 + - uses: srvaroa/labeler@v1.12.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From bafd544122633b521fe4b15f40a0d19688cb1590 Mon Sep 17 00:00:00 2001 From: boris Date: Fri, 13 Dec 2024 14:07:34 +0200 Subject: [PATCH 6/8] fix: Login to second device does not have MLS capabilities (#3164) Co-authored-by: Yamil Medina --- .../api/authenticated/conversation/ConversationResponse.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network-model/src/commonMain/kotlin/com/wire/kalium/network/api/authenticated/conversation/ConversationResponse.kt b/network-model/src/commonMain/kotlin/com/wire/kalium/network/api/authenticated/conversation/ConversationResponse.kt index 71452d4f8b8..1347c7f1110 100644 --- a/network-model/src/commonMain/kotlin/com/wire/kalium/network/api/authenticated/conversation/ConversationResponse.kt +++ b/network-model/src/commonMain/kotlin/com/wire/kalium/network/api/authenticated/conversation/ConversationResponse.kt @@ -114,7 +114,7 @@ data class ConversationResponse( @Serializable data class ConversationResponseV3( @SerialName("creator") - val creator: String, + val creator: String?, @SerialName("members") val members: ConversationMembersResponse, From 051e3eaf191bb5b9c4c1683750984191b7af8b2e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:49:30 +0000 Subject: [PATCH 7/8] chore: upgrade to cc3, fixes new_transaction in paralell (#3170) (#3171) Co-authored-by: Yamil Medina --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6746e68430..d99f1c21b15 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ pbandk = "0.14.2" turbine = "1.1.0" avs = "9.10.16" jna = "5.14.0" -core-crypto = "2.0.0" +core-crypto = "3.0.0" core-crypto-multiplatform = "0.6.0-rc.3-multiplatform-pre1" completeKotlin = "1.1.0" desugar-jdk = "2.0.4" From 5396afa48e4e3f639cbef60a73329a1294fcb665 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:49:38 +0000 Subject: [PATCH 8/8] test: add tests for old format parser in capabilities (#3173) (#3174) Co-authored-by: Yamil Medina --- .../api/v0/user/client/ClientApiV0Test.kt | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/client/ClientApiV0Test.kt b/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/client/ClientApiV0Test.kt index dd3280dde52..574ef891390 100644 --- a/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/client/ClientApiV0Test.kt +++ b/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/client/ClientApiV0Test.kt @@ -24,9 +24,9 @@ import com.wire.kalium.mocks.responses.ClientResponseJson import com.wire.kalium.mocks.responses.RegisterClientRequestJson import com.wire.kalium.mocks.responses.RegisterTokenJson import com.wire.kalium.mocks.responses.UpdateClientRequestJson -import com.wire.kalium.network.api.base.authenticated.client.ClientApi import com.wire.kalium.network.api.authenticated.client.ClientCapabilityDTO import com.wire.kalium.network.api.authenticated.client.UpdateClientCapabilitiesRequest +import com.wire.kalium.network.api.base.authenticated.client.ClientApi import com.wire.kalium.network.api.v0.authenticated.ClientApiV0 import com.wire.kalium.network.exceptions.KaliumException import com.wire.kalium.network.utils.NetworkResponse @@ -58,7 +58,26 @@ internal class ClientApiV0Test : ApiTest() { val clientApi: ClientApi = ClientApiV0(networkClient) val response = clientApi.registerClient(REGISTER_CLIENT_REQUEST.serializableData) assertTrue(response.isSuccessful()) - assertEquals(response.value, VALID_REGISTER_CLIENT_RESPONSE.serializableData) + assertEquals(VALID_REGISTER_CLIENT_RESPONSE.serializableData, response.value) + } + + @Test + fun givenAValidRegisterClientRequest_whenCallingTheRegisterClientEndpointWithOldFormat_theRequestShouldBeConfiguredCorrectly() = + runTest { + val networkClient = mockAuthenticatedNetworkClient( + VALID_REGISTER_CLIENT_OLD_RESPONSE.rawJson, + statusCode = HttpStatusCode.Created, + assertion = { + assertPost() + assertJson() + assertNoQueryParams() + assertPathEqual(PATH_CLIENTS) + } + ) + val clientApi: ClientApi = ClientApiV0(networkClient) + val response = clientApi.registerClient(REGISTER_CLIENT_REQUEST.serializableData) + assertTrue(response.isSuccessful()) + assertEquals(VALID_REGISTER_CLIENT_OLD_RESPONSE.serializableData, response.value) } @Test @@ -93,6 +112,7 @@ internal class ClientApiV0Test : ApiTest() { assertTrue(response.isSuccessful()) } + @Test fun givenAValidUpdateClientCapabilitiesRequest_whenCallingTheUpdateClientEndpoint_theRequestShouldBeConfiguredCorrectly() = runTest { @@ -172,6 +192,7 @@ internal class ClientApiV0Test : ApiTest() { const val PATH_CLIENTS = "/clients" val REGISTER_CLIENT_REQUEST = RegisterClientRequestJson.valid val VALID_REGISTER_CLIENT_RESPONSE = ClientResponseJson.valid + val VALID_REGISTER_CLIENT_OLD_RESPONSE = ClientResponseJson.validCapabilitiesObject val UPDATE_CLIENT_REQUEST = UpdateClientRequestJson.valid val ERROR_RESPONSE = ErrorResponseJson.valid.serializableData val VALID_PUSH_TOKEN_REQUEST = RegisterTokenJson.validPushTokenRequest