Don't persist local undone follow (#194)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
same deal but backwards this time Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk> Reviewed-on: #194
This commit is contained in:
parent
decbca0c91
commit
8e4de118c1
8 changed files with 61 additions and 57 deletions
|
@ -331,9 +331,9 @@ defp do_unfollow(follower, followed, activity_id, local)
|
||||||
|
|
||||||
defp do_unfollow(follower, followed, activity_id, local) when local == true do
|
defp do_unfollow(follower, followed, activity_id, local) when local == true do
|
||||||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||||
{:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
|
|
||||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||||
{:ok, activity} <- insert(unfollow_data, local),
|
{:ok, activity} <- insert(unfollow_data, local),
|
||||||
|
{:ok, _activity} <- Repo.delete(follow_activity),
|
||||||
_ <- notify_and_stream(activity),
|
_ <- notify_and_stream(activity),
|
||||||
:ok <- maybe_federate(activity) do
|
:ok <- maybe_federate(activity) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
|
@ -349,7 +349,7 @@ defp do_unfollow(follower, followed, activity_id, false) do
|
||||||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||||
{:ok, _activity} <- Repo.delete(follow_activity),
|
{:ok, _activity} <- Repo.delete(follow_activity),
|
||||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||||
unfollow_activity <- remote_unfollow_data(unfollow_data),
|
unfollow_activity <- make_unfollow_activity(unfollow_data, false),
|
||||||
_ <- notify_and_stream(unfollow_activity) do
|
_ <- notify_and_stream(unfollow_activity) do
|
||||||
{:ok, unfollow_activity}
|
{:ok, unfollow_activity}
|
||||||
else
|
else
|
||||||
|
@ -358,12 +358,12 @@ defp do_unfollow(follower, followed, activity_id, false) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp remote_unfollow_data(data) do
|
defp make_unfollow_activity(data, local) do
|
||||||
{recipients, _, _} = get_recipients(data)
|
{recipients, _, _} = get_recipients(data)
|
||||||
|
|
||||||
%Activity{
|
%Activity{
|
||||||
data: data,
|
data: data,
|
||||||
local: false,
|
local: local,
|
||||||
actor: data["actor"],
|
actor: data["actor"],
|
||||||
recipients: recipients
|
recipients: recipients
|
||||||
}
|
}
|
||||||
|
|
|
@ -472,18 +472,6 @@ def update_follow_state_for_all(
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_follow_state(
|
|
||||||
%Activity{} = activity,
|
|
||||||
state
|
|
||||||
) do
|
|
||||||
new_data = Map.put(activity.data, "state", state)
|
|
||||||
changeset = Changeset.change(activity, data: new_data)
|
|
||||||
|
|
||||||
with {:ok, activity} <- Repo.update(changeset) do
|
|
||||||
{:ok, activity}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Makes a follow activity data for the given follower and followed
|
Makes a follow activity data for the given follower and followed
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.RemoveLocalCancelledFollows do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
statement = """
|
||||||
|
DELETE FROM
|
||||||
|
activities
|
||||||
|
WHERE
|
||||||
|
(data->>'type') = 'Follow'
|
||||||
|
AND
|
||||||
|
(data->>'state') = 'cancelled'
|
||||||
|
AND
|
||||||
|
local = true;
|
||||||
|
"""
|
||||||
|
|
||||||
|
execute(statement)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
|
@ -65,7 +65,7 @@ test "relay is unfollowed" do
|
||||||
Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance])
|
Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance])
|
||||||
|
|
||||||
cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
|
cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
|
||||||
assert cancelled_activity.data["state"] == "cancelled"
|
assert is_nil(cancelled_activity)
|
||||||
|
|
||||||
[undo_activity] =
|
[undo_activity] =
|
||||||
ActivityPub.fetch_activities([], %{
|
ActivityPub.fetch_activities([], %{
|
||||||
|
@ -78,7 +78,6 @@ test "relay is unfollowed" do
|
||||||
|
|
||||||
assert undo_activity.data["type"] == "Undo"
|
assert undo_activity.data["type"] == "Undo"
|
||||||
assert undo_activity.data["actor"] == local_user.ap_id
|
assert undo_activity.data["actor"] == local_user.ap_id
|
||||||
assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"]
|
|
||||||
refute "#{target_instance}/followers" in User.following(local_user)
|
refute "#{target_instance}/followers" in User.following(local_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -142,7 +141,7 @@ test "force unfollow when relay is dead" do
|
||||||
Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance, "--force"])
|
Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance, "--force"])
|
||||||
|
|
||||||
cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
|
cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
|
||||||
assert cancelled_activity.data["state"] == "cancelled"
|
assert is_nil(cancelled_activity)
|
||||||
|
|
||||||
[undo_activity] =
|
[undo_activity] =
|
||||||
ActivityPub.fetch_activities(
|
ActivityPub.fetch_activities(
|
||||||
|
@ -152,7 +151,6 @@ test "force unfollow when relay is dead" do
|
||||||
|
|
||||||
assert undo_activity.data["type"] == "Undo"
|
assert undo_activity.data["type"] == "Undo"
|
||||||
assert undo_activity.data["actor"] == local_user.ap_id
|
assert undo_activity.data["actor"] == local_user.ap_id
|
||||||
assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"]
|
|
||||||
refute "#{target_instance}/followers" in User.following(local_user)
|
refute "#{target_instance}/followers" in User.following(local_user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -427,13 +427,12 @@ test "it doesn't create a notification for follow-unfollow-follow chains" do
|
||||||
|
|
||||||
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
|
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
|
||||||
assert FollowingRelationship.following?(user, followed_user)
|
assert FollowingRelationship.following?(user, followed_user)
|
||||||
assert [notification] = Notification.for_user(followed_user)
|
assert [_notification] = Notification.for_user(followed_user)
|
||||||
|
|
||||||
CommonAPI.unfollow(user, followed_user)
|
CommonAPI.unfollow(user, followed_user)
|
||||||
{:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
|
{:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
|
||||||
|
|
||||||
notification_id = notification.id
|
assert Enum.count(Notification.for_user(followed_user)) == 1
|
||||||
assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "dismisses the notification on follow request rejection" do
|
test "dismisses the notification on follow request rejection" do
|
||||||
|
|
|
@ -1373,6 +1373,25 @@ test "creates an undo activity for a pending follow request" do
|
||||||
assert embedded_object["id"] == follow_activity.data["id"]
|
assert embedded_object["id"] == follow_activity.data["id"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it removes the follow activity if it was local" do
|
||||||
|
follower = insert(:user, local: true)
|
||||||
|
followed = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
|
||||||
|
{:ok, activity} = ActivityPub.unfollow(follower, followed, nil, true)
|
||||||
|
|
||||||
|
assert activity.data["type"] == "Undo"
|
||||||
|
assert activity.data["actor"] == follower.ap_id
|
||||||
|
|
||||||
|
follow_activity = Activity.get_by_id(follow_activity.id)
|
||||||
|
assert is_nil(follow_activity)
|
||||||
|
assert is_nil(Utils.fetch_latest_follow(follower, followed))
|
||||||
|
|
||||||
|
# We need to keep our own undo
|
||||||
|
undo_activity = Activity.get_by_ap_id(activity.data["id"])
|
||||||
|
refute is_nil(undo_activity)
|
||||||
|
end
|
||||||
|
|
||||||
test "it removes the follow activity if it was remote" do
|
test "it removes the follow activity if it was remote" do
|
||||||
follower = insert(:user, local: false)
|
follower = insert(:user, local: false)
|
||||||
followed = insert(:user)
|
followed = insert(:user)
|
||||||
|
@ -1383,9 +1402,12 @@ test "it removes the follow activity if it was remote" do
|
||||||
assert activity.data["type"] == "Undo"
|
assert activity.data["type"] == "Undo"
|
||||||
assert activity.data["actor"] == follower.ap_id
|
assert activity.data["actor"] == follower.ap_id
|
||||||
|
|
||||||
activity = Activity.get_by_id(follow_activity.id)
|
follow_activity = Activity.get_by_id(follow_activity.id)
|
||||||
assert is_nil(activity)
|
assert is_nil(follow_activity)
|
||||||
assert is_nil(Utils.fetch_latest_follow(follower, followed))
|
assert is_nil(Utils.fetch_latest_follow(follower, followed))
|
||||||
|
|
||||||
|
undo_activity = Activity.get_by_ap_id(activity.data["id"])
|
||||||
|
assert is_nil(undo_activity)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -229,29 +229,6 @@ test "also updates the state of accepted follows" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "update_follow_state/2" do
|
|
||||||
test "updates the state of the given follow activity" do
|
|
||||||
user = insert(:user, is_locked: true)
|
|
||||||
follower = insert(:user)
|
|
||||||
|
|
||||||
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
|
|
||||||
{:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
|
|
||||||
|
|
||||||
data =
|
|
||||||
follow_activity_two.data
|
|
||||||
|> Map.put("state", "accept")
|
|
||||||
|
|
||||||
cng = Ecto.Changeset.change(follow_activity_two, data: data)
|
|
||||||
|
|
||||||
{:ok, follow_activity_two} = Repo.update(cng)
|
|
||||||
|
|
||||||
{:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
|
|
||||||
|
|
||||||
assert refresh_record(follow_activity).data["state"] == "pending"
|
|
||||||
assert refresh_record(follow_activity_two).data["state"] == "reject"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "update_element_in_object/3" do
|
describe "update_element_in_object/3" do
|
||||||
test "updates likes" do
|
test "updates likes" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
|
@ -1058,24 +1058,23 @@ test "also unsubscribes a user" do
|
||||||
refute User.subscribed_to?(follower, followed)
|
refute User.subscribed_to?(follower, followed)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "cancels a pending follow for a local user" do
|
test "removes a pending follow for a local user" do
|
||||||
follower = insert(:user)
|
follower = insert(:user)
|
||||||
followed = insert(:user, is_locked: true)
|
followed = insert(:user, is_locked: true)
|
||||||
|
|
||||||
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
|
assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
|
||||||
CommonAPI.follow(follower, followed)
|
CommonAPI.follow(follower, followed)
|
||||||
|
|
||||||
assert User.get_follow_state(follower, followed) == :follow_pending
|
assert User.get_follow_state(follower, followed) == :follow_pending
|
||||||
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
||||||
assert User.get_follow_state(follower, followed) == nil
|
assert User.get_follow_state(follower, followed) == nil
|
||||||
|
|
||||||
assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
|
assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
|
||||||
Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
|
|
||||||
|
|
||||||
assert %{
|
assert %{
|
||||||
data: %{
|
data: %{
|
||||||
"type" => "Undo",
|
"type" => "Undo",
|
||||||
"object" => %{"type" => "Follow", "state" => "cancelled"}
|
"object" => %{"type" => "Follow"}
|
||||||
}
|
}
|
||||||
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
|
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
|
||||||
end
|
end
|
||||||
|
@ -1084,20 +1083,19 @@ test "cancels a pending follow for a remote user" do
|
||||||
follower = insert(:user)
|
follower = insert(:user)
|
||||||
followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
|
followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
|
||||||
|
|
||||||
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
|
assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
|
||||||
CommonAPI.follow(follower, followed)
|
CommonAPI.follow(follower, followed)
|
||||||
|
|
||||||
assert User.get_follow_state(follower, followed) == :follow_pending
|
assert User.get_follow_state(follower, followed) == :follow_pending
|
||||||
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
||||||
assert User.get_follow_state(follower, followed) == nil
|
assert User.get_follow_state(follower, followed) == nil
|
||||||
|
|
||||||
assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
|
assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
|
||||||
Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
|
|
||||||
|
|
||||||
assert %{
|
assert %{
|
||||||
data: %{
|
data: %{
|
||||||
"type" => "Undo",
|
"type" => "Undo",
|
||||||
"object" => %{"type" => "Follow", "state" => "cancelled"}
|
"object" => %{"type" => "Follow"}
|
||||||
}
|
}
|
||||||
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
|
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue