tuwunel_service/membership/
kick.rs1use ruma::{
2 RoomId, UserId,
3 events::room::member::{MembershipState, RoomMemberEventContent},
4};
5use tuwunel_core::{Err, Result, implement, pdu::PduBuilder};
6
7use super::Service;
8use crate::rooms::timeline::RoomMutexGuard;
9
10#[implement(Service)]
11#[tracing::instrument(
12 level = "debug",
13 skip_all,
14 fields(%sender_user, %room_id, %user_id)
15)]
16pub async fn kick(
17 &self,
18 room_id: &RoomId,
19 user_id: &UserId,
20 reason: Option<&String>,
21 sender_user: &UserId,
22 state_lock: &RoomMutexGuard,
23) -> Result {
24 let Ok(event) = self
25 .services
26 .state_accessor
27 .get_member(room_id, user_id)
28 .await
29 else {
30 return Err!(Request(Forbidden("Cannot kick a user who is not in the room.")));
31 };
32
33 if !matches!(
35 event.membership,
36 MembershipState::Invite | MembershipState::Knock | MembershipState::Join,
37 ) {
38 return Err!(Request(Forbidden(
39 "Cannot kick a user who is not apart of the room (current membership: {})",
40 event.membership
41 )));
42 }
43
44 self.services
45 .timeline
46 .build_and_append_pdu(
47 PduBuilder::state(user_id.to_string(), &RoomMemberEventContent {
48 membership: MembershipState::Leave,
49 reason: reason.cloned(),
50 is_direct: None,
51 join_authorized_via_users_server: None,
52 third_party_invite: None,
53 ..event
54 }),
55 sender_user,
56 room_id,
57 state_lock,
58 )
59 .await?;
60
61 Ok(())
62}