add admin command to delete all remote media from a specific server
Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
parent
8923c9a227
commit
fb49e37067
3 changed files with 105 additions and 6 deletions
|
@ -1,5 +1,5 @@
|
|||
use conduit::{debug, info, Result};
|
||||
use ruma::{events::room::message::RoomMessageEventContent, EventId, MxcUri};
|
||||
use conduit::{debug, info, trace, warn, Result};
|
||||
use ruma::{events::room::message::RoomMessageEventContent, EventId, Mxc, MxcUri, ServerName};
|
||||
|
||||
use crate::{admin_command, utils::parse_local_user_id};
|
||||
|
||||
|
@ -201,3 +201,59 @@ pub(super) async fn delete_all_from_user(&self, username: String, force: bool) -
|
|||
"Deleted {deleted_count} total files.",
|
||||
)))
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn delete_all_from_server(
|
||||
&self, server_name: Box<ServerName>, force: bool,
|
||||
) -> Result<RoomMessageEventContent> {
|
||||
if server_name == self.services.globals.server_name() {
|
||||
return Ok(RoomMessageEventContent::text_plain("This command only works for remote media."));
|
||||
}
|
||||
|
||||
let Ok(all_mxcs) = self.services.media.get_all_mxcs().await else {
|
||||
return Ok(RoomMessageEventContent::text_plain("Failed to get MXC URIs from our database"));
|
||||
};
|
||||
|
||||
let mut deleted_count: usize = 0;
|
||||
|
||||
for mxc in all_mxcs {
|
||||
let mxc_server_name = match mxc.server_name() {
|
||||
Ok(server_name) => server_name,
|
||||
Err(e) => {
|
||||
if force {
|
||||
warn!("Failed to parse MXC {mxc} server name from database, ignoring error and skipping: {e}");
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse MXC {mxc} server name from database: {e}",
|
||||
)));
|
||||
},
|
||||
};
|
||||
|
||||
if mxc_server_name != server_name || self.services.globals.server_is_ours(mxc_server_name) {
|
||||
trace!("skipping MXC URI {mxc}");
|
||||
continue;
|
||||
}
|
||||
|
||||
let mxc: Mxc<'_> = mxc.as_str().try_into()?;
|
||||
|
||||
match self.services.media.delete(&mxc).await {
|
||||
Ok(()) => {
|
||||
deleted_count = deleted_count.saturating_add(1);
|
||||
},
|
||||
Err(e) => {
|
||||
if force {
|
||||
warn!("Failed to delete {mxc}, ignoring error and skipping: {e}");
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(RoomMessageEventContent::text_plain(format!("Failed to delete MXC {mxc}: {e}")));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Deleted {deleted_count} total files.",
|
||||
)))
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ mod commands;
|
|||
|
||||
use clap::Subcommand;
|
||||
use conduit::Result;
|
||||
use ruma::{EventId, MxcUri};
|
||||
use ruma::{EventId, MxcUri, ServerName};
|
||||
|
||||
use crate::admin_command_dispatch;
|
||||
|
||||
|
@ -46,4 +46,13 @@ pub(super) enum MediaCommand {
|
|||
#[arg(short, long)]
|
||||
force: bool,
|
||||
},
|
||||
|
||||
/// - Deletes all remote media from the specified remote server
|
||||
DeleteAllFromServer {
|
||||
server_name: Box<ServerName>,
|
||||
|
||||
/// Continues deleting media if an undeletable object is found
|
||||
#[arg(short, long)]
|
||||
force: bool,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -159,11 +159,43 @@ impl Service {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets all the MXC URIs in our media database
|
||||
pub async fn get_all_mxcs(&self) -> Result<Vec<OwnedMxcUri>> {
|
||||
let all_keys = self.db.get_all_media_keys();
|
||||
|
||||
let mut mxcs = Vec::with_capacity(all_keys.len());
|
||||
|
||||
for key in all_keys {
|
||||
debug!("Full MXC key from database: {key:?}");
|
||||
|
||||
// we need to get the MXC URL from the first part of the key (the first 0xff /
|
||||
// 255 push). this is all necessary because of conduit using magic keys for
|
||||
// media
|
||||
let mut parts = key.split(|&b| b == 0xFF);
|
||||
let mxc = parts
|
||||
.next()
|
||||
.map(|bytes| {
|
||||
utils::string_from_bytes(bytes)
|
||||
.map_err(|e| err!(Database(error!("Failed to parse MXC unicode bytes from our database: {e}"))))
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let Some(mxc_s) = mxc else {
|
||||
return Err!(Database("Parsed MXC URL unicode bytes from database but still is None"));
|
||||
};
|
||||
|
||||
debug_info!("Parsed MXC key to URL: {mxc_s}");
|
||||
let mxc = OwnedMxcUri::from(mxc_s);
|
||||
|
||||
mxcs.push(mxc);
|
||||
}
|
||||
|
||||
Ok(mxcs)
|
||||
}
|
||||
|
||||
/// Deletes all remote only media files in the given at or after
|
||||
/// time/duration. Returns a u32 with the amount of media files deleted.
|
||||
pub async fn delete_all_remote_media_at_after_time(&self, time: String, force: bool) -> Result<usize> {
|
||||
let all_keys = self.db.get_all_media_keys();
|
||||
|
||||
let user_duration: SystemTime = match cyborgtime::parse_duration(&time) {
|
||||
Err(e) => return Err!(Database(error!("Failed to parse specified time duration: {e}"))),
|
||||
Ok(duration) => SystemTime::now()
|
||||
|
@ -171,7 +203,9 @@ impl Service {
|
|||
.ok_or(err!(Arithmetic("Duration {duration:?} is too large")))?,
|
||||
};
|
||||
|
||||
let mut remote_mxcs: Vec<String> = vec![];
|
||||
let all_keys = self.db.get_all_media_keys();
|
||||
|
||||
let mut remote_mxcs = Vec::with_capacity(all_keys.len());
|
||||
|
||||
for key in all_keys {
|
||||
debug!("Full MXC key from database: {key:?}");
|
||||
|
|
Loading…
Add table
Reference in a new issue