Skip to main content

tuwunel_admin/user/
force_promote.rs

1use futures::StreamExt;
2use ruma::{
3	Int, OwnedRoomOrAliasId,
4	events::room::power_levels::{RoomPowerLevelsEventContent, UserPowerLevel},
5};
6use tuwunel_core::{Err, Result, info, matrix::pdu::PduBuilder, utils::ReadyExt};
7
8use crate::{admin_command, utils::parse_user_id};
9
10#[admin_command]
11pub(super) async fn force_promote(
12	&self,
13	target_id: String,
14	room_id: OwnedRoomOrAliasId,
15) -> Result {
16	let target_id = parse_user_id(self.services, &target_id)?;
17	let room_id = self
18		.services
19		.alias
20		.maybe_resolve(&room_id)
21		.await?;
22
23	let state_lock = self.services.state.mutex.lock(&room_id).await;
24
25	let room_power_levels = self
26		.services
27		.state_accessor
28		.get_power_levels(&room_id)
29		.await?;
30
31	let privileged_member = self
32		.services
33		.state_cache
34		.room_members(&room_id)
35		.ready_filter(|member_id| {
36			self.services.globals.user_is_local(member_id)
37				&& room_power_levels.user_can_change_user_power_level(member_id, &target_id)
38		})
39		.map(ToOwned::to_owned)
40		.ready_fold_default(|selected_user, member_id| match selected_user {
41			| None => Some(member_id),
42			| Some(selected_user) => Some(
43				if room_power_levels.for_user(&selected_user)
44					> room_power_levels.for_user(&member_id)
45				{
46					selected_user
47				} else {
48					member_id
49				},
50			),
51		})
52		.await;
53
54	let Some(privileged_member) = privileged_member else {
55		return Err!("No privileged user exists in room, cannot promote.");
56	};
57
58	info!("Selected privileged member {privileged_member}");
59
60	let power_level: Int = match room_power_levels.for_user(&privileged_member) {
61		| UserPowerLevel::Infinite => Int::MAX,
62		| UserPowerLevel::Int(x) => x,
63	};
64
65	let mut power_levels_content: RoomPowerLevelsEventContent = room_power_levels.try_into()?;
66
67	power_levels_content
68		.users
69		.insert(target_id.clone(), power_level);
70
71	let event_id = self
72		.services
73		.timeline
74		.build_and_append_pdu(
75			PduBuilder::state(String::new(), &power_levels_content),
76			&privileged_member,
77			&room_id,
78			&state_lock,
79		)
80		.await?;
81
82	drop(state_lock);
83
84	write!(
85		self,
86		"User {privileged_member} promoted {target_id} to {power_level} power level in \
87		 {room_id} - {event_id}"
88	)
89	.await?;
90
91	Ok(())
92}