defp do_unfollow(follower, followed, activity_id, local) when local == true do
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),
{:ok, activity} <- insert(unfollow_data, local),
+ {:ok, _activity} <- Repo.delete(follow_activity),
_ <- notify_and_stream(activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
{:ok, _activity} <- Repo.delete(follow_activity),
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
{:ok, unfollow_activity}
else
end
end
- defp remote_unfollow_data(data) do
+ defp make_unfollow_activity(data, local) do
{recipients, _, _} = get_recipients(data)
%Activity{
data: data,
- local: false,
+ local: local,
actor: data["actor"],
recipients: recipients
}
{:ok, activity}
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 """
Makes a follow activity data for the given follower and followed
"""
--- /dev/null
+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
Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance])
cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
- assert cancelled_activity.data["state"] == "cancelled"
+ assert is_nil(cancelled_activity)
[undo_activity] =
ActivityPub.fetch_activities([], %{
assert undo_activity.data["type"] == "Undo"
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)
end
Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance, "--force"])
cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
- assert cancelled_activity.data["state"] == "cancelled"
+ assert is_nil(cancelled_activity)
[undo_activity] =
ActivityPub.fetch_activities(
assert undo_activity.data["type"] == "Undo"
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)
end
end
{:ok, _, _, _activity} = CommonAPI.follow(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)
{:ok, _, _, _activity_dupe} = CommonAPI.follow(user, followed_user)
- notification_id = notification.id
- assert [%{id: ^notification_id}] = Notification.for_user(followed_user)
+ assert Enum.count(Notification.for_user(followed_user)) == 1
end
test "dismisses the notification on follow request rejection" do
assert embedded_object["id"] == follow_activity.data["id"]
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
follower = insert(:user, local: false)
followed = insert(:user)
assert activity.data["type"] == "Undo"
assert activity.data["actor"] == follower.ap_id
- activity = Activity.get_by_id(follow_activity.id)
- assert is_nil(activity)
+ follow_activity = Activity.get_by_id(follow_activity.id)
+ assert is_nil(follow_activity)
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
- 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
test "updates likes" do
user = insert(:user)
refute User.subscribed_to?(follower, followed)
end
- test "cancels a pending follow for a local user" do
+ test "removes a pending follow for a local user" do
follower = insert(:user)
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)
assert User.get_follow_state(follower, followed) == :follow_pending
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
assert User.get_follow_state(follower, followed) == nil
- assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
- Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
+ assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
assert %{
data: %{
"type" => "Undo",
- "object" => %{"type" => "Follow", "state" => "cancelled"}
+ "object" => %{"type" => "Follow"}
}
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
end
follower = insert(:user)
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)
assert User.get_follow_state(follower, followed) == :follow_pending
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
assert User.get_follow_state(follower, followed) == nil
- assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
- Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
+ assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
assert %{
data: %{
"type" => "Undo",
- "object" => %{"type" => "Follow", "state" => "cancelled"}
+ "object" => %{"type" => "Follow"}
}
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
end