Skip to content

Commit

Permalink
feat: Allow admins to remove groups [WPB-11559] (#3652)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-zagorski authored Nov 26, 2024
1 parent 29830bd commit 90c9cba
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.wire.kalium.logic.data.conversation.ConversationDetails.Self
import com.wire.kalium.logic.data.conversation.ConversationDetailsWithEvents
import com.wire.kalium.logic.data.conversation.MutedConversationStatus
import com.wire.kalium.logic.data.conversation.UnreadEventCount
import com.wire.kalium.logic.data.id.TeamId
import com.wire.kalium.logic.data.message.UnreadEventType
import com.wire.kalium.logic.data.user.ConnectionState
import com.wire.kalium.logic.data.user.UserAvailabilityStatus
Expand All @@ -43,6 +44,7 @@ fun ConversationDetailsWithEvents.toConversationItem(
wireSessionImageLoader: WireSessionImageLoader,
userTypeMapper: UserTypeMapper,
searchQuery: String,
selfUserTeamId: TeamId?
): ConversationItem = when (val conversationDetails = this.conversationDetails) {
is Group -> {
ConversationItem.GroupConversation(
Expand All @@ -56,7 +58,7 @@ fun ConversationDetailsWithEvents.toConversationItem(
unreadEventCount = unreadEventCount
),
hasOnGoingCall = conversationDetails.hasOngoingCall && conversationDetails.isSelfUserMember,
isSelfUserCreator = conversationDetails.isSelfUserCreator,
isFromTheSameTeam = conversationDetails.conversation.teamId == selfUserTeamId,
isSelfUserMember = conversationDetails.isSelfUserMember,
teamId = conversationDetails.conversation.teamId,
selfMemberRole = conversationDetails.selfRole,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ sealed class ConversationOptionNavigation {
}

sealed class ConversationTypeDetail {
data class Group(val conversationId: ConversationId, val isCreator: Boolean) : ConversationTypeDetail()
data class Group(val conversationId: ConversationId, val isFromTheSameTeam: Boolean) : ConversationTypeDetail()
data class Private(
val avatarAsset: UserAvatarAsset?,
val userId: UserId,
Expand Down Expand Up @@ -134,10 +134,11 @@ data class ConversationSheetContent(
&& (conversationTypeDetail.blockingState != BlockingState.BLOCKED))
|| conversationTypeDetail is ConversationTypeDetail.Group)

fun canDeleteGroup(): Boolean =
conversationTypeDetail is ConversationTypeDetail.Group &&
fun canDeleteGroup(): Boolean {
return conversationTypeDetail is ConversationTypeDetail.Group &&
selfRole == Conversation.Member.Role.Admin &&
conversationTypeDetail.isCreator && isTeamConversation
conversationTypeDetail.isFromTheSameTeam && isTeamConversation
}

fun canLeaveTheGroup(): Boolean = conversationTypeDetail is ConversationTypeDetail.Group && isSelfUserMember

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fun rememberConversationSheetState(
mutingConversationState = mutedStatus,
conversationTypeDetail = ConversationTypeDetail.Group(
conversationId = conversationId,
isCreator = isSelfUserCreator
isFromTheSameTeam = isFromTheSameTeam
),
isTeamConversation = teamId != null,
selfRole = selfMemberRole,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
Expand Down Expand Up @@ -150,7 +151,10 @@ class GroupConversationDetailsViewModel @Inject constructor(
title = groupDetails.conversation.name.orEmpty(),
conversationId = conversationId,
mutingConversationState = groupDetails.conversation.mutedStatus,
conversationTypeDetail = ConversationTypeDetail.Group(conversationId, groupDetails.isSelfUserCreator),
conversationTypeDetail = ConversationTypeDetail.Group(
conversationId = conversationId,
isFromTheSameTeam = groupDetails.conversation.teamId == observerSelfUser().firstOrNull()?.teamId
),
isTeamConversation = groupDetails.conversation.teamId?.value != null,
selfRole = groupDetails.selfRole,
isArchived = groupDetails.conversation.archived,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ import com.wire.kalium.logic.data.conversation.ConversationQueryConfig
import com.wire.kalium.logic.feature.conversation.GetPaginatedFlowOfConversationDetailsWithEventsBySearchQueryUseCase
import com.wire.kalium.logic.feature.conversation.folder.GetFavoriteFolderUseCase
import com.wire.kalium.logic.feature.conversation.folder.ObserveConversationsFromFolderUseCase
import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
Expand All @@ -46,6 +48,7 @@ class GetConversationsFromSearchUseCase @Inject constructor(
private val wireSessionImageLoader: WireSessionImageLoader,
private val userTypeMapper: UserTypeMapper,
private val dispatchers: DispatcherProvider,
private val observeSelfUser: GetSelfUserUseCase
) {
suspend operator fun invoke(
searchQuery: String = "",
Expand Down Expand Up @@ -95,7 +98,12 @@ class GetConversationsFromSearchUseCase @Inject constructor(
}
.map { pagingData ->
pagingData.map {
it.toConversationItem(wireSessionImageLoader, userTypeMapper, searchQuery)
it.toConversationItem(
wireSessionImageLoader = wireSessionImageLoader,
userTypeMapper = userTypeMapper,
searchQuery = searchQuery,
selfUserTeamId = observeSelfUser().firstOrNull()?.teamId
)
}
}.flowOn(dispatchers.io())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldStateForSelfUserU
import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase
import com.wire.kalium.logic.feature.team.DeleteTeamConversationUseCase
import com.wire.kalium.logic.feature.team.Result
import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
import com.wire.kalium.util.DateTimeUtil
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
Expand All @@ -85,6 +86,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
Expand Down Expand Up @@ -141,6 +143,7 @@ class ConversationListViewModelImpl @AssistedInject constructor(
@CurrentAccount val currentAccount: UserId,
private val wireSessionImageLoader: WireSessionImageLoader,
private val userTypeMapper: UserTypeMapper,
private val observeSelfUser: GetSelfUserUseCase
) : ConversationListViewModel, ViewModel() {

@AssistedFactory
Expand Down Expand Up @@ -238,6 +241,7 @@ class ConversationListViewModelImpl @AssistedInject constructor(
wireSessionImageLoader = wireSessionImageLoader,
userTypeMapper = userTypeMapper,
searchQuery = searchQuery,
selfUserTeamId = observeSelfUser().firstOrNull()?.teamId
).hideIndicatorForSelfUserUnderLegalHold(selfUserLegalHoldStatus)
} to searchQuery
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ fun PreviewGroupConversationItemWithUnreadCount() = WireTheme {
selfMemberRole = null,
teamId = null,
isArchived = false,
isFromTheSameTeam = false,
mlsVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
proteusVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
isFavorite = false
Expand All @@ -336,6 +337,7 @@ fun PreviewGroupConversationItemWithNoBadges() = WireTheme {
selfMemberRole = null,
teamId = null,
isArchived = false,
isFromTheSameTeam = false,
mlsVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
proteusVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
isFavorite = false
Expand Down Expand Up @@ -364,6 +366,7 @@ fun PreviewGroupConversationItemWithLastDeletedMessage() = WireTheme {
selfMemberRole = null,
teamId = null,
isArchived = false,
isFromTheSameTeam = false,
mlsVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
proteusVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
isFavorite = false
Expand All @@ -390,6 +393,7 @@ fun PreviewGroupConversationItemWithMutedBadgeAndUnreadMentionBadge() = WireThem
selfMemberRole = null,
teamId = null,
isArchived = false,
isFromTheSameTeam = false,
mlsVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
proteusVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
isFavorite = false
Expand Down Expand Up @@ -417,6 +421,7 @@ fun PreviewGroupConversationItemWithOngoingCall() = WireTheme {
teamId = null,
hasOnGoingCall = true,
isArchived = false,
isFromTheSameTeam = false,
mlsVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
proteusVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
isFavorite = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ fun previewConversationList(count: Int, startIndex: Int = 0, unread: Boolean = f
teamId = null,
hasOnGoingCall = false,
isArchived = false,
isFromTheSameTeam = false,
mlsVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
proteusVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
searchQuery = searchQuery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ sealed class ConversationItem : ConversationFolderItem {
data class GroupConversation(
val groupName: String,
val hasOnGoingCall: Boolean = false,
val isSelfUserCreator: Boolean = false,
val selfMemberRole: Conversation.Member.Role?,
val isFromTheSameTeam: Boolean,
val isSelfUserMember: Boolean = true,
override val conversationId: ConversationId,
override val mutedStatus: MutedConversationStatus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ object TestConversationItem {
),
badgeEventType = BadgeEventType.UnreadMessage(100),
selfMemberRole = null,
isFromTheSameTeam = false,
teamId = null,
isArchived = false,
mlsVerificationStatus = Conversation.VerificationStatus.NOT_VERIFIED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class GroupConversationDetailsViewModelTest {
conversationName = conversationDetails.conversation.name.orEmpty(),
conversationTypeDetail = ConversationTypeDetail.Group(
conversationId = conversationDetails.conversation.id,
isCreator = conversationDetails.isSelfUserCreator
isFromTheSameTeam = false
),
isArchived = conversationDetails.conversation.archived,
isMember = true
Expand Down Expand Up @@ -202,7 +202,7 @@ class GroupConversationDetailsViewModelTest {
conversationName = conversationDetails.conversation.name.orEmpty(),
conversationTypeDetail = ConversationTypeDetail.Group(
conversationId = conversationDetails.conversation.id,
isCreator = conversationDetails.isSelfUserCreator
isFromTheSameTeam = false
),
isArchived = conversationDetails.conversation.archived,
isMember = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import androidx.paging.testing.asSnapshot
import com.wire.android.config.CoroutineTestExtension
import com.wire.android.config.TestDispatcherProvider
import com.wire.android.framework.TestConversationDetails
import com.wire.android.framework.TestUser
import com.wire.android.mapper.UserTypeMapper
import com.wire.android.ui.home.conversationslist.model.ConversationItem
import com.wire.android.ui.home.conversationslist.model.Membership
import com.wire.android.util.ui.WireSessionImageLoader
import com.wire.kalium.logic.data.conversation.ConversationDetailsWithEvents
Expand All @@ -33,6 +35,7 @@ import com.wire.kalium.logic.data.conversation.FolderType
import com.wire.kalium.logic.feature.conversation.GetPaginatedFlowOfConversationDetailsWithEventsBySearchQueryUseCase
import com.wire.kalium.logic.feature.conversation.folder.GetFavoriteFolderUseCase
import com.wire.kalium.logic.feature.conversation.folder.ObserveConversationsFromFolderUseCase
import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.coVerify
Expand All @@ -42,6 +45,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertInstanceOf
import org.junit.jupiter.api.extension.ExtendWith

@OptIn(ExperimentalCoroutinesApi::class)
Expand Down Expand Up @@ -73,6 +77,7 @@ class GetConversationsFromSearchUseCaseTest {
)
val (arrangement, useCase) = Arrangement()
.withPaginatedResult(conversationsList)
.withSelfUser()
.arrange()
// When
val result = with(arrangement.queryConfig) {
Expand All @@ -99,6 +104,7 @@ class GetConversationsFromSearchUseCaseTest {
val (arrangement, useCase) = Arrangement()
.withFavoriteFolderResult(folderResult)
.withFolderConversationsResult(conversationsList)
.withSelfUser()
.arrange()

// When
Expand All @@ -116,6 +122,52 @@ class GetConversationsFromSearchUseCaseTest {
coVerify(exactly = 0) { arrangement.useCase(any(), any(), any()) }
}

@Test
fun givenGroupConversation_whenConversationFromTheSameTeam_thenReturnDataWithProperlySameTeamSet() =
runTest(dispatcherProvider.main()) {
// Given
val conversationsList = listOf(
ConversationDetailsWithEvents(
TestConversationDetails.GROUP.copy(
conversation = TestConversationDetails.GROUP.conversation.copy(
teamId = TestUser.SELF_USER.teamId
)
)
)
)
val (arrangement, useCase) = Arrangement()
.withPaginatedResult(conversationsList)
.withSelfUser()
.arrange()
// When
val result = with(arrangement.queryConfig) {
useCase(searchQuery, fromArchive, newActivitiesOnTop, onlyInteractionEnabled).asSnapshot()
}
// Then
val conversation = result.first()
assertInstanceOf<ConversationItem.GroupConversation>(conversation)
assertEquals(true, conversation.isFromTheSameTeam)
}

@Test
fun givenGroupConversation_whenConversationNotFromTheSameTeam_thenReturnDataWithProperlySameTeamSet() =
runTest(dispatcherProvider.main()) {
// Given
val conversationsList = listOf(ConversationDetailsWithEvents(TestConversationDetails.GROUP))
val (arrangement, useCase) = Arrangement()
.withPaginatedResult(conversationsList)
.withSelfUser()
.arrange()
// When
val result = with(arrangement.queryConfig) {
useCase(searchQuery, fromArchive, newActivitiesOnTop, onlyInteractionEnabled).asSnapshot()
}
// Then
val conversation = result.first()
assertInstanceOf<ConversationItem.GroupConversation>(conversation)
assertEquals(false, conversation.isFromTheSameTeam)
}

inner class Arrangement {

@MockK
Expand All @@ -133,6 +185,9 @@ class GetConversationsFromSearchUseCaseTest {
@MockK
lateinit var userTypeMapper: UserTypeMapper

@MockK
lateinit var observeSelfUser: GetSelfUserUseCase

val queryConfig = ConversationQueryConfig(
searchQuery = "search",
fromArchive = false,
Expand Down Expand Up @@ -162,13 +217,18 @@ class GetConversationsFromSearchUseCaseTest {
} returns flowOf(conversations)
}

fun withSelfUser() = apply {
coEvery { observeSelfUser() } returns flowOf(TestUser.SELF_USER)
}

fun arrange() = this to GetConversationsFromSearchUseCase(
useCase,
getFavoriteFolderUseCase,
observeConversationsFromFolderUseCase,
wireSessionImageLoader,
userTypeMapper,
dispatcherProvider
dispatcherProvider,
observeSelfUser
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import com.wire.kalium.logic.feature.legalhold.LegalHoldStateForSelfUser
import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldStateForSelfUserUseCase
import com.wire.kalium.logic.feature.publicuser.RefreshUsersWithoutMetadataUseCase
import com.wire.kalium.logic.feature.team.DeleteTeamConversationUseCase
import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.coVerify
Expand Down Expand Up @@ -274,6 +275,9 @@ class ConversationListViewModelTest {
@MockK
private lateinit var wireSessionImageLoader: WireSessionImageLoader

@MockK
private lateinit var observeSelfUser: GetSelfUserUseCase

init {
MockKAnnotations.init(this, relaxUnitFun = true)
withConversationsPaginated(listOf(TestConversationItem.CONNECTION, TestConversationItem.PRIVATE, TestConversationItem.GROUP))
Expand Down Expand Up @@ -343,7 +347,8 @@ class ConversationListViewModelTest {
observeLegalHoldStateForSelfUser = observeLegalHoldStateForSelfUserUseCase,
userTypeMapper = UserTypeMapper(),
wireSessionImageLoader = wireSessionImageLoader,
usePagination = true,
observeSelfUser = observeSelfUser,
usePagination = true
)
}

Expand Down

0 comments on commit 90c9cba

Please sign in to comment.