Merge branch 'docs/debian-packages' into 'develop'
[akkoma] / lib / pleroma / web / activity_pub / transmogrifier.ex
index dbb14e9aa2be8e0f76a3e7283cf777affb085265..09119137b70ad41a0d84e7ccd2a2488e75962bc4 100644 (file)
@@ -205,16 +205,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     |> Map.put("conversation", context)
   end
 
+  defp add_if_present(map, _key, nil), do: map
+
+  defp add_if_present(map, key, value) do
+    Map.put(map, key, value)
+  end
+
   def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
     attachments =
       Enum.map(attachment, fn data ->
-        media_type = data["mediaType"] || data["mimeType"]
-        href = data["url"] || data["href"]
-        url = [%{"type" => "Link", "mediaType" => media_type, "href" => href}]
+        url =
+          cond do
+            is_list(data["url"]) -> List.first(data["url"])
+            is_map(data["url"]) -> data["url"]
+            true -> nil
+          end
 
-        data
-        |> Map.put("mediaType", media_type)
-        |> Map.put("url", url)
+        media_type =
+          cond do
+            is_map(url) && is_binary(url["mediaType"]) -> url["mediaType"]
+            is_binary(data["mediaType"]) -> data["mediaType"]
+            is_binary(data["mimeType"]) -> data["mimeType"]
+            true -> nil
+          end
+
+        href =
+          cond do
+            is_map(url) && is_binary(url["href"]) -> url["href"]
+            is_binary(data["url"]) -> data["url"]
+            is_binary(data["href"]) -> data["href"]
+          end
+
+        attachment_url =
+          %{"href" => href}
+          |> add_if_present("mediaType", media_type)
+          |> add_if_present("type", Map.get(url || %{}, "type"))
+
+        %{"url" => [attachment_url]}
+        |> add_if_present("mediaType", media_type)
+        |> add_if_present("type", data["type"])
+        |> add_if_present("name", data["name"])
       end)
 
     Map.put(object, "attachment", attachments)
@@ -232,7 +262,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     Map.put(object, "url", url["href"])
   end
 
-  def fix_url(%{"type" => "Video", "url" => url} = object) when is_list(url) do
+  def fix_url(%{"type" => object_type, "url" => url} = object)
+      when object_type in ["Video", "Audio"] and is_list(url) do
     first_element = Enum.at(url, 0)
 
     link_element = Enum.find(url, fn x -> is_map(x) and x["mimeType"] == "text/html" end)
@@ -401,7 +432,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
         %{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
         options
       )
-      when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer"] do
+      when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer", "Audio"] do
     actor = Containment.get_actor(data)
 
     data =
@@ -493,7 +524,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
            {_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
            {_, {:ok, _}} <-
              {:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")},
-           {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+           {:ok, _relationship} <-
+             FollowingRelationship.update(follower, followed, :follow_accept) do
         ActivityPub.accept(%{
           to: [follower.ap_id],
           actor: followed,
@@ -503,7 +535,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
       else
         {:user_blocked, true} ->
           {:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
-          {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+          {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
 
           ActivityPub.reject(%{
             to: [follower.ap_id],
@@ -514,7 +546,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
         {:follow, {:error, _}} ->
           {:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
-          {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+          {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
 
           ActivityPub.reject(%{
             to: [follower.ap_id],
@@ -524,7 +556,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           })
 
         {:user_locked, true} ->
-          {:ok, _relationship} = FollowingRelationship.update(follower, followed, "pending")
+          {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_pending)
           :noop
       end
 
@@ -544,7 +576,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
          {:ok, follow_activity} <- get_follow_activity(follow_object, followed),
          {:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
          %User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
-         {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+         {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept) do
       ActivityPub.accept(%{
         to: follow_activity.data["to"],
         type: "Accept",
@@ -567,7 +599,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
          {:ok, follow_activity} <- get_follow_activity(follow_object, followed),
          {:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
          %User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
-         {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
+         {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
          {:ok, activity} <-
            ActivityPub.reject(%{
              to: follow_activity.data["to"],
@@ -615,12 +647,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     with {_, {:ok, cast_data_sym}} <-
            {:casting_data,
             data |> LikeValidator.cast_data() |> Ecto.Changeset.apply_action(:insert)},
-         {_, cast_data} <-
-           {:stringify_keys, ObjectValidator.stringify_keys(cast_data_sym |> Map.from_struct())},
+         cast_data = ObjectValidator.stringify_keys(Map.from_struct(cast_data_sym)),
          :ok <- ObjectValidator.fetch_actor_and_object(cast_data),
-         {_, {:ok, cast_data}} <- {:maybe_add_context, maybe_add_context_from_object(cast_data)},
+         {_, {:ok, cast_data}} <- {:ensure_context_presence, ensure_context_presence(cast_data)},
          {_, {:ok, cast_data}} <-
-           {:maybe_add_recipients, maybe_add_recipients_from_object(cast_data)},
+           {:ensure_recipients_presence, ensure_recipients_presence(cast_data)},
          {_, {:ok, activity, _meta}} <-
            {:common_pipeline, Pipeline.common_pipeline(cast_data, local: false)} do
       {:ok, activity}
@@ -680,7 +711,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
       {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
 
       actor
-      |> User.upgrade_changeset(new_user_data, true)
+      |> User.remote_user_changeset(new_user_data)
       |> User.update_and_set_cache()
 
       ActivityPub.update(%{
@@ -1115,13 +1146,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def add_mention_tags(object) do
-    mentions =
-      object
-      |> Utils.get_notified_from_object()
-      |> Enum.map(&build_mention_tag/1)
+    {enabled_receivers, disabled_receivers} = Utils.get_notified_from_object(object)
+    potential_receivers = enabled_receivers ++ disabled_receivers
+    mentions = Enum.map(potential_receivers, &build_mention_tag/1)
 
     tags = object["tag"] || []
-
     Map.put(object, "tag", tags ++ mentions)
   end
 
@@ -1131,7 +1160,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
   def take_emoji_tags(%User{emoji: emoji}) do
     emoji
-    |> Enum.flat_map(&Map.to_list/1)
+    |> Map.to_list()
     |> Enum.map(&build_emoji_tag/1)
   end
 
@@ -1225,12 +1254,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   def upgrade_user_from_ap_id(ap_id) do
     with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id),
          {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
-         already_ap <- User.ap_enabled?(user),
-         {:ok, user} <- upgrade_user(user, data) do
-      if not already_ap do
-        TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
-      end
-
+         {:ok, user} <- update_user(user, data) do
+      TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
       {:ok, user}
     else
       %User{} = user -> {:ok, user}
@@ -1238,9 +1263,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     end
   end
 
-  defp upgrade_user(user, data) do
+  defp update_user(user, data) do
     user
-    |> User.upgrade_changeset(data, true)
+    |> User.remote_user_changeset(data)
     |> User.update_and_set_cache()
   end
 
@@ -1252,46 +1277,44 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
   def maybe_fix_user_object(data), do: maybe_fix_user_url(data)
 
-  defp maybe_add_context_from_object(%{"context" => context} = data) when is_binary(context),
+  defp ensure_context_presence(%{"context" => context} = data) when is_binary(context),
     do: {:ok, data}
 
-  defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(object) do
-    if object = Object.normalize(object) do
-      data =
-        data
-        |> Map.put("context", object.data["context"])
-
-      {:ok, data}
+  defp ensure_context_presence(%{"object" => object} = data) when is_binary(object) do
+    with %{data: %{"context" => context}} when is_binary(context) <- Object.normalize(object) do
+      {:ok, Map.put(data, "context", context)}
     else
-      {:error, "No context on referenced object"}
+      _ ->
+        {:error, :no_context}
     end
   end
 
-  defp maybe_add_context_from_object(_) do
-    {:error, "No referenced object"}
+  defp ensure_context_presence(_) do
+    {:error, :no_context}
   end
 
-  defp maybe_add_recipients_from_object(%{"object" => object} = data) do
-    to = data["to"] || []
-    cc = data["cc"] || []
+  defp ensure_recipients_presence(%{"to" => [_ | _], "cc" => [_ | _]} = data),
+    do: {:ok, data}
 
-    if to == [] && cc == [] do
-      if object = Object.normalize(object) do
+  defp ensure_recipients_presence(%{"object" => object} = data) do
+    case Object.normalize(object) do
+      %{data: %{"actor" => actor}} ->
         data =
           data
-          |> Map.put("to", [object.data["actor"]])
-          |> Map.put("cc", cc)
+          |> Map.put("to", [actor])
+          |> Map.put("cc", data["cc"] || [])
 
         {:ok, data}
-      else
-        {:error, "No actor on referenced object"}
-      end
-    else
-      {:ok, data}
+
+      nil ->
+        {:error, :no_object}
+
+      _ ->
+        {:error, :no_actor}
     end
   end
 
-  defp maybe_add_recipients_from_object(_) do
-    {:error, "No referenced object"}
+  defp ensure_recipients_presence(_) do
+    {:error, :no_object}
   end
 end