Merge branch 'features/add-credo-to-ci' into 'develop'
[akkoma] / lib / pleroma / web / streamer.ex
index 6b6d40346191c00c662077c57894ff34a14852ae..aec11a79f6ba2ff016416ea853502fd4896951c5 100644 (file)
@@ -1,20 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
 defmodule Pleroma.Web.Streamer do
   use GenServer
   require Logger
-  alias Pleroma.{User, Notification, Activity, Object, Repo}
-  alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Activity
+  alias Pleroma.Notification
+  alias Pleroma.Object
+  alias Pleroma.Repo
+  alias Pleroma.User
+  alias Pleroma.Web.ActivityPub.Visibility
 
-  def init(args) do
-    {:ok, args}
-  end
+  @keepalive_interval :timer.seconds(30)
 
   def start_link do
-    spawn(fn ->
-      # 30 seconds
-      Process.sleep(1000 * 30)
-      GenServer.cast(__MODULE__, %{action: :ping})
-    end)
-
     GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
   end
 
@@ -30,6 +30,16 @@ defmodule Pleroma.Web.Streamer do
     GenServer.cast(__MODULE__, %{action: :stream, topic: topic, item: item})
   end
 
+  def init(args) do
+    spawn(fn ->
+      # 30 seconds
+      Process.sleep(@keepalive_interval)
+      GenServer.cast(__MODULE__, %{action: :ping})
+    end)
+
+    {:ok, args}
+  end
+
   def handle_cast(%{action: :ping}, topics) do
     Map.values(topics)
     |> List.flatten()
@@ -40,7 +50,7 @@ defmodule Pleroma.Web.Streamer do
 
     spawn(fn ->
       # 30 seconds
-      Process.sleep(1000 * 30)
+      Process.sleep(@keepalive_interval)
       GenServer.cast(__MODULE__, %{action: :ping})
     end)
 
@@ -61,11 +71,9 @@ defmodule Pleroma.Web.Streamer do
   end
 
   def handle_cast(%{action: :stream, topic: "list", item: item}, topics) do
-    author = User.get_cached_by_ap_id(item.data["actor"])
-
     # filter the recipient list if the activity is not public, see #270.
     recipient_lists =
-      case ActivityPub.is_public?(item) do
+      case Visibility.is_public?(item) do
         true ->
           Pleroma.List.get_lists_from_activity(item)
 
@@ -73,7 +81,8 @@ defmodule Pleroma.Web.Streamer do
           Pleroma.List.get_lists_from_activity(item)
           |> Enum.filter(fn list ->
             owner = Repo.get(User, list.user_id)
-            author.follower_address in owner.following
+
+            Visibility.visible_for_user?(item, owner)
           end)
       end
 
@@ -169,28 +178,65 @@ defmodule Pleroma.Web.Streamer do
     |> Jason.encode!()
   end
 
+  defp represent_update(%Activity{} = activity) do
+    %{
+      event: "update",
+      payload:
+        Pleroma.Web.MastodonAPI.StatusView.render(
+          "status.json",
+          activity: activity
+        )
+        |> Jason.encode!()
+    }
+    |> Jason.encode!()
+  end
+
   def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do
     Enum.each(topics[topic] || [], fn socket ->
       # Get the current user so we have up-to-date blocks etc.
-      user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
-      blocks = user.info["blocks"] || []
-
-      parent = Object.normalize(item.data["object"])
-
-      unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do
-        send(socket.transport_pid, {:text, represent_update(item, user)})
+      if socket.assigns[:user] do
+        user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
+        blocks = user.info.blocks || []
+        mutes = user.info.mutes || []
+
+        parent = Object.normalize(item.data["object"])
+
+        unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
+                 parent.data["actor"] in blocks or parent.data["actor"] in mutes do
+          send(socket.transport_pid, {:text, represent_update(item, user)})
+        end
+      else
+        send(socket.transport_pid, {:text, represent_update(item)})
       end
     end)
   end
 
+  def push_to_socket(topics, topic, %Activity{
+        data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id}
+      }) do
+    Enum.each(topics[topic] || [], fn socket ->
+      send(
+        socket.transport_pid,
+        {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()}
+      )
+    end)
+  end
+
+  def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop
+
   def push_to_socket(topics, topic, item) do
     Enum.each(topics[topic] || [], fn socket ->
       # Get the current user so we have up-to-date blocks etc.
-      user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
-      blocks = user.info["blocks"] || []
-
-      unless item.actor in blocks do
-        send(socket.transport_pid, {:text, represent_update(item, user)})
+      if socket.assigns[:user] do
+        user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
+        blocks = user.info.blocks || []
+        mutes = user.info.mutes || []
+
+        unless item.actor in blocks or item.actor in mutes do
+          send(socket.transport_pid, {:text, represent_update(item, user)})
+        end
+      else
+        send(socket.transport_pid, {:text, represent_update(item)})
       end
     end)
   end