forked from AkkomaGang/akkoma
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:
commit
7bc2ec0aa2
7 changed files with 125 additions and 11 deletions
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue