X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fobject.ex;h=740d687a3505fc03ea0cc2161aa44bba4a5f8872;hb=cdcdbd88da76f18c21da7f6f15a29883044902c8;hp=7510a09bbe27777b9729c3bd3ba7634278bba0c0;hpb=2c8deecdd2f75c6cdf1089e4266bedb8be55539c;p=akkoma diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 7510a09bb..740d687a3 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -5,15 +5,18 @@ defmodule Pleroma.Object do use Ecto.Schema - alias Pleroma.Repo - alias Pleroma.Object - alias Pleroma.User alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Object.Fetcher alias Pleroma.ObjectTombstone + alias Pleroma.Repo + alias Pleroma.User import Ecto.Query import Ecto.Changeset + require Logger + schema "objects" do field(:data, :map) @@ -38,9 +41,44 @@ defmodule Pleroma.Object do Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id))) end - 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 + def normalize(_, fetch_remote \\ true) + # 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(%Object{} = object, _), do: object + 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}}}, fetch_remote) 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, fetch_remote) + end + + def normalize(%Activity{data: %{"object" => ap_id}}, fetch_remote) 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, fetch_remote) + end + + # Old way, try fetching the object through cache. + def normalize(%{"id" => ap_id}, fetch_remote), do: normalize(ap_id, fetch_remote) + def normalize(ap_id, false) when is_binary(ap_id), do: get_cached_by_ap_id(ap_id) + def normalize(ap_id, true) when is_binary(ap_id), do: Fetcher.fetch_object_from_id!(ap_id) + def normalize(_, _), do: nil # Owned objects can only be mutated by their owner def authorize_mutation(%Object{data: %{"actor" => actor}}, %User{ap_id: ap_id}), @@ -104,4 +142,50 @@ 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 end