From 6b65a8fc86019d2c06aa36d1ecc37b8f3e5069c8 Mon Sep 17 00:00:00 2001 From: strawberry Date: Sun, 25 Aug 2024 11:46:47 -0400 Subject: [PATCH] add functions to delete media from specific local users Signed-off-by: strawberry --- src/service/media/data.rs | 19 ++++++++++++++++++- src/service/media/mod.rs | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/service/media/data.rs b/src/service/media/data.rs index 6b1d9cf0..06cd6cc7 100644 --- a/src/service/media/data.rs +++ b/src/service/media/data.rs @@ -6,7 +6,7 @@ use conduit::{ Err, Error, Result, }; use database::{Database, Map}; -use ruma::{api::client::error::ErrorKind, http_headers::ContentDisposition, Mxc, UserId}; +use ruma::{api::client::error::ErrorKind, http_headers::ContentDisposition, Mxc, OwnedMxcUri, UserId}; use super::preview::UrlPreviewData; @@ -176,6 +176,23 @@ impl Data { }) } + /// Gets all the MXCs associated with a user + pub(super) fn get_all_user_mxcs(&self, user_id: &UserId) -> Vec { + let user_id = user_id.as_bytes().to_vec(); + + self.mediaid_user + .iter() + .filter_map(|(key, user)| { + if *user == user_id { + let mxc_s = string_from_bytes(&key).ok()?; + Some(OwnedMxcUri::from(mxc_s)) + } else { + None + } + }) + .collect() + } + /// Gets all the media keys in our database (this includes all the metadata /// associated with it such as width, height, content-type, etc) pub(crate) fn get_all_media_keys(&self) -> Vec> { self.mediaid_file.iter().map(|(key, _)| key).collect() } diff --git a/src/service/media/mod.rs b/src/service/media/mod.rs index c8f8ad72..698f7dc2 100644 --- a/src/service/media/mod.rs +++ b/src/service/media/mod.rs @@ -8,7 +8,11 @@ use std::{path::PathBuf, sync::Arc, time::SystemTime}; use async_trait::async_trait; use base64::{engine::general_purpose, Engine as _}; -use conduit::{debug, debug_error, err, error, trace, utils, utils::MutexMap, Err, Result, Server}; +use conduit::{ + debug, debug_error, debug_info, err, error, trace, + utils::{self, MutexMap}, + warn, Err, Result, Server, +}; use data::{Data, Metadata}; use ruma::{http_headers::ContentDisposition, Mxc, OwnedMxcUri, UserId}; use tokio::{ @@ -106,6 +110,31 @@ impl Service { } } + /// Deletes all media by the specified user + /// + /// currently, this is only practical for local users + pub async fn delete_from_user(&self, user: &UserId, force: bool) -> Result { + let mxcs = self.db.get_all_user_mxcs(user); + let mut deletion_count: usize = 0; + + for mxc in mxcs { + let mxc: Mxc<'_> = mxc.as_str().try_into()?; + debug_info!("Deleting MXC {mxc} by user {user} from database and filesystem"); + if force { + _ = self + .delete(&mxc) + .await + .inspect_err(|e| warn!("Failed to delete {mxc} from user {user}, ignoring error: {e}")); + } else { + self.delete(&mxc).await?; + } + + deletion_count = deletion_count.saturating_add(1); + } + + Ok(deletion_count) + } + /// Downloads a file. pub async fn get(&self, mxc: &Mxc<'_>) -> Result> { if let Ok(Metadata { @@ -163,7 +192,7 @@ impl Service { return Err!(Database("Parsed MXC URL unicode bytes from database but still is None")); }; - debug!("Parsed MXC key to URL: {mxc_s}"); + debug_info!("Parsed MXC key to URL: {mxc_s}"); let mxc = OwnedMxcUri::from(mxc_s); if mxc.server_name() == Ok(self.services.globals.server_name()) { debug!("Ignoring local media MXC: {mxc}"); @@ -206,11 +235,11 @@ impl Service { return Err!(Database("Did not found any eligible MXCs to delete.")); } - debug!("Deleting media now in the past {user_duration:?}."); + debug_info!("Deleting media now in the past {user_duration:?}."); let mut deletion_count: usize = 0; for mxc in remote_mxcs { let mxc: Mxc<'_> = mxc.as_str().try_into()?; - debug!("Deleting MXC {mxc} from database and filesystem"); + debug_info!("Deleting MXC {mxc} from database and filesystem"); self.delete(&mxc).await?; deletion_count = deletion_count.saturating_add(1); }