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 }} diff --git a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt index 89c70247f9e..72faee95ae6 100644 --- a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt +++ b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt @@ -20,7 +20,10 @@ package com.wire.kalium.cryptography import com.wire.crypto.ClientId import com.wire.crypto.CoreCrypto import com.wire.crypto.CoreCryptoCallbacks +import com.wire.crypto.CoreCryptoLogLevel +import com.wire.crypto.CoreCryptoLogger import com.wire.crypto.coreCryptoDeferredInit +import com.wire.crypto.setLogger import com.wire.kalium.cryptography.MLSClientImpl.Companion.toCrlRegistration import com.wire.kalium.cryptography.exceptions.CryptographyException import java.io.File @@ -36,12 +39,28 @@ actual suspend fun coreCryptoCentral( key = databaseKey ) coreCrypto.setCallbacks(Callbacks()) + setLogger(CoreCryptoLoggerImpl(), CoreCryptoLogLevel.INFO) return CoreCryptoCentralImpl( cc = coreCrypto, rootDir = rootDir ) } +private class CoreCryptoLoggerImpl : CoreCryptoLogger { + override fun log(level: CoreCryptoLogLevel, message: String, context: String?) { + when (level) { + CoreCryptoLogLevel.TRACE -> kaliumLogger.v("$message. $context") + CoreCryptoLogLevel.DEBUG -> kaliumLogger.d("$message. $context") + CoreCryptoLogLevel.INFO -> kaliumLogger.i("$message. $context") + CoreCryptoLogLevel.WARN -> kaliumLogger.w("$message. $context") + CoreCryptoLogLevel.ERROR -> kaliumLogger.e("$message. $context") + CoreCryptoLogLevel.OFF -> { + // nop + } + } + } +} + private class Callbacks : CoreCryptoCallbacks { override suspend fun authorize(conversationId: ByteArray, clientId: ClientId): Boolean { // We always return true because our BE is currently enforcing that this constraint is always true diff --git a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/ProteusClientCoreCryptoImpl.kt b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/ProteusClientCoreCryptoImpl.kt index fdc9bc2b69c..f972b6ea165 100644 --- a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/ProteusClientCoreCryptoImpl.kt +++ b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/ProteusClientCoreCryptoImpl.kt @@ -28,6 +28,7 @@ import io.ktor.util.encodeBase64 import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import java.io.File +import com.wire.crypto.ProteusException as ProteusExceptionNative @Suppress("TooManyFunctions") class ProteusClientCoreCryptoImpl private constructor( @@ -145,13 +146,12 @@ class ProteusClientCoreCryptoImpl private constructor( private inline fun wrapException(b: () -> T): T { try { return b() - } catch (e: CoreCryptoException) { - val proteusLastErrorCode = coreCrypto.proteusLastErrorCode() + } catch (e: CoreCryptoException.Proteus) { throw ProteusException( - e.message, - ProteusException.fromProteusCode(proteusLastErrorCode.toInt()), - proteusLastErrorCode.toInt(), - e + message = e.message, + code = mapProteusExceptionToErrorCode(e.v1), + intCode = mapProteusExceptionToRawIntErrorCode(e.v1), + cause = e ) } catch (e: Exception) { throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e) @@ -187,11 +187,11 @@ class ProteusClientCoreCryptoImpl private constructor( return ProteusClientCoreCryptoImpl(coreCrypto) } catch (exception: ProteusStorageMigrationException) { throw exception - } catch (e: CoreCryptoException) { + } catch (e: CoreCryptoException.Proteus) { throw ProteusException( message = e.message, - code = ProteusException.fromProteusCode(coreCrypto.proteusLastErrorCode().toInt()), - intCode = coreCrypto.proteusLastErrorCode().toInt(), + code = mapProteusExceptionToErrorCode(e.v1), + intCode = mapProteusExceptionToRawIntErrorCode(e.v1), cause = e.cause ) } catch (e: Exception) { @@ -218,5 +218,24 @@ class ProteusClientCoreCryptoImpl private constructor( throw ProteusStorageMigrationException("Failed to migrate from crypto box at $rootDir", exception) } } + + private fun mapProteusExceptionToErrorCode(proteusException: ProteusExceptionNative): ProteusException.Code { + return when (proteusException) { + is ProteusExceptionNative.SessionNotFound -> ProteusException.Code.SESSION_NOT_FOUND + is ProteusExceptionNative.DuplicateMessage -> ProteusException.Code.DUPLICATE_MESSAGE + is ProteusExceptionNative.RemoteIdentityChanged -> ProteusException.Code.REMOTE_IDENTITY_CHANGED + is ProteusExceptionNative.Other -> ProteusException.fromProteusCode(proteusException.v1.toInt()) + } + } + + @Suppress("MagicNumber") + private fun mapProteusExceptionToRawIntErrorCode(proteusException: ProteusExceptionNative): Int { + return when (proteusException) { + is ProteusExceptionNative.SessionNotFound -> 102 + is ProteusExceptionNative.DuplicateMessage -> 209 + is ProteusExceptionNative.RemoteIdentityChanged -> 204 + is ProteusExceptionNative.Other -> proteusException.v1.toInt() + } + } } } diff --git a/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/exceptions/ProteusException.kt b/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/exceptions/ProteusException.kt index 547d0deefa9..18750c29f92 100644 --- a/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/exceptions/ProteusException.kt +++ b/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/exceptions/ProteusException.kt @@ -176,19 +176,25 @@ open class ProteusException(message: String?, val code: Code, val intCode: Int?, } } - // Mapping source: - // https://github.com/wireapp/proteus/blob/2.x/crates/proteus-traits/src/lib.rs - // https://github.com/wireapp/wire-web-core/blob/7383e108f5e9d15d0b82c41ed504964667463cfc/packages/proteus/README.md + /** + * Those error codes are mapped directly from [com.wire.crypto.ProteusException]: + * - [Code.SESSION_NOT_FOUND] + * - [Code.REMOTE_IDENTITY_CHANGED] + * - [Code.DUPLICATE_MESSAGE] + * + * See the mapping: [com.wire.kalium.cryptography.ProteusClientCoreCryptoImpl.Companion.mapProteusExceptionToErrorCode] + * + * [Mapping sources](https://github.com/wireapp/proteus/blob/2.x/crates/proteus-traits/src/lib.rs) + * + * [Mapping source README](https://github.com/wireapp/wire-web-core/blob/7383e108f5e9d15d0b82c41ed504964667463cfc/packages/proteus/README.md) + */ fun fromProteusCode(code: Int): Code { @Suppress("MagicNumber") return when (code) { 501 -> Code.STORAGE_ERROR - 102 -> Code.SESSION_NOT_FOUND 3, 301, 302, 303 -> Code.DECODE_ERROR - 204 -> Code.REMOTE_IDENTITY_CHANGED 206, 207, 210 -> Code.INVALID_SIGNATURE 200, 201, 202, 205, 213 -> Code.INVALID_MESSAGE - 209 -> Code.DUPLICATE_MESSAGE 211, 212 -> Code.TOO_DISTANT_FUTURE 208 -> Code.OUTDATED_MESSAGE 300 -> Code.IDENTITY_ERROR diff --git a/data/src/commonMain/kotlin/com/wire/kalium/logic/data/call/CallClient.kt b/data/src/commonMain/kotlin/com/wire/kalium/logic/data/call/CallClient.kt index 0c2f3bb9b79..7545545157e 100644 --- a/data/src/commonMain/kotlin/com/wire/kalium/logic/data/call/CallClient.kt +++ b/data/src/commonMain/kotlin/com/wire/kalium/logic/data/call/CallClient.kt @@ -18,55 +18,21 @@ package com.wire.kalium.logic.data.call -import com.wire.kalium.util.serialization.LenientJsonSerializer -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.nullable -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json @Serializable data class CallClient( @SerialName("userid") val userId: String, @SerialName("clientid") val clientId: String, - @SerialName("in_subconv") val isMemberOfSubconversation: Boolean = false, - @SerialName("quality") - @Serializable(with = CallQuality.CallQualityAsIntSerializer::class) - val quality: CallQuality = CallQuality.LOW + @SerialName("in_subconv") val isMemberOfSubconversation: Boolean = false ) @Serializable data class CallClientList( @SerialName("clients") val clients: List ) { - fun toJsonString(): String = LenientJsonSerializer.json.encodeToString(serializer(), this) -} - -enum class CallQuality { - ANY, - LOW, - HIGH; - - data object CallQualityAsIntSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("quality", PrimitiveKind.INT).nullable - - override fun serialize(encoder: Encoder, value: CallQuality) { - encoder.encodeInt(value.ordinal) - } - - @OptIn(ExperimentalSerializationApi::class) - override fun deserialize(decoder: Decoder): CallQuality { - val value = if (decoder.decodeNotNullMark()) decoder.decodeInt() else 0 - return when (value) { - 1 -> LOW - 2 -> HIGH - else -> ANY - } - } - } + // TODO(optimization): Use a shared Json instance instead of creating one every time. + fun toJsonString(): String = Json { isLenient = true }.encodeToString(serializer(), this) } 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/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8fe82ae3248..d99f1c21b15 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ activity-compose = "1.9.0" app-compat = "1.6.1" android-paging3 = "3.2.1" cli-kt = "3.5.0" -coroutines = "1.8.1" +coroutines = "1.8.0" compose-compiler = "1.5.13" compose-ui = "1.6.6" compose-material = "1.6.6" @@ -17,12 +17,12 @@ okio = "3.9.0" ok-http = "4.12.0" mockative = "2.2.0" android-work = "2.9.0" -android-test-runner = "1.6.2" -android-test-core-ktx = "1.6.1" -android-test-rules = "1.6.1" -android-test-core = "1.6.1" +android-test-runner = "1.5.2" +android-test-core-ktx = "1.5.0" +android-test-rules = "1.5.0" +android-test-core = "1.5.0" androidx-arch = "2.2.0" -androidx-test-orchestrator = "1.5.1" +androidx-test-orchestrator = "1.4.2" androidx-sqlite = "2.4.0" benasher-uuid = "0.8.0" ktx-datetime = { strictly = "0.5.0" } @@ -37,20 +37,20 @@ sqldelight = "2.0.1" sqlcipher-android = "4.5.6" pbandk = "0.14.2" turbine = "1.1.0" -avs = "10.0.1" +avs = "9.10.16" jna = "5.14.0" -core-crypto = "1.0.2" +core-crypto = "3.0.0" core-crypto-multiplatform = "0.6.0-rc.3-multiplatform-pre1" completeKotlin = "1.1.0" -desugar-jdk = "2.1.3" +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" libsodiumBindings = "0.8.7" protobufCodegen = "0.9.4" -annotation = "1.9.1" +annotation = "1.7.1" mordant = "2.0.0-beta13" apache-tika = "2.9.2" mockk = "1.13.10" diff --git a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/CoreCryptoExceptionMapper.kt b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/CoreCryptoExceptionMapper.kt index a41535a1dc3..d2b7342a6d1 100644 --- a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/CoreCryptoExceptionMapper.kt +++ b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/CoreCryptoExceptionMapper.kt @@ -18,21 +18,20 @@ package com.wire.kalium.logic import com.wire.crypto.CoreCryptoException -import uniffi.core_crypto.CryptoError +import com.wire.crypto.MlsException actual fun mapMLSException(exception: Exception): MLSFailure = - if (exception is CoreCryptoException.CryptoException) { - when (exception.error) { - is CryptoError.WrongEpoch -> MLSFailure.WrongEpoch - is CryptoError.DuplicateMessage -> MLSFailure.DuplicateMessage - is CryptoError.BufferedFutureMessage -> MLSFailure.BufferedFutureMessage - is CryptoError.SelfCommitIgnored -> MLSFailure.SelfCommitIgnored - is CryptoError.UnmergedPendingGroup -> MLSFailure.UnmergedPendingGroup - is CryptoError.StaleProposal -> MLSFailure.StaleProposal - is CryptoError.StaleCommit -> MLSFailure.StaleCommit - is CryptoError.ConversationAlreadyExists -> MLSFailure.ConversationAlreadyExists - is CryptoError.MessageEpochTooOld -> MLSFailure.MessageEpochTooOld - is CryptoError.MlsException -> MLSFailure.InternalErrors + if (exception is CoreCryptoException.Mls) { + when (exception.v1) { + is MlsException.WrongEpoch -> MLSFailure.WrongEpoch + is MlsException.DuplicateMessage -> MLSFailure.DuplicateMessage + is MlsException.BufferedFutureMessage -> MLSFailure.BufferedFutureMessage + is MlsException.SelfCommitIgnored -> MLSFailure.SelfCommitIgnored + is MlsException.UnmergedPendingGroup -> MLSFailure.UnmergedPendingGroup + is MlsException.StaleProposal -> MLSFailure.StaleProposal + is MlsException.StaleCommit -> MLSFailure.StaleCommit + is MlsException.ConversationAlreadyExists -> MLSFailure.ConversationAlreadyExists + is MlsException.MessageEpochTooOld -> MLSFailure.MessageEpochTooOld else -> MLSFailure.Generic(exception) } } else { diff --git a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt index 0285d2491e4..14ce1d51f68 100644 --- a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt +++ b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt @@ -466,19 +466,14 @@ class CallManagerImpl internal constructor( callClients: CallClientList ) { withCalling { - // Mapping Needed to support calls between federated and non federated environments (domain separation) + // Needed to support calls between federated and non federated environments val clients = callClients.clients.map { callClient -> CallClient( - userId = federatedIdMapper.parseToFederatedId(callClient.userId), - clientId = callClient.clientId, - isMemberOfSubconversation = callClient.isMemberOfSubconversation, - quality = callClient.quality + federatedIdMapper.parseToFederatedId(callClient.userId), + callClient.clientId ) } val clientsJson = CallClientList(clients).toJsonString() - callingLogger.d( - "$TAG - wcall_request_video_streams() called -> Requesting video streams for conversation = ${conversationId.toLogString()}" - ) val conversationIdString = federatedIdMapper.parseToFederatedId(conversationId) calling.wcall_request_video_streams( inst = it, diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/CustomServerConfigRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/CustomServerConfigRepository.kt index 519f7943258..8025edc4393 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/CustomServerConfigRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/server/CustomServerConfigRepository.kt @@ -94,7 +94,11 @@ internal class CustomServerConfigDataSource internal constructor( val storedConfigId = serverConfigurationDAO.configByLinks(serverConfigMapper.toEntity(links))?.id if (storedConfigId != null) { // if already exists then just update it - serverConfigurationDAO.updateApiVersion(storedConfigId, metadata.commonApiVersion.version) + serverConfigurationDAO.updateServerMetaData( + id = storedConfigId, + federation = metadata.federation, + commonApiVersion = metadata.commonApiVersion.version + ) if (metadata.federation) serverConfigurationDAO.setFederationToTrue(storedConfigId) storedConfigId } else { 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 faef6688735..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 @@ -57,15 +57,16 @@ interface ServerConfigRepository { suspend fun fetchApiVersionAndStore(links: ServerConfig.Links): Either /** - * update the api version of a locally stored config + * update the api version and federation status of a locally stored config */ - suspend fun updateConfigApiVersion(serverConfig: ServerConfig): Either + suspend fun updateConfigMetaData(serverConfig: ServerConfig): Either /** * Return the server links and metadata for the given userId */ suspend fun configForUser(userId: UserId): Either suspend fun commonApiVersion(domain: String): Either + suspend fun getTeamUrlForUser(userId: UserId): String? } @Suppress("LongParameterList", "TooManyFunctions") @@ -92,7 +93,11 @@ internal class ServerConfigDataSource( val storedConfigId = dao.configByLinks(serverConfigMapper.toEntity(links))?.id if (storedConfigId != null) { // if already exists then just update it - dao.updateApiVersion(storedConfigId, metadata.commonApiVersion.version) + dao.updateServerMetaData( + id = storedConfigId, + federation = metadata.federation, + commonApiVersion = metadata.commonApiVersion.version + ) if (metadata.federation) dao.setFederationToTrue(storedConfigId) storedConfigId } else { @@ -132,9 +137,17 @@ internal class ServerConfigDataSource( storeConfig(links, metaData) } - override suspend fun updateConfigApiVersion(serverConfig: ServerConfig): Either = + override suspend fun updateConfigMetaData(serverConfig: ServerConfig): Either = fetchMetadata(serverConfig.links) - .flatMap { wrapStorageRequest { dao.updateApiVersion(serverConfig.id, it.commonApiVersion.version) } } + .flatMap { newMetaData -> + wrapStorageRequest { + dao.updateServerMetaData( + id = serverConfig.id, + federation = newMetaData.federation, + commonApiVersion = newMetaData.commonApiVersion.version + ) + } + } override suspend fun configForUser(userId: UserId): Either = wrapStorageRequest { dao.configForUser(userId.toDao()) } @@ -153,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/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/data/sync/SlowSyncStatus.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/sync/SlowSyncStatus.kt index 5bb50ed3cf4..631400557e7 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/sync/SlowSyncStatus.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/sync/SlowSyncStatus.kt @@ -43,6 +43,5 @@ enum class SlowSyncStep { CONTACTS, JOINING_MLS_CONVERSATIONS, RESOLVE_ONE_ON_ONE_PROTOCOLS, - LEGAL_HOLD, - CONVERSATION_FOLDERS, + LEGAL_HOLD } 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 55b14c8e35a..c445908052c 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 @@ -212,8 +212,6 @@ import com.wire.kalium.logic.feature.conversation.RecoverMLSConversationsUseCase import com.wire.kalium.logic.feature.conversation.SyncConversationsUseCase import com.wire.kalium.logic.feature.conversation.SyncConversationsUseCaseImpl import com.wire.kalium.logic.feature.conversation.TypingIndicatorSyncManager -import com.wire.kalium.logic.feature.conversation.folder.SyncConversationFoldersUseCase -import com.wire.kalium.logic.feature.conversation.folder.SyncConversationFoldersUseCaseImpl import com.wire.kalium.logic.feature.conversation.keyingmaterials.KeyingMaterialsManager import com.wire.kalium.logic.feature.conversation.keyingmaterials.KeyingMaterialsManagerImpl import com.wire.kalium.logic.feature.conversation.mls.MLSOneOnOneConversationResolver @@ -295,6 +293,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 @@ -983,9 +982,6 @@ class UserSessionScope internal constructor( systemMessageInserter ) - private val syncConversationFolders: SyncConversationFoldersUseCase - get() = SyncConversationFoldersUseCaseImpl(conversationFolderRepository) - private val syncConnections: SyncConnectionsUseCase get() = SyncConnectionsUseCaseImpl( connectionRepository = connectionRepository @@ -1104,8 +1100,7 @@ class UserSessionScope internal constructor( syncContacts, joinExistingMLSConversations, fetchLegalHoldForSelfUserFromRemoteUseCase, - oneOnOneResolver, - syncConversationFolders + oneOnOneResolver ) } @@ -1839,6 +1834,7 @@ class UserSessionScope internal constructor( legalHoldHandler, notificationTokenRepository, this, + userStorage, userScopedLogger, ) } @@ -2160,6 +2156,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/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/GetFavoriteFolderUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/GetFavoriteFolderUseCase.kt index c8e7b950850..45565664e16 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/GetFavoriteFolderUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/GetFavoriteFolderUseCase.kt @@ -17,9 +17,13 @@ */ package com.wire.kalium.logic.feature.conversation.folder +import com.wire.kalium.logic.StorageFailure import com.wire.kalium.logic.data.conversation.ConversationFolder import com.wire.kalium.logic.data.conversation.folders.ConversationFolderRepository import com.wire.kalium.logic.feature.conversation.folder.GetFavoriteFolderUseCase.Result +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.fold /** @@ -41,9 +45,19 @@ internal class GetFavoriteFolderUseCaseImpl( ) : GetFavoriteFolderUseCase { override suspend operator fun invoke(): Result { - return conversationFolderRepository.getFavoriteConversationFolder().fold( - { Result.Failure }, - { Result.Success(it) } - ) + return conversationFolderRepository.getFavoriteConversationFolder() + .flatMapLeft { + if (it is StorageFailure.DataNotFound) { + conversationFolderRepository.fetchConversationFolders().flatMap { + conversationFolderRepository.getFavoriteConversationFolder() + } + } else { + Either.Left(it) + } + } + .fold( + { Result.Failure }, + { Result.Success(it) } + ) } } 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/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/SyncConversationFoldersUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/SyncConversationFoldersUseCase.kt deleted file mode 100644 index 216290437e3..00000000000 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/folder/SyncConversationFoldersUseCase.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.CoreFailure -import com.wire.kalium.logic.data.conversation.folders.ConversationFolderRepository -import com.wire.kalium.logic.functional.Either - -internal interface SyncConversationFoldersUseCase { - suspend operator fun invoke(): Either -} - -/** - * This use case will sync against the backend the conversation folders of the current user. - */ -internal class SyncConversationFoldersUseCaseImpl( - private val conversationRepository: ConversationFolderRepository, -) : SyncConversationFoldersUseCase { - override suspend operator fun invoke(): Either = conversationRepository.fetchConversationFolders() -} diff --git a/util/src/commonMain/kotlin/com.wire.kalium.util/serialization/LenientJsonSerializer.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt similarity index 60% rename from util/src/commonMain/kotlin/com.wire.kalium.util/serialization/LenientJsonSerializer.kt rename to logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt index 3d6507cf8ff..83588fea472 100644 --- a/util/src/commonMain/kotlin/com.wire.kalium.util/serialization/LenientJsonSerializer.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt @@ -15,18 +15,18 @@ * 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.util.serialization +package com.wire.kalium.logic.feature.debug -import kotlinx.serialization.json.Json +import com.wire.kalium.logic.di.UserStorage -/** - * The json serializer for shared usage. - */ -object LenientJsonSerializer { - - val json = Json { - isLenient = true - encodeDefaults = true - ignoreUnknownKeys = true +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/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/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionsUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionsUseCase.kt index 0d6eb9dea57..db4d2746aa0 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionsUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionsUseCase.kt @@ -80,6 +80,6 @@ class UpdateApiVersionsUseCaseImpl internal constructor( } else { null } - serverConfigRepoProvider(serverConfig, proxyCredentials).updateConfigApiVersion(serverConfig) + serverConfigRepoProvider(serverConfig, proxyCredentials).updateConfigMetaData(serverConfig) } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt index a7bce64bfa5..f34f1ec3f8d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt @@ -210,7 +210,8 @@ internal class SlowSyncManager( * Useful when a new step is added to Slow Sync, or when we fix some bug in Slow Sync, * and we'd like to get all users to take advantage of the fix. */ - const val CURRENT_VERSION = 9 + const val CURRENT_VERSION = 8 + // because we already had version 9, the next version should be 10 val MIN_RETRY_DELAY = 1.seconds val MAX_RETRY_DELAY = 10.minutes diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorker.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorker.kt index 2022b6c0f32..35fc040ee08 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorker.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorker.kt @@ -26,7 +26,6 @@ import com.wire.kalium.logic.data.event.EventRepository import com.wire.kalium.logic.data.sync.SlowSyncStep import com.wire.kalium.logic.feature.connection.SyncConnectionsUseCase import com.wire.kalium.logic.feature.conversation.SyncConversationsUseCase -import com.wire.kalium.logic.feature.conversation.folder.SyncConversationFoldersUseCase import com.wire.kalium.logic.feature.conversation.mls.OneOnOneResolver import com.wire.kalium.logic.feature.featureConfig.SyncFeatureConfigsUseCase import com.wire.kalium.logic.feature.legalhold.FetchLegalHoldForSelfUserFromRemoteUseCase @@ -72,7 +71,6 @@ internal class SlowSyncWorkerImpl( private val joinMLSConversations: JoinExistingMLSConversationsUseCase, private val fetchLegalHoldForSelfUserFromRemoteUseCase: FetchLegalHoldForSelfUserFromRemoteUseCase, private val oneOnOneResolver: OneOnOneResolver, - private val syncConversationFolders: SyncConversationFoldersUseCase, logger: KaliumLogger = kaliumLogger ) : SlowSyncWorker { @@ -104,7 +102,6 @@ internal class SlowSyncWorkerImpl( .continueWithStep(SlowSyncStep.CONTACTS, syncContacts::invoke) .continueWithStep(SlowSyncStep.JOINING_MLS_CONVERSATIONS, joinMLSConversations::invoke) .continueWithStep(SlowSyncStep.RESOLVE_ONE_ON_ONE_PROTOCOLS, oneOnOneResolver::resolveAllOneOnOneConversations) - .continueWithStep(SlowSyncStep.CONVERSATION_FOLDERS, syncConversationFolders::invoke) .flatMap { saveLastProcessedEventIdIfNeeded(lastProcessedEventIdToSaveOnSuccess) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/CustomServerConfigRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/CustomServerConfigRepositoryTest.kt index 401b0fbc908..3737f9b8900 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/CustomServerConfigRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/CustomServerConfigRepositoryTest.kt @@ -78,7 +78,7 @@ class CustomServerConfigRepositoryTest { arrangement.serverConfigurationDAO.insert(any()) }.wasNotInvoked() coVerify { - arrangement.serverConfigurationDAO.updateApiVersion(any(), any()) + arrangement.serverConfigurationDAO.updateServerMetaData(any(), any(), any()) }.wasInvoked(exactly = once) coVerify { arrangement.serverConfigurationDAO.setFederationToTrue(any()) @@ -106,7 +106,7 @@ class CustomServerConfigRepositoryTest { arrangement.serverConfigurationDAO.insert(any()) }.wasInvoked(exactly = once) coVerify { - arrangement.serverConfigurationDAO.updateApiVersion(any(), any()) + arrangement.serverConfigurationDAO.updateServerMetaData(any(), any(), any()) }.wasNotInvoked() coVerify { arrangement.serverConfigurationDAO.setFederationToTrue(any()) @@ -145,7 +145,7 @@ class CustomServerConfigRepositoryTest { arrangement.serverConfigurationDAO.insert(any()) }.wasInvoked(exactly = once) coVerify { - arrangement.serverConfigurationDAO.updateApiVersion(any(), any()) + arrangement.serverConfigurationDAO.updateServerMetaData(any(), any(), any()) }.wasNotInvoked() coVerify { arrangement.serverConfigurationDAO.setFederationToTrue(any()) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/ServerConfigRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/ServerConfigRepositoryTest.kt index 79c65a3dd2a..8f2e1416856 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/ServerConfigRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/configuration/ServerConfigRepositoryTest.kt @@ -131,7 +131,7 @@ class ServerConfigRepositoryTest { arrangement.serverConfigDAO.insert(any()) }.wasNotInvoked() coVerify { - arrangement.serverConfigDAO.updateApiVersion(any(), any()) + arrangement.serverConfigDAO.updateServerMetaData(any(), any(), any()) }.wasInvoked(exactly = once) coVerify { arrangement.serverConfigDAO.setFederationToTrue(any()) @@ -159,7 +159,7 @@ class ServerConfigRepositoryTest { arrangement.serverConfigDAO.insert(any()) }.wasInvoked(exactly = once) coVerify { - arrangement.serverConfigDAO.updateApiVersion(any(), any()) + arrangement.serverConfigDAO.updateServerMetaData(any(), any(), any()) }.wasNotInvoked() coVerify { arrangement.serverConfigDAO.setFederationToTrue(any()) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/folder/GetFavoriteFolderUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/folder/GetFavoriteFolderUseCaseTest.kt index ca6fc8e156f..23064583cf3 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/folder/GetFavoriteFolderUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/folder/GetFavoriteFolderUseCaseTest.kt @@ -18,6 +18,7 @@ package com.wire.kalium.logic.feature.conversation.folder import com.wire.kalium.logic.CoreFailure +import com.wire.kalium.logic.StorageFailure import com.wire.kalium.logic.data.conversation.ConversationFolder import com.wire.kalium.logic.data.conversation.folders.ConversationFolderRepository import com.wire.kalium.logic.feature.conversation.folder.GetFavoriteFolderUseCase.Result @@ -28,6 +29,7 @@ import io.mockative.coEvery import io.mockative.coVerify import io.mockative.mock import io.mockative.once +import io.mockative.twice import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals @@ -53,7 +55,7 @@ class GetFavoriteFolderUseCaseTest { } @Test - fun givenFavoriteFolderDoesNotExist_WhenInvoked_ThenReturnFailure() = runTest { + fun givenFavoriteFolderReturnsFailure_WhenInvoked_ThenReturnFailure() = runTest { val (arrangement, getFavoriteFolderUseCase) = Arrangement() .withFavoriteFolder(Either.Left(CoreFailure.Unknown(null))) .arrange() @@ -67,6 +69,25 @@ class GetFavoriteFolderUseCaseTest { }.wasInvoked(exactly = once) } + @Test + fun givenFavoriteFolderDoesNotExist_WhenInvoked_ThenFetchConversationFoldersIsTriggered() = runTest { + val (arrangement, getFavoriteFolderUseCase) = Arrangement() + .withFavoriteFolder(Either.Left(StorageFailure.DataNotFound)) + .withFetchConversationFolders(Either.Right(Unit)) + .arrange() + + val result = getFavoriteFolderUseCase() + + assertIs(result) + + coVerify { + arrangement.conversationFolderRepository.getFavoriteConversationFolder() + }.wasInvoked(exactly = twice) + coVerify { + arrangement.conversationFolderRepository.fetchConversationFolders() + }.wasInvoked(exactly = once) + } + private class Arrangement { @Mock val conversationFolderRepository = mock(ConversationFolderRepository::class) @@ -81,6 +102,12 @@ class GetFavoriteFolderUseCaseTest { }.returns(either) } + suspend fun withFetchConversationFolders(either: Either) = apply { + coEvery { + conversationFolderRepository.fetchConversationFolders() + }.returns(either) + } + fun arrange(block: Arrangement.() -> Unit = { }) = apply(block).let { this to getFavoriteFolderUseCase } } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionUseCaseTest.kt index d883b34e4fe..3401f58963a 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/server/UpdateApiVersionUseCaseTest.kt @@ -77,7 +77,7 @@ class UpdateApiVersionUseCaseTest { ) ) ) - withUpdateConfigApiVersion(serverConfig1, Either.Right(Unit)) + withUpdateConfigMetaData(serverConfig1, Either.Right(Unit)) } updateApiVersionsUseCase() @@ -88,7 +88,7 @@ class UpdateApiVersionUseCaseTest { }.wasNotInvoked() coVerify { - arrangement.serverConfigRepository1.updateConfigApiVersion(eq(serverConfig1)) + arrangement.serverConfigRepository1.updateConfigMetaData(eq(serverConfig1)) }.wasInvoked(exactly = once) } @@ -111,7 +111,7 @@ class UpdateApiVersionUseCaseTest { ) ) ) - withUpdateConfigApiVersion(serverConfig1, Either.Right(Unit)) + withUpdateConfigMetaData(serverConfig1, Either.Right(Unit)) } updateApiVersionsUseCase() @@ -122,7 +122,7 @@ class UpdateApiVersionUseCaseTest { }.wasNotInvoked() coVerify { - arrangement.serverConfigRepository1.updateConfigApiVersion(any()) + arrangement.serverConfigRepository1.updateConfigMetaData(any()) }.wasInvoked(exactly = once) } @@ -145,7 +145,7 @@ class UpdateApiVersionUseCaseTest { ) ) ) - withUpdateConfigApiVersion(serverConfig1, Either.Right(Unit)) + withUpdateConfigMetaData(serverConfig1, Either.Right(Unit)) withProxyCredForUser(userId1.toDao(), ProxyCredentialsEntity("user", "pass")) } @@ -158,7 +158,7 @@ class UpdateApiVersionUseCaseTest { }.wasInvoked(exactly = once) coVerify { - arrangement.serverConfigRepository1.updateConfigApiVersion(any()) + arrangement.serverConfigRepository1.updateConfigMetaData(any()) }.wasInvoked(exactly = once) } @@ -190,8 +190,8 @@ class UpdateApiVersionUseCaseTest { ) ) ) - withUpdateConfigApiVersion(serverConfig1, Either.Right(Unit)) - withUpdateConfigApiVersion(serverConfig2, Either.Right(Unit)) + withUpdateConfigMetaData(serverConfig1, Either.Right(Unit)) + withUpdateConfigMetaData(serverConfig2, Either.Right(Unit)) withProxyCredForUser(userId2.toDao(), ProxyCredentialsEntity("user", "pass")) } @@ -208,11 +208,11 @@ class UpdateApiVersionUseCaseTest { }.wasNotInvoked() coVerify { - arrangement.serverConfigRepository1.updateConfigApiVersion(any()) + arrangement.serverConfigRepository1.updateConfigMetaData(any()) }.wasInvoked(exactly = once) coVerify { - arrangement.serverConfigRepository2.updateConfigApiVersion(any()) + arrangement.serverConfigRepository2.updateConfigMetaData(any()) }.wasInvoked(exactly = once) } @@ -249,16 +249,16 @@ class UpdateApiVersionUseCaseTest { }.returns(result) } - suspend fun withUpdateConfigApiVersion( + suspend fun withUpdateConfigMetaData( serverConfig: ServerConfig, result: Either ) { when (serverConfig.id) { serverConfig1.id -> - coEvery { serverConfigRepository1.updateConfigApiVersion(any()) } + coEvery { serverConfigRepository1.updateConfigMetaData(any()) } .returns(result) - serverConfig2.id -> coEvery { serverConfigRepository2.updateConfigApiVersion(any()) } + serverConfig2.id -> coEvery { serverConfigRepository2.updateConfigMetaData(any()) } .returns(result) else -> throw IllegalArgumentException("Unexpected server config: $serverConfig") diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorkerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorkerTest.kt index facf5ddb70b..6a89816ead8 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorkerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncWorkerTest.kt @@ -24,7 +24,6 @@ import com.wire.kalium.logic.data.sync.SlowSyncStep import com.wire.kalium.logic.data.user.LegalHoldStatus import com.wire.kalium.logic.feature.connection.SyncConnectionsUseCase import com.wire.kalium.logic.feature.conversation.SyncConversationsUseCase -import com.wire.kalium.logic.feature.conversation.folder.SyncConversationFoldersUseCase import com.wire.kalium.logic.feature.conversation.mls.OneOnOneResolver import com.wire.kalium.logic.feature.featureConfig.SyncFeatureConfigsUseCase import com.wire.kalium.logic.feature.legalhold.FetchLegalHoldForSelfUserFromRemoteUseCase @@ -72,7 +71,6 @@ class SlowSyncWorkerTest { .withJoinMLSConversationsSuccess() .withResolveOneOnOneConversationsSuccess() .withFetchLegalHoldStatusSuccess() - .withSyncFoldersSuccess() .arrange() worker.slowSyncStepsFlow(successfullyMigration).collect() @@ -410,7 +408,6 @@ class SlowSyncWorkerTest { .withJoinMLSConversationsSuccess() .withResolveOneOnOneConversationsSuccess() .withFetchLegalHoldStatusSuccess() - .withSyncFoldersSuccess() .arrange() slowSyncWorker.slowSyncStepsFlow(successfullyMigration).collect() @@ -514,9 +511,6 @@ class SlowSyncWorkerTest { @Mock val fetchLegalHoldForSelfUserFromRemoteUseCase = mock(FetchLegalHoldForSelfUserFromRemoteUseCase::class) - @Mock - val syncConversationFoldersUseCase = mock(SyncConversationFoldersUseCase::class) - init { runBlocking { withLastProcessedEventIdReturning(Either.Right("lastProcessedEventId")) @@ -534,8 +528,7 @@ class SlowSyncWorkerTest { joinMLSConversations = joinMLSConversations, updateSupportedProtocols = updateSupportedProtocols, fetchLegalHoldForSelfUserFromRemoteUseCase = fetchLegalHoldForSelfUserFromRemoteUseCase, - oneOnOneResolver = oneOnOneResolver, - syncConversationFolders = syncConversationFoldersUseCase + oneOnOneResolver = oneOnOneResolver ) suspend fun withSyncSelfUserFailure() = apply { @@ -651,12 +644,6 @@ class SlowSyncWorkerTest { oneOnOneResolver.resolveAllOneOnOneConversations(any()) }.returns(success) } - - suspend fun withSyncFoldersSuccess() = apply { - coEvery { - syncConversationFoldersUseCase.invoke() - }.returns(success) - } } private companion object { 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, diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/BackendMetaDataUtil.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/BackendMetaDataUtil.kt index be435578cf3..179e1b936fa 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/BackendMetaDataUtil.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/BackendMetaDataUtil.kt @@ -23,11 +23,11 @@ import com.wire.kalium.network.api.unbound.versioning.VersionInfoDTO // They are not truly constants as set is not a primitive type, yet are treated as one in this context @Suppress("MagicNumber") -val SupportedApiVersions = setOf(0, 1, 2, 4, 5, 6) +val SupportedApiVersions: Set = setOf(0, 1, 2, 4, 5, 6, 7) // They are not truly constants as set is not a primitive type, yet are treated as one in this context @Suppress("MagicNumber") -val DevelopmentApiVersions = setOf(7) +val DevelopmentApiVersions: Set = emptySet() // You can use scripts/generate_new_api_version.sh or gradle task network:generateNewApiVersion to // bump API version and generate all needed classes diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/ConversationApiV0.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/ConversationApiV0.kt index 145a833620f..600c6102788 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/ConversationApiV0.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/ConversationApiV0.kt @@ -306,7 +306,7 @@ internal open class ConversationApiV0 internal constructor( } } - private suspend fun handleServiceAddedResponse( + protected suspend fun handleServiceAddedResponse( httpResponse: HttpResponse ): NetworkResponse = when (httpResponse.status) { diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v7/authenticated/ConversationApiV7.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v7/authenticated/ConversationApiV7.kt index cd10ebd3b2f..5e0d237b95a 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v7/authenticated/ConversationApiV7.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v7/authenticated/ConversationApiV7.kt @@ -19,16 +19,23 @@ package com.wire.kalium.network.api.v7.authenticated import com.wire.kalium.network.AuthenticatedNetworkClient +import com.wire.kalium.network.api.authenticated.conversation.AddServiceRequest import com.wire.kalium.network.api.authenticated.conversation.ConversationResponse import com.wire.kalium.network.api.authenticated.conversation.ConversationResponseV6 import com.wire.kalium.network.api.model.ApiModelMapper import com.wire.kalium.network.api.model.ApiModelMapperImpl +import com.wire.kalium.network.api.model.ConversationId +import com.wire.kalium.network.api.model.ServiceAddedResponse import com.wire.kalium.network.api.model.UserId import com.wire.kalium.network.api.v6.authenticated.ConversationApiV6 +import com.wire.kalium.network.exceptions.KaliumException import com.wire.kalium.network.utils.NetworkResponse import com.wire.kalium.network.utils.mapSuccess import com.wire.kalium.network.utils.wrapKaliumResponse import io.ktor.client.request.get +import io.ktor.client.request.post +import io.ktor.client.request.setBody +import okio.IOException internal open class ConversationApiV7 internal constructor( authenticatedNetworkClient: AuthenticatedNetworkClient, @@ -42,7 +49,21 @@ internal open class ConversationApiV7 internal constructor( apiModelMapper.fromApiV6(it) } + override suspend fun addService( + addServiceRequest: AddServiceRequest, + conversationId: ConversationId + ): NetworkResponse = try { + httpClient.post("$PATH_BOT/$PATH_CONVERSATIONS/${conversationId.value}") { + setBody(addServiceRequest) + }.let { response -> + handleServiceAddedResponse(response) + } + } catch (e: IOException) { + NetworkResponse.Error(KaliumException.GenericError(e)) + } + protected companion object { const val PATH_ONE_2_ONE_CONVERSATIONS = "one2one-conversations" + const val PATH_BOT = "bot" } } 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 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/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt b/persistence/src/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt index edb29062eb1..df3c50b7c8d 100644 --- a/persistence/src/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt +++ b/persistence/src/androidUnitTest/kotlin/com/wire/kalium/persistence/GlobalDBBaseTest.kt @@ -19,6 +19,7 @@ package com.wire.kalium.persistence import com.wire.kalium.persistence.db.GlobalDatabaseBuilder +import kotlinx.coroutines.test.TestDispatcher actual abstract class GlobalDBBaseTest { actual fun deleteDatabase() { 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 48a8d2fe6fe..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 @@ -28,8 +28,8 @@ insert: INSERT OR FAIL INTO ServerConfiguration(id, apiBaseUrl, accountBaseUrl, webSocketBaseUrl, blackListUrl, teamsUrl, websiteUrl, title, isOnPremises, federation, domain, commonApiVersion, apiProxyHost, apiProxyNeedsAuthentication, apiProxyPort) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?); -updateApiVersion: -UPDATE ServerConfiguration SET commonApiVersion = ? WHERE id = ?; +updateServerMetaData: +UPDATE ServerConfiguration SET federation = ?, commonApiVersion = ? WHERE id = ?; /** this function will be used when a config get updated from v0 where domain can be null */ updateApiVersionAndDomain: @@ -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/db_user/com/wire/kalium/persistence/ConversationFolders.sq b/persistence/src/commonMain/db_user/com/wire/kalium/persistence/ConversationFolders.sq index e1e5d8f14cb..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,5 +64,8 @@ VALUES(?, ?); deleteLabeledConversation: DELETE FROM LabeledConversation WHERE conversation_id = ? AND folder_id = ?; +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 3c19bd871b3..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,16 +85,17 @@ 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) = withContext(coroutineContext) { conversationFoldersQueries.transaction { + conversationFoldersQueries.clearLabeledConversations() conversationFoldersQueries.clearFolders() folderWithConversationsList.forEach { folderWithConversations -> conversationFoldersQueries.upsertFolder( 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 7774eae162a..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) @@ -125,10 +126,11 @@ interface ServerConfigurationDAO { suspend fun allConfig(): List fun configById(id: String): ServerConfigEntity? suspend fun configByLinks(links: ServerConfigEntity.Links): ServerConfigEntity? - suspend fun updateApiVersion(id: String, commonApiVersion: Int) suspend fun getCommonApiVersion(domain: String): Int + 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, @@ -210,8 +213,10 @@ internal class ServerConfigurationDAOImpl internal constructor( }.executeAsOneOrNull() } - override suspend fun updateApiVersion(id: String, commonApiVersion: Int) = withContext(queriesContext) { - queries.updateApiVersion(commonApiVersion, id) + override suspend fun updateServerMetaData(id: String, federation: Boolean, commonApiVersion: Int) { + withContext(queriesContext) { + queries.updateServerMetaData(federation, commonApiVersion, id) + } } override suspend fun getCommonApiVersion(domain: String): Int = withContext(queriesContext) { @@ -238,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() + } } 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 */ 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 diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt index 5ab0fe61e87..befaae85ff9 100644 --- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt +++ b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/daokaliumdb/ServerConfigurationDAOTest.kt @@ -24,17 +24,26 @@ import com.wire.kalium.persistence.GlobalDBBaseTest import com.wire.kalium.persistence.db.GlobalDatabaseBuilder import com.wire.kalium.persistence.model.ServerConfigEntity import com.wire.kalium.persistence.utils.stubs.newServerConfig +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import kotlinx.coroutines.withContext import kotlin.test.AfterTest import kotlin.test.BeforeTest +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFails import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull -@OptIn(ExperimentalCoroutinesApi::class) class ServerConfigurationDAOTest : GlobalDBBaseTest() { private val config1 = newServerConfig(id = 1) @@ -142,13 +151,31 @@ class ServerConfigurationDAOTest : GlobalDBBaseTest() { @Test fun givenNewApiVersion_thenItCanBeUpdated() = runTest { - insertConfig(config1) - val newVersion = config1.metaData.copy(apiVersion = 2) - val expected = config1.copy(metaData = newVersion) + val oldConfig = config1.copy( + metaData = config1.metaData.copy( + apiVersion = 1, + federation = false + ), + ) - globalDatabaseBuilder.serverConfigurationDAO.updateApiVersion(config1.id, newVersion.apiVersion) - val actual = globalDatabaseBuilder.serverConfigurationDAO.configById(config1.id) - assertEquals(expected, actual) + val newVersion = config1.metaData.copy( + apiVersion = 2, + federation = true + ) + + val expected = oldConfig.copy(metaData = newVersion) + + insertConfig(oldConfig) + globalDatabaseBuilder.serverConfigurationDAO.updateServerMetaData( + id = oldConfig.id, + federation = true, + commonApiVersion = 2 + ) + globalDatabaseBuilder.serverConfigurationDAO.configById(oldConfig.id) + .also { actual -> + assertEquals(expected.metaData.federation, actual!!.metaData.federation) + assertEquals(expected.metaData.apiVersion, actual!!.metaData.apiVersion) + } } @Test diff --git a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt index 31ba21d5bb5..d5d55507e5e 100644 --- a/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt +++ b/persistence/src/commonTest/kotlin/com/wire/kalium/persistence/globalDB/AccountsDAOTest.kt @@ -29,8 +29,15 @@ import com.wire.kalium.persistence.db.GlobalDatabaseBuilder import com.wire.kalium.persistence.model.LogoutReason import com.wire.kalium.persistence.model.ServerConfigEntity import com.wire.kalium.persistence.model.SsoIdEntity +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestCoroutineScheduler +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals