From 448092d6d9d17c2fad5f0e3522688d270614564a Mon Sep 17 00:00:00 2001 From: Henri Dickson <90480431+alphatownsman@users.noreply.github.com> Date: Sat, 16 Dec 2023 18:49:59 -0500 Subject: [PATCH] Improve identity deletion (#678) --- activities/models/post.py | 2 +- users/models/follow.py | 4 +++- users/models/identity.py | 44 +++++++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/activities/models/post.py b/activities/models/post.py index 3b08de2..f4b218a 100644 --- a/activities/models/post.py +++ b/activities/models/post.py @@ -583,7 +583,7 @@ class Post(StatorModel): domain=domain, fetch=True, ) - if identity is not None: + if identity is not None and not identity.deleted: mentions.add(identity) return mentions diff --git a/users/models/follow.py b/users/models/follow.py index a3959c9..cf186d8 100644 --- a/users/models/follow.py +++ b/users/models/follow.py @@ -81,7 +81,9 @@ class FollowStates(StateGraph): except httpx.RequestError: return return cls.pending_approval - # local/remote follow local, check manually_approve + # local/remote follow local, check deleted & manually_approve + if instance.target.deleted: + return cls.rejecting if instance.target.manually_approves_followers: from activities.models import TimelineEvent diff --git a/users/models/identity.py b/users/models/identity.py index 5027ae3..f65ad0b 100644 --- a/users/models/identity.py +++ b/users/models/identity.py @@ -120,12 +120,47 @@ class IdentityStates(StateGraph): @classmethod def handle_deleted(cls, instance: "Identity"): - from activities.models import FanOut + from activities.models import ( + FanOut, + Post, + PostInteraction, + PostInteractionStates, + PostStates, + TimelineEvent, + ) + from users.models import Bookmark, Follow, FollowStates, HashtagFollow, Report if not instance.local: return cls.updated + # Delete local data + TimelineEvent.objects.filter(identity=instance).delete() + Bookmark.objects.filter(identity=instance).delete() + HashtagFollow.objects.filter(identity=instance).delete() + Report.objects.filter(source_identity=instance).delete() + # Nullify all fields and fanout + instance.name = "" + instance.summary = "" + instance.metadata = [] + instance.aliases = [] + instance.icon_uri = "" + instance.discoverable = False + instance.image.delete(save=False) + instance.icon.delete(save=False) + instance.save() + cls.targets_fan_out(instance, FanOut.Types.identity_edited) + # Delete all posts and interactions + Post.transition_perform_queryset(instance.posts, PostStates.deleted) + PostInteraction.transition_perform_queryset( + instance.interactions, PostInteractionStates.undone + ) + # Fanout the deletion and unfollow from both directions cls.targets_fan_out(instance, FanOut.Types.identity_deleted) + for follower in Follow.objects.filter(target=instance): + follower.transition_perform(FollowStates.rejecting) + for following in Follow.objects.filter(source=instance): + following.transition_perform(FollowStates.undone) + return cls.deleted_fanned_out @classmethod @@ -677,10 +712,11 @@ class Identity(StatorModel): """ Marks the identity and all of its related content as deleted. """ - # Move all posts to deleted - from activities.models.post import Post, PostStates + from api.models import Authorization, Token - Post.transition_perform_queryset(self.posts, PostStates.deleted) + # Remove all login tokens + Authorization.objects.filter(identity=self).delete() + Token.objects.filter(identity=self).delete() # Remove all users from ourselves and mark deletion date self.users.set([]) self.deleted = timezone.now()