Skip to main content

tuwunel_api_client/room/
event.rs

1use axum::extract::State;
2use futures::{TryFutureExt, future::join};
3use ruma::api::client::room::get_room_event;
4use tuwunel_core::{
5	Err, Result, err,
6	result::IsErrOr,
7	utils::{BoolExt, FutureBoolExt, TryFutureExtExt, future::OptionFutureExt},
8};
9use tuwunel_matrix::{Event, Pdu};
10
11use crate::{Ruma, is_ignored_pdu, with_membership};
12
13/// # `GET /_matrix/client/r0/rooms/{roomId}/event/{eventId}`
14///
15/// Gets a single event.
16pub(crate) async fn get_room_event_route(
17	State(services): State<crate::State>,
18	body: Ruma<get_room_event::v3::Request>,
19) -> Result<get_room_event::v3::Response> {
20	let sender_user = body.sender_user();
21	let event_id = &body.event_id;
22	let room_id = &body.room_id;
23
24	let event = services
25		.timeline
26		.get_pdu(event_id)
27		.map_err(|_| err!(Request(NotFound("Event {} not found.", event_id))));
28
29	let retained_event = body
30		.include_unredacted_content
31		.then_async(async || {
32			let is_admin = services.admin.user_is_admin(sender_user);
33
34			let can_redact = services
35				.config
36				.rooms
37				.redaction
38				.allow_room_admins_to_request_unredacted_events
39				.then_async(|| {
40					services
41						.state_accessor
42						.get_power_levels(room_id)
43						.map_ok_or(false, |power_levels| {
44							power_levels.for_user(sender_user) >= power_levels.redact
45						})
46				})
47				.unwrap_or(false);
48
49			if is_admin.or(can_redact).await {
50				services
51					.retention
52					.get_original_pdu(event_id)
53					.await
54					.map_err(|_| err!(Request(NotFound("Event {} not found.", event_id))))
55			} else {
56				Err!(Request(Forbidden("You are not allowed to see the original event")))
57			}
58		});
59
60	let (event, retained_event) = join(event, retained_event).await;
61
62	let event: Result<Pdu> = retained_event
63		.filter(|_| event.as_ref().is_err_or(Event::is_redacted))
64		.unwrap_or(event);
65
66	let event = event?;
67
68	if event.room_id() != room_id
69		|| !services
70			.state_accessor
71			.user_can_see_event(sender_user, &event)
72			.await
73	{
74		return Err!(Request(NotFound("Event not found.")));
75	}
76
77	if is_ignored_pdu(&services, &event, body.sender_user()).await {
78		return Err!(HttpJson(NOT_FOUND, {
79			"errcode": "M_SENDER_IGNORED",
80			"error": "You have ignored the user that sent this event",
81			"sender": event.sender().as_str(),
82		}));
83	}
84
85	debug_assert!(event.event_id() == event_id, "Fetched PDU must match requested");
86
87	let event = event.served_to(Some(sender_user));
88	let encrypted = services
89		.state_accessor
90		.is_encrypted_room(room_id)
91		.await;
92
93	let event = with_membership(&services, event, sender_user, encrypted).await;
94	let event = services
95		.pdu_metadata
96		.bundle_aggregations(sender_user, event)
97		.await;
98
99	Ok(get_room_event::v3::Response { event: event.into_format() })
100}