From ca755f9a73649375096850ce7849688f45162de8 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 22 May 2020 16:15:29 +0200 Subject: [PATCH 1/5] ActivityPubController: Add Mastodon compatibility route. --- .../activity_pub/activity_pub_controller.ex | 5 ++-- lib/pleroma/web/ostatus/ostatus_controller.ex | 2 +- lib/pleroma/web/router.ex | 3 ++ .../activity_pub_controller_test.exs | 29 ++++++++++++++++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 62ad15d85..5a41dac5c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -21,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.Endpoint alias Pleroma.Web.FederatingPlug alias Pleroma.Web.Federator @@ -75,8 +76,8 @@ def user(conn, %{"nickname" => nickname}) do end end - def object(conn, %{"uuid" => uuid}) do - with ap_id <- o_status_url(conn, :object, uuid), + def object(conn, _) do + with ap_id <- Endpoint.url() <> conn.request_path, %Object{} = object <- Object.get_cached_by_ap_id(ap_id), {_, true} <- {:public?, Visibility.is_public?(object)} do conn diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 6971cd9f8..513e69c6e 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -32,7 +32,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do action_fallback(:errors) - def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) + def object(%{assigns: %{format: format}} = conn, _params) when format in ["json", "activity+json"] do ActivityPubController.call(conn, :object) end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index cbe320746..b437e56fb 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -556,6 +556,9 @@ defmodule Pleroma.Web.Router do get("/notice/:id", OStatus.OStatusController, :notice) get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player) + # Mastodon compat routes + get("/users/:nickname/statuses/:id", OStatus.OStatusController, :object) + get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed) get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed) diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index c432c90e3..b247163ec 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do use Pleroma.Web.ConnCase use Oban.Testing, repo: Pleroma.Repo - import Pleroma.Factory alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Delivery @@ -19,8 +18,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Endpoint alias Pleroma.Workers.ReceiverWorker + import Pleroma.Factory + + require Pleroma.Constants + setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) :ok @@ -168,6 +172,29 @@ test "it requires authentication if instance is NOT federating", %{ end end + describe "mastodon compatibility routes" do + test "it returns a json representation of the object with accept application/json", %{ + conn: conn + } do + {:ok, object} = + %{ + "type" => "Note", + "content" => "hey", + "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", + "actor" => Endpoint.url() <> "/users/raymoo", + "to" => [Pleroma.Constants.as_public()] + } + |> Object.create() + + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/users/raymoo/statuses/999999999") + + assert json_response(conn, 200) == ObjectView.render("object.json", %{object: object}) + end + end + describe "/objects/:uuid" do test "it returns a json representation of the object with accept application/json", %{ conn: conn From 8a4bd9e5d17bd1acb5c5a61b85ac125202a4aaa4 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 22 May 2020 16:47:22 +0200 Subject: [PATCH 2/5] OStatusController: Add Mastodon compatibility route for objects. --- lib/pleroma/web/ostatus/ostatus_controller.ex | 4 +-- test/web/ostatus/ostatus_controller_test.exs | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 513e69c6e..b163bfb14 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -37,8 +37,8 @@ def object(%{assigns: %{format: format}} = conn, _params) ActivityPubController.call(conn, :object) end - def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do - with id <- o_status_url(conn, :object, uuid), + def object(%{assigns: %{format: format}} = conn, _params) do + with id <- Endpoint.url() <> conn.request_path, {_, %Activity{} = activity} <- {:activity, Activity.get_create_by_object_ap_id_with_object(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)} do diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index bb349cb19..266fe2f45 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -10,7 +10,11 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do alias Pleroma.Config alias Pleroma.Object alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Endpoint + + require Pleroma.Constants setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -19,6 +23,37 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do setup do: clear_config([:instance, :federating], true) + describe "Mastodon compatibility routes" do + setup %{conn: conn} do + conn = put_req_header(conn, "accept", "text/html") + %{conn: conn} + end + + test "redirects to /notice/:id for html format", %{conn: conn} do + {:ok, object} = + %{ + "type" => "Note", + "content" => "hey", + "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", + "actor" => Endpoint.url() <> "/users/raymoo", + "to" => [Pleroma.Constants.as_public()] + } + |> Object.create() + + {:ok, activity, _} = + %{ + "type" => "Create", + "object" => object.data["id"], + "actor" => object.data["actor"], + "to" => object.data["to"] + } + |> ActivityPub.persist(local: true) + + conn = get(conn, "/users/raymoo/statuses/999999999") + assert redirected_to(conn) == "/notice/#{activity.id}" + end + end + # Note: see ActivityPubControllerTest for JSON format tests describe "GET /objects/:uuid (text/html)" do setup %{conn: conn} do From 355aa3bdc78465a42a9e0b20baaefd4fba04f596 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 22 May 2020 17:06:12 +0200 Subject: [PATCH 3/5] ActivityPubController: Add Mastodon activity compat route. --- .../activity_pub/activity_pub_controller.ex | 4 +-- lib/pleroma/web/common_api/utils.ex | 4 +++ lib/pleroma/web/ostatus/ostatus_controller.ex | 2 +- lib/pleroma/web/router.ex | 3 +- .../activity_pub_controller_test.exs | 32 +++++++++++++++++++ test/web/ostatus/ostatus_controller_test.exs | 1 + 6 files changed, 42 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 5a41dac5c..28727d619 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -102,8 +102,8 @@ def track_object_fetch(conn, object_id) do conn end - def activity(conn, %{"uuid" => uuid}) do - with ap_id <- o_status_url(conn, :activity, uuid), + def activity(conn, _params) do + with ap_id <- Endpoint.url() <> conn.request_path, %Activity{} = activity <- Activity.normalize(ap_id), {_, true} <- {:public?, Visibility.is_public?(activity)} do conn diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index b9fa21648..bf9ca7740 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -468,6 +468,8 @@ def maybe_notify_subscribers( |> Enum.map(& &1.ap_id) recipients ++ subscriber_ids + else + _e -> recipients end end @@ -479,6 +481,8 @@ def maybe_notify_followers(recipients, %Activity{data: %{"type" => "Move"}} = ac |> User.get_followers() |> Enum.map(& &1.ap_id) |> Enum.concat(recipients) + else + _e -> recipients end end diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index b163bfb14..04a4bdeb4 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -54,7 +54,7 @@ def object(%{assigns: %{format: format}} = conn, _params) do end end - def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) + def activity(%{assigns: %{format: format}} = conn, _params) when format in ["json", "activity+json"] do ActivityPubController.call(conn, :activity) end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b437e56fb..08ab3c8bb 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -556,8 +556,9 @@ defmodule Pleroma.Web.Router do get("/notice/:id", OStatus.OStatusController, :notice) get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player) - # Mastodon compat routes + # Mastodon compatibility routes get("/users/:nickname/statuses/:id", OStatus.OStatusController, :object) + get("/users/:nickname/statuses/:id/activity", OStatus.OStatusController, :activity) get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed) get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed) diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index b247163ec..dd2a48a61 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -13,6 +13,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do alias Pleroma.Object alias Pleroma.Tests.ObanHelpers alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.UserView @@ -193,6 +194,37 @@ test "it returns a json representation of the object with accept application/jso assert json_response(conn, 200) == ObjectView.render("object.json", %{object: object}) end + + test "it returns a json representation of the activity with accept application/json", %{ + conn: conn + } do + {:ok, object} = + %{ + "type" => "Note", + "content" => "hey", + "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", + "actor" => Endpoint.url() <> "/users/raymoo", + "to" => [Pleroma.Constants.as_public()] + } + |> Object.create() + + {:ok, activity, _} = + %{ + "id" => object.data["id"] <> "/activity", + "type" => "Create", + "object" => object.data["id"], + "actor" => object.data["actor"], + "to" => object.data["to"] + } + |> ActivityPub.persist(local: true) + + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/users/raymoo/statuses/999999999/activity") + + assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity}) + end end describe "/objects/:uuid" do diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index 266fe2f45..0f973d5b6 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -42,6 +42,7 @@ test "redirects to /notice/:id for html format", %{conn: conn} do {:ok, activity, _} = %{ + "id" => object.data["id"] <> "/activity", "type" => "Create", "object" => object.data["id"], "actor" => object.data["actor"], From 91c8467582d1b4b5ad12256292e86dc1c54f0234 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 22 May 2020 17:11:59 +0200 Subject: [PATCH 4/5] OStatusController: Add Mastodon activity compat route. --- lib/pleroma/web/ostatus/ostatus_controller.ex | 4 ++-- test/web/ostatus/ostatus_controller_test.exs | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 04a4bdeb4..de1b0b3f0 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -59,8 +59,8 @@ def activity(%{assigns: %{format: format}} = conn, _params) ActivityPubController.call(conn, :activity) end - def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do - with id <- o_status_url(conn, :activity, uuid), + def activity(%{assigns: %{format: format}} = conn, _params) do + with id <- Endpoint.url() <> conn.request_path, {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)} do case format do diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index 0f973d5b6..ee498f4b5 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -26,10 +26,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do describe "Mastodon compatibility routes" do setup %{conn: conn} do conn = put_req_header(conn, "accept", "text/html") - %{conn: conn} - end - test "redirects to /notice/:id for html format", %{conn: conn} do {:ok, object} = %{ "type" => "Note", @@ -50,9 +47,21 @@ test "redirects to /notice/:id for html format", %{conn: conn} do } |> ActivityPub.persist(local: true) + %{conn: conn, activity: activity} + end + + test "redirects to /notice/:id for html format", %{conn: conn, activity: activity} do conn = get(conn, "/users/raymoo/statuses/999999999") assert redirected_to(conn) == "/notice/#{activity.id}" end + + test "redirects to /notice/:id for html format for activity", %{ + conn: conn, + activity: activity + } do + conn = get(conn, "/users/raymoo/statuses/999999999/activity") + assert redirected_to(conn) == "/notice/#{activity.id}" + end end # Note: see ActivityPubControllerTest for JSON format tests From 3506e95499133654658c2d653bf636803b61f45f Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 22 May 2020 17:13:09 +0200 Subject: [PATCH 5/5] Add Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c672275e..76277a90e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - **Breaking:** removed `with_move` parameter from notifications timeline. ### Added +- ActivityPub: Added support for existing AP ids for instances migrated from Mastodon. - Instance: Add `background_image` to configuration and `/api/v1/instance` - Instance: Extend `/api/v1/instance` with Pleroma-specific information. - NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.