diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index a0426143..9eb28717 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -2,6 +2,7 @@ use ruma::{ api::{ client::{ error::ErrorKind, + knock::{self, knock_room}, membership::{ ban_user, forget_room, get_member_events, invite_user, join_room_by_id, join_room_by_id_or_alias, joined_members, joined_rooms, kick_user, leave_room, @@ -140,6 +141,53 @@ pub async fn join_room_by_id_or_alias_route( }) } +/// # `POST /_matrix/client/r0/join/{roomIdOrAlias}` +/// +/// Tries to knock the room to ask permission to join for the sender user. +pub async fn knock_room_route( + body: Ruma, +) -> Result { + let sender_user = body.sender_user.as_deref().expect("user is authenticated"); + let body = body.body; + + let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias) { + Ok(room_id) => { + let mut servers = body.server_name.clone(); + servers.extend( + services() + .rooms + .state_cache + .invite_state(sender_user, &room_id)? + .unwrap_or_default() + .iter() + .filter_map(|event| serde_json::from_str(event.json().get()).ok()) + .filter_map(|event: serde_json::Value| event.get("sender").cloned()) + .filter_map(|sender| sender.as_str().map(|s| s.to_owned())) + .filter_map(|sender| UserId::parse(sender).ok()) + .map(|user| user.server_name().to_owned()), + ); + + servers.push( + room_id + .server_name() + .expect("Room IDs should always have a server name") + .into(), + ); + + (servers, room_id) + } + Err(room_alias) => { + let response = get_alias_helper(room_alias).await?; + + (response.servers, response.room_id) + } + }; + + Ok(knock_room_by_id_or_alias::v3::Response { + room_id: knock_room_response.room_id, + }) +} + /// # `POST /_matrix/client/r0/rooms/{roomId}/leave` /// /// Tries to leave the sender user from a room.