Merge branch 'develop' into feature/mstdn-direct-api
[akkoma] / lib / pleroma / web / activity_pub / activity_pub.ex
index 973d18e52ba4fc24717d3670d6886f8232248959..f07e26afd02dd9e475caf396acb39da3d3d2c614 100644 (file)
@@ -53,15 +53,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   end
 
   def stream_out(activity) do
+    public = "https://www.w3.org/ns/activitystreams#Public"
+
     if activity.data["type"] in ["Create", "Announce"] do
       Pleroma.Web.Streamer.stream("user", activity)
 
-      if Enum.member?(activity.data["to"], "https://www.w3.org/ns/activitystreams#Public") do
+      if Enum.member?(activity.data["to"], public) do
         Pleroma.Web.Streamer.stream("public", activity)
 
         if activity.local do
           Pleroma.Web.Streamer.stream("public:local", activity)
         end
+      else
+        if !Enum.member?(activity.data["cc"] || [], public) &&
+             !Enum.member?(
+               activity.data["to"],
+               User.get_by_ap_id(activity.data["actor"]).follower_address
+             ),
+           do: Pleroma.Web.Streamer.stream("direct", activity)
       end
     end
   end
@@ -131,11 +140,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
-  def unlike(%User{} = actor, %Object{} = object) do
-    with %Activity{} = activity <- get_existing_like(actor.ap_id, object),
-         {:ok, _activity} <- Repo.delete(activity),
-         {:ok, object} <- remove_like_from_object(activity, object) do
-      {:ok, object}
+  def unlike(
+        %User{} = actor,
+        %Object{} = object,
+        activity_id \\ nil,
+        local \\ true
+      ) do
+    with %Activity{} = like_activity <- get_existing_like(actor.ap_id, object),
+         unlike_data <- make_unlike_data(actor, like_activity, activity_id),
+         {:ok, unlike_activity} <- insert(unlike_data, local),
+         {:ok, _activity} <- Repo.delete(like_activity),
+         {:ok, object} <- remove_like_from_object(like_activity, object),
+         :ok <- maybe_federate(unlike_activity) do
+      {:ok, unlike_activity, like_activity, object}
     else
       _e -> {:ok, object}
     end
@@ -252,6 +269,49 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> Enum.reverse()
   end
 
+  @valid_visibilities ~w[direct unlisted public private]
+
+  defp restrict_visibility(query, %{visibility: "direct"}) do
+    public = "https://www.w3.org/ns/activitystreams#Public"
+
+    from(
+      activity in query,
+      join: sender in User,
+      on: sender.ap_id == activity.actor,
+      # Are non-direct statuses with no to/cc possible?
+      where:
+        fragment("not coalesce(data->'to' \\? ?, false)", ^public) and
+          fragment("not coalesce(data->'cc' \\? ?, false)", ^public) and
+          fragment("not coalesce(data->'to' \\? ?, false)", sender.follower_address)
+    )
+  end
+
+  defp restrict_visibility(_query, %{visibility: visibility})
+       when visibility not in @valid_visibilities do
+    Logger.error("Could not restrict visibility to #{visibility}")
+  end
+
+  defp restrict_visibility(query, _visibility), do: query
+
+  def fetch_user_activities(user, reading_user, params \\ %{}) do
+    params =
+      params
+      |> Map.put("type", ["Create", "Announce"])
+      |> Map.put("actor_id", user.ap_id)
+      |> Map.put("whole_db", true)
+
+    recipients =
+      if reading_user do
+        ["https://www.w3.org/ns/activitystreams#Public"] ++
+          [reading_user.ap_id | reading_user.following]
+      else
+        ["https://www.w3.org/ns/activitystreams#Public"]
+      end
+
+    fetch_activities(recipients, params)
+    |> Enum.reverse()
+  end
+
   defp restrict_since(query, %{"since_id" => since_id}) do
     from(activity in query, where: activity.id > ^since_id)
   end
@@ -387,6 +447,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> restrict_recent(opts)
     |> restrict_blocked(opts)
     |> restrict_media(opts)
+    |> restrict_visibility(opts)
   end
 
   def fetch_activities(recipients, opts \\ %{}) do