Merge branch 'develop' into 'fix/admin-api-user-deletion'
[akkoma] / lib / pleroma / activity.ex
index 4a09194786f3f58ca4c998fd67d99cb0a8dc4f40..baf1e7722bb2ae710e13ecc3c72ca9ea7d9e2be1 100644 (file)
@@ -10,6 +10,7 @@ defmodule Pleroma.Activity do
   alias Pleroma.Notification
   alias Pleroma.Object
   alias Pleroma.Repo
+  alias Pleroma.ThreadMute
   alias Pleroma.User
 
   import Ecto.Changeset
@@ -37,6 +38,7 @@ defmodule Pleroma.Activity do
     field(:local, :boolean, default: true)
     field(:actor, :string)
     field(:recipients, {:array, :string}, default: [])
+    field(:thread_muted?, :boolean, virtual: true)
     # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark
     has_one(:bookmark, Bookmark)
     has_many(:notifications, Notification, on_delete: :delete_all)
@@ -60,21 +62,24 @@ defmodule Pleroma.Activity do
     timestamps()
   end
 
-  def with_preloaded_object(query) do
-    query
-    |> join(
-      :inner,
-      [activity],
-      o in Object,
+  def with_joined_object(query) do
+    join(query, :inner, [activity], o in Object,
       on:
         fragment(
           "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
           o.data,
           activity.data,
           activity.data
-        )
+        ),
+      as: :object
     )
-    |> preload([activity, object], object: object)
+  end
+
+  def with_preloaded_object(query) do
+    query
+    |> has_named_binding?(:object)
+    |> if(do: query, else: with_joined_object(query))
+    |> preload([activity, object: object], object: object)
   end
 
   def with_preloaded_bookmark(query, %User{} = user) do
@@ -87,6 +92,16 @@ defmodule Pleroma.Activity do
 
   def with_preloaded_bookmark(query, _), do: query
 
+  def with_set_thread_muted_field(query, %User{} = user) do
+    from([a] in query,
+      left_join: tm in ThreadMute,
+      on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data),
+      select: %Activity{a | thread_muted?: not is_nil(tm.id)}
+    )
+  end
+
+  def with_set_thread_muted_field(query, _), do: query
+
   def get_by_ap_id(ap_id) do
     Repo.one(
       from(
@@ -108,7 +123,7 @@ defmodule Pleroma.Activity do
 
   def change(struct, params \\ %{}) do
     struct
-    |> cast(params, [:data])
+    |> cast(params, [:data, :recipients])
     |> validate_required([:data])
     |> unique_constraint(:ap_id, name: :activities_unique_apid_index)
   end
@@ -209,6 +224,29 @@ defmodule Pleroma.Activity do
 
   def get_create_by_object_ap_id(_), do: nil
 
+  def create_by_object_ap_id_with_object(ap_ids) when is_list(ap_ids) do
+    from(
+      activity in Activity,
+      where:
+        fragment(
+          "coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)",
+          activity.data,
+          activity.data,
+          ^ap_ids
+        ),
+      where: fragment("(?)->>'type' = 'Create'", activity.data),
+      inner_join: o in Object,
+      on:
+        fragment(
+          "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
+          o.data,
+          activity.data,
+          activity.data
+        ),
+      preload: [object: o]
+    )
+  end
+
   def create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do
     from(
       activity in Activity,
@@ -248,8 +286,8 @@ defmodule Pleroma.Activity do
 
   defp get_in_reply_to_activity_from_object(_), do: nil
 
-  def get_in_reply_to_activity(%Activity{data: %{"object" => object}}) do
-    get_in_reply_to_activity_from_object(Object.normalize(object))
+  def get_in_reply_to_activity(%Activity{} = activity) do
+    get_in_reply_to_activity_from_object(Object.normalize(activity))
   end
 
   def normalize(obj) when is_map(obj), do: get_by_ap_id_with_object(obj["id"])
@@ -328,4 +366,6 @@ defmodule Pleroma.Activity do
         )
     )
   end
+
+  defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search
 end