1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Repo.Migrations.FixBlockedFollows do
13 unfollow_blocked = Config.get([:activitypub, :unfollow_blocked])
15 if unfollow_blocked do
17 |> where([activity], fragment("? ->> 'type' = 'Block'", activity.data))
18 |> distinct([activity], [
21 "coalesce((?)->'object'->>'id', (?)->>'object')",
26 |> order_by([activity], [fragment("? desc nulls last", activity.id)])
27 |> select([activity], %{
28 blocker: activity.actor,
30 fragment("coalesce((?)->'object'->>'id', (?)->>'object')", activity.data, activity.data),
31 created_at: activity.id
34 |> Enum.map(&unfollow_if_blocked/1)
36 |> Enum.each(&update_follower_count/1)
43 def unfollow_if_blocked(%{blocker: blocker_id, blocked: blocked_id, created_at: blocked_at}) do
46 activity in "activities",
47 where: fragment("? ->> 'type' = 'Follow'", activity.data),
48 where: activity.actor == ^blocked_id,
49 # this is to use the index
52 "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
57 where: activity.id > ^blocked_at,
58 where: fragment("(?)->>'state' = 'accept'", activity.data),
59 order_by: [fragment("? desc nulls last", activity.id)]
62 unless Repo.exists?(query) do
63 blocker = "users" |> select([:id, :local]) |> Repo.get_by(ap_id: blocker_id)
64 blocked = "users" |> select([:id]) |> Repo.get_by(ap_id: blocked_id)
66 if !is_nil(blocker) && !is_nil(blocked) do
67 unfollow(blocked, blocker)
72 def unfollow(%{id: follower_id}, %{id: followed_id} = followed) do
73 following_relationship =
74 "following_relationships"
75 |> where(follower_id: ^follower_id, following_id: ^followed_id, state: "accept")
79 case following_relationship do
83 %{id: following_relationship_id} ->
84 "following_relationships"
85 |> where(id: ^following_relationship_id)
92 def update_follower_count(%{id: user_id} = user) do
93 if user.local or !Pleroma.Config.get([:instance, :external_user_synchronization]) do
94 follower_count_query =
96 |> where([u], u.id != ^user_id)
97 |> where([u], u.deactivated != ^true)
98 |> join(:inner, [u], r in "following_relationships",
100 on: r.following_id == ^user_id and r.follower_id == u.id
102 |> where([relationships: r], r.state == "accept")
103 |> select([u], %{count: count(u.id)})
106 |> where(id: ^user_id)
107 |> join(:inner, [u], s in subquery(follower_count_query))
109 set: [follower_count: s.count]
111 |> Repo.update_all([])
115 def update_follower_count(_), do: :noop