Add CLI command for deleting unused media attachments

This commit is contained in:
silverpill 2022-05-07 20:27:11 +00:00
parent 439959c977
commit da6ceadd51
4 changed files with 64 additions and 3 deletions

View file

@ -155,6 +155,12 @@ Remove remote posts and media older than 30 days:
mitractl delete-extraneous-posts -d 30 mitractl delete-extraneous-posts -d 30
``` ```
Delete attachments that doesn't belong to any post:
```
mitractl delete-unused-attachments -d 5
```
Generate ethereum address: Generate ethereum address:
``` ```

View file

@ -8,6 +8,7 @@ use mitra::database::migrate::apply_migrations;
use mitra::ethereum::signatures::generate_ecdsa_key; use mitra::ethereum::signatures::generate_ecdsa_key;
use mitra::ethereum::utils::key_to_ethereum_address; use mitra::ethereum::utils::key_to_ethereum_address;
use mitra::logger::configure_logger; use mitra::logger::configure_logger;
use mitra::models::attachments::queries::delete_unused_attachments;
use mitra::models::posts::queries::{delete_post, find_extraneous_posts}; use mitra::models::posts::queries::{delete_post, find_extraneous_posts};
use mitra::models::profiles::queries::delete_profile; use mitra::models::profiles::queries::delete_profile;
use mitra::models::users::queries::{ use mitra::models::users::queries::{
@ -33,6 +34,7 @@ enum SubCommand {
DeleteProfile(DeleteProfile), DeleteProfile(DeleteProfile),
DeletePost(DeletePost), DeletePost(DeletePost),
DeleteExtraneousPosts(DeleteExtraneousPosts), DeleteExtraneousPosts(DeleteExtraneousPosts),
DeleteUnusedAttachments(DeleteUnusedAttachments),
} }
/// Generate RSA private key /// Generate RSA private key
@ -83,6 +85,13 @@ struct DeleteExtraneousPosts {
dry_run: bool, dry_run: bool,
} }
/// Delete attachments that doesn't belong to any post
#[derive(Parser)]
struct DeleteUnusedAttachments {
#[clap(short)]
days: i64,
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let opts: Opts = Opts::parse(); let opts: Opts = Opts::parse();
@ -142,6 +151,15 @@ async fn main() {
println!("post {} deleted", post_id); println!("post {} deleted", post_id);
}; };
}, },
SubCommand::DeleteUnusedAttachments(subopts) => {
let created_before = Utc::now() - Duration::days(subopts.days);
let deletion_queue = delete_unused_attachments(
db_client,
&created_before,
).await.unwrap();
deletion_queue.process(&config).await;
println!("unused attachments deleted");
},
_ => panic!(), _ => panic!(),
}; };
}, },

View file

@ -1,7 +1,13 @@
use chrono::{DateTime, Utc};
use tokio_postgres::GenericClient; use tokio_postgres::GenericClient;
use uuid::Uuid; use uuid::Uuid;
use crate::errors::DatabaseError; use crate::errors::DatabaseError;
use crate::models::cleanup::{
find_orphaned_files,
find_orphaned_ipfs_objects,
DeletionQueue,
};
use crate::utils::id::new_uuid; use crate::utils::id::new_uuid;
use super::types::DbMediaAttachment; use super::types::DbMediaAttachment;
@ -42,3 +48,32 @@ pub async fn set_attachment_ipfs_cid(
let db_attachment = row.try_get("media_attachment")?; let db_attachment = row.try_get("media_attachment")?;
Ok(db_attachment) Ok(db_attachment)
} }
pub async fn delete_unused_attachments(
db_client: &impl GenericClient,
created_before: &DateTime<Utc>,
) -> Result<DeletionQueue, DatabaseError> {
let rows = db_client.query(
"
DELETE FROM media_attachment
WHERE post_id IS NULL AND created_at < $1
RETURNING file_name, ipfs_cid
",
&[&created_before],
).await?;
let mut files = vec![];
let mut ipfs_objects = vec![];
for row in rows {
let file_name = row.try_get("file_name")?;
files.push(file_name);
if let Some(ipfs_cid) = row.try_get("ipfs_cid")? {
ipfs_objects.push(ipfs_cid);
};
};
let orphaned_files = find_orphaned_files(db_client, files).await?;
let orphaned_ipfs_objects = find_orphaned_ipfs_objects(db_client, ipfs_objects).await?;
Ok(DeletionQueue {
files: orphaned_files,
ipfs_objects: orphaned_ipfs_objects,
})
}

View file

@ -104,9 +104,11 @@ pub fn remove_files(files: Vec<String>, from_dir: &Path) -> () {
let file_path_str = file_path.to_string_lossy(); let file_path_str = file_path.to_string_lossy();
match remove_file(&file_path) { match remove_file(&file_path) {
Ok(_) => log::info!("removed file {}", file_path_str), Ok(_) => log::info!("removed file {}", file_path_str),
Err(_) => log::warn!("failed to remove file {}", file_path_str), Err(err) => {
} log::warn!("failed to remove file {} ({})", file_path_str, err);
} },
};
};
} }
#[cfg(test)] #[cfg(test)]