mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-10-31 08:15:02 +00:00
Revert to the SessionEnterpriseService approach
This commit is contained in:
+1
-1
Submodule enterprise updated: eb05f3b813...1a64cd5b86
-14
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
/** Lets a build-specific implementation adjust what the configure room screen offers. */
|
||||
interface ConfigureRoomExtension {
|
||||
/** Whether the public join rule may be offered. */
|
||||
suspend fun isPublicAccessAllowed(): Boolean
|
||||
}
|
||||
+5
-6
@@ -76,7 +76,6 @@ class ConfigureRoomPresenter(
|
||||
private val roomAliasHelper: RoomAliasHelper,
|
||||
private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider,
|
||||
private val sessionEnterpriseService: SessionEnterpriseService,
|
||||
private val configureRoomExtension: ConfigureRoomExtension,
|
||||
) : Presenter<ConfigureRoomState> {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
@@ -94,8 +93,8 @@ class ConfigureRoomPresenter(
|
||||
val isKnockFeatureEnabled by remember {
|
||||
featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock)
|
||||
}.collectAsState(initial = false)
|
||||
val isPublicAccessAllowed by produceState(true) {
|
||||
value = configureRoomExtension.isPublicAccessAllowed()
|
||||
val arePublicRoomsDisabled by produceState(false) {
|
||||
value = sessionEnterpriseService.arePublicRoomsDisabledByHomeserver()
|
||||
}
|
||||
val roomAddressValidity = remember {
|
||||
mutableStateOf<RoomAddressValidity>(RoomAddressValidity.Unknown)
|
||||
@@ -150,13 +149,13 @@ class ConfigureRoomPresenter(
|
||||
// 1. If we are creating a space.
|
||||
// 2. If it has a parent space.
|
||||
// 3. If knocking is enabled.
|
||||
// 4. If public access is allowed.
|
||||
// 4. If the homeserver forbids public rooms.
|
||||
val parentSpace = createRoomConfig.parentSpace
|
||||
val availableJoinRules = remember(parentSpace, isSpace, isKnockFeatureEnabled, isPublicAccessAllowed) {
|
||||
val availableJoinRules = remember(parentSpace, isSpace, isKnockFeatureEnabled, arePublicRoomsDisabled) {
|
||||
when {
|
||||
isSpace && parentSpace != null -> TODO("Adding a space to a parent space is not supported yet! How did you get here?")
|
||||
parentSpace == null || parentSpace.joinRule == JoinRule.Public -> listOfNotNull(
|
||||
JoinRuleItem.PublicVisibility.Public.takeIf { isPublicAccessAllowed },
|
||||
JoinRuleItem.PublicVisibility.Public.takeIf { !arePublicRoomsDisabled },
|
||||
JoinRuleItem.PublicVisibility.AskToJoin.takeIf { !isSpace && isKnockFeatureEnabled },
|
||||
JoinRuleItem.PrivateVisibility.Private,
|
||||
).toImmutableList()
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class NoopConfigureRoomExtension : ConfigureRoomExtension {
|
||||
override suspend fun isPublicAccessAllowed(): Boolean = true
|
||||
}
|
||||
+41
-4
@@ -18,7 +18,6 @@ import io.element.android.features.createroom.impl.configureroom.ConfigureRoomSt
|
||||
import io.element.android.features.createroom.impl.configureroom.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.configureroom.CreateRoomConfigStore
|
||||
import io.element.android.features.createroom.impl.configureroom.JoinRuleItem
|
||||
import io.element.android.features.createroom.impl.configureroom.NoopConfigureRoomExtension
|
||||
import io.element.android.features.createroom.impl.configureroom.RoomAddress
|
||||
import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState
|
||||
import io.element.android.features.enterprise.test.FakeSessionEnterpriseService
|
||||
@@ -58,6 +57,7 @@ import io.element.android.libraries.previewutils.room.aSpaceRoom
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.matching
|
||||
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||
@@ -523,7 +523,10 @@ class ConfigureRoomPresenterTest : RobolectricTest() {
|
||||
|
||||
@Test
|
||||
fun `present - creating a private room when encryption is disabled by the HS creates it unencrypted`() = runTest {
|
||||
val sessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { true })
|
||||
val sessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { true },
|
||||
arePublicRoomsDisabledResult = { false },
|
||||
)
|
||||
val createRoomLambda = lambdaRecorder<CreateRoomParameters, Result<RoomId>> { Result.success(A_ROOM_ID) }
|
||||
val matrixClient = createMatrixClient().apply {
|
||||
createRoomResult = createRoomLambda
|
||||
@@ -545,6 +548,38 @@ class ConfigureRoomPresenterTest : RobolectricTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - when public rooms are disabled by the HS, the public join rule is not available`() = runTest {
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
sessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { false },
|
||||
arePublicRoomsDisabledResult = { true },
|
||||
),
|
||||
)
|
||||
presenter.test {
|
||||
val expectedJoinRules = listOf(JoinRuleItem.PublicVisibility.AskToJoin, JoinRuleItem.PrivateVisibility.Private)
|
||||
val state = consumeItemsUntilPredicate { it.availableJoinRules == expectedJoinRules }.last()
|
||||
assertThat(state.availableJoinRules).containsExactlyElementsIn(expectedJoinRules).inOrder()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - when public rooms are disabled by the HS, only the private join rule is available for a space`() = runTest {
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
isSpace = true,
|
||||
sessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { false },
|
||||
arePublicRoomsDisabledResult = { true },
|
||||
),
|
||||
)
|
||||
presenter.test {
|
||||
val state = consumeItemsUntilPredicate { it.availableJoinRules == listOf(JoinRuleItem.PrivateVisibility.Private) }.last()
|
||||
assertThat(state.config.visibilityState).isEqualTo(RoomVisibilityState.Private(JoinRuleItem.PrivateVisibility.Private))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun TurbineTestContext<ConfigureRoomState>.initialState(): ConfigureRoomState {
|
||||
skipItems(1)
|
||||
return awaitItem()
|
||||
@@ -580,7 +615,10 @@ class ConfigureRoomPresenterTest : RobolectricTest() {
|
||||
permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(),
|
||||
isKnockFeatureEnabled: Boolean = true,
|
||||
mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
|
||||
sessionEnterpriseService: FakeSessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { false }),
|
||||
sessionEnterpriseService: FakeSessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { false },
|
||||
arePublicRoomsDisabledResult = { false },
|
||||
),
|
||||
) = ConfigureRoomPresenter(
|
||||
isSpace = isSpace,
|
||||
initialParentSpaceId = initialParenSpaceId,
|
||||
@@ -596,6 +634,5 @@ class ConfigureRoomPresenterTest : RobolectricTest() {
|
||||
),
|
||||
mediaOptimizationConfigProvider = mediaOptimizationConfigProvider,
|
||||
sessionEnterpriseService = sessionEnterpriseService,
|
||||
configureRoomExtension = NoopConfigureRoomExtension(),
|
||||
)
|
||||
}
|
||||
|
||||
+6
@@ -29,4 +29,10 @@ interface SessionEnterpriseService {
|
||||
|
||||
/** Whether the homeserver forbids creating encrypted rooms, in which case the app must not offer the option. */
|
||||
suspend fun isEncryptionDisabledByHomeserver(): Boolean
|
||||
|
||||
/**
|
||||
* Whether the homeserver forbids public rooms and spaces, in which case the app must not offer to create one,
|
||||
* nor to make an existing room or space public.
|
||||
*/
|
||||
suspend fun arePublicRoomsDisabledByHomeserver(): Boolean
|
||||
}
|
||||
|
||||
+1
@@ -18,4 +18,5 @@ class DefaultSessionEnterpriseService : SessionEnterpriseService {
|
||||
override suspend fun tweakMasUrl(url: String): String = url
|
||||
override suspend fun isElementCallAvailable(): Boolean = true
|
||||
override suspend fun isEncryptionDisabledByHomeserver(): Boolean = false
|
||||
override suspend fun arePublicRoomsDisabledByHomeserver(): Boolean = false
|
||||
}
|
||||
|
||||
+5
@@ -16,6 +16,7 @@ class FakeSessionEnterpriseService(
|
||||
private val isElementCallAvailableResult: () -> Boolean = { lambdaError() },
|
||||
private val tweakMasUrlResult: (String) -> String = { lambdaError() },
|
||||
private val isEncryptionDisabledResult: () -> Boolean = { lambdaError() },
|
||||
private val arePublicRoomsDisabledResult: () -> Boolean = { lambdaError() },
|
||||
) : SessionEnterpriseService {
|
||||
override suspend fun init() {
|
||||
}
|
||||
@@ -31,4 +32,8 @@ class FakeSessionEnterpriseService(
|
||||
override suspend fun isEncryptionDisabledByHomeserver(): Boolean {
|
||||
return isEncryptionDisabledResult()
|
||||
}
|
||||
|
||||
override suspend fun arePublicRoomsDisabledByHomeserver(): Boolean {
|
||||
return arePublicRoomsDisabledResult()
|
||||
}
|
||||
}
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.securityandprivacy.impl.root
|
||||
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
|
||||
@ContributesBinding(RoomScope::class)
|
||||
class NoopSecurityAndPrivacyExtension : SecurityAndPrivacyExtension {
|
||||
override suspend fun isPublicAccessAllowed(): Boolean = true
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.securityandprivacy.impl.root
|
||||
|
||||
/** Lets a build-specific implementation adjust what the security and privacy screen offers. */
|
||||
interface SecurityAndPrivacyExtension {
|
||||
/** Whether the room access may be changed to anyone. */
|
||||
suspend fun isPublicAccessAllowed(): Boolean
|
||||
}
|
||||
+3
-4
@@ -65,7 +65,6 @@ class SecurityAndPrivacyPresenter(
|
||||
private val room: JoinedRoom,
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
private val sessionEnterpriseService: SessionEnterpriseService,
|
||||
private val securityAndPrivacyExtension: SecurityAndPrivacyExtension,
|
||||
) : Presenter<SecurityAndPrivacyState> {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
@@ -90,8 +89,8 @@ class SecurityAndPrivacyPresenter(
|
||||
value = sessionEnterpriseService.isEncryptionDisabledByHomeserver()
|
||||
}
|
||||
|
||||
val isPublicAccessAllowed by produceState(true) {
|
||||
value = securityAndPrivacyExtension.isPublicAccessAllowed()
|
||||
val arePublicRoomsDisabledByHomeserver by produceState(false) {
|
||||
value = sessionEnterpriseService.arePublicRoomsDisabledByHomeserver()
|
||||
}
|
||||
|
||||
val savedIsVisibleInRoomDirectory = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) }
|
||||
@@ -259,7 +258,7 @@ class SecurityAndPrivacyPresenter(
|
||||
selectableJoinedSpaces = selectableJoinedSpaces,
|
||||
spaceSelectionMode = spaceSelectionMode,
|
||||
isEncryptionDisabledByHomeserver = isEncryptionDisabledByHomeserver,
|
||||
isPublicAccessAllowed = isPublicAccessAllowed,
|
||||
arePublicRoomsDisabledByHomeserver = arePublicRoomsDisabledByHomeserver,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
|
||||
|
||||
+3
-3
@@ -28,7 +28,7 @@ data class SecurityAndPrivacyState(
|
||||
val editedSettings: SecurityAndPrivacySettings,
|
||||
val homeserverName: String,
|
||||
val isEncryptionDisabledByHomeserver: Boolean,
|
||||
private val isPublicAccessAllowed: Boolean,
|
||||
private val arePublicRoomsDisabledByHomeserver: Boolean,
|
||||
val showEnableEncryptionConfirmation: Boolean,
|
||||
private val isKnockEnabled: Boolean,
|
||||
val saveAction: AsyncAction<Unit>,
|
||||
@@ -42,8 +42,8 @@ data class SecurityAndPrivacyState(
|
||||
|
||||
// Show Anyone option when:
|
||||
// - Anyone is the current saved value, OR
|
||||
// - Public access is allowed
|
||||
val showAnyoneOption = savedSettings.roomAccess == SecurityAndPrivacyRoomAccess.Anyone || isPublicAccessAllowed
|
||||
// - The homeserver allows public rooms
|
||||
val showAnyoneOption = savedSettings.roomAccess == SecurityAndPrivacyRoomAccess.Anyone || !arePublicRoomsDisabledByHomeserver
|
||||
|
||||
// Show SpaceMember option in two cases:
|
||||
// - SpaceMember is the current saved value
|
||||
|
||||
+6
-2
@@ -37,6 +37,10 @@ open class SecurityAndPrivacyStatePreviewParam : PreviewParameterProvider<Securi
|
||||
showEncryptionConfirmation = true,
|
||||
isSpace = false,
|
||||
),
|
||||
aSecurityAndPrivacyState(
|
||||
arePublicRoomsDisabledByHomeserver = true,
|
||||
isSpace = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -139,7 +143,7 @@ fun aSecurityAndPrivacyState(
|
||||
selectableJoinedSpaces: Set<SpaceRoom> = emptySet(),
|
||||
spaceSelectionMode: SpaceSelectionMode = SpaceSelectionMode.None,
|
||||
isEncryptionDisabledByHomeserver: Boolean = false,
|
||||
isPublicAccessAllowed: Boolean = true,
|
||||
arePublicRoomsDisabledByHomeserver: Boolean = false,
|
||||
eventSink: (SecurityAndPrivacyEvent) -> Unit = {}
|
||||
) = SecurityAndPrivacyState(
|
||||
editedSettings = editedSettings,
|
||||
@@ -153,6 +157,6 @@ fun aSecurityAndPrivacyState(
|
||||
selectableJoinedSpaces = selectableJoinedSpaces.toImmutableSet(),
|
||||
spaceSelectionMode = spaceSelectionMode,
|
||||
isEncryptionDisabledByHomeserver = isEncryptionDisabledByHomeserver,
|
||||
isPublicAccessAllowed = isPublicAccessAllowed,
|
||||
arePublicRoomsDisabledByHomeserver = arePublicRoomsDisabledByHomeserver,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
+43
-2
@@ -34,6 +34,8 @@ import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
|
||||
import io.element.android.libraries.matrix.test.spaces.FakeSpaceService
|
||||
import io.element.android.libraries.previewutils.room.aSpaceRoom
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.consumeItemsUntilTimeout
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
@@ -1048,7 +1050,10 @@ class SecurityAndPrivacyPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - showEncryptionSection is false if the HS disabled encryption`() = runTest {
|
||||
val sessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { true })
|
||||
val sessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { true },
|
||||
arePublicRoomsDisabledResult = { false },
|
||||
)
|
||||
val presenter = createSecurityAndPrivacyPresenter(
|
||||
sessionEnterpriseService = sessionEnterpriseService,
|
||||
)
|
||||
@@ -1060,6 +1065,42 @@ class SecurityAndPrivacyPresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - showAnyoneOption is false if the HS disabled public rooms`() = runTest {
|
||||
val presenter = createSecurityAndPrivacyPresenter(
|
||||
sessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { false },
|
||||
arePublicRoomsDisabledResult = { true },
|
||||
),
|
||||
)
|
||||
presenter.test {
|
||||
consumeItemsUntilPredicate { !it.showAnyoneOption }
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - showAnyoneOption is true if the HS disabled public rooms but the room is already public`() = runTest {
|
||||
val presenter = createSecurityAndPrivacyPresenter(
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
roomPermissions = roomPermissions(),
|
||||
getRoomVisibilityResult = { Result.success(RoomVisibility.Public) },
|
||||
initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Public)
|
||||
),
|
||||
),
|
||||
sessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { false },
|
||||
arePublicRoomsDisabledResult = { true },
|
||||
),
|
||||
)
|
||||
presenter.test {
|
||||
val states = consumeItemsUntilTimeout()
|
||||
assertThat(states).isNotEmpty()
|
||||
assertThat(states.all { it.showAnyoneOption }).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
private fun roomPermissions(
|
||||
canChangeRoomAccess: Boolean = true,
|
||||
canChangeHistoryVisibility: Boolean = true,
|
||||
@@ -1100,6 +1141,7 @@ class SecurityAndPrivacyPresenterTest {
|
||||
spaceSelectionStateHolder: SpaceSelectionStateHolder = SpaceSelectionStateHolder(),
|
||||
sessionEnterpriseService: FakeSessionEnterpriseService = FakeSessionEnterpriseService(
|
||||
isEncryptionDisabledResult = { false },
|
||||
arePublicRoomsDisabledResult = { false },
|
||||
)
|
||||
): SecurityAndPrivacyPresenter {
|
||||
return SecurityAndPrivacyPresenter(
|
||||
@@ -1109,7 +1151,6 @@ class SecurityAndPrivacyPresenterTest {
|
||||
featureFlagService = featureFlagService,
|
||||
spaceSelectionStateHolder = spaceSelectionStateHolder,
|
||||
sessionEnterpriseService = sessionEnterpriseService,
|
||||
securityAndPrivacyExtension = NoopSecurityAndPrivacyExtension(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user