From def4ac69dca248cc2ceb973c4e7e1b1ac04f90ed Mon Sep 17 00:00:00 2001 From: silverpill Date: Sun, 26 Sep 2021 00:11:37 +0000 Subject: [PATCH] Make delete-profile command update counters and clean files --- src/bin/mitractl.rs | 5 +-- src/models/profiles/queries.rs | 56 +++++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/bin/mitractl.rs b/src/bin/mitractl.rs index aa524b6..0c6b808 100644 --- a/src/bin/mitractl.rs +++ b/src/bin/mitractl.rs @@ -8,7 +8,7 @@ use mitra::database::migrate::apply_migrations; use mitra::ethereum::utils::generate_ethereum_address; use mitra::logger::configure_logger; use mitra::models::posts::queries::delete_post; -use mitra::models::profiles::queries as profiles; +use mitra::models::profiles::queries::delete_profile; use mitra::models::users::queries::{ generate_invite_code, get_invite_codes, @@ -68,7 +68,8 @@ async fn main() { match opts.subcmd { SubCommand::DeleteProfile(subopts) => { - profiles::delete_profile(db_client, &subopts.id).await.unwrap(); + let orphaned_files = delete_profile(db_client, &subopts.id).await.unwrap(); + remove_files(orphaned_files, &config.media_dir()); println!("profile deleted"); }, SubCommand::DeletePost(subopts) => { diff --git a/src/models/profiles/queries.rs b/src/models/profiles/queries.rs index 1a88041..1f6ca67 100644 --- a/src/models/profiles/queries.rs +++ b/src/models/profiles/queries.rs @@ -2,6 +2,7 @@ use tokio_postgres::GenericClient; use uuid::Uuid; use crate::errors::DatabaseError; +use crate::models::attachments::queries::find_orphaned_files; use super::types::{ ExtraFields, DbActorProfile, @@ -179,18 +180,63 @@ pub async fn get_followers( Ok(profiles) } +/// Deletes profile from database and returns list of orphaned files. pub async fn delete_profile( - db_client: &impl GenericClient, + db_client: &mut impl GenericClient, profile_id: &Uuid, -) -> Result<(), DatabaseError> { - let deleted_count = db_client.execute( - "DELETE FROM actor_profile WHERE id = $1", +) -> Result, DatabaseError> { + let transaction = db_client.transaction().await?; + // Get list of media files owned by actor + let files_rows = transaction.query( + " + SELECT file_name + FROM media_attachment WHERE owner_id = $1 + UNION ALL + SELECT unnest(array_remove(ARRAY[avatar_file_name, banner_file_name], NULL)) + FROM actor_profile WHERE id = $1 + ", + &[&profile_id], + ).await?; + let files: Vec = files_rows.iter() + .map(|row| row.try_get("file_name")) + .collect::>()?; + // Update counters + transaction.execute( + " + UPDATE actor_profile + SET follower_count = follower_count - 1 + FROM relationship + WHERE + actor_profile.id = relationship.target_id + AND relationship.source_id = $1 + ", + &[&profile_id], + ).await?; + transaction.execute( + " + UPDATE actor_profile + SET following_count = following_count - 1 + FROM relationship + WHERE + actor_profile.id = relationship.source_id + AND relationship.target_id = $1 + ", + &[&profile_id], + ).await?; + // Delete profile + let deleted_count = transaction.execute( + " + DELETE FROM actor_profile WHERE id = $1 + RETURNING actor_profile + ", &[&profile_id], ).await?; if deleted_count == 0 { return Err(DatabaseError::NotFound("profile")); } - Ok(()) + let orphaned_files = find_orphaned_files(&transaction, files).await?; + transaction.commit().await?; + Ok(orphaned_files) } pub async fn search_profile(