From 480fa70b1f44a5d0a6ed1a363ec4305aaa7492fe Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Wed, 21 Dec 2022 16:11:58 +0000 Subject: [PATCH] Handle rejected follows --- users/models/follow.py | 18 ++++++++++++++++++ users/models/inbox_message.py | 8 ++++++++ users/services/identity.py | 6 +----- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/users/models/follow.py b/users/models/follow.py index 697c464..1a93421 100644 --- a/users/models/follow.py +++ b/users/models/follow.py @@ -16,11 +16,13 @@ class FollowStates(StateGraph): undone = State(try_interval=60 * 60) undone_remotely = State() failed = State() + rejected = State() unrequested.transitions_to(local_requested) unrequested.transitions_to(remote_requested) unrequested.times_out_to(failed, seconds=86400 * 7) local_requested.transitions_to(accepted) + local_requested.transitions_to(rejected) remote_requested.transitions_to(accepted) accepted.transitions_to(undone) undone.transitions_to(undone_remotely) @@ -279,3 +281,19 @@ class Follow(StatorModel): raise ValueError("No Follow locally for incoming Undo", data) # Delete the follow follow.delete() + + @classmethod + def handle_reject_ap(cls, data): + """ + Handles an incoming Follow Reject for one of our follows + """ + # Ensure the Accept actor is the Follow's object + if data["actor"] != data["object"]["object"]: + raise ValueError("Accept actor does not match its Follow object", data) + # Resolve source and target and see if a Follow exists (it really should) + try: + follow = cls.by_ap(data["object"]) + except KeyError: + raise ValueError("No Follow locally for incoming Reject", data) + # Mark the follow rejected + follow.transition_perform(FollowStates.rejected) diff --git a/users/models/inbox_message.py b/users/models/inbox_message.py index d6f3839..533f152 100644 --- a/users/models/inbox_message.py +++ b/users/models/inbox_message.py @@ -69,6 +69,14 @@ class InboxMessageStates(StateGraph): raise ValueError( f"Cannot handle activity of type accept.{unknown}" ) + case "reject": + match instance.message_object_type: + case "follow": + await sync_to_async(Follow.handle_reject_ap)(instance.message) + case unknown: + raise ValueError( + f"Cannot handle activity of type reject.{unknown}" + ) case "undo": match instance.message_object_type: case "follow": diff --git a/users/services/identity.py b/users/services/identity.py index e6b44f4..743258a 100644 --- a/users/services/identity.py +++ b/users/services/identity.py @@ -19,11 +19,7 @@ class IdentityService: existing_follow = Follow.maybe_get(from_identity, self.identity) if not existing_follow: Follow.create_local(from_identity, self.identity) - elif existing_follow.state in [ - FollowStates.undone, - FollowStates.undone_remotely, - FollowStates.failed, - ]: + elif existing_follow.state not in FollowStates.group_active(): existing_follow.transition_perform(FollowStates.unrequested) return cast(Follow, existing_follow)