tuwunel_service/deactivate/
mod.rs1use std::sync::Arc;
2
3use futures::{FutureExt, StreamExt};
4use ruma::{
5 OwnedRoomId, UserId,
6 events::{StateEventType, room::power_levels::RoomPowerLevelsEventContent},
7};
8use tuwunel_core::{Event, Result, info, pdu::PduBuilder, utils::ReadyExt, warn};
9
10use crate::users::Propagation;
11
12pub struct Service {
13 services: Arc<crate::services::OnceServices>,
14}
15
16impl crate::Service for Service {
17 fn build(args: &crate::Args<'_>) -> Result<Arc<Self>> {
18 Ok(Arc::new(Self { services: args.services.clone() }))
19 }
20
21 fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
22}
23
24impl Service {
25 pub async fn full_deactivate(&self, user_id: &UserId, erase: bool) -> Result {
36 self.services
37 .users
38 .deactivate_account(user_id)
39 .await?;
40
41 let all_joined_rooms: Vec<OwnedRoomId> = self
42 .services
43 .state_cache
44 .rooms_joined(user_id)
45 .map(Into::into)
46 .collect()
47 .await;
48
49 self.services
50 .users
51 .update_displayname(user_id, None, &all_joined_rooms, Propagation::All)
52 .await;
53 self.services
54 .users
55 .update_avatar_url(user_id, None, None, &all_joined_rooms, Propagation::All)
56 .await;
57
58 self.services
59 .users
60 .all_profile_keys(user_id)
61 .ready_for_each(|(profile_key, _)| {
62 self.services
63 .users
64 .set_profile_key(user_id, &profile_key, None);
65 })
66 .await;
67
68 for room_id in all_joined_rooms {
69 let state_lock = self.services.state.mutex.lock(&room_id).await;
70
71 let room_power_levels = self
72 .services
73 .state_accessor
74 .get_power_levels(&room_id)
75 .await
76 .ok();
77
78 let user_can_change_self = room_power_levels
79 .as_ref()
80 .is_some_and(|power_levels| {
81 power_levels.user_can_change_user_power_level(user_id, user_id)
82 });
83
84 let user_can_demote_self = user_can_change_self
85 || self
86 .services
87 .state_accessor
88 .room_state_get(&room_id, &StateEventType::RoomCreate, "")
89 .await
90 .is_ok_and(|event| event.sender() == user_id);
91
92 if user_can_demote_self {
93 let mut power_levels_content: RoomPowerLevelsEventContent = room_power_levels
94 .map(TryInto::try_into)
95 .transpose()?
96 .unwrap_or_default();
97
98 power_levels_content.users.remove(user_id);
99
100 match self
102 .services
103 .timeline
104 .build_and_append_pdu(
105 PduBuilder::state(String::new(), &power_levels_content),
106 user_id,
107 &room_id,
108 &state_lock,
109 )
110 .await
111 {
112 | Err(e) => {
113 warn!(%room_id, %user_id, "Failed to demote user's own power level: {e}");
114 },
115 | _ => {
116 info!("Demoted {user_id} in {room_id} as part of account deactivation");
117 },
118 }
119 }
120 }
121
122 let rooms_joined = self
123 .services
124 .state_cache
125 .rooms_joined(user_id)
126 .map(ToOwned::to_owned);
127
128 let rooms_invited = self
129 .services
130 .state_cache
131 .rooms_invited(user_id)
132 .map(ToOwned::to_owned);
133
134 let rooms_knocked = self
135 .services
136 .state_cache
137 .rooms_knocked(user_id)
138 .map(ToOwned::to_owned);
139
140 let all_rooms: Vec<_> = rooms_joined
141 .chain(rooms_invited)
142 .chain(rooms_knocked)
143 .collect()
144 .await;
145
146 if erase {
148 self.services
149 .account_data
150 .erase_user(user_id, None)
151 .await;
152
153 let rooms_left: Vec<OwnedRoomId> = self
154 .services
155 .state_cache
156 .rooms_left(user_id)
157 .map(ToOwned::to_owned)
158 .collect()
159 .await;
160
161 for room_id in all_rooms.iter().chain(rooms_left.iter()) {
162 self.services
163 .account_data
164 .erase_user(user_id, Some(room_id))
165 .await;
166 }
167 }
168
169 for room_id in all_rooms {
170 let state_lock = self.services.state.mutex.lock(&room_id).await;
171
172 if let Err(e) = self
174 .services
175 .membership
176 .leave(user_id, &room_id, None, false, &state_lock)
177 .boxed()
178 .await
179 {
180 warn!(%user_id, "Failed to leave {room_id} remotely: {e}");
181 }
182
183 drop(state_lock);
184
185 self.services
186 .state_cache
187 .forget(&room_id, user_id);
188 }
189
190 Ok(())
191 }
192}