Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel
[akkoma] / lib / pleroma / web / common_api / common_api.ex
index 2ec017ff87e1316f38ac70208babce335330059a..a95fffcfcc6f68050823275ba5a8c0dfa00842bb 100644 (file)
@@ -6,16 +6,22 @@ defmodule Pleroma.Web.CommonAPI do
   alias Pleroma.Activity
   alias Pleroma.ActivityExpiration
   alias Pleroma.Conversation.Participation
+  alias Pleroma.FollowingRelationship
   alias Pleroma.Object
   alias Pleroma.ThreadMute
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.ActivityPub.Builder
+  alias Pleroma.Web.ActivityPub.Pipeline
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.ActivityPub.Visibility
 
   import Pleroma.Web.Gettext
   import Pleroma.Web.CommonAPI.Utils
 
+  require Pleroma.Constants
+  require Logger
+
   def follow(follower, followed) do
     timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout])
 
@@ -38,6 +44,7 @@ defmodule Pleroma.Web.CommonAPI do
     with {:ok, follower} <- User.follow(follower, followed),
          %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
          {:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
+         {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept"),
          {:ok, _activity} <-
            ActivityPub.accept(%{
              to: [follower.ap_id],
@@ -52,6 +59,7 @@ defmodule Pleroma.Web.CommonAPI do
   def reject_follow_request(follower, followed) do
     with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
          {:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
+         {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
          {:ok, _activity} <-
            ActivityPub.reject(%{
              to: [follower.ap_id],
@@ -76,11 +84,12 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  def repeat(id_or_ap_id, user) do
+  def repeat(id_or_ap_id, user, params \\ %{}) do
     with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
          object <- Object.normalize(activity),
-         nil <- Utils.get_existing_announce(user.ap_id, object) do
-      ActivityPub.announce(user, object)
+         nil <- Utils.get_existing_announce(user.ap_id, object),
+         public <- public_announce?(object, params) do
+      ActivityPub.announce(user, object, nil, true, public)
     else
       _ -> {:error, dgettext("errors", "Could not repeat")}
     end
@@ -95,13 +104,18 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  def favorite(id_or_ap_id, user) do
-    with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
-         object <- Object.normalize(activity),
-         nil <- Utils.get_existing_like(user.ap_id, object) do
-      ActivityPub.like(user, object)
+  @spec favorite(User.t(), binary()) :: {:ok, Activity.t()} | {:error, any()}
+  def favorite(%User{} = user, id) do
+    with {_, %Activity{object: object}} <- {:find_object, Activity.get_by_id_with_object(id)},
+         {_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
+         {_, {:ok, %Activity{} = activity, _meta}} <-
+           {:common_pipeline,
+            Pipeline.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
+      {:ok, activity}
     else
-      _ -> {:error, dgettext("errors", "Could not favorite")}
+      e ->
+        Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
+        {:error, dgettext("errors", "Could not favorite")}
     end
   end
 
@@ -114,6 +128,25 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
+  def react_with_emoji(id, user, emoji) do
+    with %Activity{} = activity <- Activity.get_by_id(id),
+         object <- Object.normalize(activity) do
+      ActivityPub.react_with_emoji(user, object, emoji)
+    else
+      _ ->
+        {:error, dgettext("errors", "Could not add reaction emoji")}
+    end
+  end
+
+  def unreact_with_emoji(id, user, emoji) do
+    with %Activity{} = reaction_activity <- Utils.get_latest_reaction(id, user, emoji) do
+      ActivityPub.unreact_with_emoji(user, reaction_activity.data["id"])
+    else
+      _ ->
+        {:error, dgettext("errors", "Could not remove reaction emoji")}
+    end
+  end
+
   def vote(user, %{data: %{"type" => "Question"}} = object, choices) do
     with :ok <- validate_not_author(object, user),
          :ok <- validate_existing_votes(user, object),
@@ -169,6 +202,14 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
+  def public_announce?(_, %{"visibility" => visibility})
+      when visibility in ~w{public unlisted private direct},
+      do: visibility in ~w(public unlisted)
+
+  def public_announce?(object, _) do
+    Visibility.is_public?(object)
+  end
+
   def get_visibility(_, _, %Participation{}), do: {"direct", "direct"}
 
   def get_visibility(%{"visibility" => visibility}, in_reply_to, _)
@@ -252,17 +293,17 @@ defmodule Pleroma.Web.CommonAPI do
   # Updates the emojis for a user based on their profile
   def update(user) do
     emoji = emoji_from_profile(user)
-    source_data = user.info |> Map.get(:source_data, %{}) |> Map.put("tag", emoji)
+    source_data = Map.put(user.source_data, "tag", emoji)
 
     user =
-      case User.update_info(user, &User.Info.set_source_data(&1, source_data)) do
+      case User.update_source_data(user, source_data) do
         {:ok, user} -> user
         _ -> user
       end
 
     ActivityPub.update(%{
       local: true,
-      to: [user.follower_address],
+      to: [Pleroma.Constants.as_public(), user.follower_address],
       cc: [],
       actor: user.ap_id,
       object: Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
@@ -276,20 +317,20 @@ defmodule Pleroma.Web.CommonAPI do
            object: %Object{data: %{"type" => "Note"}}
          } = activity <- get_by_id_or_ap_id(id_or_ap_id),
          true <- Visibility.is_public?(activity),
-         {:ok, _user} <- User.update_info(user, &User.Info.add_pinnned_activity(&1, activity)) do
+         {:ok, _user} <- User.add_pinnned_activity(user, activity) do
       {:ok, activity}
     else
-      {:error, %{changes: %{info: %{errors: [pinned_activities: {err, _}]}}}} -> {:error, err}
+      {:error, %{errors: [pinned_activities: {err, _}]}} -> {:error, err}
       _ -> {:error, dgettext("errors", "Could not pin")}
     end
   end
 
   def unpin(id_or_ap_id, user) do
     with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
-         {:ok, _user} <- User.update_info(user, &User.Info.remove_pinnned_activity(&1, activity)) do
+         {:ok, _user} <- User.remove_pinnned_activity(user, activity) do
       {:ok, activity}
     else
-      %{errors: [pinned_activities: {err, _}]} -> {:error, err}
+      {:error, %{errors: [pinned_activities: {err, _}]}} -> {:error, err}
       _ -> {:error, dgettext("errors", "Could not unpin")}
     end
   end
@@ -337,6 +378,13 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
+  def update_report_state(activity_ids, state) when is_list(activity_ids) do
+    case Utils.update_report_state(activity_ids, state) do
+      :ok -> {:ok, activity_ids}
+      _ -> {:error, dgettext("errors", "Could not update state")}
+    end
+  end
+
   def update_report_state(activity_id, state) do
     with %Activity{} = activity <- Activity.get_by_id(activity_id) do
       Utils.update_report_state(activity, state)
@@ -381,14 +429,14 @@ defmodule Pleroma.Web.CommonAPI do
   defp set_visibility(activity, _), do: {:ok, activity}
 
   def hide_reblogs(user, %{ap_id: ap_id} = _muted) do
-    if ap_id not in user.info.muted_reblogs do
-      User.update_info(user, &User.Info.add_reblog_mute(&1, ap_id))
+    if ap_id not in user.muted_reblogs do
+      User.add_reblog_mute(user, ap_id)
     end
   end
 
   def show_reblogs(user, %{ap_id: ap_id} = _muted) do
-    if ap_id in user.info.muted_reblogs do
-      User.update_info(user, &User.Info.remove_reblog_mute(&1, ap_id))
+    if ap_id in user.muted_reblogs do
+      User.remove_reblog_mute(user, ap_id)
     end
   end
 end