mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-17 15:51:23 +01:00
add admin command to delete individual media files
This commit is contained in:
parent
7672cc8473
commit
d7087c66bb
4 changed files with 78 additions and 3 deletions
|
|
@ -140,4 +140,25 @@ impl service::media::Data for KeyValueDatabase {
|
||||||
let parts = MediaFileKeyParts::try_from(&key)?;
|
let parts = MediaFileKeyParts::try_from(&key)?;
|
||||||
Ok((parts.meta, key))
|
Ok((parts.meta, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn delete_file_metadata(&self, key: MediaFileKey) -> Result<()> {
|
||||||
|
self.mediaid_file.remove(key.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_thumbnails_metadata(
|
||||||
|
&self,
|
||||||
|
mxc: OwnedMxcUri,
|
||||||
|
) -> Result<Vec<(FileMeta, MediaFileKey)>> {
|
||||||
|
let mut prefix = mxc.as_bytes().to_vec();
|
||||||
|
prefix.push(0xFF);
|
||||||
|
|
||||||
|
self.mediaid_file
|
||||||
|
.scan_prefix(prefix)
|
||||||
|
.map(|(key, _)| {
|
||||||
|
let key = MediaFileKey::new(key);
|
||||||
|
let parts = MediaFileKeyParts::try_from(&key)?;
|
||||||
|
Ok((parts.meta, key))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ use ruma::{
|
||||||
TimelineEventType,
|
TimelineEventType,
|
||||||
},
|
},
|
||||||
signatures::verify_json,
|
signatures::verify_json,
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId, RoomVersionId,
|
EventId, MilliSecondsSinceUnixEpoch, OwnedMxcUri, OwnedRoomId, RoomId,
|
||||||
ServerName, UserId,
|
RoomVersionId, ServerName, UserId,
|
||||||
};
|
};
|
||||||
use serde_json::value::to_raw_value;
|
use serde_json::value::to_raw_value;
|
||||||
use tokio::sync::{mpsc, Mutex, RwLock};
|
use tokio::sync::{mpsc, Mutex, RwLock};
|
||||||
|
|
@ -179,6 +179,12 @@ enum AdminCommand {
|
||||||
room_id: Box<RoomId>,
|
room_id: Box<RoomId>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Delete media and all associated thumbnails.
|
||||||
|
DeleteMedia {
|
||||||
|
/// mxc:// URI of the media to delete
|
||||||
|
mxc: OwnedMxcUri,
|
||||||
|
},
|
||||||
|
|
||||||
/// Verify json signatures
|
/// Verify json signatures
|
||||||
/// [commandbody]()
|
/// [commandbody]()
|
||||||
/// # ```
|
/// # ```
|
||||||
|
|
@ -791,6 +797,12 @@ impl Service {
|
||||||
services().rooms.metadata.disable_room(&room_id, false)?;
|
services().rooms.metadata.disable_room(&room_id, false)?;
|
||||||
RoomMessageEventContent::text_plain("Room enabled.")
|
RoomMessageEventContent::text_plain("Room enabled.")
|
||||||
}
|
}
|
||||||
|
AdminCommand::DeleteMedia {
|
||||||
|
mxc,
|
||||||
|
} => {
|
||||||
|
services().media.delete(mxc).await?;
|
||||||
|
RoomMessageEventContent::text_plain("Media deleted.")
|
||||||
|
}
|
||||||
AdminCommand::DeactivateUser {
|
AdminCommand::DeactivateUser {
|
||||||
leave_rooms,
|
leave_rooms,
|
||||||
user_id,
|
user_id,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::io::Cursor;
|
||||||
use image::imageops::FilterType;
|
use image::imageops::FilterType;
|
||||||
use ruma::{http_headers::ContentDisposition, OwnedMxcUri};
|
use ruma::{http_headers::ContentDisposition, OwnedMxcUri};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::File,
|
fs::{self, File},
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
};
|
};
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
@ -110,6 +110,37 @@ impl Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes a media object and all associated thumbnails.
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
pub(crate) async fn delete(&self, mxc: OwnedMxcUri) -> Result<()> {
|
||||||
|
let (_, key) = self.db.search_file_metadata(mxc.clone(), 0, 0)?;
|
||||||
|
|
||||||
|
let thumbnails = self.db.search_thumbnails_metadata(mxc)?;
|
||||||
|
for (_, thumbnail_key) in thumbnails {
|
||||||
|
self.delete_by_key(thumbnail_key).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.delete_by_key(key).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes a specific media key, which may or may not be a thumbnail.
|
||||||
|
///
|
||||||
|
/// When deleting a non-thumbnail key with this method, the associated
|
||||||
|
/// thumbnails are not deleted.
|
||||||
|
async fn delete_by_key(&self, key: MediaFileKey) -> Result<()> {
|
||||||
|
let path = services().globals.get_media_file(&key);
|
||||||
|
match fs::remove_file(path).await {
|
||||||
|
Ok(()) => (),
|
||||||
|
// The file in the fs may already have been deleted by hand
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
|
||||||
|
other_error => other_error?,
|
||||||
|
}
|
||||||
|
self.db.delete_file_metadata(key)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns width, height of the thumbnail and whether it should be cropped.
|
/// Returns width, height of the thumbnail and whether it should be cropped.
|
||||||
/// Returns None when the server should send the original file.
|
/// Returns None when the server should send the original file.
|
||||||
fn thumbnail_properties(
|
fn thumbnail_properties(
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,15 @@ pub(crate) trait Data: Send + Sync {
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<(FileMeta, MediaFileKey)>;
|
) -> Result<(FileMeta, MediaFileKey)>;
|
||||||
|
|
||||||
|
fn delete_file_metadata(&self, key: MediaFileKey) -> Result<()>;
|
||||||
|
|
||||||
|
/// Return all thumbnail keys/metadata associated with a MXC.
|
||||||
|
///
|
||||||
|
/// The original file is not returned. To fetch the key/metadata of the
|
||||||
|
/// original file, use [`Data::search_file_metadata`].
|
||||||
|
fn search_thumbnails_metadata(
|
||||||
|
&self,
|
||||||
|
mxc: OwnedMxcUri,
|
||||||
|
) -> Result<Vec<(FileMeta, MediaFileKey)>>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue