Merge pull request #7950 from element-hq/mauroromito/support_roomV12_powerlevels

Support for MSC 4289 and V12 room version power levels
This commit is contained in:
Mauro
2025-07-23 14:08:26 +02:00
committed by GitHub
23 changed files with 65 additions and 52 deletions

View File

@@ -345,7 +345,7 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
// Check user's power in the room
MXRoomPowerLevels *powerLevels = roomState.powerLevels;
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:room.mxSession.myUser.userId];
NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:room.mxSession.myUser.userId];
// The user must be able to send state events to manage widgets
if (oneSelfPowerLevel < powerLevels.stateDefault)

View File

@@ -105,10 +105,12 @@ class AllChatsEditActionProvider {
spaceRoom.state { [weak self] roomState in
guard let self = self else { return }
guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else {
guard let roomState,
let powerLevels = roomState.powerLevels,
let userId = session.myUserId else {
return
}
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId)
let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId)
self.isInviteAvailable = userPowerLevel >= powerLevels.invite
self.isAddRoomAvailable = userPowerLevel >= parentSpace.minimumPowerLevelForAddingRoom(with: powerLevels)

View File

@@ -77,10 +77,12 @@ class AllChatsSpaceActionProvider {
spaceRoom.state { [weak self] roomState in
guard let self = self else { return }
guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else {
guard let roomState,
let powerLevels = roomState.powerLevels,
let userId = session.myUserId else {
return
}
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId)
let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId)
self.isInviteAvailable = userPowerLevel >= powerLevels.invite

View File

@@ -489,7 +489,7 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
MXJSONModelSetBoolean(isState, requestData[@"is_state"]);
MXRoomPowerLevels *powerLevels = roomState.powerLevels;
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self->mxSession.myUser.userId];
NSInteger userPowerLevel = [roomState powerLevelOfUserWithUserID:self->mxSession.myUser.userId];
BOOL canSend = NO;

View File

@@ -94,7 +94,7 @@ NSString *const kJavascriptSendResponseToPostMessageAPI = @"riotIOS.sendResponse
{
// Check user's power in the room
MXRoomPowerLevels *powerLevels = roomState.powerLevels;
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:session.myUser.userId];
NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:session.myUser.userId];
// The user must be able to send state events to manage widgets
if (oneSelfPowerLevel >= powerLevels.stateDefault)

View File

@@ -639,9 +639,10 @@ Please see LICENSE in the repository root for full details.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Check user's power level before allowing an action (kick, ban, ...)
MXRoomState *roomState = self.mxRoomLiveTimeline.state;
MXRoomPowerLevels *powerLevels = [self.mxRoomLiveTimeline.state powerLevels];
NSInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:_mxRoomMember.userId];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger memberPowerLevel = [roomState powerLevelOfUserWithUserID:_mxRoomMember.userId];
NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
[actionsArray removeAllObjects];
@@ -894,14 +895,14 @@ Please see LICENSE in the repository root for full details.
- (void)setPowerLevel:(NSInteger)value promptUser:(BOOL)promptUser
{
NSInteger currentPowerLevel = [self.mxRoomLiveTimeline.state.powerLevels powerLevelOfUserWithUserID:_mxRoomMember.userId];
NSInteger currentPowerLevel = [self.mxRoomLiveTimeline.state powerLevelOfUserWithUserID:_mxRoomMember.userId];
// check if the power level has not yet been set to 0
if (value != currentPowerLevel)
{
__weak typeof(self) weakSelf = self;
if (promptUser && value == [self.mxRoomLiveTimeline.state.powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId])
if (promptUser && value == [self.mxRoomLiveTimeline.state powerLevelOfUserWithUserID:self.mainSession.myUser.userId])
{
// If the user is setting the same power level as his to another user, ask him for a confirmation
if (currentAlert)
@@ -999,7 +1000,7 @@ Please see LICENSE in the repository root for full details.
typeof(self) self = weakSelf;
textField.secureTextEntry = NO;
textField.text = [NSString stringWithFormat:@"%ld", (long)[self.mxRoomLiveTimeline.state.powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId]];
textField.text = [NSString stringWithFormat:@"%ld", (long)[self.mxRoomLiveTimeline.state powerLevelOfUserWithUserID:self.mxRoomMember.userId]];
textField.placeholder = nil;
textField.keyboardType = UIKeyboardTypeDecimalPad;
}];

View File

@@ -307,7 +307,7 @@ Please see LICENSE in the repository root for full details.
if (showInvitationOption && self->dataSource)
{
// Check conditions to be able to invite someone
NSInteger oneSelfPowerLevel = [roomState.powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel < [roomState.powerLevels invite])
{
showInvitationOption = NO;

View File

@@ -691,7 +691,7 @@ Please see LICENSE in the repository root for full details.
- (BOOL)canInvitePeople
{
NSInteger requiredLevel = roomDataSource.roomState.powerLevels.invite;
NSInteger myLevel = [roomDataSource.roomState.powerLevels powerLevelOfUserWithUserID:roomDataSource.mxSession.myUserId];
NSInteger myLevel = [roomDataSource.roomState powerLevelOfUserWithUserID:roomDataSource.mxSession.myUserId];
return myLevel >= requiredLevel;
}

View File

@@ -123,7 +123,7 @@ Please see LICENSE in the repository root for full details.
MXStrongifyAndReturnIfNil(self);
MXRoomPowerLevels *powerLevels = [roomState powerLevels];
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self->mxSession.myUser.userId];
NSInteger userPowerLevel = [roomState powerLevelOfUserWithUserID:self->mxSession.myUser.userId];
if (powerLevels.redact)
{
if (userPowerLevel >= powerLevels.redact)

View File

@@ -176,7 +176,7 @@ Please see LICENSE in the repository root for full details.
// Check whether the user has enough power to rename the room
MXRoomPowerLevels *powerLevels = _mxRoom.dangerousSyncState.powerLevels;
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:_mxRoom.mxSession.myUser.userId];
NSInteger userPowerLevel = [_mxRoom.dangerousSyncState powerLevelOfUserWithUserID:_mxRoom.mxSession.myUser.userId];
if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName])
{
// Only the room name is edited here, update the text field with the room name

View File

@@ -354,7 +354,7 @@ Please see LICENSE in the repository root for full details.
{
// Check whether the user has enough power to rename the room
MXRoomPowerLevels *powerLevels = self.mxRoom.dangerousSyncState.powerLevels;
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId];
NSInteger userPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId];
if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName])
{
// Only the room name is edited here, update the text field with the room name
@@ -384,7 +384,7 @@ Please see LICENSE in the repository root for full details.
{
// Check whether the user has enough power to edit room topic
MXRoomPowerLevels *powerLevels = self.mxRoom.dangerousSyncState.powerLevels;
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId];
NSInteger userPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId];
if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomTopic])
{
textField.backgroundColor = [UIColor whiteColor];

View File

@@ -351,7 +351,7 @@ Please see LICENSE in the repository root for full details.
MXStrongifyAndReturnIfNil(self);
MXRoomPowerLevels *powerLevels = [roomState powerLevels];
NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId];
NSInteger powerLevel = [roomState powerLevelOfUserWithUserID:self.mxRoomMember.userId];
RoomPowerLevel roomPowerLevel = [RoomPowerLevelHelper roomPowerLevelFrom:powerLevel];
@@ -500,8 +500,8 @@ Please see LICENSE in the repository root for full details.
// Check user's power level before allowing an action (kick, ban, ...)
MXRoomPowerLevels *powerLevels = [self.mxRoom.dangerousSyncState powerLevels];
NSInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger memberPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mxRoomMember.userId];
NSInteger oneSelfPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
[adminActionsArray removeAllObjects];
[otherActionsArray removeAllObjects];

View File

@@ -716,8 +716,8 @@ Please see LICENSE in the repository root for full details.
{
// Order first by power levels (admins then moderators then others)
MXRoomPowerLevels *powerLevels = [roomState powerLevels];
NSInteger powerLevelA = [powerLevels powerLevelOfUserWithUserID:contactA.mxMember.userId];
NSInteger powerLevelB = [powerLevels powerLevelOfUserWithUserID:contactB.mxMember.userId];
NSInteger powerLevelA = [roomState powerLevelOfUserWithUserID:contactA.mxMember.userId];
NSInteger powerLevelB = [roomState powerLevelOfUserWithUserID:contactB.mxMember.userId];
if (powerLevelA == powerLevelB)
{
@@ -981,7 +981,7 @@ Please see LICENSE in the repository root for full details.
// Update member power level
MXRoomPowerLevels *powerLevels = [roomState powerLevels];
NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:contact.mxMember.userId];
NSInteger powerLevel = [roomState powerLevelOfUserWithUserID:contact.mxMember.userId];
RoomPowerLevel roomPowerLevel = [RoomPowerLevelHelper roomPowerLevelFrom:powerLevel];

View File

@@ -163,12 +163,13 @@ final class RoomParticipantsInviteCoordinatorBridgePresenter: NSObject {
}
room.state { roomState in
guard let powerLevels = roomState?.powerLevels else {
guard let roomState,
let powerLevels = roomState.powerLevels else {
MXLog.error("[RoomParticipantsInviteCoordinatorBridgePresenter] canInvite: room powerLevels not found")
completion(false)
return
}
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId)
let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId)
completion(userPowerLevel >= powerLevels.invite)
}

View File

@@ -1200,7 +1200,7 @@ static CGSize kThreadListBarButtonItemImageSize;
if (self.roomDataSource.roomState)
{
MXRoomPowerLevels *powerLevels = self.roomDataSource.roomState.powerLevels;
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger userPowerLevel = [self.roomDataSource.roomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
BOOL canSend = (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsMessage:kMXEventTypeStringRoomMessage]);
BOOL isRoomObsolete = self.roomDataSource.roomState.isObsolete;
@@ -1856,7 +1856,7 @@ static CGSize kThreadListBarButtonItemImageSize;
{
MXRoomPowerLevels *powerLevels = [self.roomDataSource.roomState powerLevels];
NSInteger requiredPower = [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventTypeString];
NSInteger myPower = [powerLevels powerLevelOfUserWithUserID:self.roomDataSource.mxSession.myUserId];
NSInteger myPower = [self.roomDataSource.roomState powerLevelOfUserWithUserID:self.roomDataSource.mxSession.myUserId];
return myPower >= requiredPower;
}

View File

@@ -609,7 +609,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
{
// Check user's power level to know whether the user is allowed to turn on the encryption mode
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption])
{
@@ -652,7 +652,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
return;
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel < [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventTypeForSelectedField])
return;
@@ -2082,7 +2082,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
// Check user's power level to know which settings are editable.
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
// general settings
if (section == SECTION_TAG_MAIN)
@@ -3092,7 +3092,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
{
// Check user's power level to know whether the user is allowed to set the main address
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAliases])
{

View File

@@ -329,11 +329,12 @@ final class SideMenuCoordinator: NSObject, SideMenuCoordinatorType {
spaceRoom.state { [weak self] roomState in
guard let self = self else { return }
guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else {
guard let roomState,
let powerLevels = roomState.powerLevels, let userId = session.myUserId else {
MXLog.error("[SpaceMembersCoordinator] spaceMemberListCoordinatorShowInvite: failed to find powerLevels for room")
return
}
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId)
let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId)
guard userPowerLevel >= powerLevels.invite else {
let alert = UIAlertController(title: VectorL10n.spacesInvitePeople, message: VectorL10n.spaceInviteNotEnoughPermission, preferredStyle: .alert)

View File

@@ -165,11 +165,12 @@ extension SpaceMembersCoordinator: SpaceMemberListCoordinatorDelegate {
spaceRoom.state { [weak self] roomState in
guard let self = self else { return }
guard let powerLevels = roomState?.powerLevels, let userId = self.parameters.session.myUserId else {
guard let roomState,
let powerLevels = roomState.powerLevels, let userId = self.parameters.session.myUserId else {
MXLog.error("[SpaceMembersCoordinator] spaceMemberListCoordinatorShowInvite: failed to find powerLevels for room")
return
}
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId)
let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId)
guard userPowerLevel >= powerLevels.invite else {
let alert = UIAlertController(title: VectorL10n.spacesInvitePeople, message: VectorL10n.spaceInviteNotEnoughPermission, preferredStyle: .alert)

View File

@@ -166,7 +166,7 @@ final class SpaceExploreRoomViewModel: SpaceExploreRoomViewModelType {
if let spaceRoom = self.spaceRoom {
spaceRoom.state { roomState in
self.powerLevels = roomState?.powerLevels
self.powerLevelOfCurrentUser = self.powerLevels?.powerLevelOfUser(withUserID: self.session.myUserId)
self.powerLevelOfCurrentUser = roomState?.powerLevelOfUser(withUserID: self.session.myUserId)
}
}

View File

@@ -158,8 +158,9 @@ final class LocationSharingCoordinator: Coordinator, Presentable {
// Check if user can send beacon info state event
private func canShareLiveLocation() -> Bool {
guard let myUserId = parameters.roomDataSource.mxSession.myUserId,
let roomPowerLevels = parameters.roomDataSource.roomState.powerLevels,
let userPowerLevel = RoomPowerLevel(rawValue: roomPowerLevels.powerLevelOfUser(withUserID: myUserId)) else {
let roomState = parameters.roomDataSource.roomState,
let roomPowerLevels = roomState.powerLevels,
let userPowerLevel = RoomPowerLevel(rawValue: roomState.powerLevelOfUser(withUserID: myUserId)) else {
return false
}

View File

@@ -162,8 +162,10 @@ private class CompletionSuggestionCoordinatorRoomMemberProvider: RoomMembersProv
/// Gets the power levels for the room to update suggestions accordingly.
func updateWithPowerLevels() {
room.state { [weak self] state in
guard let self, let powerLevels = state?.powerLevels else { return }
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: self.userID)
guard let self,
let state,
let powerLevels = state.powerLevels else { return }
let userPowerLevel = state.powerLevelOfUser(withUserID: self.userID)
let mentionRoomPowerLevel = powerLevels.minimumPowerLevel(forNotifications: kMXRoomPowerLevelNotificationsRoomKey,
defaultPower: kMXRoomPowerLevelNotificationsRoomDefault)
self.canMentionRoom = userPowerLevel >= mentionRoomPowerLevel
@@ -208,9 +210,11 @@ private class CompletionSuggestionCoordinatorCommandProvider: CommandsProviderPr
func updateWithPowerLevels() {
room.state { [weak self] state in
guard let self, let powerLevels = state?.powerLevels else { return }
guard let self,
let state,
let powerLevels = state.powerLevels else { return }
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: self.userID)
let userPowerLevel = state.powerLevelOfUser(withUserID: self.userID)
self.isRoomAdmin = RoomPowerLevel(rawValue: userPowerLevel) == .admin
}
}

View File

@@ -150,12 +150,12 @@ class SpaceSettingsService: SpaceSettingsServiceProtocol {
return allowedParentIds
}
private func isField(ofType notification: String, editableWith powerLevels: MXRoomPowerLevels?) -> Bool {
guard let powerLevels = powerLevels else {
private func isField(ofType notification: String, editableWith roomState: MXRoomState) -> Bool {
guard let powerLevels = roomState.powerLevels else {
return false
}
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: session.myUserId)
let userPowerLevel = roomState.powerLevelOfUser(withUserID: session.myUserId)
return userPowerLevel >= powerLevels.minimumPowerLevel(forNotifications: notification, defaultPower: powerLevels.stateDefault)
}
@@ -226,11 +226,11 @@ class SpaceSettingsService: SpaceSettingsServiceProtocol {
avatarUrl: roomState.avatar,
visibility: visibility(with: roomState),
allowedParentIds: allowedParentIds(with: roomState),
isAvatarEditable: isField(ofType: kMXEventTypeStringRoomAvatar, editableWith: roomState.powerLevels),
isNameEditable: isField(ofType: kMXEventTypeStringRoomName, editableWith: roomState.powerLevels),
isTopicEditable: isField(ofType: kMXEventTypeStringRoomTopic, editableWith: roomState.powerLevels),
isAddressEditable: isField(ofType: kMXEventTypeStringRoomAliases, editableWith: roomState.powerLevels),
isAccessEditable: isField(ofType: kMXEventTypeStringRoomJoinRules, editableWith: roomState.powerLevels)
isAvatarEditable: isField(ofType: kMXEventTypeStringRoomAvatar, editableWith: roomState),
isNameEditable: isField(ofType: kMXEventTypeStringRoomName, editableWith: roomState),
isTopicEditable: isField(ofType: kMXEventTypeStringRoomTopic, editableWith: roomState),
isAddressEditable: isField(ofType: kMXEventTypeStringRoomAliases, editableWith: roomState),
isAccessEditable: isField(ofType: kMXEventTypeStringRoomJoinRules, editableWith: roomState)
)
}