Browse Source

Merge branch 'feature/object-normalize-preload' into 'develop'

preloaded object normalization

See merge request pleroma/pleroma!967
tags/v1.1.4
kaniini 5 years ago
parent
commit
9b6b2395e4
17 changed files with 223 additions and 52 deletions
  1. +100
    -3
      lib/pleroma/activity.ex
  2. +10
    -1
      lib/pleroma/notification.ex
  3. +29
    -0
      lib/pleroma/object.ex
  4. +4
    -2
      lib/pleroma/user.ex
  5. +20
    -3
      lib/pleroma/web/activity_pub/activity_pub.ex
  6. +1
    -1
      lib/pleroma/web/activity_pub/relay.ex
  7. +3
    -3
      lib/pleroma/web/activity_pub/utils.ex
  8. +2
    -2
      lib/pleroma/web/activity_pub/views/object_view.ex
  9. +7
    -7
      lib/pleroma/web/common_api/common_api.ex
  10. +5
    -4
      lib/pleroma/web/common_api/utils.ex
  11. +1
    -1
      lib/pleroma/web/ostatus/handlers/note_handler.ex
  12. +5
    -5
      lib/pleroma/web/ostatus/ostatus.ex
  13. +7
    -6
      lib/pleroma/web/ostatus/ostatus_controller.ex
  14. +4
    -2
      lib/pleroma/web/rich_media/helpers.ex
  15. +1
    -1
      lib/pleroma/web/streamer.ex
  16. +2
    -1
      test/tasks/relay_test.exs
  17. +22
    -10
      test/web/activity_pub/activity_pub_test.exs

+ 100
- 3
lib/pleroma/activity.ex View File

@@ -7,6 +7,7 @@ defmodule Pleroma.Activity do


alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo


import Ecto.Query import Ecto.Query
@@ -33,9 +34,41 @@ defmodule Pleroma.Activity do
field(:recipients, {:array, :string}) field(:recipients, {:array, :string})
has_many(:notifications, Notification, on_delete: :delete_all) 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!
# The foreign key is embedded in a jsonb field.
#
# To use it, you probably want to do an inner join and a preload:
#
# ```
# |> join(:inner, [activity], o in Object,
# on: fragment("(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)",
# o.data, activity.data))
# |> preload([activity, object], [object: object])
# ```
#
# As a convenience, Activity.with_preloaded_object() sets up an inner join and preload for the
# typical case.
has_one(:object, Object, on_delete: :nothing, foreign_key: :id)

timestamps() timestamps()
end end


def with_preloaded_object(query) do
query
|> join(
:inner,
[activity],
o in Object,
on:
fragment(
"(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)",
o.data,
activity.data
)
)
|> preload([activity, object], object: object)
end

def get_by_ap_id(ap_id) do def get_by_ap_id(ap_id) do
Repo.one( Repo.one(
from( from(
@@ -45,10 +78,42 @@ defmodule Pleroma.Activity do
) )
end 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'::text) ->> 'id'::text)",
o.data,
activity.data
),
preload: [object: o]
)
)
end

def get_by_id(id) do def get_by_id(id) do
Repo.get(Activity, id) Repo.get(Activity, id)
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'::text) ->> 'id'::text)",
o.data,
activity.data
),
preload: [object: o]
)
|> Repo.one()
end

def by_object_ap_id(ap_id) do def by_object_ap_id(ap_id) do
from( from(
activity in Activity, activity in Activity,
@@ -76,7 +141,7 @@ defmodule Pleroma.Activity do
) )
end end


def create_by_object_ap_id(ap_id) do
def create_by_object_ap_id(ap_id) when is_binary(ap_id) do
from( from(
activity in Activity, activity in Activity,
where: where:
@@ -90,6 +155,8 @@ defmodule Pleroma.Activity do
) )
end end


def create_by_object_ap_id(_), do: nil

def get_all_create_by_object_ap_id(ap_id) do def get_all_create_by_object_ap_id(ap_id) do
Repo.all(create_by_object_ap_id(ap_id)) Repo.all(create_by_object_ap_id(ap_id))
end end
@@ -101,8 +168,38 @@ defmodule Pleroma.Activity do


def get_create_by_object_ap_id(_), do: nil def get_create_by_object_ap_id(_), do: nil


def normalize(obj) when is_map(obj), do: Activity.get_by_ap_id(obj["id"])
def normalize(ap_id) when is_binary(ap_id), do: Activity.get_by_ap_id(ap_id)
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'::text) ->> 'id'::text)",
o.data,
activity.data
),
preload: [object: o]
)
end

def create_by_object_ap_id_with_object(_), do: nil

def get_create_by_object_ap_id_with_object(ap_id) do
ap_id
|> create_by_object_ap_id_with_object()
|> Repo.one()
end

def normalize(obj) when is_map(obj), do: get_by_ap_id_with_object(obj["id"])
def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id)
def normalize(_), do: nil def normalize(_), do: nil


def get_in_reply_to_activity(%Activity{data: %{"object" => %{"inReplyTo" => ap_id}}}) do def get_in_reply_to_activity(%Activity{data: %{"object" => %{"inReplyTo" => ap_id}}}) do


+ 10
- 1
lib/pleroma/notification.ex View File

@@ -7,6 +7,7 @@ defmodule Pleroma.Notification do


alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Pagination alias Pleroma.Pagination
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
@@ -33,7 +34,15 @@ defmodule Pleroma.Notification do
Notification Notification
|> where(user_id: ^user.id) |> where(user_id: ^user.id)
|> join(:inner, [n], activity in assoc(n, :activity)) |> join(:inner, [n], activity in assoc(n, :activity))
|> preload(:activity)
|> join(:left, [n, a], object in Object,
on:
fragment(
"(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)",
object.data,
a.data
)
)
|> preload([n, a, o], activity: {a, object: o})
end end


def for_user(user, opts \\ %{}) do def for_user(user, opts \\ %{}) do


+ 29
- 0
lib/pleroma/object.ex View File

@@ -14,6 +14,8 @@ defmodule Pleroma.Object do
import Ecto.Query import Ecto.Query
import Ecto.Changeset import Ecto.Changeset


require Logger

schema "objects" do schema "objects" do
field(:data, :map) field(:data, :map)


@@ -38,6 +40,33 @@ defmodule Pleroma.Object do
Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id))) Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
end 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

# 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(%{"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(ap_id) when is_binary(ap_id), do: get_cached_by_ap_id(ap_id)
def normalize(_), do: nil def normalize(_), do: nil


+ 4
- 2
lib/pleroma/user.ex View File

@@ -1110,13 +1110,15 @@ defmodule Pleroma.User do
friends friends
|> Enum.each(fn followed -> User.unfollow(user, followed) end) |> Enum.each(fn followed -> User.unfollow(user, followed) end)


query = from(a in Activity, where: a.actor == ^user.ap_id)
query =
from(a in Activity, where: a.actor == ^user.ap_id)
|> Activity.with_preloaded_object()


Repo.all(query) Repo.all(query)
|> Enum.each(fn activity -> |> Enum.each(fn activity ->
case activity.data["type"] do case activity.data["type"] do
"Create" -> "Create" ->
ActivityPub.delete(Object.normalize(activity.data["object"]))
ActivityPub.delete(Object.normalize(activity))


# TODO: Do something with likes, follows, repeats. # TODO: Do something with likes, follows, repeats.
_ -> _ ->


+ 20
- 3
lib/pleroma/web/activity_pub/activity_pub.ex View File

@@ -95,7 +95,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
:ok <- check_actor_is_active(map["actor"]), :ok <- check_actor_is_active(map["actor"]),
{_, true} <- {:remote_limit_error, check_remote_limit(map)}, {_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map), {:ok, map} <- MRF.filter(map),
:ok <- insert_full_object(map) do
{:ok, object} <- insert_full_object(map) do
{recipients, _, _} = get_recipients(map) {recipients, _, _} = get_recipients(map)


{:ok, activity} = {:ok, activity} =
@@ -106,6 +106,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
recipients: recipients recipients: recipients
}) })


# Splice in the child object if we have one.
activity =
if !is_nil(object) do
Map.put(activity, :object, object)
else
activity
end

Task.start(fn -> Task.start(fn ->
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
end) end)
@@ -430,6 +438,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
), ),
order_by: [desc: :id] order_by: [desc: :id]
) )
|> Activity.with_preloaded_object()


Repo.all(query) Repo.all(query)
end end
@@ -709,6 +718,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do


defp restrict_muted_reblogs(query, _), do: query defp restrict_muted_reblogs(query, _), do: query


defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query

defp maybe_preload_objects(query, _) do
query
|> Activity.with_preloaded_object()
end

def fetch_activities_query(recipients, opts \\ %{}) do def fetch_activities_query(recipients, opts \\ %{}) do
base_query = base_query =
from( from(
@@ -718,6 +734,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
) )


base_query base_query
|> maybe_preload_objects(opts)
|> restrict_recipients(recipients, opts["user"]) |> restrict_recipients(recipients, opts["user"])
|> restrict_tag(opts) |> restrict_tag(opts)
|> restrict_tag_reject(opts) |> restrict_tag_reject(opts)
@@ -940,7 +957,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
}, },
:ok <- Transmogrifier.contain_origin(id, params), :ok <- Transmogrifier.contain_origin(id, params),
{:ok, activity} <- Transmogrifier.handle_incoming(params) do {:ok, activity} <- Transmogrifier.handle_incoming(params) do
{:ok, Object.normalize(activity.data["object"])}
{:ok, Object.normalize(activity)}
else else
{:error, {:reject, nil}} -> {:error, {:reject, nil}} ->
{:reject, nil} {:reject, nil}
@@ -952,7 +969,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Logger.info("Couldn't get object via AP, trying out OStatus fetching...") Logger.info("Couldn't get object via AP, trying out OStatus fetching...")


case OStatus.fetch_activity_from_url(id) do case OStatus.fetch_activity_from_url(id) do
{:ok, [activity | _]} -> {:ok, Object.normalize(activity.data["object"])}
{:ok, [activity | _]} -> {:ok, Object.normalize(activity)}
e -> e e -> e
end end
end end


+ 1
- 1
lib/pleroma/web/activity_pub/relay.ex View File

@@ -41,7 +41,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do


def publish(%Activity{data: %{"type" => "Create"}} = activity) do def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(), with %User{} = user <- get_actor(),
%Object{} = object <- Object.normalize(activity.data["object"]["id"]) do
%Object{} = object <- Object.normalize(activity) do
ActivityPub.announce(user, object, nil, true, false) ActivityPub.announce(user, object, nil, true, false)
else else
e -> Logger.error("error: #{inspect(e)}") e -> Logger.error("error: #{inspect(e)}")


+ 3
- 3
lib/pleroma/web/activity_pub/utils.ex View File

@@ -209,12 +209,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do
""" """
def insert_full_object(%{"object" => %{"type" => type} = object_data}) def insert_full_object(%{"object" => %{"type" => type} = object_data})
when is_map(object_data) and type in @supported_object_types do when is_map(object_data) and type in @supported_object_types do
with {:ok, _} <- Object.create(object_data) do
:ok
with {:ok, object} <- Object.create(object_data) do
{:ok, object}
end end
end end


def insert_full_object(_), do: :ok
def insert_full_object(_), do: {:ok, nil}


def update_object_in_activities(%{data: %{"id" => id}} = object) do def update_object_in_activities(%{data: %{"id" => id}} = object) do
# TODO # TODO


+ 2
- 2
lib/pleroma/web/activity_pub/views/object_view.ex View File

@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do


def render("object.json", %{object: %Activity{data: %{"type" => "Create"}} = activity}) do def render("object.json", %{object: %Activity{data: %{"type" => "Create"}} = activity}) do
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header() base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
object = Object.normalize(activity.data["object"])
object = Object.normalize(activity)


additional = additional =
Transmogrifier.prepare_object(activity.data) Transmogrifier.prepare_object(activity.data)
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do


def render("object.json", %{object: %Activity{} = activity}) do def render("object.json", %{object: %Activity{} = activity}) do
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header() base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
object = Object.normalize(activity.data["object"])
object = Object.normalize(activity)


additional = additional =
Transmogrifier.prepare_object(activity.data) Transmogrifier.prepare_object(activity.data)


+ 7
- 7
lib/pleroma/web/common_api/common_api.ex View File

@@ -6,7 +6,6 @@ defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Formatter alias Pleroma.Formatter
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ThreadMute alias Pleroma.ThreadMute
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
@@ -64,8 +63,9 @@ defmodule Pleroma.Web.CommonAPI do
end end


def delete(activity_id, user) do def delete(activity_id, user) do
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
%Object{} = object <- Object.normalize(object_id),
with %Activity{data: %{"object" => _}} = activity <-
Activity.get_by_id_with_object(activity_id),
%Object{} = object <- Object.normalize(activity),
true <- User.superuser?(user) || user.ap_id == object.data["actor"], true <- User.superuser?(user) || user.ap_id == object.data["actor"],
{:ok, _} <- unpin(activity_id, user), {:ok, _} <- unpin(activity_id, user),
{:ok, delete} <- ActivityPub.delete(object) do {:ok, delete} <- ActivityPub.delete(object) do
@@ -75,7 +75,7 @@ defmodule Pleroma.Web.CommonAPI do


def repeat(id_or_ap_id, user) do def repeat(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
object <- Object.normalize(activity.data["object"]["id"]),
object <- Object.normalize(activity),
nil <- Utils.get_existing_announce(user.ap_id, object) do nil <- Utils.get_existing_announce(user.ap_id, object) do
ActivityPub.announce(user, object) ActivityPub.announce(user, object)
else else
@@ -86,7 +86,7 @@ defmodule Pleroma.Web.CommonAPI do


def unrepeat(id_or_ap_id, user) do def unrepeat(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
object <- Object.normalize(activity.data["object"]["id"]) do
object <- Object.normalize(activity) do
ActivityPub.unannounce(user, object) ActivityPub.unannounce(user, object)
else else
_ -> _ ->
@@ -96,7 +96,7 @@ defmodule Pleroma.Web.CommonAPI do


def favorite(id_or_ap_id, user) do def favorite(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
object <- Object.normalize(activity.data["object"]["id"]),
object <- Object.normalize(activity),
nil <- Utils.get_existing_like(user.ap_id, object) do nil <- Utils.get_existing_like(user.ap_id, object) do
ActivityPub.like(user, object) ActivityPub.like(user, object)
else else
@@ -107,7 +107,7 @@ defmodule Pleroma.Web.CommonAPI do


def unfavorite(id_or_ap_id, user) do def unfavorite(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
object <- Object.normalize(activity.data["object"]["id"]) do
object <- Object.normalize(activity) do
ActivityPub.unlike(user, object) ActivityPub.unlike(user, object)
else else
_ -> _ ->


+ 5
- 4
lib/pleroma/web/common_api/utils.ex View File

@@ -17,13 +17,14 @@ defmodule Pleroma.Web.CommonAPI.Utils do


# This is a hack for twidere. # This is a hack for twidere.
def get_by_id_or_ap_id(id) do def get_by_id_or_ap_id(id) do
activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
activity =
Activity.get_by_id_with_object(id) || Activity.get_create_by_object_ap_id_with_object(id)


activity && activity &&
if activity.data["type"] == "Create" do if activity.data["type"] == "Create" do
activity activity
else else
Activity.get_create_by_object_ap_id(activity.data["object"])
Activity.get_create_by_object_ap_id_with_object(activity.data["object"])
end end
end end


@@ -302,10 +303,10 @@ defmodule Pleroma.Web.CommonAPI.Utils do


def maybe_notify_mentioned_recipients( def maybe_notify_mentioned_recipients(
recipients, recipients,
%Activity{data: %{"to" => _to, "type" => type} = data} = _activity
%Activity{data: %{"to" => _to, "type" => type} = data} = activity
) )
when type == "Create" do when type == "Create" do
object = Object.normalize(data["object"])
object = Object.normalize(activity)


object_data = object_data =
cond do cond do


+ 1
- 1
lib/pleroma/web/ostatus/handlers/note_handler.ex View File

@@ -106,7 +106,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
# TODO: Clean this up a bit. # TODO: Clean this up a bit.
def handle_note(entry, doc \\ nil) do def handle_note(entry, doc \\ nil) do
with id <- XML.string_from_xpath("//id", entry), with id <- XML.string_from_xpath("//id", entry),
activity when is_nil(activity) <- Activity.get_create_by_object_ap_id(id),
activity when is_nil(activity) <- Activity.get_create_by_object_ap_id_with_object(id),
[author] <- :xmerl_xpath.string('//author[1]', doc), [author] <- :xmerl_xpath.string('//author[1]', doc),
{:ok, actor} <- OStatus.find_make_or_update_user(author), {:ok, actor} <- OStatus.find_make_or_update_user(author),
content_html <- OStatus.get_content(entry), content_html <- OStatus.get_content(entry),


+ 5
- 5
lib/pleroma/web/ostatus/ostatus.ex View File

@@ -23,8 +23,8 @@ defmodule Pleroma.Web.OStatus do
alias Pleroma.Web.WebFinger alias Pleroma.Web.WebFinger
alias Pleroma.Web.Websub alias Pleroma.Web.Websub


def is_representable?(%Activity{data: data}) do
object = Object.normalize(data["object"])
def is_representable?(%Activity{} = activity) do
object = Object.normalize(activity)


cond do cond do
is_nil(object) -> is_nil(object) ->
@@ -119,7 +119,7 @@ defmodule Pleroma.Web.OStatus do


def make_share(entry, doc, retweeted_activity) do def make_share(entry, doc, retweeted_activity) do
with {:ok, actor} <- find_make_or_update_user(doc), with {:ok, actor} <- find_make_or_update_user(doc),
%Object{} = object <- Object.normalize(retweeted_activity.data["object"]),
%Object{} = object <- Object.normalize(retweeted_activity),
id when not is_nil(id) <- string_from_xpath("/entry/id", entry), id when not is_nil(id) <- string_from_xpath("/entry/id", entry),
{:ok, activity, _object} = ActivityPub.announce(actor, object, id, false) do {:ok, activity, _object} = ActivityPub.announce(actor, object, id, false) do
{:ok, activity} {:ok, activity}
@@ -137,7 +137,7 @@ defmodule Pleroma.Web.OStatus do


def make_favorite(entry, doc, favorited_activity) do def make_favorite(entry, doc, favorited_activity) do
with {:ok, actor} <- find_make_or_update_user(doc), with {:ok, actor} <- find_make_or_update_user(doc),
%Object{} = object <- Object.normalize(favorited_activity.data["object"]),
%Object{} = object <- Object.normalize(favorited_activity),
id when not is_nil(id) <- string_from_xpath("/entry/id", entry), id when not is_nil(id) <- string_from_xpath("/entry/id", entry),
{:ok, activity, _object} = ActivityPub.like(actor, object, id, false) do {:ok, activity, _object} = ActivityPub.like(actor, object, id, false) do
{:ok, activity} {:ok, activity}
@@ -159,7 +159,7 @@ defmodule Pleroma.Web.OStatus do
Logger.debug("Trying to get entry from db") Logger.debug("Trying to get entry from db")


with id when not is_nil(id) <- string_from_xpath("//activity:object[1]/id", entry), with id when not is_nil(id) <- string_from_xpath("//activity:object[1]/id", entry),
%Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
%Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do
{:ok, activity} {:ok, activity}
else else
_ -> _ ->


+ 7
- 6
lib/pleroma/web/ostatus/ostatus_controller.ex View File

@@ -102,7 +102,8 @@ defmodule Pleroma.Web.OStatus.OStatusController do
ActivityPubController.call(conn, :object) ActivityPubController.call(conn, :object)
else else
with id <- o_status_url(conn, :object, uuid), with id <- o_status_url(conn, :object, uuid),
{_, %Activity{} = activity} <- {:activity, Activity.get_create_by_object_ap_id(id)},
{_, %Activity{} = activity} <-
{:activity, Activity.get_create_by_object_ap_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)}, {_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case get_format(conn) do case get_format(conn) do
@@ -148,13 +149,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
end end


def notice(conn, %{"id" => id}) do def notice(conn, %{"id" => id}) do
with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id(id)},
with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)}, {_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case format = get_format(conn) do case format = get_format(conn) do
"html" -> "html" ->
if activity.data["type"] == "Create" do if activity.data["type"] == "Create" do
%Object{} = object = Object.normalize(activity.data["object"])
%Object{} = object = Object.normalize(activity)


Fallback.RedirectController.redirector_with_meta(conn, %{ Fallback.RedirectController.redirector_with_meta(conn, %{
activity_id: activity.id, activity_id: activity.id,
@@ -191,9 +192,9 @@ defmodule Pleroma.Web.OStatus.OStatusController do


# Returns an HTML embedded <audio> or <video> player suitable for embed iframes. # Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
def notice_player(conn, %{"id" => id}) do def notice_player(conn, %{"id" => id}) do
with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id),
with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.is_public?(activity), true <- Visibility.is_public?(activity),
%Object{} = object <- Object.normalize(activity.data["object"]),
%Object{} = object <- Object.normalize(activity),
%{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object, %{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
conn conn
@@ -219,7 +220,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do
%Activity{data: %{"type" => "Create"}} = activity, %Activity{data: %{"type" => "Create"}} = activity,
_user _user
) do ) do
object = Object.normalize(activity.data["object"])
object = Object.normalize(activity)


conn conn
|> put_resp_header("content-type", "application/activity+json") |> put_resp_header("content-type", "application/activity+json")


+ 4
- 2
lib/pleroma/web/rich_media/helpers.ex View File

@@ -21,9 +21,9 @@ defmodule Pleroma.Web.RichMedia.Helpers do
defp validate_page_url(%URI{}), do: :ok defp validate_page_url(%URI{}), do: :ok
defp validate_page_url(_), do: :error defp validate_page_url(_), do: :error


def fetch_data_for_activity(%Activity{} = activity) do
def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) do
with true <- Pleroma.Config.get([:rich_media, :enabled]), with true <- Pleroma.Config.get([:rich_media, :enabled]),
%Object{} = object <- Object.normalize(activity.data["object"]),
%Object{} = object <- Object.normalize(activity),
{:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]), {:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]),
:ok <- validate_page_url(page_url), :ok <- validate_page_url(page_url),
{:ok, rich_media} <- Parser.parse(page_url) do {:ok, rich_media} <- Parser.parse(page_url) do
@@ -32,4 +32,6 @@ defmodule Pleroma.Web.RichMedia.Helpers do
_ -> %{} _ -> %{}
end end
end end

def fetch_data_for_activity(_), do: %{}
end end

+ 1
- 1
lib/pleroma/web/streamer.ex View File

@@ -202,7 +202,7 @@ defmodule Pleroma.Web.Streamer do
mutes = user.info.mutes || [] mutes = user.info.mutes || []
reblog_mutes = user.info.muted_reblogs || [] reblog_mutes = user.info.muted_reblogs || []


parent = Object.normalize(item.data["object"])
parent = Object.normalize(item)


unless is_nil(parent) or item.actor in blocks or item.actor in mutes or unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
item.actor in reblog_mutes or not ActivityPub.contain_activity(item, user) or item.actor in reblog_mutes or not ActivityPub.contain_activity(item, user) or


+ 2
- 1
test/tasks/relay_test.exs View File

@@ -60,7 +60,8 @@ defmodule Mix.Tasks.Pleroma.RelayTest do
ActivityPub.fetch_activities([], %{ ActivityPub.fetch_activities([], %{
"type" => "Undo", "type" => "Undo",
"actor_id" => follower_id, "actor_id" => follower_id,
"limit" => 1
"limit" => 1,
"skip_preload" => true
}) })


assert undo_activity.data["type"] == "Undo" assert undo_activity.data["type"] == "Undo"


+ 22
- 10
test/web/activity_pub/activity_pub_test.exs View File

@@ -140,7 +140,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity = insert(:note_activity) activity = insert(:note_activity)
{:ok, new_activity} = ActivityPub.insert(activity.data) {:ok, new_activity} = ActivityPub.insert(activity.data)


assert activity == new_activity
assert activity.id == new_activity.id
end end


test "inserts a given map into the activity database, giving it an id if it has none." do test "inserts a given map into the activity database, giving it an id if it has none." do
@@ -270,7 +270,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
booster = insert(:user) booster = insert(:user)
{:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]}) {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]})


activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
@@ -278,7 +279,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do


{:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})


activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
@@ -289,14 +291,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Repo.get(Activity, activity_three.id) activity_three = Repo.get(Activity, activity_three.id)


activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
refute Enum.member?(activities, activity_three) refute Enum.member?(activities, activity_three)
refute Enum.member?(activities, boost_activity) refute Enum.member?(activities, boost_activity)
assert Enum.member?(activities, activity_one) assert Enum.member?(activities, activity_one)


activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil})
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
@@ -312,14 +316,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
booster = insert(:user) booster = insert(:user)
{:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]}) {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]})


activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
refute Enum.member?(activities, activity_one) refute Enum.member?(activities, activity_one)


# Calling with 'with_muted' will deliver muted activities, too. # Calling with 'with_muted' will deliver muted activities, too.
activities = ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true})
activities =
ActivityPub.fetch_activities([], %{
"muting_user" => user,
"with_muted" => true,
"skip_preload" => true
})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
@@ -327,7 +337,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do


{:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]}) {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})


activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
@@ -338,14 +349,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Repo.get(Activity, activity_three.id) activity_three = Repo.get(Activity, activity_three.id)


activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
refute Enum.member?(activities, activity_three) refute Enum.member?(activities, activity_three)
refute Enum.member?(activities, boost_activity) refute Enum.member?(activities, boost_activity)
assert Enum.member?(activities, activity_one) assert Enum.member?(activities, activity_one)


activities = ActivityPub.fetch_activities([], %{"muting_user" => nil})
activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})


assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)


Loading…
Cancel
Save