tuwunel_api/client/membership/
invite.rs1use axum::extract::State;
2use futures::{FutureExt, join};
3use ruma::{
4 api::client::membership::invite_user::{
5 self,
6 v3::{InvitationRecipient, InviteUserId},
7 },
8 events::room::member::MembershipState,
9};
10use tuwunel_core::{Err, Result};
11
12use super::banned_room_check;
13use crate::{ClientIp, Ruma, client::utils::invite_check};
14
15#[tracing::instrument(skip_all, fields(%client), name = "invite")]
19pub(crate) async fn invite_user_route(
20 State(services): State<crate::State>,
21 ClientIp(client): ClientIp,
22 body: Ruma<invite_user::v3::Request>,
23) -> Result<invite_user::v3::Response> {
24 let sender_user = body.sender_user();
25
26 let room_id = &body.room_id;
27
28 invite_check(&services, sender_user, room_id).await?;
29
30 banned_room_check(&services, sender_user, room_id, None, client).await?;
31
32 let InvitationRecipient::UserId(InviteUserId { user_id, reason }) = &body.recipient else {
33 return Err!(Request(ThreepidDenied("Third party identifiers are not implemented")));
34 };
35
36 let sender_ignored_recipient = services
37 .users
38 .user_is_ignored(sender_user, user_id);
39
40 let recipient_ignored_by_sender = services
41 .users
42 .user_is_ignored(user_id, sender_user);
43
44 let (sender_ignored_recipient, recipient_ignored_by_sender) =
45 join!(sender_ignored_recipient, recipient_ignored_by_sender);
46
47 if sender_ignored_recipient {
48 return Ok(invite_user::v3::Response {});
49 }
50
51 if let Ok(target_user_membership) = services
55 .state_accessor
56 .get_member(room_id, user_id)
57 .await && target_user_membership.membership == MembershipState::Ban
58 {
59 return Err!(Request(Forbidden("User is banned from this room.")));
60 }
61
62 if recipient_ignored_by_sender {
63 return Ok(invite_user::v3::Response {});
66 }
67
68 services
69 .membership
70 .invite(sender_user, user_id, room_id, reason.as_ref(), false)
71 .boxed()
72 .await?;
73
74 Ok(invite_user::v3::Response {})
75}