hyaenidae/profiles/src/apub/actions/profile.rs

189 lines
6.5 KiB
Rust

use crate::{
apub::actions::{CreateProfile, DeleteProfile, DeleteSubmission, UpdateProfile},
Action, Context, Error, Outbound, Required,
};
impl Action for CreateProfile {
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, 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 = ctx.store.profiles.update(&changes)?;
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 = ctx.store.profiles.update_images(&changes)?;
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<Option<Box<dyn Outbound + Send>>, 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 = ctx.store.profiles.update(&changes)?;
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 = ctx.store.profiles.update_images(&changes)?;
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<Option<Box<dyn Outbound + Send>>, 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 context_clone = ctx.clone();
ctx.spawn_blocking(move || {
for submission_id in context_clone.store.submissions.for_profile(profile_id) {
if let Err(e) = delete_submission(submission_id, &context_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::<Vec<_>>();
let context_clone = ctx.clone();
ctx.spawn_blocking(move || {
for follow_id in context_clone.store.view.follows.forward_iter(profile_id) {
if let Err(e) = context_clone.store.view.follows.remove(follow_id) {
log::error!("Failed to delete follow {}: {}", follow_id, e);
}
}
});
let context_clone = ctx.clone();
ctx.spawn_blocking(move || {
for follow_request_id in context_clone
.store
.view
.follow_requests
.forward_iter(profile_id)
{
if let Err(e) = context_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)
}
}