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

247 lines
7.4 KiB
Rust

use crate::{
apub::actions::{
CreateProfile, DeleteProfile, DeleteSubmission, SuspendProfile, UpdateProfile,
},
store::Profile,
Action, Context, Error, Outbound, Required,
};
impl Action for CreateProfile {
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
log::debug!("CreateProfile");
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(&hyaenidae_content::html(display_name));
}
if let Some(description) = &self.description {
changes.description(&hyaenidae_content::html(description));
}
if let Some(banner) = self.banner {
changes.banner(banner);
}
if let Some(icon) = self.icon {
changes.icon(icon);
}
let profile = if changes.any_changes() {
ctx.store.profiles.update(&changes)?
} else {
profile
};
if let Some(apub) = &self.apub {
ctx.apub.profile(&apub.person_apub_id, profile.id())?;
ctx.apub.store_profile_public_key(
profile.id(),
&apub.endpoints.public_key,
&apub.public_key,
)?;
ctx.apub.store_profile_endpoints(
profile.id(),
&apub.person_apub_id,
apub.endpoints.clone(),
)?;
}
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> {
log::debug!("UpdateProfile");
let profile = ctx
.store
.profiles
.by_id(self.profile_id)?
.req("profile by id")?;
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(&hyaenidae_content::html(display_name));
}
if let Some(display_name_source) = &self.display_name_source {
changes.display_name_source(display_name_source);
}
if let Some(description) = &self.description {
changes.description(&hyaenidae_content::html(description));
}
if let Some(description_source) = &self.description_source {
changes.description_source(description_source);
}
let previous_banner = profile.banner();
let previous_icon = profile.icon();
if let Some(banner) = self.banner {
changes.banner(banner);
if let Some(old_banner) = previous_banner {
if old_banner != banner {
ctx.spawner.purge_file(old_banner);
}
}
}
if let Some(icon) = self.icon {
changes.icon(icon);
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(&changes)?
} else {
profile
};
if let Some(apub) = &self.apub {
let person_apub_id = ctx
.apub
.apub_for_profile(profile.id())?
.req("apub id for profile")?;
ctx.apub.store_profile_public_key(
profile.id(),
&apub.endpoints.public_key,
&apub.public_key,
)?;
ctx.apub.store_profile_endpoints(
profile.id(),
&person_apub_id,
apub.endpoints.clone(),
)?;
}
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(())
}
fn clean_profile(profile: &Profile, ctx: &Context) -> Result<(), Error> {
let profile_id = profile.id();
let person_apub_id = ctx
.apub
.apub_for_profile(profile_id)?
.req("apub for profile")?;
ctx.apub.delete_object(&person_apub_id)?;
if let Some(banner) = profile.banner() {
ctx.spawner.purge_file(banner);
}
if let Some(icon) = profile.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 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);
}
}
});
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.suspend(profile_id)?;
if let Some(undo_profile) = opt {
clean_profile(&undo_profile.0, ctx)?;
if undo_profile.0.owner_source().is_local() {
return Ok(Some(Box::new(crate::apub::results::ProfileDeleted {
profile_id,
})));
}
}
Ok(None)
}
}
impl Action for SuspendProfile {
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
let profile_id = self.profile_id;
let opt = ctx.store.profiles.suspend(profile_id)?;
if let Some(undo_profile) = opt {
clean_profile(&undo_profile.0, ctx)?;
}
Ok(None)
}
}