ChatController: Handle pagination.
[akkoma] / lib / pleroma / web / common_api / common_api.ex
index d530da42cf6b8e4093b8732422f8487ef94161ff..2c25850db4cfb9a20e1b69c4deb2a3a1860b6b93 100644 (file)
@@ -8,17 +8,49 @@ defmodule Pleroma.Web.CommonAPI do
   alias Pleroma.Conversation.Participation
   alias Pleroma.FollowingRelationship
   alias Pleroma.Object
+  alias Pleroma.Repo
   alias Pleroma.ThreadMute
   alias Pleroma.User
   alias Pleroma.UserRelationship
   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
+  alias Pleroma.Formatter
 
   import Pleroma.Web.Gettext
   import Pleroma.Web.CommonAPI.Utils
 
   require Pleroma.Constants
+  require Logger
+
+  def post_chat_message(%User{} = user, %User{} = recipient, content) do
+    transaction =
+      Repo.transaction(fn ->
+        with {_, {:ok, chat_message_data, _meta}} <-
+               {:build_object,
+                Builder.chat_message(
+                  user,
+                  recipient.ap_id,
+                  content |> Formatter.html_escape("text/plain")
+                )},
+             {_, {:ok, chat_message_object}} <-
+               {:create_object, Object.create(chat_message_data)},
+             {_, {:ok, create_activity_data, _meta}} <-
+               {:build_create_activity,
+                Builder.create(user, chat_message_object.data["id"], [recipient.ap_id])},
+             {_, {:ok, %Activity{} = activity, _meta}} <-
+               {:common_pipeline, Pipeline.common_pipeline(create_activity_data, local: true)} do
+          {:ok, activity}
+        end
+      end)
+
+    case transaction do
+      {:ok, value} -> value
+      error -> error
+    end
+  end
 
   def follow(follower, followed) do
     timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout])
@@ -109,18 +141,51 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  def favorite(id_or_ap_id, user) do
-    with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)},
-         object <- Object.normalize(activity),
-         like_activity <- Utils.get_existing_like(user.ap_id, object) do
-      if like_activity do
-        {:ok, like_activity, object}
-      else
-        ActivityPub.like(user, object)
-      end
+  @spec favorite(User.t(), binary()) :: {:ok, Activity.t() | :already_liked} | {:error, any()}
+  def favorite(%User{} = user, id) do
+    case favorite_helper(user, id) do
+      {:ok, _} = res ->
+        res
+
+      {:error, :not_found} = res ->
+        res
+
+      {:error, e} ->
+        Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
+        {:error, dgettext("errors", "Could not favorite")}
+    end
+  end
+
+  def favorite_helper(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
-      {:find_activity, _} -> {:error, :not_found}
-      _ -> {:error, dgettext("errors", "Could not favorite")}
+      {:find_object, _} ->
+        {:error, :not_found}
+
+      {:common_pipeline,
+       {
+         :error,
+         {
+           :validate_object,
+           {
+             :error,
+             changeset
+           }
+         }
+       }} = e ->
+        if {:object, {"already liked by this actor", []}} in changeset.errors do
+          {:ok, :already_liked}
+        else
+          {:error, e}
+        end
+
+      e ->
+        {:error, e}
     end
   end