Merge pull request #4909 from element-hq/feature/fga/invalid-invite

Change : handle invalid invite error
This commit is contained in:
ganfra 2025-06-20 18:42:09 +02:00 committed by GitHub
commit 7fab4edd41
19 changed files with 121 additions and 38 deletions

View file

@ -10,16 +10,23 @@ package io.element.android.features.invite.impl
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.features.invite.api.SeenInvitesStore import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.libraries.core.extensions.mapFailure
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.exception.ClientException
import io.element.android.libraries.matrix.api.exception.ErrorKind
import io.element.android.libraries.matrix.api.room.join.JoinRoom import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.push.api.notifications.NotificationCleaner import io.element.android.libraries.push.api.notifications.NotificationCleaner
import javax.inject.Inject import javax.inject.Inject
interface AcceptInvite { interface AcceptInvite {
suspend operator fun invoke(roomId: RoomId): Result<RoomId> suspend operator fun invoke(roomId: RoomId): Result<RoomId>
sealed class Failures : Exception() {
data object InvalidInvite : Failures()
}
} }
@ContributesBinding(SessionScope::class) @ContributesBinding(SessionScope::class)
@ -37,6 +44,15 @@ class DefaultAcceptInvite @Inject constructor(
).onSuccess { ).onSuccess {
notificationCleaner.clearMembershipNotificationForRoom(client.sessionId, roomId) notificationCleaner.clearMembershipNotificationForRoom(client.sessionId, roomId)
seenInvitesStore.markAsUnSeen(roomId) seenInvitesStore.markAsUnSeen(roomId)
}.mapFailure {
if (it is ClientException.MatrixApi) {
when (it.kind) {
ErrorKind.Unknown -> AcceptInvite.Failures.InvalidInvite
else -> it
}
} else {
it
}
}.map { roomId } }.map { roomId }
} }
} }

View file

@ -1,14 +1,18 @@
/* /*
* Copyright 2024 New Vector Ltd. * Copyright 2025 New Vector Ltd.
* *
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.invite.api.acceptdecline package io.element.android.features.invite.impl.acceptdecline
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.invite.api.InviteData import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.features.invite.api.acceptdecline.ConfirmingDeclineInvite
import io.element.android.features.invite.impl.AcceptInvite
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
@ -18,26 +22,37 @@ open class AcceptDeclineInviteStateProvider : PreviewParameterProvider<AcceptDec
anAcceptDeclineInviteState(), anAcceptDeclineInviteState(),
anAcceptDeclineInviteState( anAcceptDeclineInviteState(
declineAction = ConfirmingDeclineInvite( declineAction = ConfirmingDeclineInvite(
InviteData(roomId = RoomId("!room:matrix.org"), isDm = true, roomName = "Alice"), InviteData(
roomId = RoomId("!room:matrix.org"),
isDm = true,
roomName = "Alice"
),
blockUser = false, blockUser = false,
), ),
), ),
anAcceptDeclineInviteState( anAcceptDeclineInviteState(
declineAction = ConfirmingDeclineInvite( declineAction = ConfirmingDeclineInvite(
InviteData(roomId = RoomId("!room:matrix.org"), isDm = true, roomName = "Alice"), InviteData(
roomId = RoomId("!room:matrix.org"),
isDm = true,
roomName = "Alice"
),
blockUser = true, blockUser = true,
), ),
), ),
anAcceptDeclineInviteState( anAcceptDeclineInviteState(
acceptAction = AsyncAction.Failure(RuntimeException("Error while accepting invite")), acceptAction = AsyncAction.Failure(RuntimeException("Error while accepting invite")),
), ),
anAcceptDeclineInviteState(
acceptAction = AsyncAction.Failure(AcceptInvite.Failures.InvalidInvite),
),
anAcceptDeclineInviteState( anAcceptDeclineInviteState(
declineAction = AsyncAction.Failure(RuntimeException("Error while declining invite")), declineAction = AsyncAction.Failure(RuntimeException("Error while declining invite")),
), ),
) )
} }
fun anAcceptDeclineInviteState( private fun anAcceptDeclineInviteState(
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized, acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized, declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
eventSink: (AcceptDeclineInviteEvents) -> Unit = {} eventSink: (AcceptDeclineInviteEvents) -> Unit = {}

View file

@ -15,8 +15,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.invite.api.InviteData import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteStateProvider
import io.element.android.features.invite.api.acceptdecline.ConfirmingDeclineInvite import io.element.android.features.invite.api.acceptdecline.ConfirmingDeclineInvite
import io.element.android.features.invite.impl.AcceptInvite
import io.element.android.features.invite.impl.R import io.element.android.features.invite.impl.R
import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
@ -39,6 +39,16 @@ fun AcceptDeclineInviteView(
onErrorDismiss = { onErrorDismiss = {
state.eventSink(InternalAcceptDeclineInviteEvents.DismissAcceptError) state.eventSink(InternalAcceptDeclineInviteEvents.DismissAcceptError)
}, },
errorTitle = {
stringResource(CommonStrings.common_something_went_wrong)
},
errorMessage = { error ->
if (error is AcceptInvite.Failures.InvalidInvite) {
stringResource(CommonStrings.error_invalid_invite)
} else {
stringResource(CommonStrings.error_network_or_server_issue)
}
}
) )
AsyncActionView( AsyncActionView(
async = state.declineAction, async = state.declineAction,
@ -46,6 +56,12 @@ fun AcceptDeclineInviteView(
onErrorDismiss = { onErrorDismiss = {
state.eventSink(InternalAcceptDeclineInviteEvents.DismissDeclineError) state.eventSink(InternalAcceptDeclineInviteEvents.DismissDeclineError)
}, },
errorTitle = {
stringResource(CommonStrings.common_something_went_wrong)
},
errorMessage = {
stringResource(CommonStrings.error_network_or_server_issue)
},
confirmationDialog = { confirming -> confirmationDialog = { confirming ->
// Note: confirming will always be of type ConfirmingDeclineInvite. // Note: confirming will always be of type ConfirmingDeclineInvite.
if (confirming is ConfirmingDeclineInvite) { if (confirming is ConfirmingDeclineInvite) {

View file

@ -34,7 +34,6 @@ import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runUpdatingState import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.core.extensions.mapFailure
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
@ -222,13 +221,7 @@ class JoinRoomPresenter @AssistedInject constructor(
roomIdOrAlias = roomIdOrAlias, roomIdOrAlias = roomIdOrAlias,
serverNames = serverNames, serverNames = serverNames,
trigger = trigger trigger = trigger
).mapFailure { )
if (it is ClientException.MatrixApi && it.kind == ErrorKind.Forbidden) {
JoinRoomFailures.UnauthorizedJoin
} else {
it
}
}
} }
} }

View file

@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.room.RoomType import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.ui.model.InviteSender import io.element.android.libraries.matrix.ui.model.InviteSender
internal const val MAX_KNOCK_MESSAGE_LENGTH = 500 internal const val MAX_KNOCK_MESSAGE_LENGTH = 500
@ -36,7 +37,7 @@ data class JoinRoomState(
val canReportRoom: Boolean, val canReportRoom: Boolean,
val eventSink: (JoinRoomEvents) -> Unit val eventSink: (JoinRoomEvents) -> Unit
) { ) {
val isJoinActionUnauthorized = joinAction is AsyncAction.Failure && joinAction.error is JoinRoomFailures.UnauthorizedJoin val isJoinActionUnauthorized = joinAction is AsyncAction.Failure && joinAction.error is JoinRoom.Failures.UnauthorizedJoin
val joinAuthorisationStatus = when (contentState) { val joinAuthorisationStatus = when (contentState) {
is ContentState.Loaded -> { is ContentState.Loaded -> {
when { when {
@ -107,7 +108,3 @@ sealed interface JoinAuthorisationStatus {
data object Unknown : JoinAuthorisationStatus data object Unknown : JoinAuthorisationStatus
data object Unauthorized : JoinAuthorisationStatus data object Unauthorized : JoinAuthorisationStatus
} }
sealed class JoinRoomFailures : Exception() {
data object UnauthorizedJoin : JoinRoomFailures()
}

View file

@ -9,8 +9,8 @@ package io.element.android.features.joinroom.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.invite.api.InviteData import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.exception.ClientException import io.element.android.libraries.matrix.api.exception.ClientException
import io.element.android.libraries.matrix.api.room.RoomType import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.ui.model.InviteSender import io.element.android.libraries.matrix.ui.model.InviteSender
open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> { open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
@ -44,7 +45,7 @@ open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
), ),
aJoinRoomState( aJoinRoomState(
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin), contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin),
joinAction = AsyncAction.Failure(JoinRoomFailures.UnauthorizedJoin) joinAction = AsyncAction.Failure(JoinRoom.Failures.UnauthorizedJoin)
), ),
aJoinRoomState( aJoinRoomState(
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin), contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin),
@ -198,6 +199,16 @@ fun aJoinRoomState(
eventSink = eventSink eventSink = eventSink
) )
internal fun anAcceptDeclineInviteState(
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
eventSink: (AcceptDeclineInviteEvents) -> Unit = {}
) = AcceptDeclineInviteState(
acceptAction = acceptAction,
declineAction = declineAction,
eventSink = eventSink,
)
internal fun anInviteSender( internal fun anInviteSender(
userId: UserId = UserId("@bob:domain"), userId: UserId = UserId("@bob:domain"),
displayName: String = "Bob", displayName: String = "Bob",

View file

@ -13,7 +13,6 @@ import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.api.SeenInvitesStore import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
import io.element.android.features.invite.api.toInviteData import io.element.android.features.invite.api.toInviteData
import io.element.android.features.invite.test.InMemorySeenInvitesStore import io.element.android.features.invite.test.InMemorySeenInvitesStore
import io.element.android.features.joinroom.impl.di.CancelKnockRoom import io.element.android.features.joinroom.impl.di.CancelKnockRoom
@ -36,6 +35,7 @@ import io.element.android.libraries.matrix.api.exception.ErrorKind
import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
import io.element.android.libraries.matrix.api.room.RoomType import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
@ -304,7 +304,7 @@ class JoinRoomPresenterTest {
val presenter = createJoinRoomPresenter( val presenter = createJoinRoomPresenter(
roomDescription = Optional.of(roomDescription), roomDescription = Optional.of(roomDescription),
joinRoomLambda = { _, _, _ -> joinRoomLambda = { _, _, _ ->
Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden", null)) Result.failure(JoinRoom.Failures.UnauthorizedJoin)
}, },
) )
presenter.test { presenter.test {
@ -316,7 +316,7 @@ class JoinRoomPresenterTest {
assertThat(state.joinAction).isEqualTo(AsyncAction.Loading) assertThat(state.joinAction).isEqualTo(AsyncAction.Loading)
} }
awaitItem().also { state -> awaitItem().also { state ->
assertThat(state.joinAction).isEqualTo(AsyncAction.Failure(JoinRoomFailures.UnauthorizedJoin)) assertThat(state.joinAction).isEqualTo(AsyncAction.Failure(JoinRoom.Failures.UnauthorizedJoin))
assertThat(state.joinAuthorisationStatus).isEqualTo(JoinAuthorisationStatus.Unauthorized) assertThat(state.joinAuthorisationStatus).isEqualTo(JoinAuthorisationStatus.Unauthorized)
} }
} }

View file

@ -15,6 +15,7 @@ import io.element.android.features.invite.api.InviteData
import io.element.android.features.invite.test.anInviteData import io.element.android.features.invite.test.anInviteData
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.room.RoomType import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.ui.model.toInviteSender import io.element.android.libraries.matrix.ui.model.toInviteSender
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@ -199,9 +200,9 @@ class JoinRoomViewTest {
canReportRoom = false, canReportRoom = false,
eventSink = eventsRecorder, eventSink = eventsRecorder,
) )
rule.setJoinRoomView(state = joinRoomState,) rule.setJoinRoomView(state = joinRoomState)
rule.clickOn(R.string.screen_join_room_decline_and_block_button_title) rule.clickOn(R.string.screen_join_room_decline_and_block_button_title)
eventsRecorder.assertSingle(JoinRoomEvents.DeclineInvite(inviteData, true)) eventsRecorder.assertSingle(JoinRoomEvents.DeclineInvite(inviteData, true))
} }
@Test @Test
@ -239,7 +240,7 @@ class JoinRoomViewTest {
rule.setJoinRoomView( rule.setJoinRoomView(
aJoinRoomState( aJoinRoomState(
contentState = aLoadedContentState(), contentState = aLoadedContentState(),
joinAction = AsyncAction.Failure(JoinRoomFailures.UnauthorizedJoin), joinAction = AsyncAction.Failure(JoinRoom.Failures.UnauthorizedJoin),
eventSink = eventsRecorder, eventSink = eventsRecorder,
), ),
onBackClick = it onBackClick = it

View file

@ -8,8 +8,8 @@
package io.element.android.features.roomlist.impl package io.element.android.features.roomlist.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
import io.element.android.features.leaveroom.api.LeaveRoomState import io.element.android.features.leaveroom.api.LeaveRoomState
import io.element.android.features.leaveroom.api.aLeaveRoomState import io.element.android.features.leaveroom.api.aLeaveRoomState
import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.features.logout.api.direct.DirectLogoutState
@ -22,9 +22,11 @@ import io.element.android.features.roomlist.impl.model.aRoomListRoomSummary
import io.element.android.features.roomlist.impl.model.anInviteSender import io.element.android.features.roomlist.impl.model.anInviteSender
import io.element.android.features.roomlist.impl.search.RoomListSearchState import io.element.android.features.roomlist.impl.search.RoomListSearchState
import io.element.android.features.roomlist.impl.search.aRoomListSearchState import io.element.android.features.roomlist.impl.search.aRoomListSearchState
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.push.api.battery.aBatteryOptimizationState import io.element.android.libraries.push.api.battery.aBatteryOptimizationState
@ -86,6 +88,16 @@ internal fun aRoomListState(
eventSink = eventSink, eventSink = eventSink,
) )
internal fun anAcceptDeclineInviteState(
acceptAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
declineAction: AsyncAction<RoomId> = AsyncAction.Uninitialized,
eventSink: (AcceptDeclineInviteEvents) -> Unit = {}
) = AcceptDeclineInviteState(
acceptAction = acceptAction,
declineAction = declineAction,
eventSink = eventSink,
)
internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> { internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> {
return persistentListOf( return persistentListOf(
aRoomListRoomSummary( aRoomListRoomSummary(

View file

@ -15,7 +15,6 @@ import im.vector.app.features.analytics.plan.Interaction
import io.element.android.features.invite.api.SeenInvitesStore import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInviteState
import io.element.android.features.invite.test.InMemorySeenInvitesStore import io.element.android.features.invite.test.InMemorySeenInvitesStore
import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomEvent
import io.element.android.features.leaveroom.api.LeaveRoomState import io.element.android.features.leaveroom.api.LeaveRoomState

View file

@ -16,4 +16,8 @@ interface JoinRoom {
serverNames: List<String>, serverNames: List<String>,
trigger: JoinedRoom.Trigger, trigger: JoinedRoom.Trigger,
): Result<Unit> ): Result<Unit>
sealed class Failures : Exception() {
data object UnauthorizedJoin : Failures()
}
} }

View file

@ -9,9 +9,12 @@ package io.element.android.libraries.matrix.impl.room.join
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.core.extensions.mapFailure
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.exception.ClientException
import io.element.android.libraries.matrix.api.exception.ErrorKind
import io.element.android.libraries.matrix.api.room.join.JoinRoom import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.impl.analytics.toAnalyticsJoinedRoom import io.element.android.libraries.matrix.impl.analytics.toAnalyticsJoinedRoom
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
@ -42,6 +45,15 @@ class DefaultJoinRoom @Inject constructor(
if (roomInfo != null) { if (roomInfo != null) {
analyticsService.capture(roomInfo.toAnalyticsJoinedRoom(trigger)) analyticsService.capture(roomInfo.toAnalyticsJoinedRoom(trigger))
} }
}.mapFailure {
if (it is ClientException.MatrixApi) {
when (it.kind) {
ErrorKind.Forbidden -> JoinRoom.Failures.UnauthorizedJoin
else -> it
}
} else {
it
}
}.map { } }.map { }
} }
} }

View file

@ -333,6 +333,7 @@ Are you sure you want to continue?"</string>
<string name="error_failed_loading_messages">"Failed loading messages"</string> <string name="error_failed_loading_messages">"Failed loading messages"</string>
<string name="error_failed_locating_user">"%1$s could not access your location. Please try again later."</string> <string name="error_failed_locating_user">"%1$s could not access your location. Please try again later."</string>
<string name="error_failed_uploading_voice_message">"Failed to upload your voice message."</string> <string name="error_failed_uploading_voice_message">"Failed to upload your voice message."</string>
<string name="error_invalid_invite">"The room no longer exists or the invite is no longer valid."</string>
<string name="error_message_not_found">"Message not found"</string> <string name="error_message_not_found">"Message not found"</string>
<string name="error_missing_location_auth_android">"%1$s does not have permission to access your location. You can enable access in Settings."</string> <string name="error_missing_location_auth_android">"%1$s does not have permission to access your location. You can enable access in Settings."</string>
<string name="error_missing_location_rationale_android">"%1$s does not have permission to access your location. Enable access below."</string> <string name="error_missing_location_rationale_android">"%1$s does not have permission to access your location. Enable access below."</string>

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:05e7a67dfcec946de1e355afed430198c6c89f1938755907db1e83ab1bb68488 oid sha256:db20190581472583a2f493275d0f7dc46ed4a2128cef475b98730e3695b918c7
size 12177 size 19149

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:96e2d9fd6b20b70dd3bb9b3caaea2cc3eaed1644c3371889cbc56d608bd4b49b oid sha256:784fd291db5fc825b8c1f0bac5ed3066e3aaa67fd6cbc35fd65b0df92f7cb052
size 11826 size 20504

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:db20190581472583a2f493275d0f7dc46ed4a2128cef475b98730e3695b918c7
size 19149

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:24adccc976a5611f31d0caaa614212da841a5a9abd5e9ebb706fe1f9cbfb6408 oid sha256:d4557838eceb90ec501062367413359550ccc927cd4e0c50c9a01c2d9eb0938f
size 10729 size 17146

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:7f41edac4c092e5999950e97b0352ffa46c083ba2cd50c8b5b408eff8a85df06 oid sha256:e620cc1fe0e21a92da88948bc8da2db49c3bcaea0480f8abaa61e22a0882a56e
size 10376 size 18341

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d4557838eceb90ec501062367413359550ccc927cd4e0c50c9a01c2d9eb0938f
size 17146