Force promotion (closes #136)
This commit is contained in:
@@ -2,11 +2,11 @@ use std::{collections::BTreeMap, fmt::Write as _};
|
||||
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use ruma::{
|
||||
OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedUserId, UserId,
|
||||
Int, OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedUserId, UserId,
|
||||
events::{
|
||||
RoomAccountDataEventType, StateEventType,
|
||||
room::{
|
||||
power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent},
|
||||
power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent, UserPowerLevel},
|
||||
redaction::RoomRedactionEventContent,
|
||||
},
|
||||
tag::{TagEvent, TagEventContent, TagInfo},
|
||||
@@ -22,7 +22,7 @@ use tuwunel_service::Services;
|
||||
|
||||
use crate::{
|
||||
admin_command, get_room_info,
|
||||
utils::{parse_active_local_user_id, parse_local_user_id},
|
||||
utils::{parse_active_local_user_id, parse_local_user_id, parse_user_id},
|
||||
};
|
||||
|
||||
const AUTO_GEN_PASSWORD_LENGTH: usize = 25;
|
||||
@@ -737,6 +737,85 @@ pub(super) async fn force_demote(&self, user_id: String, room_id: OwnedRoomOrAli
|
||||
.await
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn force_promote(
|
||||
&self,
|
||||
target_id: String,
|
||||
room_id: OwnedRoomOrAliasId,
|
||||
) -> Result {
|
||||
let target_id = parse_user_id(self.services, &target_id)?;
|
||||
let room_id = self.services.alias.resolve(&room_id).await?;
|
||||
|
||||
let state_lock = self.services.state.mutex.lock(&room_id).await;
|
||||
|
||||
let room_power_levels = self
|
||||
.services
|
||||
.state_accessor
|
||||
.get_power_levels(&room_id)
|
||||
.await?;
|
||||
|
||||
let privileged_member = self
|
||||
.services
|
||||
.state_cache
|
||||
.room_members(&room_id)
|
||||
.ready_filter(|member_id| {
|
||||
self.services.globals.user_is_local(member_id)
|
||||
&& room_power_levels.user_can_change_user_power_level(member_id, &target_id)
|
||||
})
|
||||
.map(ToOwned::to_owned)
|
||||
.ready_fold_default(|selected_user, member_id| match selected_user {
|
||||
| None => Some(member_id),
|
||||
| Some(selected_user) => Some(
|
||||
if room_power_levels.for_user(&selected_user)
|
||||
> room_power_levels.for_user(&member_id)
|
||||
{
|
||||
selected_user
|
||||
} else {
|
||||
member_id
|
||||
},
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
let Some(privileged_member) = privileged_member else {
|
||||
return Err!("No privileged user exists in room, cannot promote.");
|
||||
};
|
||||
|
||||
info!("Selected privileged member {privileged_member}");
|
||||
|
||||
let power_level: Int = match room_power_levels.for_user(&privileged_member) {
|
||||
| UserPowerLevel::Infinite => Int::MAX,
|
||||
| UserPowerLevel::Int(x) => x,
|
||||
};
|
||||
|
||||
let mut power_levels_content: RoomPowerLevelsEventContent = room_power_levels.try_into()?;
|
||||
|
||||
power_levels_content
|
||||
.users
|
||||
.insert(target_id.clone(), power_level);
|
||||
|
||||
let event_id = self
|
||||
.services
|
||||
.timeline
|
||||
.build_and_append_pdu(
|
||||
PduBuilder::state(String::new(), &power_levels_content),
|
||||
&privileged_member,
|
||||
&room_id,
|
||||
&state_lock,
|
||||
)
|
||||
.await?;
|
||||
|
||||
drop(state_lock);
|
||||
|
||||
self.write_str(&format!(
|
||||
"User {privileged_member} promoted {target_id} to {power_level} power level in \
|
||||
{room_id} - {event_id}"
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn make_user_admin(&self, user_id: String) -> Result {
|
||||
let user_id = parse_local_user_id(self.services, &user_id)?;
|
||||
|
||||
@@ -88,6 +88,12 @@ pub(super) enum UserCommand {
|
||||
room_id: OwnedRoomOrAliasId,
|
||||
},
|
||||
|
||||
/// - Force promote
|
||||
ForcePromote {
|
||||
user_id: String,
|
||||
room_id: OwnedRoomOrAliasId,
|
||||
},
|
||||
|
||||
/// - Grant server-admin privileges to a user.
|
||||
MakeUserAdmin {
|
||||
user_id: String,
|
||||
|
||||
Reference in New Issue
Block a user