Skip to main content

tuwunel_api/server/
make_leave.rs

1use axum::extract::State;
2use futures::TryFutureExt;
3use ruma::{
4	api::federation::membership::prepare_leave_event,
5	events::room::member::{MembershipState, RoomMemberEventContent},
6};
7use tuwunel_core::{Err, Result, at, matrix::pdu::PduBuilder};
8
9use crate::Ruma;
10
11/// # `GET /_matrix/federation/v1/make_leave/{roomId}/{eventId}`
12///
13/// Creates a leave template.
14pub(crate) async fn create_leave_event_template_route(
15	State(services): State<crate::State>,
16	body: Ruma<prepare_leave_event::v1::Request>,
17) -> Result<prepare_leave_event::v1::Response> {
18	if !services.metadata.exists(&body.room_id).await {
19		return Err!(Request(NotFound("Room is unknown to this server.")));
20	}
21
22	if body.user_id.server_name() != body.origin() {
23		return Err!(Request(Forbidden(
24			"Not allowed to leave on behalf of another server/user."
25		)));
26	}
27
28	// ACL check origin
29	services
30		.event_handler
31		.acl_check(body.origin(), &body.room_id)
32		.await?;
33
34	let room_version = services
35		.state
36		.get_room_version(&body.room_id)
37		.map_ok(Some)
38		.await?;
39
40	let state_lock = services.state.mutex.lock(&body.room_id).await;
41
42	let pdu_json = services
43		.timeline
44		.create_hash_and_sign_event(
45			PduBuilder::state(
46				body.user_id.to_string(),
47				&RoomMemberEventContent::new(MembershipState::Leave),
48			),
49			&body.user_id,
50			&body.room_id,
51			&state_lock,
52		)
53		.map_ok(at!(1))
54		.await?;
55
56	drop(state_lock);
57
58	let event = services
59		.federation
60		.format_pdu_into(pdu_json, room_version.as_ref())
61		.await;
62
63	Ok(prepare_leave_event::v1::Response { room_version, event })
64}