logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

20191029172832_fix_blocked_follows.exs (3485B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Repo.Migrations.FixBlockedFollows do
  5. use Ecto.Migration
  6. import Ecto.Query
  7. alias Pleroma.Config
  8. alias Pleroma.Repo
  9. def up do
  10. unfollow_blocked = Config.get([:activitypub, :unfollow_blocked])
  11. if unfollow_blocked do
  12. "activities"
  13. |> where([activity], fragment("? ->> 'type' = 'Block'", activity.data))
  14. |> distinct([activity], [
  15. activity.actor,
  16. fragment(
  17. "coalesce((?)->'object'->>'id', (?)->>'object')",
  18. activity.data,
  19. activity.data
  20. )
  21. ])
  22. |> order_by([activity], [fragment("? desc nulls last", activity.id)])
  23. |> select([activity], %{
  24. blocker: activity.actor,
  25. blocked:
  26. fragment("coalesce((?)->'object'->>'id', (?)->>'object')", activity.data, activity.data),
  27. created_at: activity.id
  28. })
  29. |> Repo.stream()
  30. |> Enum.map(&unfollow_if_blocked/1)
  31. |> Enum.uniq()
  32. |> Enum.each(&update_follower_count/1)
  33. end
  34. end
  35. def down do
  36. end
  37. def unfollow_if_blocked(%{blocker: blocker_id, blocked: blocked_id, created_at: blocked_at}) do
  38. query =
  39. from(
  40. activity in "activities",
  41. where: fragment("? ->> 'type' = 'Follow'", activity.data),
  42. where: activity.actor == ^blocked_id,
  43. # this is to use the index
  44. where:
  45. fragment(
  46. "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
  47. activity.data,
  48. activity.data,
  49. ^blocker_id
  50. ),
  51. where: activity.id > ^blocked_at,
  52. where: fragment("(?)->>'state' = 'accept'", activity.data),
  53. order_by: [fragment("? desc nulls last", activity.id)]
  54. )
  55. unless Repo.exists?(query) do
  56. blocker = "users" |> select([:id, :local]) |> Repo.get_by(ap_id: blocker_id)
  57. blocked = "users" |> select([:id]) |> Repo.get_by(ap_id: blocked_id)
  58. if !is_nil(blocker) && !is_nil(blocked) do
  59. unfollow(blocked, blocker)
  60. end
  61. end
  62. end
  63. def unfollow(%{id: follower_id}, %{id: followed_id} = followed) do
  64. following_relationship =
  65. "following_relationships"
  66. |> where(follower_id: ^follower_id, following_id: ^followed_id, state: "accept")
  67. |> select([:id])
  68. |> Repo.one()
  69. case following_relationship do
  70. nil ->
  71. {:ok, nil}
  72. %{id: following_relationship_id} ->
  73. "following_relationships"
  74. |> where(id: ^following_relationship_id)
  75. |> Repo.delete_all()
  76. followed
  77. end
  78. end
  79. def update_follower_count(%{id: user_id} = user) do
  80. if user.local or !Pleroma.Config.get([:instance, :external_user_synchronization]) do
  81. follower_count_query =
  82. "users"
  83. |> where([u], u.id != ^user_id)
  84. |> where([u], u.deactivated != ^true)
  85. |> join(:inner, [u], r in "following_relationships",
  86. as: :relationships,
  87. on: r.following_id == ^user_id and r.follower_id == u.id
  88. )
  89. |> where([relationships: r], r.state == "accept")
  90. |> select([u], %{count: count(u.id)})
  91. "users"
  92. |> where(id: ^user_id)
  93. |> join(:inner, [u], s in subquery(follower_count_query))
  94. |> update([u, s],
  95. set: [follower_count: s.count]
  96. )
  97. |> Repo.update_all([])
  98. end
  99. end
  100. def update_follower_count(_), do: :noop
  101. end