Merge branch 'mastodon-migration-compat' into 'develop'

Add compatibility routes for converted mastodon instances

Closes #1797

See merge request pleroma/pleroma!2572
This commit is contained in:
rinpatch 2020-05-24 19:05:57 +00:00
commit 7bc2ec0aa2
7 changed files with 125 additions and 11 deletions

View file

@ -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. - **Breaking:** removed `with_move` parameter from notifications timeline.
### Added ### Added
- ActivityPub: Added support for existing AP ids for instances migrated from Mastodon.
- Instance: Add `background_image` to configuration and `/api/v1/instance` - Instance: Add `background_image` to configuration and `/api/v1/instance`
- Instance: Extend `/api/v1/instance` with Pleroma-specific information. - Instance: Extend `/api/v1/instance` with Pleroma-specific information.
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list. - NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.

View file

@ -21,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Endpoint
alias Pleroma.Web.FederatingPlug alias Pleroma.Web.FederatingPlug
alias Pleroma.Web.Federator alias Pleroma.Web.Federator
@ -75,8 +76,8 @@ def user(conn, %{"nickname" => nickname}) do
end end
end end
def object(conn, %{"uuid" => uuid}) do def object(conn, _) do
with ap_id <- o_status_url(conn, :object, uuid), with ap_id <- Endpoint.url() <> conn.request_path,
%Object{} = object <- Object.get_cached_by_ap_id(ap_id), %Object{} = object <- Object.get_cached_by_ap_id(ap_id),
{_, true} <- {:public?, Visibility.is_public?(object)} do {_, true} <- {:public?, Visibility.is_public?(object)} do
conn conn
@ -101,8 +102,8 @@ def track_object_fetch(conn, object_id) do
conn conn
end end
def activity(conn, %{"uuid" => uuid}) do def activity(conn, _params) do
with ap_id <- o_status_url(conn, :activity, uuid), with ap_id <- Endpoint.url() <> conn.request_path,
%Activity{} = activity <- Activity.normalize(ap_id), %Activity{} = activity <- Activity.normalize(ap_id),
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.is_public?(activity)} do
conn conn

View file

@ -470,6 +470,8 @@ def maybe_notify_subscribers(
|> Enum.map(& &1.ap_id) |> Enum.map(& &1.ap_id)
recipients ++ subscriber_ids recipients ++ subscriber_ids
else
_e -> recipients
end end
end end
@ -481,6 +483,8 @@ def maybe_notify_followers(recipients, %Activity{data: %{"type" => "Move"}} = ac
|> User.get_followers() |> User.get_followers()
|> Enum.map(& &1.ap_id) |> Enum.map(& &1.ap_id)
|> Enum.concat(recipients) |> Enum.concat(recipients)
else
_e -> recipients
end end
end end

View file

@ -32,13 +32,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
action_fallback(:errors) 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 when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :object) ActivityPubController.call(conn, :object)
end end
def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do def object(%{assigns: %{format: format}} = conn, _params) do
with id <- o_status_url(conn, :object, uuid), with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {_, %Activity{} = activity} <-
{:activity, Activity.get_create_by_object_ap_id_with_object(id)}, {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.is_public?(activity)} do
@ -54,13 +54,13 @@ def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
end end
end end
def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) def activity(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :activity) ActivityPubController.call(conn, :activity)
end end
def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do def activity(%{assigns: %{format: format}} = conn, _params) do
with id <- o_status_url(conn, :activity, uuid), with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.is_public?(activity)} do
case format do case format do

View file

@ -556,6 +556,10 @@ defmodule Pleroma.Web.Router do
get("/notice/:id", OStatus.OStatusController, :notice) get("/notice/:id", OStatus.OStatusController, :notice)
get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player) get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player)
# 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", Feed.UserController, :feed, as: :user_feed)
get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed) get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed)

View file

@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
use Pleroma.Web.ConnCase use Pleroma.Web.ConnCase
use Oban.Testing, repo: Pleroma.Repo use Oban.Testing, repo: Pleroma.Repo
import Pleroma.Factory
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Config alias Pleroma.Config
alias Pleroma.Delivery alias Pleroma.Delivery
@ -14,13 +13,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers alias Pleroma.Tests.ObanHelpers
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
alias Pleroma.Workers.ReceiverWorker alias Pleroma.Workers.ReceiverWorker
import Pleroma.Factory
require Pleroma.Constants
setup_all do setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok :ok
@ -168,6 +173,60 @@ test "it requires authentication if instance is NOT federating", %{
end end
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
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 describe "/objects/:uuid" do
test "it returns a json representation of the object with accept application/json", %{ test "it returns a json representation of the object with accept application/json", %{
conn: conn conn: conn

View file

@ -10,7 +10,11 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
alias Pleroma.Config alias Pleroma.Config
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
require Pleroma.Constants
setup_all do setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@ -19,6 +23,47 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
setup do: clear_config([:instance, :federating], true) setup do: clear_config([:instance, :federating], true)
describe "Mastodon compatibility routes" do
setup %{conn: conn} do
conn = put_req_header(conn, "accept", "text/html")
{: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, 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 # Note: see ActivityPubControllerTest for JSON format tests
describe "GET /objects/:uuid (text/html)" do describe "GET /objects/:uuid (text/html)" do
setup %{conn: conn} do setup %{conn: conn} do