diff options
-rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 22 | ||||
-rw-r--r-- | lib/pleroma/web/twitter_api/twitter_api.ex | 1 | ||||
-rw-r--r-- | lib/pleroma/web/twitter_api/views/activity_view.ex | 51 | ||||
-rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 21 | ||||
-rw-r--r-- | test/web/twitter_api/twitter_api_controller_test.exs | 6 | ||||
-rw-r--r-- | test/web/twitter_api/views/activity_view_test.exs | 26 |
6 files changed, 110 insertions, 17 deletions
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 16a1d3e97..ac3a57e03 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -45,6 +45,18 @@ defmodule Pleroma.Web.ActivityPub.Utils do "#{Web.base_url()}/#{type}/#{UUID.generate()}" end + def create_context(context) do + context = context || generate_id("contexts") + changeset = Object.context_mapping(context) + + case Repo.insert(changeset) do + {:ok, object} -> object + # This should be solved by an upsert, but it seems ecto + # has problems accessing the constraint inside the jsonb. + {:error, _} -> Object.get_cached_by_ap_id(context) + end + end + @doc """ Enqueues an activity for federation if it's local """ @@ -67,13 +79,17 @@ defmodule Pleroma.Web.ActivityPub.Utils do also adds it to an included object """ def lazy_put_activity_defaults(map) do + %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) + map = map |> Map.put_new_lazy("id", &generate_activity_id/0) |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", context) + |> Map.put_new("context_id", context_id) if is_map(map["object"]) do - object = lazy_put_object_defaults(map["object"]) + object = lazy_put_object_defaults(map["object"], map) %{map | "object" => object} else map @@ -83,10 +99,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do @doc """ Adds an id and published date if they aren't there. """ - def lazy_put_object_defaults(map) do + def lazy_put_object_defaults(map, activity \\ %{}) do map |> Map.put_new_lazy("id", &generate_object_id/0) |> Map.put_new_lazy("published", &make_date/0) + |> Map.put_new("context", activity["context"]) + |> Map.put_new("context_id", activity["context_id"]) end @doc """ diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 30362ef70..027b97154 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -212,6 +212,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do DateTime.utc_now() |> DateTime.to_iso8601() end + # DEPRECATED mostly, context objects are now created at insertion time. def context_to_conversation_id(context) do with %Object{id: id} <- Object.get_cached_by_ap_id(context) do id diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 3e69af3e3..760840239 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -7,9 +7,48 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Repo alias Pleroma.Formatter + import Ecto.Query + + defp query_context_ids([]), do: [] + defp query_context_ids(contexts) do + query = from o in Object, + where: fragment("(?)->>'id' = ANY(?)", o.data, ^contexts) + + Repo.all(query) + end + + defp collect_context_ids(activities) do + contexts = activities + |> Enum.reject(&(&1.data["context_id"])) + |> Enum.map(fn(%{data: data}) -> + data["context"] + end) + |> Enum.filter(&(&1)) + |> query_context_ids() + |> Enum.reduce(%{}, fn(%{data: %{"id" => ap_id}, id: id}, acc) -> + Map.put(acc, ap_id, id) + end) + end + + defp get_context_id(%{data: %{"context_id" => context_id}}, _) when not is_nil(context_id), do: context_id + defp get_context_id(%{data: %{"context" => nil}}, _), do: nil + defp get_context_id(%{data: %{"context" => context}}, options) do + cond do + id = options[:context_ids][context] -> id + true -> TwitterAPI.context_to_conversation_id(context) + end + end + defp get_context_id(_, _), do: nil + def render("index.json", opts) do + context_ids = collect_context_ids(opts.activities) + opts = opts + |> Map.put(:context_ids, context_ids) + render_many( opts.activities, ActivityView, @@ -80,7 +119,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "uri" => "tag:#{activity.data["id"]}:objectType=note", "created_at" => created_at, "retweeted_status" => retweeted_status, - "statusnet_conversation_id" => conversation_id(announced_activity), + "statusnet_conversation_id" => get_context_id(announced_activity, opts), "external_url" => activity.data["id"], "activity_type" => "repeat" } @@ -130,7 +169,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do |> Enum.filter(& &1) |> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end) - conversation_id = conversation_id(activity) + conversation_id = get_context_id(activity, opts) tags = activity.data["object"]["tag"] || [] possibly_sensitive = activity.data["object"]["sensitive"] || Enum.member?(tags, "nsfw") @@ -174,12 +213,4 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "possibly_sensitive" => possibly_sensitive } end - - defp conversation_id(activity) do - with context when not is_nil(context) <- activity.data["context"] do - TwitterAPI.context_to_conversation_id(context) - else - _e -> nil - end - end end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index cf25abfc1..c6434f789 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -40,12 +40,31 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do data = %{ "ok" => true, - "id" => given_id + "id" => given_id, + "context" => "blabla" } {:ok, %Activity{} = activity} = ActivityPub.insert(data) assert activity.data["ok"] == data["ok"] assert activity.data["id"] == given_id + assert activity.data["context"] == "blabla" + assert activity.data["context_id"] + end + + test "adds a context when none is there" do + data = %{ + "id" => "some_id", + "object" => %{ + "id" => "object_id" + } + } + + {:ok, %Activity{} = activity} = ActivityPub.insert(data) + + assert is_binary(activity.data["context"]) + assert is_binary(activity.data["object"]["context"]) + assert activity.data["context_id"] + assert activity.data["object"]["context_id"] end test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 2cbcfd086..6084381cb 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -160,15 +160,13 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do describe "GET /statusnet/conversation/:id.json" do test "returns the statuses in the conversation", %{conn: conn} do {:ok, _user} = UserBuilder.insert() - {:ok, _activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) + {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) {:ok, _activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) - {:ok, object} = Object.context_mapping("2hu") |> Repo.insert() - conn = conn - |> get("/api/statusnet/conversation/#{object.id}.json") + |> get("/api/statusnet/conversation/#{activity.data["context_id"]}.json") response = json_response(conn, 200) diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs index cb8f60fcf..46ffdef44 100644 --- a/test/web/twitter_api/views/activity_view_test.exs +++ b/test/web/twitter_api/views/activity_view_test.exs @@ -10,7 +10,9 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do alias Pleroma.Activity alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + import Pleroma.Factory + import Mock test "a create activity with a note" do user = insert(:user) @@ -51,6 +53,30 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do assert result == expected end + test "a list of activities" do + user = insert(:user) + other_user = insert(:user, %{nickname: "shp"}) + {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"}) + + convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"]) + + mocks = [ + { + TwitterAPI, + [], + [context_to_conversation_id: fn(_) -> false end] + } + ] + + with_mocks mocks do + [result] = ActivityView.render("index.json", activities: [activity]) + + assert result["statusnet_conversation_id"] == convo_id + assert result["user"] + refute called TwitterAPI.context_to_conversation_id(:_) + end + end + test "an activity that is a reply" do user = insert(:user) other_user = insert(:user, %{nickname: "shp"}) |