use crate::{ apub::actions::{CreateSubmission, DeleteComment, DeleteSubmission, UpdateSubmission}, Action, Context, Error, Outbound, Required, }; impl Action for CreateSubmission { fn perform(&self, ctx: &Context) -> Result>, Error> { let submission = ctx.store .submissions .create(self.profile_id, &self.title, self.visibility)?; let submission_id = submission.id(); let mut changes = submission.update(); if self.published.is_some() { changes.publish(self.published); } if let Some(description) = &self.description { changes.description(description); } let submission = if changes.any_changes() { ctx.store.submissions.update(&changes)? } else { submission }; let mut changes = submission.update_files(); for file in &self.files { if let Ok(Some(file)) = ctx.store.files.by_id(*file) { changes.add_file(&file); } } let submission = if changes.any_changes() { ctx.store.submissions.update_files(&changes)? } else { submission }; if let Some(apub_id) = &self.note_apub_id { ctx.apub.submission(apub_id, submission_id)?; } if let Some(published) = submission.published() { let profile_id = self.profile_id; let ctx_clone = ctx.clone(); ctx.spawn_blocking(move || { for follower_id in ctx_clone.store.view.follows.forward_iter(profile_id) { if let Ok(Some(true)) = ctx_clone.store.profiles.is_local(follower_id) { ctx_clone .store .view .submissions .new(follower_id, submission_id, published); } } }); } if ctx.is_local(submission.profile_id())? && submission.published().is_some() { return Ok(Some(Box::new(crate::apub::results::SubmissionCreated { submission_id, }))); } Ok(Some(Box::new( crate::apub::results::UnpublishedSubmissionCreated { submission_id }, ))) } } impl Action for UpdateSubmission { fn perform(&self, ctx: &Context) -> Result>, Error> { let submission_id = self.submission_id; let submission = ctx .store .submissions .by_id(submission_id)? .req("submission by id")?; let initial_published = submission.published().is_some(); let mut changes = submission.update(); if let Some(published) = self.published { changes.publish(Some(published)); } if let Some(title) = &self.title { changes.title(title); } if let Some(description) = &self.description { changes.description(description); } let submission = ctx.store.submissions.update(&changes)?; let mut changes = submission.update_files(); if let Some(removed) = &self.removed_files { for file in removed { if let Ok(Some(file)) = ctx.store.files.by_id(*file) { changes.delete_file(&file); ctx.spawner.purge_file(file.id()); } } } if let Some(new) = &self.new_files { for file in new { if let Ok(Some(file)) = ctx.store.files.by_id(*file) { changes.add_file(&file); } } } ctx.store.submissions.update_files(&changes)?; let newly_published = !initial_published && submission.published().is_some(); let profile_id = submission.profile_id(); if ctx.is_local(profile_id)? { if newly_published { return Ok(Some(Box::new(crate::apub::results::SubmissionCreated { submission_id, }))); } else if submission.published().is_some() { return Ok(Some(Box::new(crate::apub::results::SubmissionUpdated { submission_id, }))); } } Ok(None) } } fn delete_comment(comment_id: uuid::Uuid, ctx: &Context) -> Result<(), Error> { Action::perform( &DeleteComment { delete_apub_id: None, comment_id, }, ctx, )?; Ok(()) } impl Action for DeleteSubmission { fn perform(&self, ctx: &Context) -> Result>, Error> { let submission_id = self.submission_id; let opt = ctx.store.submissions.delete(submission_id)?; if let Some(undo_submission) = opt { if undo_submission.0.published().is_some() { let note_apub_id = ctx .apub .apub_for_submission(submission_id)? .req("apub for submission")?; ctx.apub.delete_object(¬e_apub_id)?; } let ctx_clone = ctx.clone(); ctx.spawn_blocking(move || { for comment_id in ctx_clone.store.comments.for_submission(submission_id) { if let Err(e) = delete_comment(comment_id, &ctx_clone) { log::error!("Failed to delete comment {}: {}", comment_id, e); } } }); for file_id in undo_submission.0.files() { ctx.spawner.purge_file(*file_id); } let ctx_clone = ctx.clone(); ctx.spawn_blocking(move || { ctx_clone.store.view.submissions.remove(submission_id); }); let profile_id = undo_submission.0.profile_id(); if ctx.is_local(profile_id)? && undo_submission.0.published().is_some() { return Ok(Some(Box::new(crate::apub::results::SubmissionDeleted { profile_id, submission_id, }))); } } Ok(None) } }