Skip to content
Snippets Groups Projects
Commit 4d624846 authored by 🥺's avatar 🥺 :transgender_flag: Committed by 🥺
Browse files

admin command to delete media via MXC url

parent 27c29e60
No related branches found
No related tags found
No related merge requests found
use ruma::api::client::error::ErrorKind; use ruma::api::client::error::ErrorKind;
use tracing::debug;
use crate::{ use crate::{
database::KeyValueDatabase, database::KeyValueDatabase,
...@@ -40,14 +41,46 @@ fn create_file_metadata( ...@@ -40,14 +41,46 @@ fn create_file_metadata(
} }
fn delete_file_mxc(&self, mxc: String) -> Result<()> { fn delete_file_mxc(&self, mxc: String) -> Result<()> {
let mut key = mxc.as_bytes().to_vec(); debug!("MXC URI: {:?}", mxc);
key.push(0xff);
let mut prefix = mxc.as_bytes().to_vec();
prefix.push(0xff);
debug!("MXC db prefix: {:?}", prefix);
self.mediaid_file.remove(&key)?; for (key, _) in self.mediaid_file.scan_prefix(prefix) {
debug!("Deleting key: {:?}", key);
self.mediaid_file.remove(&key)?;
}
//return Err(Error::bad_database("Media not found."));
Ok(()) Ok(())
} }
/// Searches for all files with the given MXC (e.g. thumbnail and original image)
fn search_mxc_metadata_prefix(&self, mxc: String) -> Result<Vec<Vec<u8>>> {
debug!("MXC URI: {:?}", mxc);
let mut prefix = mxc.as_bytes().to_vec();
prefix.push(0xff);
let mut keys: Vec<Vec<u8>> = vec![];
for (key, _) in self.mediaid_file.scan_prefix(prefix) {
keys.push(key);
}
if keys.is_empty() {
return Err(Error::bad_database(
"Failed to find any keys in database with the provided MXC.",
));
}
debug!("Got the following keys: {:?}", keys);
Ok(keys)
}
fn search_file_metadata( fn search_file_metadata(
&self, &self,
mxc: String, mxc: String,
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
}, },
TimelineEventType, TimelineEventType,
}, },
EventId, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, RoomOrAliasId, EventId, MxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId,
RoomVersionId, ServerName, UserId, RoomOrAliasId, RoomVersionId, ServerName, UserId,
}; };
use serde_json::value::to_raw_value; use serde_json::value::to_raw_value;
use tokio::sync::{mpsc, Mutex}; use tokio::sync::{mpsc, Mutex};
...@@ -69,6 +69,10 @@ enum AdminCommand { ...@@ -69,6 +69,10 @@ enum AdminCommand {
/// - Commands for managing the server /// - Commands for managing the server
Server(ServerCommand), Server(ServerCommand),
#[command(subcommand)]
/// - Commands for managing media
Media(MediaCommand),
#[command(subcommand)] #[command(subcommand)]
// TODO: should i split out debug commands to a separate thing? the // TODO: should i split out debug commands to a separate thing? the
// debug commands seem like they could fit in the other categories fine // debug commands seem like they could fit in the other categories fine
...@@ -77,6 +81,16 @@ enum AdminCommand { ...@@ -77,6 +81,16 @@ enum AdminCommand {
Debug(DebugCommand), Debug(DebugCommand),
} }
#[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)]
enum MediaCommand {
/// - Deletes a single media file from our database and on the filesystem via a single MXC URI
Delete {
/// The MXC URI to delete
mxc: Box<MxcUri>,
},
}
#[cfg_attr(test, derive(Debug))] #[cfg_attr(test, derive(Debug))]
#[derive(Subcommand)] #[derive(Subcommand)]
enum AppserviceCommand { enum AppserviceCommand {
...@@ -606,6 +620,16 @@ async fn process_admin_command( ...@@ -606,6 +620,16 @@ async fn process_admin_command(
} }
} }
}, },
AdminCommand::Media(command) => match command {
MediaCommand::Delete { mxc } => {
debug!("Got MXC URI: {}", mxc);
services().media.delete(mxc.to_string()).await?;
return Ok(RoomMessageEventContent::text_plain(
"Deleted the MXC from our database and on our filesystem.",
));
}
},
AdminCommand::Users(command) => match command { AdminCommand::Users(command) => match command {
UserCommand::List => match services().users.list_local_users() { UserCommand::List => match services().users.list_local_users() {
Ok(users) => { Ok(users) => {
......
...@@ -20,6 +20,8 @@ fn search_file_metadata( ...@@ -20,6 +20,8 @@ fn search_file_metadata(
height: u32, height: u32,
) -> Result<(Option<String>, Option<String>, Vec<u8>)>; ) -> Result<(Option<String>, Option<String>, Vec<u8>)>;
fn search_mxc_metadata_prefix(&self, mxc: String) -> Result<Vec<Vec<u8>>>;
fn remove_url_preview(&self, url: &str) -> Result<()>; fn remove_url_preview(&self, url: &str) -> Result<()>;
fn set_url_preview( fn set_url_preview(
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
pub(crate) use data::Data; pub(crate) use data::Data;
use serde::Serialize; use serde::Serialize;
use tracing::{debug, error, warn}; use tracing::{debug, error};
use crate::{services, Error, Result}; use crate::{services, Error, Result};
use image::imageops::FilterType; use image::imageops::FilterType;
...@@ -93,45 +93,30 @@ pub async fn create( ...@@ -93,45 +93,30 @@ pub async fn create(
/// Deletes a file in the database and from the media directory via an MXC /// Deletes a file in the database and from the media directory via an MXC
pub async fn delete(&self, mxc: String) -> Result<()> { pub async fn delete(&self, mxc: String) -> Result<()> {
if let Ok(filemeta) = self.get(mxc.clone()).await { if let Ok(keys) = self.db.search_mxc_metadata_prefix(mxc.clone()) {
match filemeta { for key in keys {
Some(filemeta) => { let file_path = if cfg!(feature = "sha256_media") {
debug!("Got file metadata: {:?}", filemeta); services().globals.get_media_file_new(&key)
let file_key = filemeta.file; } else {
debug!("File key from file metadata: {:?}", file_key); #[allow(deprecated)]
services().globals.get_media_file(&key)
let file_path = if cfg!(feature = "sha256_media") { };
services().globals.get_media_file_new(&file_key) debug!("Got local file path: {:?}", file_path);
} else {
#[allow(deprecated)]
services().globals.get_media_file(&file_key)
};
debug!("Got local file path: {:?}", file_path);
debug!(
"Deleting local file {:?} from filesystem, original MXC: {mxc}",
file_path
);
tokio::fs::remove_file(file_path).await?;
debug!("Deleting MXC {mxc} from database"); debug!(
self.db.delete_file_mxc(mxc)?; "Deleting local file {:?} from filesystem, original MXC: {}",
file_path, mxc
);
tokio::fs::remove_file(file_path).await?;
Ok(()) debug!("Deleting MXC {mxc} from database");
} self.db.delete_file_mxc(mxc.clone())?;
None => {
warn!(
"MXC {mxc} does not exist in our database or file in MXC does not exist."
);
Err(Error::bad_database(
"MXC does not exist in our database or file in MXC does not exist.",
))
}
} }
Ok(())
} else { } else {
// we shouldn't get to this point as this is failing to actually attempt to get the file metadata (Result) error!("Failed to find any media keys for MXC \"{mxc}\" in our database (MXC does not exist)");
error!("Failed getting file metadata for MXC \"{mxc}\" in database (does not exist or database issue?)"); Err(Error::bad_database("Failed to find any media keys for the provided MXC in our database (MXC does not exist)"))
Err(Error::bad_database("Failed getting file metadata via MXC in database (does not exist or database issue?)"))
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment