use crate::{ apub::actions::{ AnnounceSubmission, CreateSubmission, DeleteComment, DeleteSubmission, UpdateSubmission, }, Action, Context, Error, Required, }; use std::collections::HashSet; impl Action for CreateSubmission { fn perform(&self, context: &Context) -> Result<(), Error> { let submission = context .store .submissions .create(self.profile_id, &self.title, self.visibility)?; let mut changes = submission.update(); changes.publish(Some(self.published)); if let Some(description) = &self.description { changes.description(description); } let submission = context.store.submissions.update(&changes)?; let mut changes = submission.update_files(); for file in &self.files { if let Ok(Some(file)) = context.store.files.by_id(*file) { changes.add_file(&file); } } let submission = context.store.submissions.update_files(&changes)?; context.apub.submission(&self.apub_id, submission.id())?; let submission_id = submission.id(); let profile_id = self.profile_id; let published = submission.published().req()?; let context_clone = context.clone(); context.arbiter.send(Box::pin(async move { let _ = actix_web::web::block(move || { for follower_id in context_clone.store.view.follows.forward_iter(profile_id) { if let Ok(Some(true)) = context_clone.store.profiles.is_local(follower_id) { context_clone.store.view.submissions.new( follower_id, submission_id, published, ); } } Ok(()) as Result<(), ()> }) .await; })); Ok(()) } } impl Action for AnnounceSubmission { fn perform(&self, _: &Context) -> Result<(), Error> { Ok(()) } } impl Action for UpdateSubmission { fn perform(&self, context: &Context) -> Result<(), Error> { let submission = context.store.submissions.by_id(self.submission_id)?.req()?; let mut changes = submission.update(); if let Some(title) = &self.title { changes.title(title); } if let Some(description) = &self.description { changes.description(description); } let submission = context.store.submissions.update(&changes)?; let mut original_files = submission.files().iter().cloned().collect::>(); let mut changes = submission.update_files(); for file in &self.files { original_files.remove(file); if let Ok(Some(file)) = context.store.files.by_id(*file) { changes.add_file(&file); } } context.store.submissions.update_files(&changes)?; for file in original_files { context.spawner.purge_file(file); } Ok(()) } } impl Action for DeleteSubmission { fn perform(&self, context: &Context) -> Result<(), Error> { let opt = context.store.submissions.delete(self.submission_id)?; if let Some(undo_submission) = opt { for comment_id in context.store.comments.for_submission(self.submission_id) { if let Err(e) = Action::perform(&DeleteComment { comment_id }, context) { log::error!("Failed to delete comment {}: {}", comment_id, e); } } for file_id in undo_submission.0.files() { context.spawner.purge_file(*file_id); } let submission_id = self.submission_id; let context_clone = context.clone(); context.arbiter.send(Box::pin(async move { let _ = actix_web::web::block(move || { context_clone.store.view.submissions.remove(submission_id); Ok(()) as Result<(), ()> }) .await; })); } Ok(()) } }