Profiles: Update profile delete to profile suspend

Clear profile data on suspend
Clear comment body on delete
Update Unfollow and Unblock operations to only delete apub IDs if present
This commit is contained in:
asonix 2021-01-14 20:41:53 -06:00
parent 3f446a0b16
commit 29bdf064e9
13 changed files with 129 additions and 148 deletions

View file

@ -24,7 +24,7 @@ pub(crate) fn block(
let actor = actor.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -66,7 +66,7 @@ pub(crate) fn undo_block(
let actor = actor.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {

View file

@ -49,7 +49,7 @@ pub(crate) fn follow(
let actor = actor.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -82,7 +82,7 @@ pub(crate) fn reject_follow(
let actor = recover!(reject_actor, ctx.apub.id_for_apub(reject_actor)?);
let actor = actor.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -118,7 +118,7 @@ pub(crate) fn accept_follow(
let actor = recover!(accept_actor, ctx.apub.id_for_apub(accept_actor)?);
let actor = actor.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -159,7 +159,7 @@ pub(crate) fn undo_follow(
let actor = recover!(undo_actor, ctx.apub.id_for_apub(undo_actor)?);
let actor = actor.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -180,10 +180,7 @@ pub(crate) fn undo_follow(
.by_forward(follow_object, follow_actor)?;
if let Some(follow_id) = follow_id_opt {
return Ok(Ok(Box::new(UndoFollow {
follow_apub_id: follow_object_id.to_owned(),
follow_id,
})));
return Ok(Ok(Box::new(UndoFollow { follow_id })));
}
let follow_request_id = ctx
@ -204,7 +201,6 @@ pub(crate) fn undo_accept_follow(
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
let undo_actor = undo.actor()?.as_single_id().req()?;
let accept_actor = accept.actor()?.as_single_id().req()?;
let follow_id = follow.id_unchecked().req()?;
if accept_actor != undo_actor {
return Err(Error::Invalid);
@ -213,7 +209,7 @@ pub(crate) fn undo_accept_follow(
let actor = recover!(undo_actor, ctx.apub.id_for_apub(undo_actor)?);
let actor = actor.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -229,8 +225,5 @@ pub(crate) fn undo_accept_follow(
return Ok(Err(e));
}
Ok(Ok(Box::new(UndoAcceptFollow {
follow_apub_id: follow_id.to_owned(),
follow_id: id,
})))
Ok(Ok(Box::new(UndoAcceptFollow { follow_id: id })))
}

View file

@ -23,7 +23,7 @@ pub(crate) fn like(
let actor_id = recover!(actor, ctx.apub.id_for_apub(actor)?);
let actor_id = actor_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -75,7 +75,7 @@ pub(crate) fn undo_like(
let actor_id = recover!(actor_id, ctx.apub.id_for_apub(actor_id)?);
let actor_id = actor_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {

View file

@ -54,7 +54,7 @@ pub(crate) fn note(
let profile_id = recover!(attributed_to, ctx.apub.id_for_apub(attributed_to)?);
let profile_id = profile_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(profile_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -165,7 +165,7 @@ pub(crate) fn announce_note(
let actor_id = recover!(actor_id, ctx.apub.id_for_apub(actor_id)?);
let actor_id = actor_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(actor_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -216,7 +216,7 @@ pub(crate) fn update_note(
let profile_id = recover!(attributed_to, ctx.apub.id_for_apub(attributed_to)?);
let profile_id = profile_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(profile_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -323,7 +323,7 @@ pub(crate) fn delete_note(
let profile_id = recover!(attributed_to, ctx.apub.id_for_apub(attributed_to)?);
let profile_id = profile_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(profile_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {

View file

@ -122,7 +122,7 @@ pub(crate) fn update_person(
let profile_id = recover!(id, ctx.apub.id_for_apub(id)?);
let profile_id = profile_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(profile_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {
@ -188,7 +188,7 @@ pub(crate) fn delete_person(
let profile_id = recover!(id, ctx.apub.id_for_apub(id)?);
let profile_id = profile_id.profile().req()?;
if let Some(actor_profile) = ctx.store.profiles.by_id(profile_id)? {
if actor_profile.suspended() {
if actor_profile.is_suspended() {
return Err(Error::Invalid);
}
} else {

View file

@ -1,6 +1,6 @@
use crate::{
apub::actions::{CreateBlock, DeleteBlock, RejectFollowRequest, UndoFollow},
Action, Context, Error, Outbound, Required,
Action, Context, Error, Outbound,
};
impl Action for CreateBlock {
@ -39,20 +39,7 @@ impl Action for CreateBlock {
.follows
.by_forward(self.blocked_profile, self.blocked_by_profile)
{
let follow_apub_id = {
use activitystreams::{activity::Accept, prelude::*};
let accept_apub_id = ctx.apub.apub_for_follow(follow_id)?.req()?;
let accept = ctx.apub.object(&accept_apub_id)?.req()?;
let accept: Accept = accept.extend()?.req()?;
accept.object().as_single_id().req()?.to_owned()
};
Action::perform(
&UndoFollow {
follow_apub_id,
follow_id,
},
ctx,
)?;
Action::perform(&UndoFollow { follow_id }, ctx)?;
}
if let Ok(Some(follow_id)) = ctx
@ -61,20 +48,7 @@ impl Action for CreateBlock {
.follows
.by_backward(self.blocked_by_profile, self.blocked_profile)
{
let follow_apub_id = {
use activitystreams::{activity::Accept, prelude::*};
let accept_apub_id = ctx.apub.apub_for_follow(follow_id)?.req()?;
let accept = ctx.apub.object(&accept_apub_id)?.req()?;
let accept: Accept = accept.extend()?.req()?;
accept.object().as_single_id().req()?.to_owned()
};
Action::perform(
&UndoFollow {
follow_apub_id,
follow_id,
},
ctx,
)?;
Action::perform(&UndoFollow { follow_id }, ctx)?;
}
if ctx.is_local(self.blocked_by_profile)? && !ctx.is_local(self.blocked_profile)? {
@ -90,16 +64,17 @@ impl Action for CreateBlock {
impl Action for DeleteBlock {
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
let opt = ctx.store.view.blocks.remove(self.block_id)?;
let block_apub_id = ctx.apub.apub_for_block(self.block_id)?.req()?;
ctx.apub.delete_object(&block_apub_id)?;
if let Some(block_apub_id) = ctx.apub.apub_for_block(self.block_id)? {
ctx.apub.delete_object(&block_apub_id)?;
if let Some(undo_block) = opt {
if ctx.is_local(undo_block.0.right)? {
return Ok(Some(Box::new(crate::apub::results::UndoBlock {
block_apub_id,
profile_id: undo_block.0.right,
blocked_id: undo_block.0.left,
})));
if let Some(undo_block) = opt {
if ctx.is_local(undo_block.0.right)? {
return Ok(Some(Box::new(crate::apub::results::UndoBlock {
block_apub_id,
profile_id: undo_block.0.right,
blocked_id: undo_block.0.left,
})));
}
}
}

View file

@ -2,21 +2,34 @@ use crate::{
apub::actions::{UndoAcceptFollow, UndoFollow},
Action, Context, Error, Outbound, Required,
};
use url::Url;
// Get Follow from Undo Follow or Accept Follow or Reject Follow
fn follow_apub_id(parent_apub_id: &Url, ctx: &Context) -> Result<Url, Error> {
use activitystreams::{activity::ActorAndObject, prelude::*};
let parent_any_base = ctx.apub.object(parent_apub_id)?.req()?;
let parent: ActorAndObject<String> = parent_any_base.extend()?.req()?;
let follow_id = parent.object().as_single_id().req()?;
Ok(follow_id.to_owned())
}
impl Action for UndoFollow {
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
let opt = ctx.store.view.follows.remove(self.follow_id)?;
let accept_apub_id = ctx.apub.apub_for_follow(self.follow_id)?.req()?;
ctx.apub.delete_object(&accept_apub_id)?;
ctx.apub.delete_object(&self.follow_apub_id)?;
if let Some(undo_follow) = opt {
if ctx.is_local(undo_follow.0.right)? {
return Ok(Some(Box::new(crate::apub::results::UndoFollow {
follow_apub_id: self.follow_apub_id.clone(),
profile_id: undo_follow.0.right,
followed_id: undo_follow.0.left,
})));
if let Some(accept_apub_id) = ctx.apub.apub_for_follow(self.follow_id)? {
let follow_apub_id = follow_apub_id(&accept_apub_id, ctx)?;
ctx.apub.delete_object(&accept_apub_id)?;
ctx.apub.delete_object(&follow_apub_id)?;
if let Some(undo_follow) = opt {
if ctx.is_local(undo_follow.0.right)? {
return Ok(Some(Box::new(crate::apub::results::UndoFollow {
follow_apub_id,
profile_id: undo_follow.0.right,
followed_id: undo_follow.0.left,
})));
}
}
}
@ -27,17 +40,20 @@ impl Action for UndoFollow {
impl Action for UndoAcceptFollow {
fn perform(&self, ctx: &Context) -> Result<Option<Box<dyn Outbound + Send>>, Error> {
let opt = ctx.store.view.follows.remove(self.follow_id)?;
let accept_apub_id = ctx.apub.apub_for_follow(self.follow_id)?.req()?;
ctx.apub.delete_object(&accept_apub_id)?;
ctx.apub.delete_object(&self.follow_apub_id)?;
if let Some(undo_follow) = opt {
if ctx.is_local(undo_follow.0.right)? {
return Ok(Some(Box::new(crate::apub::results::UndoAcceptFollow {
accept_apub_id,
profile_id: undo_follow.0.left,
requester_id: undo_follow.0.right,
})));
if let Some(accept_apub_id) = ctx.apub.apub_for_follow(self.follow_id)? {
let follow_apub_id = follow_apub_id(&accept_apub_id, ctx)?;
ctx.apub.delete_object(&accept_apub_id)?;
ctx.apub.delete_object(&follow_apub_id)?;
if let Some(undo_follow) = opt {
if ctx.is_local(undo_follow.0.right)? {
return Ok(Some(Box::new(crate::apub::results::UndoAcceptFollow {
accept_apub_id,
profile_id: undo_follow.0.left,
requester_id: undo_follow.0.right,
})));
}
}
}

View file

@ -122,25 +122,25 @@ impl Action for UndoFollowRequest {
.remove(self.follow_request_id)?;
if let Some(undo_follow_request) = opt {
let follow_apub_id = ctx
.apub
.apub_for_follow_request(self.follow_request_id)?
.req()?;
ctx.apub.delete_object(&follow_apub_id)?;
ctx.store
.view
.follow_request_notifs
.remove(undo_follow_request.0.id);
if ctx.is_local(undo_follow_request.0.right)?
&& !ctx.is_local(undo_follow_request.0.left)?
if let Some(follow_apub_id) =
ctx.apub.apub_for_follow_request(self.follow_request_id)?
{
return Ok(Some(Box::new(crate::apub::results::UndoFollow {
follow_apub_id,
profile_id: undo_follow_request.0.right,
followed_id: undo_follow_request.0.left,
})));
ctx.apub.delete_object(&follow_apub_id)?;
if ctx.is_local(undo_follow_request.0.right)?
&& !ctx.is_local(undo_follow_request.0.left)?
{
return Ok(Some(Box::new(crate::apub::results::UndoFollow {
follow_apub_id,
profile_id: undo_follow_request.0.right,
followed_id: undo_follow_request.0.left,
})));
}
}
}

View file

@ -377,6 +377,17 @@ pub struct CreateFollowRequest {
published: DateTime<Utc>,
}
impl CreateFollowRequest {
pub fn from_profiles(followed_profile: Uuid, followed_by_profile: Uuid) -> Self {
CreateFollowRequest {
follow_apub_id: None,
followed_profile,
followed_by_profile,
published: Utc::now(),
}
}
}
pub struct AcceptFollowRequest {
accept_apub_id: Option<Url>,
follow_request_id: Uuid,
@ -391,6 +402,12 @@ pub struct UndoFollowRequest {
follow_request_id: Uuid,
}
impl UndoFollowRequest {
pub fn from_id(follow_request_id: Uuid) -> Self {
UndoFollowRequest { follow_request_id }
}
}
pub struct CreateBlock {
block_apub_id: Option<Url>,
blocked_profile: Uuid,
@ -398,16 +415,37 @@ pub struct CreateBlock {
published: DateTime<Utc>,
}
impl CreateBlock {
pub fn from_profiles(blocked_profile: Uuid, blocked_by_profile: Uuid) -> Self {
CreateBlock {
block_apub_id: None,
blocked_profile,
blocked_by_profile,
published: Utc::now(),
}
}
}
pub struct DeleteBlock {
block_id: Uuid,
}
impl DeleteBlock {
pub fn from_id(block_id: Uuid) -> Self {
DeleteBlock { block_id }
}
}
pub struct UndoFollow {
follow_apub_id: Url,
follow_id: Uuid,
}
impl UndoFollow {
pub fn from_id(follow_id: Uuid) -> Self {
UndoFollow { follow_id }
}
}
pub struct UndoAcceptFollow {
follow_apub_id: Url,
follow_id: Uuid,
}

View file

@ -207,7 +207,7 @@ fn clean_profile(profile: &Profile, ctx: &Context) -> Result<Vec<uuid::Uuid>, Er
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)?;
let opt = ctx.store.profiles.suspend(profile_id)?;
if let Some(undo_profile) = opt {
let follower_ids = clean_profile(&undo_profile.0, ctx)?;

View file

@ -263,6 +263,7 @@ impl Store {
let mut stored_comment: StoredComment = serde_json::from_slice(&stored_comment_ivec)?;
stored_comment.deleted_at = Some(Utc::now());
stored_comment.body = String::new();
let stored_comment_vec = serde_json::to_vec(&stored_comment)?;
if self

View file

@ -247,7 +247,7 @@ impl Profile {
self.login_required
}
pub(crate) fn suspended(&self) -> bool {
pub fn is_suspended(&self) -> bool {
self.suspended
}
}

View file

@ -370,8 +370,14 @@ impl Store {
None => return Ok(None),
};
let now = Utc::now();
let mut stored_profile: StoredProfile = serde_json::from_slice(&stored_profile_ivec)?;
stored_profile.suspended_at = Some(Utc::now());
stored_profile.banner = None;
stored_profile.icon = None;
stored_profile.description = None;
stored_profile.display_name = None;
stored_profile.suspended_at = Some(now);
stored_profile.updated_at = now;
let stored_profile_vec = serde_json::to_vec(&stored_profile)?;
if self
@ -388,54 +394,6 @@ impl Store {
Ok(Some(Undo(stored_profile.into())))
}
pub(crate) fn delete(&self, profile_id: Uuid) -> Result<Option<Undo<Profile>>, StoreError> {
let stored_profile_ivec = match self
.profile_tree
.get(id_profile_key(profile_id).as_bytes())?
{
Some(ivec) => ivec,
None => return Ok(None),
};
let stored_profile: StoredProfile = serde_json::from_slice(&stored_profile_ivec)?;
let created_at = stored_profile.created_at;
let handle_id_key = handle_id_key(stored_profile.handle, stored_profile.domain);
let source: OwnerSource = stored_profile.owner_source.clone().into();
[
&self.profile_tree,
&self.handle_tree,
&self.owner_tree,
&self.owner_created_tree,
&self.created_tree,
&self.count_tree,
]
.transaction(move |trees| {
let profile_tree = &trees[0];
let handle_tree = &trees[1];
let owner_tree = &trees[2];
let owner_created_tree = &trees[3];
let created_tree = &trees[4];
let count_tree = &trees[5];
profile_tree.remove(id_profile_key(profile_id).as_bytes())?;
handle_tree.remove(handle_id_key.as_bytes())?;
owner_tree.remove(owner_key(&source, profile_id).as_bytes())?;
owner_created_tree
.remove(owner_created_profile_key(&source, created_at, profile_id).as_bytes())?;
created_tree.remove(created_profile_key(created_at, profile_id).as_bytes())?;
super::count(count_tree, &owner_profile_count_key(&source), |c| {
c.saturating_sub(1)
})?;
Ok(())
})?;
Ok(Some(Undo(stored_profile.into())))
}
}
// Used to map id -> Profile