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 member = services
40 .state_accessor
41 .get_member(room_id, user_id);
42
43 let ignored = services
44 .users
45 .user_is_ignored(user_id, sender_user);
46
47 let (member, ignored) = join!(member, ignored);
48
49 if member.is_ok_and(|member| member.membership == MembershipState::Ban) {
50 return Err!(Request(Forbidden("User is banned from this room.")));
51 }
52
53 if ignored {
54 return Ok(invite_user::v3::Response {});
57 }
58
59 services
60 .membership
61 .invite(sender_user, user_id, room_id, reason.as_ref(), false)
62 .boxed()
63 .await?;
64
65 Ok(invite_user::v3::Response {})
66}