From 27c29e60637443ee53768cc000a0865d59a7e78d Mon Sep 17 00:00:00 2001
From: strawberry <strawberry@puppygock.gay>
Date: Wed, 21 Feb 2024 20:34:11 -0500
Subject: [PATCH] db functions to delete media via MXC

Signed-off-by: strawberry <strawberry@puppygock.gay>
---
 src/database/key_value/media.rs |  9 +++++++
 src/service/media/data.rs       |  2 ++
 src/service/media/mod.rs        | 48 ++++++++++++++++++++++++++++++++-
 3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/src/database/key_value/media.rs b/src/database/key_value/media.rs
index 712da165..da7162b6 100644
--- a/src/database/key_value/media.rs
+++ b/src/database/key_value/media.rs
@@ -39,6 +39,15 @@ impl service::media::Data for KeyValueDatabase {
         Ok(key)
     }
 
+    fn delete_file_mxc(&self, mxc: String) -> Result<()> {
+        let mut key = mxc.as_bytes().to_vec();
+        key.push(0xff);
+
+        self.mediaid_file.remove(&key)?;
+
+        Ok(())
+    }
+
     fn search_file_metadata(
         &self,
         mxc: String,
diff --git a/src/service/media/data.rs b/src/service/media/data.rs
index 0cb7c097..667267f6 100644
--- a/src/service/media/data.rs
+++ b/src/service/media/data.rs
@@ -10,6 +10,8 @@ pub trait Data: Send + Sync {
         content_type: Option<&str>,
     ) -> Result<Vec<u8>>;
 
+    fn delete_file_mxc(&self, mxc: String) -> Result<()>;
+
     /// Returns content_disposition, content_type and the metadata key.
     fn search_file_metadata(
         &self,
diff --git a/src/service/media/mod.rs b/src/service/media/mod.rs
index 70e1b182..7ecd7519 100644
--- a/src/service/media/mod.rs
+++ b/src/service/media/mod.rs
@@ -8,8 +8,9 @@ use std::{
 
 pub(crate) use data::Data;
 use serde::Serialize;
+use tracing::{debug, error, warn};
 
-use crate::{services, Result};
+use crate::{services, Error, Result};
 use image::imageops::FilterType;
 
 use tokio::{
@@ -18,6 +19,7 @@ use tokio::{
     sync::Mutex,
 };
 
+#[derive(Debug)]
 pub struct FileMeta {
     pub content_disposition: Option<String>,
     pub content_type: Option<String>,
@@ -89,6 +91,50 @@ impl Service {
         Ok(())
     }
 
+    /// Deletes a file in the database and from the media directory via an MXC
+    pub async fn delete(&self, mxc: String) -> Result<()> {
+        if let Ok(filemeta) = self.get(mxc.clone()).await {
+            match filemeta {
+                Some(filemeta) => {
+                    debug!("Got file metadata: {:?}", filemeta);
+                    let file_key = filemeta.file;
+                    debug!("File key from file metadata: {:?}", file_key);
+
+                    let file_path = if cfg!(feature = "sha256_media") {
+                        services().globals.get_media_file_new(&file_key)
+                    } 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");
+                    self.db.delete_file_mxc(mxc)?;
+
+                    Ok(())
+                }
+                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.",
+                    ))
+                }
+            }
+        } else {
+            // we shouldn't get to this point as this is failing to actually attempt to get the file metadata (Result)
+            error!("Failed getting file metadata for MXC \"{mxc}\" in database (does not exist or database issue?)");
+            Err(Error::bad_database("Failed getting file metadata via MXC in database (does not exist or database issue?)"))
+        }
+    }
+
     /// Uploads or replaces a file thumbnail.
     pub async fn upload_thumbnail(
         &self,