Remove bookmarks assoc and add a fake bookmark assoc instead

This commit is contained in:
rinpatch 2019-05-07 18:00:50 +03:00 committed by William Pitcock
parent be067ec2ab
commit 4c5125dedc
6 changed files with 71 additions and 79 deletions

View file

@ -10,6 +10,7 @@ defmodule Pleroma.Activity do
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query import Ecto.Query
@ -36,8 +37,9 @@ defmodule Pleroma.Activity do
field(:local, :boolean, default: true) field(:local, :boolean, default: true)
field(:actor, :string) field(:actor, :string)
field(:recipients, {:array, :string}, default: []) field(:recipients, {:array, :string}, default: [])
# 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) has_many(:notifications, Notification, on_delete: :delete_all)
has_many(:bookmarks, Bookmark, on_delete: :delete_all)
# Attention: this is a fake relation, don't try to preload it blindly and expect it to work! # 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. # The foreign key is embedded in a jsonb field.
@ -73,14 +75,18 @@ defmodule Pleroma.Activity do
) )
) )
|> preload([activity, object], object: object) |> preload([activity, object], object: object)
|> with_preloaded_bookmarks()
end end
def with_preloaded_bookmarks(query) do def with_preloaded_bookmark(query, %User{} = user) do
query from([a] in query,
|> preload(:bookmarks) left_join: b in Bookmark,
on: b.user_id == ^user.id and b.activity_id == a.id,
preload: [bookmark: b]
)
end end
def with_preloaded_bookmark(query, _), do: query
def get_by_ap_id(ap_id) do def get_by_ap_id(ap_id) do
Repo.one( Repo.one(
from( from(
@ -90,6 +96,16 @@ defmodule Pleroma.Activity do
) )
end end
def get_bookmark(%Activity{} = activity, %User{} = user) do
if Ecto.assoc_loaded?(activity.bookmark) do
activity.bookmark
else
Bookmark.get(user.id, activity.id)
end
end
def get_bookmark(_, _), do: nil
def change(struct, params \\ %{}) do def change(struct, params \\ %{}) do
struct struct
|> cast(params, [:data]) |> cast(params, [:data])
@ -112,7 +128,6 @@ defmodule Pleroma.Activity do
), ),
preload: [object: o] preload: [object: o]
) )
|> with_preloaded_bookmarks()
) )
end end
@ -133,7 +148,6 @@ defmodule Pleroma.Activity do
), ),
preload: [object: o] preload: [object: o]
) )
|> with_preloaded_bookmarks()
|> Repo.one() |> Repo.one()
end end
@ -212,7 +226,6 @@ defmodule Pleroma.Activity do
), ),
preload: [object: o] preload: [object: o]
) )
|> with_preloaded_bookmarks()
end end
def create_by_object_ap_id_with_object(_), do: nil def create_by_object_ap_id_with_object(_), do: nil

View file

@ -38,8 +38,7 @@ defmodule Pleroma.Bookmark do
Bookmark Bookmark
|> where(user_id: ^user_id) |> where(user_id: ^user_id)
|> join(:inner, [b], activity in assoc(b, :activity)) |> join(:inner, [b], activity in assoc(b, :activity))
|> join(:inner, [_b, a], bookmarks in assoc(a, :bookmarks)) |> preload([b, a], activity: a)
|> preload([b, a, b2], activity: {a, bookmarks: b2})
end end
def get(user_id, activity_id) do def get(user_id, activity_id) do

View file

@ -137,13 +137,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
activity activity
end end
activity =
if activity.data["type"] in ["Create", "Announce"] do
Repo.preload(activity, :bookmarks)
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)
@ -822,11 +815,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> Activity.with_preloaded_object() |> Activity.with_preloaded_object()
end end
defp maybe_preload_bookmarks(query, %{"skip_preload" => true}), do: query
defp maybe_preload_bookmarks(query, opts) do
query
|> Activity.with_preloaded_bookmark(opts["user"])
end
def fetch_activities_query(recipients, opts \\ %{}) do def fetch_activities_query(recipients, opts \\ %{}) do
base_query = from(activity in Activity) base_query = from(activity in Activity)
base_query base_query
|> maybe_preload_objects(opts) |> maybe_preload_objects(opts)
|> maybe_preload_bookmarks(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)

View file

@ -563,9 +563,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
with %Activity{} = activity <- Activity.get_by_id_with_object(id), with %Activity{} = activity <- Activity.get_by_id_with_object(id),
%User{} = user <- User.get_cached_by_nickname(user.nickname), %User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user), true <- Visibility.visible_for_user?(activity, user),
{:ok, bookmark} <- Bookmark.create(user.id, activity.id) do {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do
activity = %{activity | bookmarks: [bookmark | activity.bookmarks]}
conn conn
|> put_view(StatusView) |> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity}) |> try_render("status.json", %{activity: activity, for: user, as: :activity})
@ -577,11 +575,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
%User{} = user <- User.get_cached_by_nickname(user.nickname), %User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user), true <- Visibility.visible_for_user?(activity, user),
{:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do
bookmarks =
Enum.filter(activity.bookmarks, fn %{user_id: user_id} -> user_id != user.id end)
activity = %{activity | bookmarks: bookmarks}
conn conn
|> put_view(StatusView) |> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity}) |> try_render("status.json", %{activity: activity, for: user, as: :activity})
@ -1154,7 +1147,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
activities = activities =
bookmarks bookmarks
|> Enum.map(fn b -> b.activity end) |> Enum.map(fn b -> Map.put(b.activity, :bookmark, Map.delete(b, :activity)) end)
conn conn
|> add_link_headers(:bookmarks, bookmarks) |> add_link_headers(:bookmarks, bookmarks)

View file

@ -75,26 +75,22 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
def render( def render(
"status.json", "status.json",
%{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts %{activity: %{data: %{"type" => "Announce", "object" => _object}} = activity} = opts
) do ) do
user = get_user(activity.data["actor"]) user = get_user(activity.data["actor"])
created_at = Utils.to_masto_date(activity.data["published"]) created_at = Utils.to_masto_date(activity.data["published"])
activity_object = Object.normalize(activity)
reblogged_activity = reblogged_activity =
Activity.create_by_object_ap_id(object) Activity.create_by_object_ap_id(activity_object.data["id"])
|> Activity.with_preloaded_bookmarks() |> Activity.with_preloaded_bookmark(opts[:for])
|> Repo.one() |> Repo.one()
reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity)) reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity))
activity_object = Object.normalize(activity)
favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || []) favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || [])
bookmarked = bookmarked = Activity.get_bookmark(reblogged_activity, opts[:for]) != nil
opts[:for] && Ecto.assoc_loaded?(reblogged_activity.bookmarks) &&
Enum.any?(reblogged_activity.bookmarks, fn %{user_id: user_id} ->
user_id == opts[:for].id
end)
mentions = mentions =
activity.recipients activity.recipients
@ -104,8 +100,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
%{ %{
id: to_string(activity.id), id: to_string(activity.id),
uri: object, uri: activity_object.data["id"],
url: object, url: activity_object.data["id"],
account: AccountView.render("account.json", %{user: user}), account: AccountView.render("account.json", %{user: user}),
in_reply_to_id: nil, in_reply_to_id: nil,
in_reply_to_account_id: nil, in_reply_to_account_id: nil,
@ -157,11 +153,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || []) favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || [])
bookmarked = bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil
opts[:for] && Ecto.assoc_loaded?(activity.bookmarks) &&
Enum.any?(activity.bookmarks, fn %{user_id: user_id} ->
user_id == opts[:for].id
end)
attachment_data = object.data["attachment"] || [] attachment_data = object.data["attachment"] || []
attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)

View file

@ -6,7 +6,6 @@ defmodule Pleroma.ActivityTest do
use Pleroma.DataCase use Pleroma.DataCase
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Bookmark alias Pleroma.Bookmark
alias Pleroma.Object
import Pleroma.Factory import Pleroma.Factory
test "returns an activity by it's AP id" do test "returns an activity by it's AP id" do
@ -31,52 +30,47 @@ defmodule Pleroma.ActivityTest do
assert activity == found_activity assert activity == found_activity
end end
describe "preloading bookmarks" do test "preloading a bookmark" do
setup do user = insert(:user)
user1 = insert(:user) user2 = insert(:user)
user2 = insert(:user) user3 = insert(:user)
activity = insert(:note_activity)
{:ok, _bookmark} = Bookmark.create(user.id, activity.id)
{:ok, _bookmark2} = Bookmark.create(user2.id, activity.id)
{:ok, bookmark3} = Bookmark.create(user3.id, activity.id)
queried_activity =
Ecto.Query.from(Pleroma.Activity)
|> Activity.with_preloaded_bookmark(user3)
|> Repo.one()
assert queried_activity.bookmark == bookmark3
end
describe "getting a bookmark" do
test "when association is loaded" do
user = insert(:user)
activity = insert(:note_activity) activity = insert(:note_activity)
{:ok, bookmark1} = Bookmark.create(user1.id, activity.id) {:ok, bookmark} = Bookmark.create(user.id, activity.id)
{:ok, bookmark2} = Bookmark.create(user2.id, activity.id)
[activity: activity, bookmarks: Enum.sort([bookmark1, bookmark2])]
end
test "using with_preloaded_bookmarks", %{activity: activity, bookmarks: bookmarks} do
queried_activity = queried_activity =
Ecto.Query.from(a in Activity, where: a.id == ^activity.id) Ecto.Query.from(Pleroma.Activity)
|> Activity.with_preloaded_bookmarks() |> Activity.with_preloaded_bookmark(user)
|> Repo.one() |> Repo.one()
assert Enum.sort(queried_activity.bookmarks) == bookmarks assert Activity.get_bookmark(queried_activity, user) == bookmark
end end
test "using with_preloaded_object", %{activity: activity, bookmarks: bookmarks} do test "when association is not loaded" do
user = insert(:user)
activity = insert(:note_activity)
{:ok, bookmark} = Bookmark.create(user.id, activity.id)
queried_activity = queried_activity =
Ecto.Query.from(a in Activity, where: a.id == ^activity.id) Ecto.Query.from(Pleroma.Activity)
|> Activity.with_preloaded_object()
|> Repo.one() |> Repo.one()
assert Enum.sort(queried_activity.bookmarks) == bookmarks assert Activity.get_bookmark(queried_activity, user) == bookmark
end
test "using get_by_ap_id_with_object", %{activity: activity, bookmarks: bookmarks} do
queried_activity = Activity.get_by_ap_id_with_object(activity.data["id"])
assert Enum.sort(queried_activity.bookmarks) == bookmarks
end
test "using get_by_id_with_object", %{activity: activity, bookmarks: bookmarks} do
queried_activity = Activity.get_by_id_with_object(activity.id)
assert Enum.sort(queried_activity.bookmarks) == bookmarks
end
test "using get_create_by_object_ap_id_with_object", %{
activity: activity,
bookmarks: bookmarks
} do
queried_activity =
Activity.get_create_by_object_ap_id_with_object(Object.normalize(activity).data["id"])
assert Enum.sort(queried_activity.bookmarks) == bookmarks
end end
end end
end end