Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: connect to upgrade-personal-to-team API #WPB-11992 #3103

Merged
merged 29 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
cabcc1d
add v7
damian-kaczmarek Nov 8, 2024
d824dba
capabilities update
damian-kaczmarek Nov 8, 2024
6351438
remove too much copied code
damian-kaczmarek Nov 8, 2024
98002e1
one2one paths change
damian-kaczmarek Nov 12, 2024
4189e4c
revert magic number Suppress
damian-kaczmarek Nov 12, 2024
43d27eb
Merge remote-tracking branch 'refs/remotes/origin/develop' into featu…
damian-kaczmarek Nov 12, 2024
e3927d8
tests and CR changes
damian-kaczmarek Nov 13, 2024
31265e6
feature: connect to upgrade-personal-to-team API #WPB-11992
damian-kaczmarek Nov 13, 2024
f60103a
self review
damian-kaczmarek Nov 13, 2024
de4bc40
detekt
damian-kaczmarek Nov 13, 2024
c1729c1
fix ConversationResponse versions usage for notifications
damian-kaczmarek Nov 14, 2024
de80e42
Merge remote-tracking branch 'refs/remotes/origin/feature/api-v7' int…
damian-kaczmarek Nov 14, 2024
f520d26
detekt
damian-kaczmarek Nov 14, 2024
3c4f4e1
Merge remote-tracking branch 'refs/remotes/origin/feature/api-v7' int…
damian-kaczmarek Nov 14, 2024
2c383ac
fix test
damian-kaczmarek Nov 14, 2024
63ea6a9
Merge remote-tracking branch 'refs/remotes/origin/feature/api-v7' int…
damian-kaczmarek Nov 14, 2024
55fa044
test fix
damian-kaczmarek Nov 14, 2024
87b0a25
added tests
damian-kaczmarek Nov 16, 2024
3249de2
detekt
damian-kaczmarek Nov 16, 2024
90af792
revert code formatting
damian-kaczmarek Nov 18, 2024
efffa6e
revert code formatting
damian-kaczmarek Nov 18, 2024
b2e0cf4
test fix
damian-kaczmarek Nov 18, 2024
2db6c6e
wrong extended class
damian-kaczmarek Nov 19, 2024
29af93a
Merge remote-tracking branch 'refs/remotes/origin/develop' into featu…
damian-kaczmarek Nov 19, 2024
234cfb0
Merge remote-tracking branch 'refs/remotes/origin/feature/upgrade-per…
damian-kaczmarek Nov 19, 2024
5711022
CR changes
damian-kaczmarek Nov 19, 2024
01da6ac
CR
damian-kaczmarek Nov 19, 2024
c37eb15
Merge remote-tracking branch 'refs/remotes/origin/develop' into featu…
damian-kaczmarek Nov 19, 2024
e8b7477
detekt
damian-kaczmarek Nov 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -390,14 +390,16 @@ sealed class Event(open val id: String) {
val uri: String?,
val isPasswordProtected: Boolean,
) : Conversation(id, conversationId) {
override fun toLogMap(): Map<String, Any?> = mapOf(typeKey to "Conversation.CodeUpdated")
override fun toLogMap(): Map<String, Any?> =
mapOf(typeKey to "Conversation.CodeUpdated")
}

data class CodeDeleted(
override val id: String,
override val conversationId: ConversationId,
) : Conversation(id, conversationId) {
override fun toLogMap(): Map<String, Any?> = mapOf(typeKey to "Conversation.CodeDeleted")
override fun toLogMap(): Map<String, Any?> =
mapOf(typeKey to "Conversation.CodeDeleted")
}

data class TypingIndicator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,14 @@ import com.wire.kalium.logic.kaliumLogger
import com.wire.kalium.logic.sync.receiver.handler.legalhold.LegalHoldHandler
import com.wire.kalium.logic.wrapApiRequest
import com.wire.kalium.logic.wrapStorageRequest
import com.wire.kalium.network.api.authenticated.CreateUserTeamDTO
import com.wire.kalium.network.api.authenticated.teams.TeamMemberDTO
import com.wire.kalium.network.api.authenticated.teams.TeamMemberIdList
import com.wire.kalium.network.api.authenticated.userDetails.ListUserRequest
import com.wire.kalium.network.api.authenticated.userDetails.ListUsersDTO
import com.wire.kalium.network.api.authenticated.userDetails.qualifiedIds
import com.wire.kalium.network.api.base.authenticated.TeamsApi
import com.wire.kalium.network.api.base.authenticated.UpgradePersonalToTeamApi
import com.wire.kalium.network.api.base.authenticated.self.SelfApi
import com.wire.kalium.network.api.base.authenticated.userDetails.UserDetailsApi
import com.wire.kalium.network.api.model.LegalHoldStatusDTO
Expand Down Expand Up @@ -164,6 +166,7 @@ interface UserRepository {
suspend fun getOneOnOnConversationId(userId: QualifiedID): Either<StorageFailure, ConversationId>
suspend fun getUsersMinimizedByQualifiedIDs(userIds: List<UserId>): Either<StorageFailure, List<OtherUserMinimized>>
suspend fun getNameAndHandle(userId: UserId): Either<StorageFailure, NameAndHandle>
suspend fun migrateUserToTeam(teamName: String): Either<CoreFailure, CreateUserTeamDTO>
}

@Suppress("LongParameterList", "TooManyFunctions")
Expand All @@ -173,6 +176,7 @@ internal class UserDataSource internal constructor(
private val clientDAO: ClientDAO,
private val selfApi: SelfApi,
private val userDetailsApi: UserDetailsApi,
private val upgradePersonalToTeamApi: UpgradePersonalToTeamApi,
private val teamsApi: TeamsApi,
private val sessionRepository: SessionRepository,
private val selfUserId: UserId,
Expand Down Expand Up @@ -647,6 +651,18 @@ internal class UserDataSource internal constructor(
userDAO.getNameAndHandle(userId.toDao())
}.map { NameAndHandle.fromEntity(it) }

override suspend fun migrateUserToTeam(teamName: String): Either<CoreFailure, CreateUserTeamDTO> {
damian-kaczmarek marked this conversation as resolved.
Show resolved Hide resolved
return wrapApiRequest { upgradePersonalToTeamApi.migrateToTeam(teamName) }
.onSuccess {
kaliumLogger.d("Migrated user to team")
fetchSelfUser()
// TODO Invalidate team id in memory so UserSessionScope.selfTeamId got updated data WPB-12187
damian-kaczmarek marked this conversation as resolved.
Show resolved Hide resolved
}
.onFailure { failure ->
kaliumLogger.e("Failed to migrate user to team: $failure")
}
}

companion object {
internal const val SELF_USER_ID_KEY = "selfUserID"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ import com.wire.kalium.logic.feature.user.guestroomlink.MarkGuestLinkFeatureFlag
import com.wire.kalium.logic.feature.user.guestroomlink.MarkGuestLinkFeatureFlagAsNotChangedUseCaseImpl
import com.wire.kalium.logic.feature.user.guestroomlink.ObserveGuestRoomLinkFeatureFlagUseCase
import com.wire.kalium.logic.feature.user.guestroomlink.ObserveGuestRoomLinkFeatureFlagUseCaseImpl
import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamUseCase
import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamUseCaseImpl
import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigUseCase
import com.wire.kalium.logic.feature.user.screenshotCensoring.ObserveScreenshotCensoringConfigUseCaseImpl
import com.wire.kalium.logic.feature.user.screenshotCensoring.PersistScreenshotCensoringConfigUseCase
Expand Down Expand Up @@ -782,16 +784,17 @@ class UserSessionScope internal constructor(
)

private val userRepository: UserRepository = UserDataSource(
userStorage.database.userDAO,
userStorage.database.metadataDAO,
userStorage.database.clientDAO,
authenticatedNetworkContainer.selfApi,
authenticatedNetworkContainer.userDetailsApi,
authenticatedNetworkContainer.teamsApi,
globalScope.sessionRepository,
userId,
selfTeamId,
legalHoldHandler
userDAO = userStorage.database.userDAO,
metadataDAO = userStorage.database.metadataDAO,
clientDAO = userStorage.database.clientDAO,
selfApi = authenticatedNetworkContainer.selfApi,
userDetailsApi = authenticatedNetworkContainer.userDetailsApi,
upgradePersonalToTeamApi = authenticatedNetworkContainer.upgradePersonalToTeamApi,
teamsApi = authenticatedNetworkContainer.teamsApi,
sessionRepository = globalScope.sessionRepository,
selfUserId = userId,
selfTeamIdProvider = selfTeamId,
legalHoldHandler = legalHoldHandler,
)

private val accountRepository: AccountRepository
Expand Down Expand Up @@ -2074,6 +2077,9 @@ class UserSessionScope internal constructor(
userScopedLogger
)

val migrateFromPersonalToTeam: MigrateFromPersonalToTeamUseCase
get() = MigrateFromPersonalToTeamUseCaseImpl(userRepository)

internal val getProxyCredentials: GetProxyCredentialsUseCase
get() = GetProxyCredentialsUseCaseImpl(sessionManager)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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.user.migration

import com.wire.kalium.logic.CoreFailure
import com.wire.kalium.logic.data.user.UserRepository
import com.wire.kalium.logic.functional.fold

/**
* Use case to migrate user personal account to team account.
* This needs at least API V7 to work.
*/
interface MigrateFromPersonalToTeamUseCase {
suspend operator fun invoke(teamName: String): MigrateFromPersonalToTeamResult
}

sealed class MigrateFromPersonalToTeamResult {
data class Success(val teamId: String, val teamName: String) : MigrateFromPersonalToTeamResult()
Copy link
Member

@ohassine ohassine Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to pass to the app teamId and teamName ?, the app is already having those values

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed id as we don't use it. Left the team name and updated the state just in case API somehow changed the name

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but API should not change a name provided by the user

data class Error(val failure: CoreFailure) : MigrateFromPersonalToTeamResult()
}

internal class MigrateFromPersonalToTeamUseCaseImpl internal constructor(
private val userRepository: UserRepository,
) : MigrateFromPersonalToTeamUseCase {
override suspend operator fun invoke(
teamName: String,
): MigrateFromPersonalToTeamResult {
return userRepository.migrateUserToTeam(teamName)
.fold(
{ error -> return MigrateFromPersonalToTeamResult.Error(error) },
{ success ->
MigrateFromPersonalToTeamResult.Success(
teamId = success.teamId,
teamName = success.teamName,
)
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,17 @@ internal class NewConversationEventHandlerImpl(
.flatMap { isNewUnhandledConversation ->
resolveConversationIfOneOnOne(selfUserTeamId, event)
.flatMap {
conversationRepository.updateConversationModifiedDate(event.conversationId, DateTimeUtil.currentInstant())
conversationRepository.updateConversationModifiedDate(
event.conversationId,
DateTimeUtil.currentInstant()
)
}
.flatMap {
userRepository.fetchUsersIfUnknownByIds(event.conversation.members.otherMembers.map { it.id.toModel() }.toSet())
userRepository.fetchUsersIfUnknownByIds(
event.conversation.members.otherMembers.map {
it.id.toModel()
}.toSet()
)
}
.map { isNewUnhandledConversation }
}.onSuccess { isNewUnhandledConversation ->
Expand All @@ -73,9 +80,13 @@ internal class NewConversationEventHandlerImpl(
}
}

private suspend fun resolveConversationIfOneOnOne(selfUserTeamId: TeamId?, event: Event.Conversation.NewConversation) =
private suspend fun resolveConversationIfOneOnOne(
selfUserTeamId: TeamId?,
event: Event.Conversation.NewConversation
) =
if (event.conversation.toConversationType(selfUserTeamId) == ConversationEntity.Type.ONE_ON_ONE) {
val otherUserId = event.conversation.members.otherMembers.first().id.toModel()
val otherUserId =
event.conversation.members.otherMembers.first().id.toModel()
oneOnOneResolver.resolveOneOnOneConversationWithUserId(
userId = otherUserId,
invalidateCurrentKnownProtocols = true
Expand All @@ -94,13 +105,20 @@ internal class NewConversationEventHandlerImpl(
event: Event.Conversation.NewConversation
) {
if (isNewUnhandledConversation) {
newGroupConversationSystemMessagesCreator.conversationStarted(event.senderUserId, event.conversation, event.dateTime)
newGroupConversationSystemMessagesCreator.conversationStarted(
event.senderUserId,
event.conversation,
event.dateTime
)
newGroupConversationSystemMessagesCreator.conversationResolvedMembersAdded(
event.conversationId.toDao(),
event.conversation.members.otherMembers.map { it.id.toModel() },
event.dateTime
)
newGroupConversationSystemMessagesCreator.conversationReadReceiptStatus(event.conversation, event.dateTime)
newGroupConversationSystemMessagesCreator.conversationReadReceiptStatus(
event.conversation,
event.dateTime
)
newGroupConversationSystemMessagesCreator.conversationStartedUnverifiedWarning(
event.conversation.id.toModel(),
event.dateTime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ import com.wire.kalium.logic.framework.TestEvent
import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.util.shouldFail
import com.wire.kalium.logic.util.shouldSucceed
import com.wire.kalium.network.api.base.authenticated.client.ClientApi
import com.wire.kalium.network.api.authenticated.client.ClientDTO
import com.wire.kalium.network.api.authenticated.client.ClientTypeDTO
import com.wire.kalium.network.api.authenticated.client.DeviceTypeDTO
import com.wire.kalium.network.api.authenticated.client.SimpleClientResponse
import com.wire.kalium.network.api.base.authenticated.client.ClientApi
import com.wire.kalium.network.api.model.ErrorResponse
import com.wire.kalium.network.exceptions.KaliumException
import com.wire.kalium.network.utils.NetworkResponse
Expand Down Expand Up @@ -257,7 +257,7 @@ class ClientRepositoryTest {
deviceType = DeviceTypeDTO.Desktop,
label = null,
model = "Mac ox",
capabilities = null,
capabilities = listOf(),
mlsPublicKeys = null,
cookie = null
),
Expand All @@ -269,7 +269,7 @@ class ClientRepositoryTest {
deviceType = DeviceTypeDTO.Phone,
label = null,
model = "iphone 15",
capabilities = null,
capabilities = listOf(),
mlsPublicKeys = null,
cookie = null
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,17 @@ import com.wire.kalium.logic.test_util.TestNetworkException.generic
import com.wire.kalium.logic.test_util.TestNetworkResponseError
import com.wire.kalium.logic.util.shouldFail
import com.wire.kalium.logic.util.shouldSucceed
import com.wire.kalium.network.api.base.authenticated.TeamsApi
import com.wire.kalium.network.api.base.authenticated.self.SelfApi
import com.wire.kalium.network.api.authenticated.CreateUserTeamDTO
import com.wire.kalium.network.api.authenticated.teams.TeamMemberDTO
import com.wire.kalium.network.api.authenticated.teams.TeamMemberListNonPaginated
import com.wire.kalium.network.api.authenticated.userDetails.ListUserRequest
import com.wire.kalium.network.api.authenticated.userDetails.ListUsersDTO
import com.wire.kalium.network.api.authenticated.userDetails.QualifiedUserIdListRequest
import com.wire.kalium.network.api.base.authenticated.userDetails.UserDetailsApi
import com.wire.kalium.network.api.authenticated.userDetails.qualifiedIds
import com.wire.kalium.network.api.base.authenticated.TeamsApi
import com.wire.kalium.network.api.base.authenticated.UpgradePersonalToTeamApi
import com.wire.kalium.network.api.base.authenticated.self.SelfApi
import com.wire.kalium.network.api.base.authenticated.userDetails.UserDetailsApi
import com.wire.kalium.network.api.model.LegalHoldStatusDTO
import com.wire.kalium.network.api.model.UserProfileDTO
import com.wire.kalium.network.utils.NetworkResponse
Expand Down Expand Up @@ -801,6 +803,37 @@ class UserRepositoryTest {
}.wasInvoked(exactly = once)
}

@Test
fun givenApiRequestSucceeds_whenPersonalUserUpgradesToTeam_thenShouldSucceed() = runTest {
// given
val (arrangement, userRepository) = Arrangement()
.withRemoteGetSelfReturningDeletedUser()
.withMigrateUserToTeamSuccess()
.arrange()
// when
val result = userRepository.migrateUserToTeam("teamName")
// then
result.shouldSucceed()
coVerify {
arrangement.upgradePersonalToTeamApi.migrateToTeam(any())
}.wasInvoked(exactly = once)
}

@Test
fun givenApiRequestFails_whenPersonalUserUpgradesToTeam_thenShouldPropagateError() = runTest {
// given
val (arrangement, userRepository) = Arrangement()
.withMigrateUserToTeamFailure()
.arrange()
// when
val result = userRepository.migrateUserToTeam("teamName")
// then
result.shouldFail()
coVerify {
arrangement.upgradePersonalToTeamApi.migrateToTeam(any())
}.wasInvoked(exactly = once)
}

private class Arrangement {
@Mock
val userDAO = mock(UserDAO::class)
Expand Down Expand Up @@ -829,20 +862,25 @@ class UserRepositoryTest {
@Mock
val legalHoldHandler: LegalHoldHandler = mock(LegalHoldHandler::class)

@Mock
val upgradePersonalToTeamApi: UpgradePersonalToTeamApi =
mock(UpgradePersonalToTeamApi::class)

val selfUserId = TestUser.SELF.id

val userRepository: UserRepository by lazy {
UserDataSource(
userDAO,
metadataDAO,
clientDAO,
selfApi,
userDetailsApi,
teamsApi,
sessionRepository,
selfUserId,
selfTeamIdProvider,
legalHoldHandler
userDAO = userDAO,
metadataDAO = metadataDAO,
clientDAO = clientDAO,
selfApi = selfApi,
userDetailsApi = userDetailsApi,
teamsApi = teamsApi,
sessionRepository = sessionRepository,
selfUserId = selfUserId,
selfTeamIdProvider = selfTeamIdProvider,
legalHoldHandler = legalHoldHandler,
upgradePersonalToTeamApi = upgradePersonalToTeamApi,
)
}

Expand Down Expand Up @@ -1029,6 +1067,24 @@ class UserRepositoryTest {
}.returns(NetworkResponse.Success(result, mapOf(), 200))
}

suspend fun withMigrateUserToTeamSuccess() = apply {
coEvery {
upgradePersonalToTeamApi.migrateToTeam(any())
}.returns(
NetworkResponse.Success(
CreateUserTeamDTO("teamId", "teamName"),
mapOf(),
200
)
)
}

suspend fun withMigrateUserToTeamFailure() = apply {
coEvery {
upgradePersonalToTeamApi.migrateToTeam(any())
}.returns(NetworkResponse.Error(generic))
}

suspend inline fun arrange(block: (Arrangement.() -> Unit) = { }): Pair<Arrangement, UserRepository> {
withSelfUserIdFlowMetadataReturning(flowOf(TestUser.JSON_QUALIFIED_ID))
coEvery {
Expand Down
Loading
Loading