Merge branch 'develop' into foxing-patch-1
[akkoma] / lib / pleroma / web / activity_pub / activity_pub.ex
index a4f1c7041969510c30a2a2cecefb9ac6f98132ff..649bf909544d3f07f484c2bf966623bc29ec4e7b 100644 (file)
@@ -739,9 +739,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> fetch_activities(params, :offset)
   end
 
-  defp user_activities_recipients(%{godmode: true}), do: []
+  def user_activities_recipients(%{godmode: true}), do: []
 
-  defp user_activities_recipients(%{reading_user: reading_user}) do
+  def user_activities_recipients(%{reading_user: reading_user}) do
     if not is_nil(reading_user) and reading_user.local do
       [
         Constants.as_public(),
@@ -933,6 +933,31 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     )
   end
 
+  # Essentially, either look for activities addressed to `recipients`, _OR_ ones
+  # that reference a hashtag that the user follows
+  # Firstly, two fallbacks in case there's no hashtag constraint, or the user doesn't
+  # follow any
+  defp restrict_recipients_or_hashtags(query, recipients, user, nil) do
+    restrict_recipients(query, recipients, user)
+  end
+
+  defp restrict_recipients_or_hashtags(query, recipients, user, []) do
+    restrict_recipients(query, recipients, user)
+  end
+
+  defp restrict_recipients_or_hashtags(query, recipients, _user, hashtag_ids) do
+    from([activity, object] in query)
+    |> join(:left, [activity, object], hto in "hashtags_objects",
+      on: hto.object_id == object.id,
+      as: :hto
+    )
+    |> where(
+      [activity, object, hto: hto],
+      (hto.hashtag_id in ^hashtag_ids and ^Constants.as_public() in activity.recipients) or
+        fragment("? && ?", ^recipients, activity.recipients)
+    )
+  end
+
   defp restrict_local(query, %{local_only: true}) do
     from(activity in query, where: activity.local == true)
   end
@@ -1380,7 +1405,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       |> maybe_preload_report_notes(opts)
       |> maybe_set_thread_muted_field(opts)
       |> maybe_order(opts)
-      |> restrict_recipients(recipients, opts[:user])
+      |> restrict_recipients_or_hashtags(recipients, opts[:user], opts[:followed_hashtags])
       |> restrict_replies(opts)
       |> restrict_since(opts)
       |> restrict_local(opts)
@@ -1477,13 +1502,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   @spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
   def upload(file, opts \\ []) do
-    with {:ok, data} <- Upload.store(file, opts) do
+    with {:ok, data} <- Upload.store(sanitize_upload_file(file), opts) do
       obj_data = Maps.put_if_present(data, "actor", opts[:actor])
 
       Repo.insert(%Object{data: obj_data})
     end
   end
 
+  defp sanitize_upload_file(%Plug.Upload{filename: filename} = upload) when is_binary(filename) do
+    %Plug.Upload{
+      upload
+      | filename: Path.basename(filename)
+    }
+  end
+
+  defp sanitize_upload_file(upload), do: upload
+
   @spec get_actor_url(any()) :: binary() | nil
   defp get_actor_url(url) when is_binary(url), do: url
   defp get_actor_url(%{"href" => href}) when is_binary(href), do: href
@@ -1506,6 +1540,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image()
   defp normalize_image(_), do: nil
 
+  defp normalize_also_known_as(aka) when is_list(aka), do: aka
+  defp normalize_also_known_as(aka) when is_binary(aka), do: [aka]
+  defp normalize_also_known_as(nil), do: []
+
   defp object_to_user_data(data, additional) do
     fields =
       data
@@ -1551,6 +1589,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     also_known_as =
       data
       |> Map.get("alsoKnownAs", [])
+      |> normalize_also_known_as()
       |> Enum.filter(fn url ->
         case URI.parse(url) do
           %URI{scheme: "http"} -> true
@@ -1686,7 +1725,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       {:ok, maybe_update_follow_information(data)}
     else
       # If this has been deleted, only log a debug and not an error
-      {:error, "Object has been deleted" = e} ->
+      {:error, {"Object has been deleted", _, _} = e} ->
         Logger.debug("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
         {:error, e}