Skip to main content

tuwunel_api/client/membership/
forget.rs

1use axum::extract::State;
2use futures::{TryFutureExt, pin_mut};
3use ruma::{api::client::membership::forget_room, events::room::member::MembershipState};
4use tuwunel_core::{
5	Err, Result, is_matching,
6	utils::{FutureBoolExt, TryFutureExtExt},
7};
8
9use crate::Ruma;
10
11/// # `POST /_matrix/client/v3/rooms/{roomId}/forget`
12///
13/// Forgets a room the sender user has left.
14///
15/// A user still joined, knocked, or invited must leave the room first. Any
16/// other call succeeds, including a repeat and one for a room whose state the
17/// server no longer holds.
18///
19/// The user's other devices have no way of knowing the room was forgotten, so
20/// this has to be called from every device.
21pub(crate) async fn forget_room_route(
22	State(services): State<crate::State>,
23	body: Ruma<forget_room::v3::Request>,
24) -> Result<forget_room::v3::Response> {
25	let user_id = body.sender_user();
26	let room_id = &body.room_id;
27
28	let joined = services.state_cache.is_joined(user_id, room_id);
29	let knocked = services.state_cache.is_knocked(user_id, room_id);
30	let invited = services.state_cache.is_invited(user_id, room_id);
31
32	pin_mut!(joined, knocked, invited);
33	if joined.or(knocked).or(invited).await {
34		return Err!(Request(Unknown("You must leave the room before forgetting it")));
35	}
36
37	let left = services.state_cache.is_left(user_id, room_id);
38	let left_or_banned = services
39		.state_accessor
40		.get_member(room_id, user_id)
41		.map_ok(|member| member.membership)
42		.map_ok_or(false, is_matching!(MembershipState::Leave | MembershipState::Ban));
43
44	pin_mut!(left, left_or_banned);
45	if left.or(left_or_banned).await {
46		services.state_cache.forget(room_id, user_id);
47	}
48
49	Ok(forget_room::v3::Response::new())
50}