user: add helper function to fetch a user given only an ap_id (fix tests)
[akkoma] / lib / pleroma / user.ex
index 35f3371ba17a858df16e3577ac84119f1d02595c..aba8742a09be5dfd4c639324a7e859f3a72ce1c8 100644 (file)
@@ -197,6 +197,14 @@ defmodule Pleroma.User do
     end
   end
 
+  def maybe_follow(%User{} = follower, %User{info: info} = followed) do
+    if not following?(follower, followed) do
+      follow(follower, followed)
+    else
+      {:ok, follower}
+    end
+  end
+
   def follow(%User{} = follower, %User{info: info} = followed) do
     ap_followers = followed.follower_address
 
@@ -356,19 +364,22 @@ defmodule Pleroma.User do
   def get_follow_requests_query(%User{} = user) do
     from(
       a in Activity,
-      where: fragment(
-        "? ->> 'type' = 'Follow'",
-        a.data
-      ),
-      where: fragment(
-        "? ->> 'state' = 'pending'",
-        a.data
-      ),
-      where: fragment(
-        "? @> ?",
-        a.data,
-        ^%{"object" => user.ap_id}
-      )
+      where:
+        fragment(
+          "? ->> 'type' = 'Follow'",
+          a.data
+        ),
+      where:
+        fragment(
+          "? ->> 'state' = 'pending'",
+          a.data
+        ),
+      where:
+        fragment(
+          "? @> ?",
+          a.data,
+          ^%{"object" => user.ap_id}
+        )
     )
   end
 
@@ -377,8 +388,9 @@ defmodule Pleroma.User do
     reqs = Repo.all(q)
 
     users =
-      Enum.map(reqs, fn (req) -> req.actor end)
-      |> Enum.map(fn (ap_id) -> get_by_ap_id(ap_id) end)
+      Enum.map(reqs, fn req -> req.actor end)
+      |> Enum.uniq()
+      |> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end)
 
     {:ok, users}
   end
@@ -493,15 +505,33 @@ defmodule Pleroma.User do
     Repo.all(q)
   end
 
-  def block(user, %{ap_id: ap_id}) do
-    blocks = user.info["blocks"] || []
+  def block(blocker, %User{ap_id: ap_id} = blocked) do
+    # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)
+    blocker =
+      if following?(blocker, blocked) do
+        {:ok, blocker, _} = unfollow(blocker, blocked)
+        blocker
+      else
+        blocker
+      end
+
+    if following?(blocked, blocker) do
+      unfollow(blocked, blocker)
+    end
+
+    blocks = blocker.info["blocks"] || []
     new_blocks = Enum.uniq([ap_id | blocks])
-    new_info = Map.put(user.info, "blocks", new_blocks)
+    new_info = Map.put(blocker.info, "blocks", new_blocks)
 
-    cs = User.info_changeset(user, %{info: new_info})
+    cs = User.info_changeset(blocker, %{info: new_info})
     update_and_set_cache(cs)
   end
 
+  # helper to handle the block given only an actor's AP id
+  def block(blocker, %{ap_id: ap_id}) do
+    block(blocker, User.get_by_ap_id(ap_id))
+  end
+
   def unblock(user, %{ap_id: ap_id}) do
     blocks = user.info["blocks"] || []
     new_blocks = List.delete(blocks, ap_id)