tuwunel_api_client/
redact.rs1use axum::extract::State;
2use ruma::{
3 api::client::redact::redact_event::v3::{Request, Response},
4 events::room::redaction::RoomRedactionEventContent,
5};
6use tuwunel_core::{Err, Result, result::NotFound, warn};
7use tuwunel_matrix::pdu::PduBuilder;
8use tuwunel_service::transaction_ids::{RoomScope, RoomTxn};
9
10use crate::{
11 Ruma,
12 utils::{is_self_redaction, txnid_event_id, txnid_unsigned},
13};
14
15pub(crate) async fn redact_event_route(
23 State(services): State<crate::State>,
24 body: Ruma<Request>,
25) -> Result<Response> {
26 let sender_user = body.sender_user();
27 let sender_device = body.sender_device.as_deref();
28
29 if services.config.rooms.redaction.disable_local
30 && !services.admin.user_is_admin(sender_user).await
31 {
32 warn!(
33 %sender_user,
34 event_id = %body.event_id,
35 "Local redactions are disabled, non-admin user attempted to redact an event"
36 );
37 return Err!(Request(Forbidden("Redactions are disabled on this server.")));
38 }
39
40 if services.users.is_suspended(sender_user).await
41 && !is_self_redaction(&services, sender_user, &body.event_id).await
42 {
43 return Err!(Request(UserSuspended("Account is suspended.")));
44 }
45
46 let state_lock = services.state.mutex.lock(&body.room_id).await;
47 let scope = RoomScope::Redact(&body.event_id);
48 let txn = RoomTxn {
49 user_id: sender_user,
50 device_id: sender_device,
51 txn_id: &body.txn_id,
52 room_id: &body.room_id,
53 };
54
55 let existing = services
56 .transaction_ids
57 .existing_room_txnid(txn, scope)
58 .await
59 .optional()?;
60
61 if let Some(response) = existing {
62 return txnid_event_id(&response).map(Response::new);
63 }
64
65 let redacts = || Some(body.event_id.clone());
66 let pdu = PduBuilder {
67 redacts: redacts(),
68 unsigned: txnid_unsigned(&body.txn_id).into(),
69 ..PduBuilder::timeline(&RoomRedactionEventContent {
70 redacts: redacts(),
71 reason: body.reason.clone(),
72 })
73 };
74
75 let event_id = services
76 .timeline
77 .build_and_append_pdu(pdu, sender_user, &body.room_id, &state_lock)
78 .await?;
79
80 services
81 .transaction_ids
82 .add_room_txnid(txn, scope, event_id.as_bytes());
83
84 drop(state_lock);
85
86 Ok(Response { event_id })
87}