Room admins can change user roles (#2423)

Allow Admins to modify room member roles:

- Add a 'roles and permissions' option for each room.
- Allow promoting users to admins, adding or removing moderators, and demote yourself if you're and admin.

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
Jorge Martin Espinosa 2024-03-05 17:46:47 +01:00 committed by GitHub
parent 1d892b4bc8
commit b9d902e3fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
110 changed files with 2398 additions and 160 deletions

View file

@ -29,12 +29,19 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler
import io.element.android.libraries.matrix.api.media.VideoInfo
import io.element.android.libraries.matrix.api.poll.PollKind
import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import java.io.Closeable
import java.io.File
@ -56,7 +63,7 @@ interface MatrixRoom : Closeable {
/** Whether the room is a direct message. */
val isDm: Boolean get() = isDirect && isOneToOne
val roomInfoFlow: Flow<MatrixRoomInfo>
val roomInfoFlow: SharedFlow<MatrixRoomInfo>
val roomTypingMembersFlow: Flow<List<UserId>>
/**
@ -91,6 +98,10 @@ interface MatrixRoom : Closeable {
suspend fun unsubscribeFromSync()
suspend fun userRole(userId: UserId): Result<RoomMember.Role>
suspend fun updateUsersRoles(changes: List<UserRoleChange>): Result<Unit>
suspend fun userDisplayName(userId: UserId): Result<String?>
suspend fun userAvatarUrl(userId: UserId): Result<String?>
@ -144,6 +155,18 @@ interface MatrixRoom : Closeable {
suspend fun canUserJoinCall(userId: UserId): Result<Boolean> =
canUserSendState(userId, StateEventType.CALL_MEMBER)
fun usersWithRole(role: RoomMember.Role): Flow<ImmutableList<RoomMember>> {
return roomInfoFlow
.map { it.userPowerLevels.filter { (_, powerLevel) -> RoomMember.Role.forPowerLevel(powerLevel) == role } }
.distinctUntilChanged()
.combine(membersStateFlow) { powerLevels, membersState ->
membersState.roomMembers()
.orEmpty()
.filter { powerLevels.containsKey(it.userId) }
.toPersistentList()
}
}
suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit>
suspend fun removeAvatar(): Result<Unit>

View file

@ -17,8 +17,10 @@
package io.element.android.libraries.matrix.api.room
import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap
@Immutable
data class MatrixRoomInfo(
@ -39,6 +41,7 @@ data class MatrixRoomInfo(
val activeMembersCount: Long,
val invitedMembersCount: Long,
val joinedMembersCount: Long,
val userPowerLevels: ImmutableMap<UserId, Long>,
val highlightCount: Long,
val notificationCount: Long,
val userDefinedNotificationMode: RoomNotificationMode?,

View file

@ -32,10 +32,20 @@ data class RoomMember(
/**
* Role of the RoomMember, based on its [powerLevel].
*/
enum class Role {
ADMIN,
MODERATOR,
USER
enum class Role(val powerLevel: Long) {
ADMIN(100L),
MODERATOR(50L),
USER(0L);
companion object {
fun forPowerLevel(powerLevel: Long): Role {
return when {
powerLevel >= ADMIN.powerLevel -> ADMIN
powerLevel >= MODERATOR.powerLevel -> MODERATOR
else -> USER
}
}
}
}
/**

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* 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 io.element.android.libraries.matrix.api.room.powerlevels
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomMember
data class UserRoleChange(
val userId: UserId,
val role: RoomMember.Role,
) {
val powerLevel: Long = role.powerLevel
}