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

Feature/bca/spaces create private #3160

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -40,7 +40,7 @@ data class RoomGuestAccessContent(
}

@JsonClass(generateAdapter = false)
enum class GuestAccess {
@Json(name = "can_join") CanJoin,
@Json(name = "forbidden") Forbidden
enum class GuestAccess(val value: String) {
@Json(name = "can_join") CanJoin("can_join"),
@Json(name = "forbidden") Forbidden("forbidden")
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import com.squareup.moshi.JsonClass
* Enum for [RoomJoinRulesContent] : https://matrix.org/docs/spec/client_server/r0.4.0#m-room-join-rules
*/
@JsonClass(generateAdapter = false)
enum class RoomJoinRules {
@Json(name = "public") PUBLIC,
@Json(name = "invite") INVITE,
@Json(name = "knock") KNOCK,
@Json(name = "private") PRIVATE
enum class RoomJoinRules(val value: String) {
@Json(name = "public") PUBLIC("public"),
@Json(name = "invite") INVITE("invite"),
@Json(name = "knock") KNOCK("knock"),
@Json(name = "private") PRIVATE("private"),
@Json(name = "restricted") RESTRICTED("restricted")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.matrix.android.sdk.api.session.room.model

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class RoomJoinRulesAllowEntry(
/**
* space: The room ID of the space to check the membership of.
*/
@Json(name = "space") val spaceID: String,
/**
* via: A list of servers which may be used to peek for membership of the space.
*/
@Json(name = "via") val via: List<String>
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,14 +27,19 @@ import timber.log.Timber
*/
@JsonClass(generateAdapter = true)
data class RoomJoinRulesContent(
@Json(name = "join_rule") val _joinRules: String? = null
@Json(name = "join_rule") val _joinRules: String? = null,
/**
* If the allow key is an empty list (or not a list at all), then the room reverts to standard public join rules
*/
@Json(name = "allow") val allowList:List<RoomJoinRulesAllowEntry>? = null
) {
val joinRules: RoomJoinRules? = when (_joinRules) {
"public" -> RoomJoinRules.PUBLIC
"invite" -> RoomJoinRules.INVITE
"knock" -> RoomJoinRules.KNOCK
"public" -> RoomJoinRules.PUBLIC
"invite" -> RoomJoinRules.INVITE
"knock" -> RoomJoinRules.KNOCK
"private" -> RoomJoinRules.PRIVATE
else -> {
"restricted" -> RoomJoinRules.RESTRICTED
else -> {
Timber.w("Invalid value for RoomJoinRules: `$_joinRules`")
null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM

// TODO Give a way to include other initial states
Expand Down Expand Up @@ -153,6 +154,10 @@ open class CreateRoomParams {
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
}

var roomVersion: String? = null

var joinRuleRestricted: List<RoomJoinRulesAllowEntry>? = null

companion object {
private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
private const val CREATION_CONTENT_KEY_ROOM_TYPE = "org.matrix.msc1772.type"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,12 @@ internal data class CreateRoomBody(
* The power level content to override in the default power level event
*/
@Json(name = "power_level_content_override")
val powerLevelContentOverride: PowerLevelsContent?
val powerLevelContentOverride: PowerLevelsContent?,

/**
* The room version to set for the room. If not provided, the homeserver is to use its configured default.
* If provided, the homeserver will return a 400 error with the errcode M_UNSUPPORTED_ROOM_VERSION if it does not support the room version.
*/
@Json(name = "room_version")
val roomVersion: String?
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.toMedium
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.DeviceListManager
Expand Down Expand Up @@ -70,11 +74,17 @@ internal class CreateRoomBodyBuilder @Inject constructor(
}
}

if (params.joinRuleRestricted != null) {
params.roomVersion = "org.matrix.msc3083"
params.historyVisibility = params.historyVisibility ?: RoomHistoryVisibility.SHARED
params.guestAccess = params.guestAccess ?: GuestAccess.Forbidden
}
val initialStates = listOfNotNull(
buildEncryptionWithAlgorithmEvent(params),
buildHistoryVisibilityEvent(params),
buildAvatarEvent(params),
buildGuestAccess(params)
buildGuestAccess(params),
buildJoinRulesRestricted(params)
)
.takeIf { it.isNotEmpty() }

Expand All @@ -89,7 +99,9 @@ internal class CreateRoomBodyBuilder @Inject constructor(
initialStates = initialStates,
preset = params.preset,
isDirect = params.isDirect,
powerLevelContentOverride = params.powerLevelContentOverride
powerLevelContentOverride = params.powerLevelContentOverride,
roomVersion = params.roomVersion

)
}

Expand Down Expand Up @@ -129,7 +141,21 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event(
type = EventType.STATE_ROOM_GUEST_ACCESS,
stateKey = "",
content = RoomGuestAccessContent(it.name).toContent()
content = RoomGuestAccessContent(it.value).toContent()
)
}
}

private fun buildJoinRulesRestricted(params: CreateRoomParams): Event? {
return params.joinRuleRestricted
?.let { allowList ->
Event(
type = EventType.STATE_ROOM_JOIN_RULES,
stateKey = "",
content = RoomJoinRulesContent(
_joinRules = RoomJoinRules.RESTRICTED.value,
allowList = allowList
).toContent()
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
Expand Down Expand Up @@ -67,14 +68,18 @@ internal class DefaultSpaceService @Inject constructor(
return createSpace(CreateSpaceParams().apply {
this.name = name
this.topic = topic
this.preset = if (isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
this.avatarUri = avatarUri
if (isPublic) {
this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContent()).copy(
invite = 0
)
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
this.historyVisibility = RoomHistoryVisibility.WORLD_READABLE
this.guestAccess = GuestAccess.CanJoin
} else {
this.preset = CreateRoomPreset.PRESET_PRIVATE_CHAT
visibility = RoomDirectoryVisibility.PRIVATE
enableEncryption()
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion tools/check/forbidden_strings_in_code.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ Formatter\.formatShortFileSize===1
# android\.text\.TextUtils

### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
enum class===97
enum class===98

### Do not import temporary legacy classes
import org.matrix.android.sdk.internal.legacy.riot===3
Expand Down
6 changes: 6 additions & 0 deletions vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ import im.vector.app.features.settings.threepids.ThreePidsSettingsFragment
import im.vector.app.features.share.IncomingShareFragment
import im.vector.app.features.signout.soft.SoftLogoutFragment
import im.vector.app.features.spaces.SpaceListFragment
import im.vector.app.features.spaces.create.ChoosePrivateSpaceTypeFragment
import im.vector.app.features.spaces.create.ChooseSpaceTypeFragment
import im.vector.app.features.spaces.create.CreateSpaceDefaultRoomsFragment
import im.vector.app.features.spaces.create.CreateSpaceDetailsFragment
Expand Down Expand Up @@ -672,4 +673,9 @@ interface FragmentModule {
@IntoMap
@FragmentKey(SpaceDirectoryFragment::class)
fun bindSpaceDirectoryFragment(fragment: SpaceDirectoryFragment): Fragment

@Binds
@IntoMap
@FragmentKey(ChoosePrivateSpaceTypeFragment::class)
fun bindChoosePrivateSpaceTypeFragment(fragment: ChoosePrivateSpaceTypeFragment): Fragment
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ class RoomSettingsController @Inject constructor(
id("avatar")
enabled(data.actionPermissions.canChangeAvatar)
when (val avatarAction = data.avatarAction) {
RoomSettingsViewState.AvatarAction.None -> {
RoomSettingsViewState.AvatarAction.None -> {
// Use the current value
avatarRenderer(avatarRenderer)
// We do not want to use the fallback avatar url, which can be the other user avatar, or the current user avatar.
matrixItem(roomSummary.toMatrixItem().copy(avatarUrl = data.currentRoomAvatarUrl))
}
RoomSettingsViewState.AvatarAction.DeleteAvatar ->
RoomSettingsViewState.AvatarAction.DeleteAvatar ->
imageUri(null)
is RoomSettingsViewState.AvatarAction.UpdateAvatar ->
imageUri(avatarAction.newAvatarUri)
Expand Down Expand Up @@ -128,14 +128,36 @@ class RoomSettingsController @Inject constructor(
private fun RoomSettingsViewState.getJoinRuleWording(): String {
val joinRule = newRoomJoinRules.newJoinRules ?: currentRoomJoinRules
val guestAccess = newRoomJoinRules.newGuestAccess ?: currentGuestAccess
return stringProvider.getString(if (joinRule == RoomJoinRules.INVITE) {
R.string.room_settings_room_access_entry_only_invited
} else {
if (guestAccess == GuestAccess.CanJoin) {
R.string.room_settings_room_access_entry_anyone_with_link_including_guest
} else {
R.string.room_settings_room_access_entry_anyone_with_link_apart_guest
val resId = when (joinRule) {
RoomJoinRules.INVITE -> {
R.string.room_settings_room_access_entry_only_invited to null
}
})
RoomJoinRules.PRIVATE -> {
R.string.room_settings_room_access_entry_unknown to joinRule.value
}
RoomJoinRules.PUBLIC -> {
if (guestAccess == GuestAccess.CanJoin) {
R.string.room_settings_room_access_entry_anyone_with_link_including_guest to null
} else {
R.string.room_settings_room_access_entry_anyone_with_link_apart_guest to null
}
}
RoomJoinRules.KNOCK -> {
R.string.room_settings_room_access_entry_knock to null
}
RoomJoinRules.RESTRICTED -> {
R.string.room_settings_room_access_entry_restricted to null
}
}
return if (resId.second == null) stringProvider.getString(resId.first) else stringProvider.getString(resId.first, resId.second)
// return stringProvider.getString(if (joinRule == RoomJoinRules.INVITE) {
// R.string.room_settings_room_access_entry_only_invited
// } else {
// if (guestAccess == GuestAccess.CanJoin) {
// R.string.room_settings_room_access_entry_anyone_with_link_including_guest
// } else {
// R.string.room_settings_room_access_entry_anyone_with_link_apart_guest
// }
// })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ class RoomJoinRuleController @Inject constructor(
title = stringProvider.getString(R.string.room_settings_room_access_entry_anyone_with_link_including_guest),
iconResId = 0,
isSelected = state.currentRoomJoinRule == RoomJoinRules.PUBLIC && state.currentGuestAccess == GuestAccess.CanJoin
),
RoomJoinRuleAction(
roomJoinRule = RoomJoinRules.RESTRICTED,
roomGuestAccess = null,
title = stringProvider.getString(R.string.room_settings_room_access_entry_restricted),
iconResId = 0,
isSelected = state.currentRoomJoinRule == RoomJoinRules.RESTRICTED
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.toMvRxBundle
import im.vector.app.core.platform.SimpleFragmentActivity
import im.vector.app.features.spaces.create.ChoosePrivateSpaceTypeFragment
import im.vector.app.features.spaces.create.ChooseSpaceTypeFragment
import im.vector.app.features.spaces.create.CreateSpaceAction
import im.vector.app.features.spaces.create.CreateSpaceDefaultRoomsFragment
import im.vector.app.features.spaces.create.CreateSpaceDetailsFragment
import im.vector.app.features.spaces.create.CreateSpaceEvents
import im.vector.app.features.spaces.create.CreateSpaceState
import im.vector.app.features.spaces.create.CreateSpaceViewModel
import im.vector.app.features.spaces.create.SpaceType
import javax.inject.Inject

class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Factory {
Expand All @@ -59,7 +61,12 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
CreateSpaceState.Step.SetDetails -> {
navigateToFragment(ChooseSpaceTypeFragment::class.java)
}
CreateSpaceState.Step.AddRooms -> TODO()
CreateSpaceState.Step.AddRooms -> {
navigateToFragment(CreateSpaceDefaultRoomsFragment::class.java)
}
CreateSpaceState.Step.ChoosePrivateType -> {
navigateToFragment(ChoosePrivateSpaceTypeFragment::class.java)
}
}
}
}
Expand All @@ -85,6 +92,9 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
CreateSpaceEvents.NavigateToAddRooms -> {
navigateToFragment(CreateSpaceDefaultRoomsFragment::class.java)
}
CreateSpaceEvents.NavigateToChoosePrivateType -> {
navigateToFragment(ChoosePrivateSpaceTypeFragment::class.java)
}
is CreateSpaceEvents.ShowModalError -> {
hideWaitingView()
AlertDialog.Builder(this)
Expand Down Expand Up @@ -124,8 +134,12 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
private fun renderState(state: CreateSpaceState) {
val titleRes = when (state.step) {
CreateSpaceState.Step.ChooseType -> R.string.activity_create_space_title
CreateSpaceState.Step.SetDetails -> R.string.your_public_space
CreateSpaceState.Step.AddRooms -> R.string.your_public_space
CreateSpaceState.Step.SetDetails,
CreateSpaceState.Step.AddRooms -> {
if (state.spaceType == SpaceType.Public) R.string.your_public_space
else R.string.your_private_space
}
CreateSpaceState.Step.ChoosePrivateType -> R.string.your_private_space
}
supportActionBar?.let {
it.title = getString(titleRes)
Expand Down
Loading