267 lines
8.1 KiB
Rust
267 lines
8.1 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));
|
|
}
|
|
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.icon(&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_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 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(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)
|
|
}
|
|
}
|