Skip to content

Commit

Permalink
fix: asset restriction [WPB-9947] (#2831) (#2856) (#2862) (#3157)
Browse files Browse the repository at this point in the history
(cherry picked from commit 3213876)
  • Loading branch information
MohamadJaara committed Jul 8, 2024
1 parent 9bb37df commit a666930
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 74 deletions.
3 changes: 2 additions & 1 deletion app/src/main/kotlin/com/wire/android/ui/WireActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import com.wire.android.ui.home.E2EICertificateRevokedDialog
import com.wire.android.ui.home.E2EIRequiredDialog
import com.wire.android.ui.home.E2EIResultDialog
import com.wire.android.ui.home.E2EISnoozeDialog
import com.wire.android.ui.home.FeatureFlagState
import com.wire.android.ui.home.appLock.LockCodeTimeManager
import com.wire.android.ui.home.sync.FeatureFlagNotificationViewModel
import com.wire.android.ui.legalhold.dialog.deactivated.LegalHoldDeactivatedDialog
Expand Down Expand Up @@ -377,7 +378,7 @@ class WireActivity : AppCompatActivity() {
}
if (showFileSharingDialog) {
FileRestrictionDialog(
isFileSharingEnabled = isFileSharingEnabledState,
isFileSharingEnabled = (isFileSharingState !is FeatureFlagState.FileSharingState.DisabledByTeam),
hideDialogStatus = featureFlagNotificationViewModel::dismissFileSharingDialog
)
}
Expand Down
22 changes: 18 additions & 4 deletions app/src/main/kotlin/com/wire/android/ui/home/FeatureFlagState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
package com.wire.android.ui.home

import com.wire.android.ui.home.messagecomposer.SelfDeletionDuration
import com.wire.kalium.logic.configuration.FileSharingStatus
import kotlin.time.Duration

data class FeatureFlagState(
val showFileSharingDialog: Boolean = false,
val isFileSharingEnabledState: Boolean = true,
val fileSharingRestrictedState: SharingRestrictedState? = null,
val isFileSharingState: FileSharingState = FileSharingState.NoUser,
val shouldShowGuestRoomLinkDialog: Boolean = false,
val shouldShowE2eiCertificateRevokedDialog: Boolean = false,
val shouldShowTeamAppLockDialog: Boolean = false,
Expand All @@ -40,8 +40,12 @@ data class FeatureFlagState(
val showCallEndedBecauseOfConversationDegraded: Boolean = false,
val startGettingE2EICertificate: Boolean = false
) {
enum class SharingRestrictedState {
NONE, NO_USER, RESTRICTED_IN_TEAM

sealed interface FileSharingState {
data object NoUser : FileSharingState
data object AllowAll : FileSharingState
data class AllowSome(val allowedList: List<String>) : FileSharingState
data object DisabledByTeam : FileSharingState
}

data class E2EISnooze(val timeLeft: Duration)
Expand All @@ -64,3 +68,13 @@ data class FeatureFlagState(
data class Success(val certificate: String) : E2EIResult()
}
}

fun FileSharingStatus.Value.toFeatureFlagState(): FeatureFlagState.FileSharingState {
return when (this) {
FileSharingStatus.Value.Disabled -> FeatureFlagState.FileSharingState.DisabledByTeam
FileSharingStatus.Value.EnabledAll -> FeatureFlagState.FileSharingState.AllowAll
is FileSharingStatus.Value.EnabledSome -> FeatureFlagState.FileSharingState.AllowSome(
allowedType
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ import com.wire.android.model.SnackBarMessage
import com.wire.android.util.ui.UIText

sealed class ConversationSnackbarMessages(override val uiText: UIText) : SnackBarMessage {
object ErrorPickingAttachment : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_generic))
object ErrorSendingAsset : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_sending_asset))
object ErrorSendingImage : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_sending_image))
object ErrorDownloadingAsset : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_downloading_asset))
object ErrorOpeningAssetFile : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_opening_asset_file))
object ErrorDeletingMessage : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_deleting_message))
data object ErrorPickingAttachment : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_generic))
data object ErrorSendingAsset : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_sending_asset))
data object ErrorSendingImage : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_sending_image))
data object ErrorDownloadingAsset : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_downloading_asset))
data object ErrorOpeningAssetFile : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_opening_asset_file))
data object ErrorDeletingMessage : ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_deleting_message))
data object ErrorAssetRestriction : ConversationSnackbarMessages(UIText.StringResource(R.string.restricted_asset_error_toast_message))
data class ErrorMaxAssetSize(val maxLimitInMB: Int) :
ConversationSnackbarMessages(UIText.StringResource(R.string.error_conversation_max_asset_size_limit, maxLimitInMB))

Expand All @@ -42,6 +43,6 @@ sealed class MediaGallerySnackbarMessages(override val uiText: UIText) : SnackBa
class OnImageDownloaded(val assetName: String? = null) :
MediaGallerySnackbarMessages(UIText.StringResource(R.string.media_gallery_on_image_downloaded, assetName ?: ""))

object OnImageDownloadError : MediaGallerySnackbarMessages(UIText.StringResource(R.string.media_gallery_on_image_download_error))
object DeletingMessageError : MediaGallerySnackbarMessages(UIText.StringResource(R.string.error_conversation_deleting_message))
data object OnImageDownloadError : MediaGallerySnackbarMessages(UIText.StringResource(R.string.media_gallery_on_image_download_error))
data object DeletingMessageError : MediaGallerySnackbarMessages(UIText.StringResource(R.string.error_conversation_deleting_message))
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.wire.android.ui.navArgs
import com.wire.android.ui.sharing.SendMessagesSnackbarMessages
import com.wire.android.util.SUPPORTED_AUDIO_MIME_TYPE
import com.wire.android.util.ImageUtil
import com.wire.android.util.SUPPORTED_AUDIO_MIME_TYPE
import com.wire.android.util.dispatchers.DispatcherProvider
import com.wire.android.util.getAudioLengthInMs
import com.wire.kalium.logic.CoreFailure
Expand Down Expand Up @@ -338,18 +339,29 @@ class SendMessageViewModel @Inject constructor(
}
}

private fun Either<CoreFailure, Unit>.handleLegalHoldFailureAfterSendingMessage(conversationId: ConversationId) =
private fun Either<CoreFailure, Unit>.handleLegalHoldFailureAfterSendingMessage(
conversationId: ConversationId
): Either<CoreFailure, Unit> =
onFailure { it.handleLegalHoldFailureAfterSendingMessage(conversationId) }

private fun ScheduleNewAssetMessageResult.handleLegalHoldFailureAfterSendingMessage(conversationId: ConversationId) = let {
if (it is ScheduleNewAssetMessageResult.Failure) {
it.coreFailure.handleLegalHoldFailureAfterSendingMessage(conversationId)
}
when (this) {
is ScheduleNewAssetMessageResult.Failure -> Either.Left(coreFailure)
is ScheduleNewAssetMessageResult.Success -> Either.Right(Unit)
private fun ScheduleNewAssetMessageResult.handleLegalHoldFailureAfterSendingMessage(
conversationId: ConversationId
): Either<CoreFailure?, Unit> =
let {
when (this) {
is ScheduleNewAssetMessageResult.Success -> Either.Right(Unit)
ScheduleNewAssetMessageResult.Failure.DisabledByTeam,
ScheduleNewAssetMessageResult.Failure.RestrictedFileType -> {
onSnackbarMessage(ConversationSnackbarMessages.ErrorAssetRestriction)
Either.Left(null)
}

is ScheduleNewAssetMessageResult.Failure.Generic -> {
this.coreFailure.handleLegalHoldFailureAfterSendingMessage(conversationId)
Either.Left(coreFailure)
}
}
}
}

fun retrySendingMessages(messageIdList: List<String>, conversationId: ConversationId) {
messageIdList.forEach {
Expand Down Expand Up @@ -405,5 +417,11 @@ class SendMessageViewModel @Inject constructor(

private companion object {
const val MAX_LIMIT_MESSAGE_SEND = 20
private fun beforeSendingMessage() {
viewState = viewState.copy(messageSent = false, inProgress = true)
}

private fun Either<CoreFailure?, Unit>.handleAfterMessageResult() {
viewState = viewState.copy(messageSent = this.isRight(), inProgress = false)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ import com.wire.android.feature.DisableAppLockUseCase
import com.wire.android.ui.home.FeatureFlagState
import com.wire.android.ui.home.conversations.selfdeletion.SelfDeletionMapper.toSelfDeletionDuration
import com.wire.android.ui.home.messagecomposer.SelfDeletionDuration
import com.wire.android.ui.home.toFeatureFlagState
import com.wire.kalium.logic.CoreFailure
import com.wire.kalium.logic.CoreLogic
import com.wire.kalium.logic.configuration.FileSharingStatus
import com.wire.kalium.logic.data.message.TeamSelfDeleteTimer
import com.wire.kalium.logic.data.sync.SyncState
import com.wire.kalium.logic.data.user.UserId
Expand Down Expand Up @@ -87,14 +87,14 @@ class FeatureFlagNotificationViewModel @Inject constructor(
currentUserId = null
appLogger.i("$TAG: Failure while getting current session")
featureFlagState = FeatureFlagState( // no session, clear feature flag state to default and set NO_USER
fileSharingRestrictedState = FeatureFlagState.SharingRestrictedState.NO_USER
isFileSharingState = FeatureFlagState.FileSharingState.NoUser
)
}

currentSessionResult is CurrentSessionResult.Success && !currentSessionResult.accountInfo.isValid() -> {
appLogger.i("$TAG: Invalid current session")
featureFlagState = FeatureFlagState( // invalid session, clear feature flag state to default and set NO_USER
fileSharingRestrictedState = FeatureFlagState.SharingRestrictedState.NO_USER
isFileSharingState = FeatureFlagState.FileSharingState.NoUser
)
}

Expand Down Expand Up @@ -132,22 +132,11 @@ class FeatureFlagNotificationViewModel @Inject constructor(

private suspend fun setFileSharingState(userId: UserId) {
coreLogic.getSessionScope(userId).observeFileSharingStatus().collect { fileSharingStatus ->
fileSharingStatus.state.let {
// TODO: handle restriction when sending assets
val (fileSharingRestrictedState, state) = if (it is FileSharingStatus.Value.EnabledAll) {
FeatureFlagState.SharingRestrictedState.NONE to true
} else {
FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM to false
}

featureFlagState = featureFlagState.copy(
fileSharingRestrictedState = fileSharingRestrictedState,
isFileSharingEnabledState = state
)
}
fileSharingStatus.isStatusChanged?.let {
featureFlagState = featureFlagState.copy(showFileSharingDialog = it)
}
val state: FeatureFlagState.FileSharingState = fileSharingStatus.state.toFeatureFlagState()
featureFlagState = featureFlagState.copy(
isFileSharingState = state,
showFileSharingDialog = fileSharingStatus.isStatusChanged ?: false
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ import com.wire.android.util.ui.PreviewMultipleThemes
@Destination
@Composable
fun AboutThisAppScreen(
viewModel: AboutThisAppViewModel = hiltViewModel(),
navigator: Navigator
navigator: Navigator,
viewModel: AboutThisAppViewModel = hiltViewModel()
) {
val context = LocalContext.current
AboutThisAppContent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
*/
package com.wire.android.ui.sharing

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Parcelable
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.runtime.Stable
Expand All @@ -36,6 +38,8 @@ import com.wire.android.mapper.toUIPreview
import com.wire.android.model.ImageAsset
import com.wire.android.model.SnackBarMessage
import com.wire.android.model.UserAvatarData
import com.wire.android.ui.home.conversations.ConversationSnackbarMessages
import com.wire.android.ui.home.conversations.model.AssetBundle
import com.wire.android.ui.common.textfield.textAsFlow
import com.wire.android.ui.home.conversations.search.DEFAULT_SEARCH_QUERY_DEBOUNCE
import com.wire.android.ui.home.conversations.usecase.HandleUriAssetUseCase
Expand All @@ -59,6 +63,7 @@ import com.wire.kalium.logic.feature.selfDeletingMessages.ObserveSelfDeletionTim
import com.wire.kalium.logic.feature.selfDeletingMessages.PersistNewSelfDeletionTimerUseCase
import com.wire.kalium.logic.feature.user.GetSelfUserUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
Expand All @@ -81,6 +86,7 @@ import javax.inject.Inject
@OptIn(FlowPreview::class)
@Suppress("LongParameterList", "TooManyFunctions")
class ImportMediaAuthenticatedViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val getSelf: GetSelfUserUseCase,
private val userTypeMapper: UserTypeMapper,
private val observeConversationListDetails: ObserveConversationListDetailsUseCase,
Expand Down Expand Up @@ -301,6 +307,73 @@ class ImportMediaAuthenticatedViewModel @Inject constructor(
}
}

fun checkRestrictionsAndSendImportedMedia(onSent: (ConversationId) -> Unit) =
viewModelScope.launch(dispatchers.default()) {
val conversation =
importMediaState.selectedConversationItem.firstOrNull() ?: return@launch
val assetsToSend = importMediaState.importedAssets
val textToSend = importMediaState.importedText

if (assetsToSend.size > MAX_LIMIT_MEDIA_IMPORT) {
onSnackbarMessage(ImportMediaSnackbarMessages.MaxAmountOfAssetsReached)
} else {
val jobs: MutableCollection<Job> = mutableListOf()

textToSend?.let {
sendTextMessage(
conversationId = conversation.conversationId,
text = it
)
} ?: assetsToSend.forEach { importedAsset ->
val isImage = importedAsset is ImportedMediaAsset.Image
val job = viewModelScope.launch {
sendAssetMessage(
conversationId = conversation.conversationId,
assetDataPath = importedAsset.assetBundle.dataPath,
assetName = importedAsset.assetBundle.fileName,
assetDataSize = importedAsset.assetBundle.dataSize,
assetMimeType = importedAsset.assetBundle.mimeType,
assetWidth = if (isImage) (importedAsset as ImportedMediaAsset.Image).width else 0,
assetHeight = if (isImage) (importedAsset as ImportedMediaAsset.Image).height else 0,
audioLengthInMs = getAudioLengthInMs(
dataPath = importedAsset.assetBundle.dataPath,
mimeType = importedAsset.assetBundle.mimeType,
)
).also {
handleError(it, conversation.conversationId)
}
}
jobs.add(job)
}

jobs.joinAll()
withContext(dispatchers.main()) {
onSent(conversation.conversationId)
}
}
}

private fun handleError(result: ScheduleNewAssetMessageResult, conversationId: ConversationId) {
when (result) {
is ScheduleNewAssetMessageResult.Success -> appLogger.d(
"Successfully imported asset message to conversationId=${conversationId.toLogString()}"
)

is ScheduleNewAssetMessageResult.Failure.Generic ->
appLogger.e(
"Failed to import asset message to conversationId=${conversationId.toLogString()}"
)

ScheduleNewAssetMessageResult.Failure.RestrictedFileType,
ScheduleNewAssetMessageResult.Failure.DisabledByTeam -> {
onSnackbarMessage(ConversationSnackbarMessages.ErrorAssetRestriction)
appLogger.e(
"Failed to import asset message to conversationId=${conversationId.toLogString()}"
)
}
}
}

fun onNewConversationPicked(conversationId: ConversationId) = viewModelScope.launch {
importMediaState = importMediaState.copy(
selfDeletingTimer = observeSelfDeletionSettingsForConversation(
Expand Down Expand Up @@ -342,7 +415,7 @@ class ImportMediaAuthenticatedViewModel @Inject constructor(
}
}

fun onSnackbarMessage(type: SnackBarMessage) = viewModelScope.launch {
private fun onSnackbarMessage(type: SnackBarMessage) = viewModelScope.launch {
_infoMessage.emit(type)
}
}
Expand All @@ -355,5 +428,6 @@ data class ImportMediaAuthenticatedState(
val isImporting: Boolean = false,
val shareableConversationListState: ShareableConversationListState = ShareableConversationListState(),
val selectedConversationItem: List<ConversationItem> = emptyList(),
val selfDeletingTimer: SelfDeletionTimer = SelfDeletionTimer.Enabled(null)
val selfDeletingTimer: SelfDeletionTimer = SelfDeletionTimer.Enabled(null),
val assetSendError: AssetSendError? = null
)
Loading

0 comments on commit a666930

Please sign in to comment.