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