X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fobject.ex;h=786d6296cfcc24a3964e943003b245ace3b77667;hb=fc92a0fd8d5be0352f4791b79bda04960f36f707;hp=7b46a3b05266fd47d8a3fa928975c4d9cc54e018;hpb=25a659d2dcd093939aa2cba049902ea54ab89312;p=akkoma diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 7b46a3b05..786d6296c 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -4,8 +4,17 @@ defmodule Pleroma.Object do use Ecto.Schema - alias Pleroma.{Repo, Object, User, Activity, ObjectTombstone} - import Ecto.{Query, Changeset} + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.ObjectTombstone + alias Pleroma.Repo + alias Pleroma.User + + import Ecto.Query + import Ecto.Changeset + + require Logger schema "objects" do field(:data, :map) @@ -31,6 +40,38 @@ defmodule Pleroma.Object do Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id))) end + # If we pass an Activity to Object.normalize(), we can try to use the preloaded object. + # Use this whenever possible, especially when walking graphs in an O(N) loop! + def normalize(%Activity{object: %Object{} = object}), do: object + + # A hack for fake activities + def normalize(%Activity{data: %{"object" => %{"fake" => true} = data}}) do + %Object{id: "pleroma:fake_object_id", data: data} + end + + # Catch and log Object.normalize() calls where the Activity's child object is not + # preloaded. + def normalize(%Activity{data: %{"object" => %{"id" => ap_id}}}) do + Logger.debug( + "Object.normalize() called without preloaded object (#{ap_id}). Consider preloading the object!" + ) + + Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}") + + normalize(ap_id) + end + + def normalize(%Activity{data: %{"object" => ap_id}}) do + Logger.debug( + "Object.normalize() called without preloaded object (#{ap_id}). Consider preloading the object!" + ) + + Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}") + + normalize(ap_id) + end + + # Old way, try fetching the object through cache. def normalize(%{"id" => ap_id}), do: normalize(ap_id) def normalize(ap_id) when is_binary(ap_id), do: get_cached_by_ap_id(ap_id) def normalize(_), do: nil @@ -79,9 +120,9 @@ defmodule Pleroma.Object do def delete(%Object{data: %{"id" => id}} = object) do with {:ok, _obj} = swap_object_with_tombstone(object), - Repo.delete_all(Activity.by_object_ap_id(id)), + deleted_activity = Activity.delete_by_ap_id(id), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do - {:ok, object} + {:ok, object, deleted_activity} end end @@ -97,4 +138,58 @@ defmodule Pleroma.Object do e -> e end end + + def increase_replies_count(ap_id) do + Object + |> where([o], fragment("?->>'id' = ?::text", o.data, ^to_string(ap_id))) + |> update([o], + set: [ + data: + fragment( + """ + jsonb_set(?, '{repliesCount}', + (coalesce((?->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true) + """, + o.data, + o.data + ) + ] + ) + |> Repo.update_all([]) + |> case do + {1, [object]} -> set_cache(object) + _ -> {:error, "Not found"} + end + end + + def decrease_replies_count(ap_id) do + Object + |> where([o], fragment("?->>'id' = ?::text", o.data, ^to_string(ap_id))) + |> update([o], + set: [ + data: + fragment( + """ + jsonb_set(?, '{repliesCount}', + (greatest(0, (?->>'repliesCount')::int - 1))::varchar::jsonb, true) + """, + o.data, + o.data + ) + ] + ) + |> Repo.update_all([]) + |> case do + {1, [object]} -> set_cache(object) + _ -> {:error, "Not found"} + end + end + + def enforce_user_objects(user, object_ids) do + Object + |> where([o], fragment("?->>'actor' = ?", o.data, ^user.ap_id)) + |> where([o], o.id in ^object_ids) + |> select([o], o.id) + |> Repo.all() + end end