use crate::{ apub::actions::{CreateProfile, DeleteProfile, DeleteSubmission, UpdateProfile}, Action, Context, Error, Outbound, Required, }; impl Action for CreateProfile { fn perform(&self, ctx: &Context) -> Result>, Error> { let profile = ctx.store.profiles.create( self.owner_source.clone(), &self.handle, &self.domain, self.published, )?; let mut changes = profile.update(); changes.login_required(self.login_required); if let Some(display_name) = &self.display_name { changes.display_name(display_name); } if let Some(description) = &self.description { changes.description(description); } let profile = if changes.any_changes() { ctx.store.profiles.update(&changes)? } else { profile }; let mut changes = profile.update_images(); if let Some(banner) = self.banner { if let Ok(Some(file)) = ctx.store.files.by_id(banner) { changes.banner(&file); } } if let Some(icon) = self.icon { if let Ok(Some(file)) = ctx.store.files.by_id(icon) { changes.banner(&file); } } let profile = if changes.any_changes() { ctx.store.profiles.update_images(&changes)? } else { profile }; if let Some(apub) = &self.apub { ctx.apub.profile(&apub.person_apub_id, profile.id())?; ctx.apub .store_public_key(profile.id(), &apub.public_key_id, &apub.public_key)?; } if profile.owner_source().is_local() { return Ok(Some(Box::new(crate::apub::results::ProfileCreated { profile_id: profile.id(), }))); } Ok(None) } } impl Action for UpdateProfile { fn perform(&self, ctx: &Context) -> Result>, Error> { let profile = ctx.store.profiles.by_id(self.profile_id)?.req()?; let mut changes = profile.update(); if let Some(login_required) = self.login_required { changes.login_required(login_required); } if let Some(display_name) = &self.display_name { changes.display_name(display_name); } if let Some(description) = &self.description { changes.description(description); } let profile = if changes.any_changes() { ctx.store.profiles.update(&changes)? } else { profile }; let previous_banner = profile.banner(); let previous_icon = profile.icon(); let mut changes = profile.update_images(); if let Some(banner) = self.banner { if let Ok(Some(file)) = ctx.store.files.by_id(banner) { changes.banner(&file); if let Some(old_banner) = previous_banner { if old_banner != banner { ctx.spawner.purge_file(old_banner); } } } } if let Some(icon) = self.icon { if let Ok(Some(file)) = ctx.store.files.by_id(icon) { changes.icon(&file); if let Some(old_icon) = previous_icon { if old_icon != icon { ctx.spawner.purge_file(old_icon); } } } } let profile = if changes.any_changes() { ctx.store.profiles.update_images(&changes)? } else { profile }; if let Some(id) = &self.public_key_id { if let Some(key) = &self.public_key { ctx.apub.store_public_key(profile.id(), id, key)?; } } if profile.owner_source().is_local() { return Ok(Some(Box::new(crate::apub::results::ProfileUpdated { profile_id: profile.id(), }))); } Ok(None) } } fn delete_submission(submission_id: uuid::Uuid, ctx: &Context) -> Result<(), Error> { Action::perform(&DeleteSubmission { submission_id }, ctx)?; Ok(()) } impl Action for DeleteProfile { fn perform(&self, ctx: &Context) -> Result>, Error> { let profile_id = self.profile_id; let opt = ctx.store.profiles.delete(profile_id)?; if let Some(undo_profile) = opt { let person_apub_id = ctx.apub.apub_for_profile(profile_id)?.req()?; ctx.apub.delete_object(&person_apub_id)?; if let Some(banner) = undo_profile.0.banner() { ctx.spawner.purge_file(banner); } if let Some(icon) = undo_profile.0.icon() { ctx.spawner.purge_file(icon); } let ctx_clone = ctx.clone(); ctx.spawn_blocking(move || { for submission_id in ctx_clone .store .submissions .published_for_profile(profile_id) { if let Err(e) = delete_submission(submission_id, &ctx_clone) { log::error!("Failed to delete submission {}: {}", submission_id, e); } } for submission_id in ctx_clone.store.submissions.drafted_for_profile(profile_id) { if let Err(e) = delete_submission(submission_id, &ctx_clone) { log::error!("Failed to delete submission {}: {}", submission_id, e); } } }); let follower_ids = ctx .store .view .follows .forward_iter(profile_id) .filter_map(|follow_id| ctx.store.view.follows.right(follow_id).ok()?) .collect::>(); let ctx_clone = ctx.clone(); ctx.spawn_blocking(move || { for follow_id in ctx_clone.store.view.follows.forward_iter(profile_id) { if let Err(e) = ctx_clone.store.view.follows.remove(follow_id) { log::error!("Failed to delete follow {}: {}", follow_id, e); } } }); let ctx_clone = ctx.clone(); ctx.spawn_blocking(move || { for follow_request_id in ctx_clone .store .view .follow_requests .forward_iter(profile_id) { if let Err(e) = ctx_clone .store .view .follow_requests .remove(follow_request_id) { log::error!("Failed to delete follow {}: {}", follow_request_id, e); } } }); if undo_profile.0.owner_source().is_local() { return Ok(Some(Box::new(crate::apub::results::ProfileDeleted { profile_id, follower_ids, }))); } } Ok(None) } }