Skip to main content

tuwunel_api_admin/media/
delete_user_media.rs

1use axum::extract::State;
2use futures::StreamExt;
3use synapse_admin_api::media::delete_user_media::v1 as delete_user_media;
4use tuwunel_core::{
5	Err, Result,
6	utils::{
7		math::ruma_from_usize_saturating,
8		stream::{IterStream, WidebandExt},
9	},
10};
11
12use super::{select_page, usize_from};
13use crate::{Ruma, require_admin};
14
15/// # `DELETE /_synapse/admin/v1/users/{user_id}/media`
16///
17/// Deletes a single page of the user's media per call; callers loop to drain,
18/// mirroring Synapse (the remaining media reorders after each page, so there is
19/// no continuation token).
20pub(crate) async fn admin_delete_user_media_route(
21	State(services): State<crate::State>,
22	body: Ruma<delete_user_media::Request>,
23) -> Result<delete_user_media::Response> {
24	require_admin(&services, body.sender_user()).await?;
25
26	if !services
27		.globals
28		.server_is_ours(body.user_id.server_name())
29	{
30		return Err!(Request(InvalidParam("Can only look up local users")));
31	}
32
33	if !services.users.exists(&body.user_id).await {
34		return Err!(Request(NotFound("User not found")));
35	}
36
37	let entries = services.media.user_media(&body.user_id).await?;
38
39	let from = body.from.map(usize_from).unwrap_or(0);
40	let limit = body.limit.map(usize_from).unwrap_or(100);
41
42	let page = select_page(entries, body.order_by.as_ref(), body.dir, from, limit);
43
44	let deleted_media: Vec<String> = page
45		.iter()
46		.stream()
47		.wide_filter_map(async |entry| {
48			let mxc = entry.mxc.parts().ok()?;
49
50			services
51				.media
52				.delete(&mxc)
53				.await
54				.ok()
55				.map(|()| mxc.media_id.to_owned())
56		})
57		.collect()
58		.await;
59
60	let total = ruma_from_usize_saturating(deleted_media.len());
61
62	Ok(delete_user_media::Response { deleted_media, total })
63}