X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Factivity.ex;h=510d3273c1bb9c9244701498145de730530eef1e;hb=3ecf131511afc1fc366be6402ca94cf0e6c30e11;hp=44f1e30110bcaaa3c206ab082fa062ccb3626bcc;hpb=b40b10b53d00d13f24b5667acc02b1642abc6ec4;p=akkoma diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 44f1e3011..510d3273c 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -6,11 +6,13 @@ defmodule Pleroma.Activity do use Ecto.Schema alias Pleroma.Activity + alias Pleroma.Activity.Queries alias Pleroma.ActivityExpiration alias Pleroma.Bookmark alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.ReportNote alias Pleroma.ThreadMute alias Pleroma.User @@ -20,14 +22,15 @@ defmodule Pleroma.Activity do @type t :: %__MODULE__{} @type actor :: String.t() - @primary_key {:id, Pleroma.FlakeId, autogenerate: true} + @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} # https://github.com/tootsuite/mastodon/blob/master/app/models/notification.rb#L19 @mastodon_notification_types %{ "Create" => "mention", "Follow" => "follow", "Announce" => "reblog", - "Like" => "favourite" + "Like" => "favourite", + "Move" => "move" } @mastodon_to_ap_notification_types for {k, v} <- @mastodon_notification_types, @@ -40,8 +43,14 @@ defmodule Pleroma.Activity do 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_user_actor/with_joined_user_actor + has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id) # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark has_one(:bookmark, Bookmark) + # This is a fake relation, do not use outside of with_preloaded_report_notes + has_many(:report_notes, ReportNote) has_many(:notifications, Notification, on_delete: :delete_all) # Attention: this is a fake relation, don't try to preload it blindly and expect it to work! @@ -65,8 +74,8 @@ defmodule Pleroma.Activity do timestamps() end - def with_joined_object(query) do - join(query, :inner, [activity], o in Object, + def with_joined_object(query, join_type \\ :inner) do + join(query, join_type, [activity], o in Object, on: fragment( "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", @@ -78,13 +87,26 @@ defmodule Pleroma.Activity do ) end - def with_preloaded_object(query) do + def with_preloaded_object(query, join_type \\ :inner) do query |> has_named_binding?(:object) - |> if(do: query, else: with_joined_object(query)) + |> if(do: query, else: with_joined_object(query, join_type)) |> preload([activity, object: object], object: object) end + def with_joined_user_actor(query, join_type \\ :inner) do + join(query, join_type, [activity], u in User, + on: u.ap_id == activity.actor, + as: :user_actor + ) + end + + def with_preloaded_user_actor(query, join_type \\ :inner) do + query + |> with_joined_user_actor(join_type) + |> preload([activity, user_actor: user_actor], user_actor: user_actor) + end + def with_preloaded_bookmark(query, %User{} = user) do from([a] in query, left_join: b in Bookmark, @@ -95,6 +117,16 @@ defmodule Pleroma.Activity do def with_preloaded_bookmark(query, _), do: query + def with_preloaded_report_notes(query) do + from([a] in query, + left_join: r in ReportNote, + on: a.id == r.activity_id, + preload: [report_notes: r] + ) + end + + def with_preloaded_report_notes(query, _), do: query + def with_set_thread_muted_field(query, %User{} = user) do from([a] in query, left_join: tm in ThreadMute, @@ -107,12 +139,9 @@ defmodule Pleroma.Activity do def with_set_thread_muted_field(query, _), do: query def get_by_ap_id(ap_id) do - Repo.one( - from( - activity in Activity, - where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)) - ) - ) + ap_id + |> Queries.by_ap_id() + |> Repo.one() end def get_bookmark(%Activity{} = activity, %User{} = user) do @@ -133,43 +162,30 @@ defmodule Pleroma.Activity do end def get_by_ap_id_with_object(ap_id) do - Repo.one( - from( - activity in Activity, - where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)), - left_join: o in Object, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", - o.data, - activity.data, - activity.data - ), - preload: [object: o] - ) - ) + ap_id + |> Queries.by_ap_id() + |> with_preloaded_object(:left) + |> Repo.one() end + @spec get_by_id(String.t()) :: Activity.t() | nil def get_by_id(id) do - Activity - |> where([a], a.id == ^id) - |> restrict_deactivated_users() - |> Repo.one() + case FlakeId.flake_id?(id) do + true -> + Activity + |> where([a], a.id == ^id) + |> restrict_deactivated_users() + |> Repo.one() + + _ -> + nil + end end def get_by_id_with_object(id) do - from(activity in Activity, - where: activity.id == ^id, - inner_join: o in Object, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", - o.data, - activity.data, - activity.data - ), - preload: [object: o] - ) + Activity + |> where(id: ^id) + |> with_preloaded_object() |> Repo.one() end @@ -180,51 +196,21 @@ defmodule Pleroma.Activity do |> Repo.all() end - def by_object_ap_id(ap_id) do - from( - activity in Activity, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^to_string(ap_id) - ) - ) - end - - def create_by_object_ap_id(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) - ) - end - - def create_by_object_ap_id(ap_id) when is_binary(ap_id) do - from( - activity in Activity, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^to_string(ap_id) - ), - where: fragment("(?)->>'type' = 'Create'", activity.data) - ) + @doc """ + Accepts `ap_id` or list of `ap_id`. + Returns a query. + """ + @spec create_by_object_ap_id(String.t() | [String.t()]) :: Ecto.Queryable.t() + def create_by_object_ap_id(ap_id) do + ap_id + |> Queries.by_object_id() + |> Queries.by_type("Create") end - def create_by_object_ap_id(_), do: nil - def get_all_create_by_object_ap_id(ap_id) do - Repo.all(create_by_object_ap_id(ap_id)) + ap_id + |> create_by_object_ap_id() + |> Repo.all() end def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do @@ -235,54 +221,17 @@ 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, - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, - activity.data, - ^to_string(ap_id) - ), - 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] - ) + @doc """ + Accepts `ap_id` or list of `ap_id`. + Returns a query. + """ + @spec create_by_object_ap_id_with_object(String.t() | [String.t()]) :: Ecto.Queryable.t() + def create_by_object_ap_id_with_object(ap_id) do + ap_id + |> create_by_object_ap_id() + |> with_preloaded_object() end - def create_by_object_ap_id_with_object(_), do: nil - def get_create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do ap_id |> create_by_object_ap_id_with_object() @@ -305,8 +254,10 @@ defmodule Pleroma.Activity do def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id) def normalize(_), do: nil - def delete_by_ap_id(id) when is_binary(id) do - by_object_ap_id(id) + def delete_all_by_object_ap_id(id) when is_binary(id) do + id + |> Queries.by_object_id() + |> Queries.exclude_type("Delete") |> select([u], u) |> Repo.delete_all() |> elem(1) @@ -318,7 +269,7 @@ defmodule Pleroma.Activity do |> purge_web_resp_cache() end - def delete_by_ap_id(_), do: nil + def delete_all_by_object_ap_id(_), do: nil defp purge_web_resp_cache(%Activity{} = activity) do %{path: path} = URI.parse(activity.data["id"]) @@ -350,31 +301,10 @@ defmodule Pleroma.Activity do end def follow_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do - from( - a in Activity, - where: - fragment( - "? ->> 'type' = 'Follow'", - a.data - ), - where: - fragment( - "? ->> 'state' = 'pending'", - a.data - ), - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - a.data, - a.data, - ^ap_id - ) - ) - end - - @spec query_by_actor(actor()) :: Ecto.Query.t() - def query_by_actor(actor) do - from(a in Activity, where: a.actor == ^actor) + ap_id + |> Queries.by_object_id() + |> Queries.by_type("Follow") + |> where([a], fragment("? ->> 'state' = 'pending'", a.data)) end def restrict_deactivated_users(query) do @@ -388,4 +318,17 @@ defmodule Pleroma.Activity do end defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search + + def direct_conversation_id(activity, for_user) do + alias Pleroma.Conversation.Participation + + with %{data: %{"context" => context}} when is_binary(context) <- activity, + %Pleroma.Conversation{} = conversation <- Pleroma.Conversation.get_for_ap_id(context), + %Participation{id: participation_id} <- + Participation.for_user_and_conversation(for_user, conversation) do + participation_id + else + _ -> nil + end + end end