Benoit Review: avoid duplicate (again) class PowerLevelsContent

This commit is contained in:
Benoit Marty 2021-03-29 14:46:12 +02:00 committed by Valere
parent 46290f1ed4
commit 2cccbb3fce
11 changed files with 77 additions and 122 deletions

View file

@ -28,43 +28,43 @@ data class PowerLevelsContent(
/**
* The level required to ban a user. Defaults to 50 if unspecified.
*/
@Json(name = "ban") val ban: Int = Role.Moderator.value,
@Json(name = "ban") val ban: Int? = null,
/**
* The level required to kick a user. Defaults to 50 if unspecified.
*/
@Json(name = "kick") val kick: Int = Role.Moderator.value,
@Json(name = "kick") val kick: Int? = null,
/**
* The level required to invite a user. Defaults to 50 if unspecified.
*/
@Json(name = "invite") val invite: Int = Role.Moderator.value,
@Json(name = "invite") val invite: Int? = null,
/**
* The level required to redact an event. Defaults to 50 if unspecified.
*/
@Json(name = "redact") val redact: Int = Role.Moderator.value,
@Json(name = "redact") val redact: Int? = null,
/**
* The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified.
*/
@Json(name = "events_default") val eventsDefault: Int = Role.Default.value,
@Json(name = "events_default") val eventsDefault: Int? = null,
/**
* The level required to send specific event types. This is a mapping from event type to power level required.
*/
@Json(name = "events") val events: Map<String, Int> = emptyMap(),
@Json(name = "events") val events: Map<String, Int>? = null,
/**
* The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified.
*/
@Json(name = "users_default") val usersDefault: Int = Role.Default.value,
@Json(name = "users_default") val usersDefault: Int? = null,
/**
* The power levels for specific users. This is a mapping from user_id to power level for that user.
*/
@Json(name = "users") val users: Map<String, Int> = emptyMap(),
@Json(name = "users") val users: Map<String, Int>? = null,
/**
* The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified.
*/
@Json(name = "state_default") val stateDefault: Int = Role.Moderator.value,
@Json(name = "state_default") val stateDefault: Int? = null,
/**
* The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key.
*/
@Json(name = "notifications") val notifications: Map<String, Any> = emptyMap()
@Json(name = "notifications") val notifications: Map<String, Any>? = null
) {
/**
* Return a copy of this content with a new power level for the specified user
@ -74,7 +74,7 @@ data class PowerLevelsContent(
*/
fun setUserPowerLevel(userId: String, powerLevel: Int?): PowerLevelsContent {
return copy(
users = users.toMutableMap().apply {
users = users.orEmpty().toMutableMap().apply {
if (powerLevel == null || powerLevel == usersDefault) {
remove(userId)
} else {
@ -91,7 +91,7 @@ data class PowerLevelsContent(
* @return the level, default to Moderator if the key is not found
*/
fun notificationLevel(key: String): Int {
return when (val value = notifications[key]) {
return when (val value = notifications.orEmpty()[key]) {
// the first implementation was a string value
is String -> value.toInt()
is Double -> value.toInt()
@ -107,3 +107,12 @@ data class PowerLevelsContent(
const val NOTIFICATIONS_ROOM_KEY = "room"
}
}
// Fallback to default value, defined in the Matrix specification
fun PowerLevelsContent.banOrDefault() = ban ?: Role.Moderator.value
fun PowerLevelsContent.kickOrDefault() = kick ?: Role.Moderator.value
fun PowerLevelsContent.inviteOrDefault() = invite ?: Role.Moderator.value
fun PowerLevelsContent.redactOrDefault() = redact ?: Role.Moderator.value
fun PowerLevelsContent.eventsDefaultOrDefault() = eventsDefault ?: Role.Default.value
fun PowerLevelsContent.usersDefaultOrDefault() = usersDefault ?: Role.Default.value
fun PowerLevelsContent.stateDefaultOrDefault() = stateDefault ?: Role.Moderator.value

View file

@ -1,67 +0,0 @@
/*
* Copyright 2020 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
/**
* Class representing the EventType.EVENT_TYPE_STATE_ROOM_POWER_LEVELS state event content.
*/
@JsonClass(generateAdapter = true)
data class PowerLevelsContentOverride(
/**
* The level required to ban a user. Defaults to 50 if unspecified.
*/
@Json(name = "ban") val ban: Int? = null,
/**
* The level required to kick a user. Defaults to 50 if unspecified.
*/
@Json(name = "kick") val kick: Int? = null,
/**
* The level required to invite a user. Defaults to 50 if unspecified.
*/
@Json(name = "invite") val invite: Int? = null,
/**
* The level required to redact an event. Defaults to 50 if unspecified.
*/
@Json(name = "redact") val redact: Int? = null,
/**
* The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified.
*/
@Json(name = "events_default") val eventsDefault: Int? = null,
/**
* The level required to send specific event types. This is a mapping from event type to power level required.
*/
@Json(name = "events") val events: Map<String, Int>? = null,
/**
* The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified.
*/
@Json(name = "users_default") val usersDefault: Int? = null,
/**
* The power levels for specific users. This is a mapping from user_id to power level for that user.
*/
@Json(name = "users") val users: Map<String, Int>? = null,
/**
* The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified.
*/
@Json(name = "state_default") val stateDefault: Int? = null,
/**
* The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key.
*/
@Json(name = "notifications") val notifications: Map<String, Any>? = null
)

View file

@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.session.room.model.create
import android.net.Uri
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContentOverride
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.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
@ -128,7 +128,7 @@ open class CreateRoomParams {
/**
* The power level content to override in the default power level event
*/
var powerLevelContentOverride: PowerLevelsContentOverride? = null
var powerLevelContentOverride: PowerLevelsContent? = null
/**
* Mark as a direct message room.

View file

@ -18,6 +18,13 @@
package org.matrix.android.sdk.api.session.room.powerlevels
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.banOrDefault
import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
import org.matrix.android.sdk.api.session.room.model.kickOrDefault
import org.matrix.android.sdk.api.session.room.model.redactOrDefault
import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
/**
* This class is an helper around PowerLevelsContent.
@ -31,8 +38,9 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
* @return the power level
*/
fun getUserPowerLevelValue(userId: String): Int {
return powerLevelsContent.users.get(userId)
?: powerLevelsContent.usersDefault
return powerLevelsContent.users
?.get(userId)
?: powerLevelsContent.usersDefaultOrDefault()
}
/**
@ -44,7 +52,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
fun getUserRole(userId: String): Role {
val value = getUserPowerLevelValue(userId)
// I think we should use powerLevelsContent.usersDefault, but Ganfra told me that it was like that on riot-Web
return Role.fromValue(value, powerLevelsContent.eventsDefault)
return Role.fromValue(value, powerLevelsContent.eventsDefaultOrDefault())
}
/**
@ -58,11 +66,11 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
fun isUserAllowedToSend(userId: String, isState: Boolean, eventType: String?): Boolean {
return if (userId.isNotEmpty()) {
val powerLevel = getUserPowerLevelValue(userId)
val minimumPowerLevel = powerLevelsContent.events[eventType]
val minimumPowerLevel = powerLevelsContent.events?.get(eventType)
?: if (isState) {
powerLevelsContent.stateDefault
powerLevelsContent.stateDefaultOrDefault()
} else {
powerLevelsContent.eventsDefault
powerLevelsContent.eventsDefaultOrDefault()
}
powerLevel >= minimumPowerLevel
} else false
@ -75,7 +83,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToInvite(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.invite
return powerLevel >= powerLevelsContent.inviteOrDefault()
}
/**
@ -85,7 +93,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToBan(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.ban
return powerLevel >= powerLevelsContent.banOrDefault()
}
/**
@ -95,7 +103,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToKick(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.kick
return powerLevel >= powerLevelsContent.kickOrDefault()
}
/**
@ -105,6 +113,6 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToRedact(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.redact
return powerLevel >= powerLevelsContent.redactOrDefault()
}
}

View file

@ -16,7 +16,7 @@
package org.matrix.android.sdk.api.session.space
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContentOverride
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
@ -28,7 +28,7 @@ class CreateSpaceParams : CreateRoomParams() {
// Space-rooms should be created with a power level for events_default of 100,
// to prevent the rooms accidentally/maliciously clogging up with messages from random members of the space.
powerLevelContentOverride = PowerLevelsContentOverride(
powerLevelContentOverride = PowerLevelsContent(
eventsDefault = 100
)
}

View file

@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.session.room.create
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContentOverride
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.create.CreateRoomPreset
import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody
@ -111,5 +111,5 @@ internal data class CreateRoomBody(
* The power level content to override in the default power level event
*/
@Json(name = "power_level_content_override")
val powerLevelContentOverride: PowerLevelsContentOverride?
val powerLevelContentOverride: PowerLevelsContent?
)

View file

@ -21,22 +21,21 @@ import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.powerlevels.Role
import org.matrix.android.sdk.api.util.JsonDict
@JsonClass(generateAdapter = true)
internal data class SerializablePowerLevelsContent(
@Json(name = "ban") val ban: Int = Role.Moderator.value,
@Json(name = "kick") val kick: Int = Role.Moderator.value,
@Json(name = "invite") val invite: Int = Role.Moderator.value,
@Json(name = "redact") val redact: Int = Role.Moderator.value,
@Json(name = "events_default") val eventsDefault: Int = Role.Default.value,
@Json(name = "events") val events: Map<String, Int> = emptyMap(),
@Json(name = "users_default") val usersDefault: Int = Role.Default.value,
@Json(name = "users") val users: Map<String, Int> = emptyMap(),
@Json(name = "state_default") val stateDefault: Int = Role.Moderator.value,
@Json(name = "ban") val ban: Int?,
@Json(name = "kick") val kick: Int?,
@Json(name = "invite") val invite: Int?,
@Json(name = "redact") val redact: Int?,
@Json(name = "events_default") val eventsDefault: Int?,
@Json(name = "events") val events: Map<String, Int>?,
@Json(name = "users_default") val usersDefault: Int?,
@Json(name = "users") val users: Map<String, Int>?,
@Json(name = "state_default") val stateDefault: Int?,
// `Int` is the diff here (instead of `Any`)
@Json(name = "notifications") val notifications: Map<String, Int> = emptyMap()
@Json(name = "notifications") val notifications: Map<String, Int>?
)
internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict {
@ -52,7 +51,7 @@ internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict {
usersDefault = content.usersDefault,
users = content.users,
stateDefault = content.stateDefault,
notifications = content.notifications.mapValues { content.notificationLevel(it.key) }
notifications = content.notifications?.mapValues { content.notificationLevel(it.key) }
)
}
?.toContent()

View file

@ -26,7 +26,6 @@ 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.PowerLevelsContentOverride
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
@ -74,7 +73,7 @@ internal class DefaultSpaceService @Inject constructor(
this.preset = if (isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
this.avatarUri = avatarUri
if (isPublic) {
this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContentOverride()).copy(
this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContent()).copy(
invite = 0
)
this.historyVisibility = RoomHistoryVisibility.WORLD_READABLE

View file

@ -121,8 +121,8 @@ class NoticeEventFormatter @Inject constructor(
val powerLevelsContent: PowerLevelsContent = event.getClearContent().toModel() ?: return null
val previousPowerLevelsContent: PowerLevelsContent = event.resolvedPrevContent().toModel() ?: return null
val userIds = HashSet<String>()
userIds.addAll(powerLevelsContent.users.keys)
userIds.addAll(previousPowerLevelsContent.users.keys)
userIds.addAll(powerLevelsContent.users.orEmpty().keys)
userIds.addAll(previousPowerLevelsContent.users.orEmpty().keys)
val diffs = ArrayList<String>()
userIds.forEach { userId ->
val from = PowerLevelsHelper(previousPowerLevelsContent).getUserRole(userId)

View file

@ -27,6 +27,13 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.features.discovery.settingsInfoItem
import im.vector.app.features.form.formAdvancedToggleItem
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.banOrDefault
import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
import org.matrix.android.sdk.api.session.room.model.kickOrDefault
import org.matrix.android.sdk.api.session.room.model.redactOrDefault
import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
import org.matrix.android.sdk.api.session.room.powerlevels.Role
import javax.inject.Inject
@ -139,21 +146,21 @@ class RoomPermissionsController @Inject constructor(
private fun getCurrentRole(editablePermission: EditablePermission, content: PowerLevelsContent): Role {
val value = when (editablePermission) {
is EditablePermission.EventTypeEditablePermission -> content.events[editablePermission.eventType] ?: content.stateDefault
is EditablePermission.DefaultRole -> content.usersDefault
is EditablePermission.SendMessages -> content.eventsDefault
is EditablePermission.InviteUsers -> content.invite
is EditablePermission.ChangeSettings -> content.stateDefault
is EditablePermission.KickUsers -> content.kick
is EditablePermission.BanUsers -> content.ban
is EditablePermission.RemoveMessagesSentByOthers -> content.redact
is EditablePermission.EventTypeEditablePermission -> content.events?.get(editablePermission.eventType) ?: content.stateDefaultOrDefault()
is EditablePermission.DefaultRole -> content.usersDefaultOrDefault()
is EditablePermission.SendMessages -> content.eventsDefaultOrDefault()
is EditablePermission.InviteUsers -> content.inviteOrDefault()
is EditablePermission.ChangeSettings -> content.stateDefaultOrDefault()
is EditablePermission.KickUsers -> content.kickOrDefault()
is EditablePermission.BanUsers -> content.banOrDefault()
is EditablePermission.RemoveMessagesSentByOthers -> content.redactOrDefault()
is EditablePermission.NotifyEveryone -> content.notificationLevel(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY)
}
return Role.fromValue(
value,
when (editablePermission) {
is EditablePermission.EventTypeEditablePermission -> content.stateDefault
is EditablePermission.EventTypeEditablePermission -> content.stateDefaultOrDefault()
is EditablePermission.DefaultRole -> Role.Default.value
is EditablePermission.SendMessages -> Role.Default.value
is EditablePermission.InviteUsers -> Role.Moderator.value

View file

@ -114,7 +114,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat
try {
val newPowerLevelsContent = when (action.editablePermission) {
is EditablePermission.EventTypeEditablePermission -> currentPowerLevel.copy(
events = currentPowerLevel.events.toMutableMap().apply {
events = currentPowerLevel.events.orEmpty().toMutableMap().apply {
put(action.editablePermission.eventType, action.powerLevel)
}
)
@ -126,7 +126,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat
is EditablePermission.BanUsers -> currentPowerLevel.copy(ban = action.powerLevel)
is EditablePermission.RemoveMessagesSentByOthers -> currentPowerLevel.copy(redact = action.powerLevel)
is EditablePermission.NotifyEveryone -> currentPowerLevel.copy(
notifications = currentPowerLevel.notifications.toMutableMap().apply {
notifications = currentPowerLevel.notifications.orEmpty().toMutableMap().apply {
put(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY, action.powerLevel)
}
)