Skip to main content

tuwunel_api/client/room/
event.rs

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