From 2ad50583f0cc341413663a595890047823c9abeb Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 23 Sep 2019 18:54:23 +0200 Subject: [PATCH 1/6] Document and test /api/ap/whoami --- .../web/activity_pub/activity_pub_controller.ex | 1 + .../activity_pub/activity_pub_controller_test.exs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 01b34fb1d..34bf04a20 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -293,6 +293,7 @@ def internal_fetch(conn, _params) do |> represent_service_actor(conn) end + @doc "Returns the authenticated user's ActivityPub User object or a 404 Not Found if non-authenticated" def whoami(%{assigns: %{user: %User{} = user}} = conn, _params) do conn |> put_resp_content_type("application/activity+json") diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 9e8e420ec..0f8638a94 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -976,4 +976,19 @@ test "it tracks a signed activity fetch when the json is cached", %{conn: conn} assert Delivery.get(object.id, other_user.id) end end + + describe "Additionnal ActivityPub C2S endpoints" do + test "/api/ap/whoami", %{conn: conn} do + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> get("/api/ap/whoami") + + user = User.get_cached_by_id(user.id) + + assert UserView.render("user.json", %{user: user}) == json_response(conn, 200) + end + end end From 815b9045087ff4f88355b4cfa6c0a9b8080c6db6 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 23 Sep 2019 19:16:36 +0200 Subject: [PATCH 2/6] Add support for AP C2S uploadMedia Closes: https://git.pleroma.social/pleroma/pleroma/issues/1171 --- .../activity_pub/activity_pub_controller.ex | 27 +++++++++++++++++++ .../web/activity_pub/views/user_view.ex | 3 ++- lib/pleroma/web/router.ex | 1 + .../activity_pub_controller_test.exs | 25 +++++++++++++++++ test/web/ostatus/ostatus_controller_test.exs | 6 +++-- 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 34bf04a20..6b60132d4 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -443,4 +443,31 @@ defp ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user) do {new_user, for_user} end + + # TODO: Add support for "object" field + @doc """ + Endpoint based on + + Parameters: + - (required) `file`: data of the media + - (optionnal) `description`: description of the media, intended for accessibility + + Response: + - HTTP Code: 201 Created + - HTTP Body: ActivityPub object to be inserted into another's `attachment` field + """ + def upload_media(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do + with {:ok, object} <- + ActivityPub.upload( + file, + actor: User.ap_id(user), + description: Map.get(data, "description") + ) do + Logger.debug(inspect(object)) + + conn + |> put_status(:created) + |> json(object.data) + end + end end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index a2f73e140..ff54b95ed 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -25,7 +25,8 @@ def render("endpoints.json", %{user: %User{local: true} = _user}) do "oauthAuthorizationEndpoint" => Helpers.o_auth_url(Endpoint, :authorize), "oauthRegistrationEndpoint" => Helpers.mastodon_api_url(Endpoint, :create_app), "oauthTokenEndpoint" => Helpers.o_auth_url(Endpoint, :token_exchange), - "sharedInbox" => Helpers.activity_pub_url(Endpoint, :inbox) + "sharedInbox" => Helpers.activity_pub_url(Endpoint, :inbox), + "uploadMedia" => Helpers.activity_pub_url(Endpoint, :upload_media) } end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b9b85fd67..8ee188f08 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -572,6 +572,7 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_write) post("/users/:nickname/outbox", ActivityPubController, :update_outbox) + post("/api/ap/uploadMedia", ActivityPubController, :upload_media) end scope [] do diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 0f8638a94..c2bcddf85 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -990,5 +990,30 @@ test "/api/ap/whoami", %{conn: conn} do assert UserView.render("user.json", %{user: user}) == json_response(conn, 200) end + + clear_config([:media_proxy]) + clear_config([Pleroma.Upload]) + + test "uploadMedia", %{conn: conn} do + user = insert(:user) + + desc = "Description of the image" + + image = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + conn = + conn + |> assign(:user, user) + |> post("/api/ap/uploadMedia", %{"file" => image, "description" => desc}) + + assert object = json_response(conn, :created) + assert object["name"] == desc + assert object["type"] == "Document" + assert object["actor"] == user.ap_id + end end end diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index ec96f0012..fc1635a2f 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -400,7 +400,8 @@ test "activity+json format. it redirects on actual feed of user", %{conn: conn} "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", - "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox" + "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", + "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/uploadMedia" } assert response["@context"] == [ @@ -462,7 +463,8 @@ test "json format. it redirects on actual feed of user", %{conn: conn} do "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", - "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox" + "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", + "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/uploadMedia" } assert response["@context"] == [ From 5820dc40fcf325b882344258fe26fc662b7afb54 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 24 Sep 2019 19:00:31 +0200 Subject: [PATCH 3/6] litepub-0.1.jsonld: Add uploadMedia --- priv/static/schemas/litepub-0.1.jsonld | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld index 57ed05eba..c312648ea 100644 --- a/priv/static/schemas/litepub-0.1.jsonld +++ b/priv/static/schemas/litepub-0.1.jsonld @@ -27,6 +27,10 @@ "oauthRegistrationEndpoint": { "@id": "litepub:oauthRegistrationEndpoint", "@type": "@id" + }, + "uploadMedia": { + "@id": "litepub:uploadMedia", + "@type": "@id" } } ] From 0dc8f3d6d2fa18261e9a6fa8da540c434f1fa67b Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 24 Sep 2019 19:03:06 +0200 Subject: [PATCH 4/6] =?UTF-8?q?/api/ap/uploadMedia=20=E2=86=92=20/api/ap/u?= =?UTF-8?q?pload=5Fmedia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pleroma/web/router.ex | 2 +- test/web/activity_pub/activity_pub_controller_test.exs | 2 +- test/web/ostatus/ostatus_controller_test.exs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8ee188f08..2e8fda4ab 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -572,7 +572,7 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_write) post("/users/:nickname/outbox", ActivityPubController, :update_outbox) - post("/api/ap/uploadMedia", ActivityPubController, :upload_media) + post("/api/ap/upload_media", ActivityPubController, :upload_media) end scope [] do diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index c2bcddf85..8868d8a0d 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -1008,7 +1008,7 @@ test "uploadMedia", %{conn: conn} do conn = conn |> assign(:user, user) - |> post("/api/ap/uploadMedia", %{"file" => image, "description" => desc}) + |> post("/api/ap/upload_media", %{"file" => image, "description" => desc}) assert object = json_response(conn, :created) assert object["name"] == desc diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index fc1635a2f..3a867b8c0 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -401,7 +401,7 @@ test "activity+json format. it redirects on actual feed of user", %{conn: conn} "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", - "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/uploadMedia" + "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" } assert response["@context"] == [ @@ -464,7 +464,7 @@ test "json format. it redirects on actual feed of user", %{conn: conn} do "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", - "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/uploadMedia" + "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" } assert response["@context"] == [ From b7f27a4f584e54b13d0b7c1b288ad3e7bffcf95a Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 30 Sep 2019 17:04:03 +0700 Subject: [PATCH 5/6] Extract report actions from `MastodonAPIController` to `ReportController` Update MastodonAPI.ReportView --- .../controllers/mastodon_api_controller.ex | 15 ---- .../controllers/report_controller.ex | 16 ++++ .../web/mastodon_api/views/report_view.ex | 2 +- lib/pleroma/web/router.ex | 2 +- .../controllers/report_controller_test.exs | 88 +++++++++++++++++++ .../mastodon_api_controller_test.exs | 79 ----------------- 6 files changed, 106 insertions(+), 96 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/controllers/report_controller.ex create mode 100644 test/web/mastodon_api/controllers/report_controller_test.exs diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 0878f7ba6..1ec699b6f 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -31,7 +31,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI alias Pleroma.Web.MastodonAPI.MastodonView - alias Pleroma.Web.MastodonAPI.ReportView alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy alias Pleroma.Web.OAuth.App @@ -946,20 +945,6 @@ defp fetch_suggestion_id(attrs) do end end - def reports(%{assigns: %{user: user}} = conn, params) do - case CommonAPI.report(user, params) do - {:ok, activity} -> - conn - |> put_view(ReportView) - |> try_render("report.json", %{activity: activity}) - - {:error, err} -> - conn - |> put_status(:bad_request) - |> json(%{error: err}) - end - end - def account_register( %{assigns: %{app: app}} = conn, %{"username" => nickname, "email" => _, "password" => _, "agreement" => true} = params diff --git a/lib/pleroma/web/mastodon_api/controllers/report_controller.ex b/lib/pleroma/web/mastodon_api/controllers/report_controller.ex new file mode 100644 index 000000000..1c084b740 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/report_controller.ex @@ -0,0 +1,16 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ReportController do + use Pleroma.Web, :controller + + action_fallback(Pleroma.Web.MastodonAPI.FallbackController) + + @doc "POST /api/v1/reports" + def create(%{assigns: %{user: user}} = conn, params) do + with {:ok, activity} <- Pleroma.Web.CommonAPI.report(user, params) do + render(conn, "show.json", activity: activity) + end + end +end diff --git a/lib/pleroma/web/mastodon_api/views/report_view.ex b/lib/pleroma/web/mastodon_api/views/report_view.ex index a16e7ff10..9da2dd740 100644 --- a/lib/pleroma/web/mastodon_api/views/report_view.ex +++ b/lib/pleroma/web/mastodon_api/views/report_view.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Web.MastodonAPI.ReportView do use Pleroma.Web, :view - def render("report.json", %{activity: activity}) do + def render("show.json", %{activity: activity}) do %{ id: to_string(activity.id), action_taken: false diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 805bef16f..7bdc80fcc 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -396,7 +396,7 @@ defmodule Pleroma.Web.Router do get("/pleroma/mascot", MastodonAPIController, :get_mascot) put("/pleroma/mascot", MastodonAPIController, :set_mascot) - post("/reports", MastodonAPIController, :reports) + post("/reports", ReportController, :create) end scope [] do diff --git a/test/web/mastodon_api/controllers/report_controller_test.exs b/test/web/mastodon_api/controllers/report_controller_test.exs new file mode 100644 index 000000000..fcece40fb --- /dev/null +++ b/test/web/mastodon_api/controllers/report_controller_test.exs @@ -0,0 +1,88 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Web.CommonAPI + + import Pleroma.Factory + + setup do + reporter = insert(:user) + target_user = insert(:user) + + {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"}) + + [reporter: reporter, target_user: target_user, activity: activity] + end + + test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do + assert %{"action_taken" => false, "id" => _} = + conn + |> assign(:user, reporter) + |> post("/api/v1/reports", %{"account_id" => target_user.id}) + |> json_response(200) + end + + test "submit a report with statuses and comment", %{ + conn: conn, + reporter: reporter, + target_user: target_user, + activity: activity + } do + assert %{"action_taken" => false, "id" => _} = + conn + |> assign(:user, reporter) + |> post("/api/v1/reports", %{ + "account_id" => target_user.id, + "status_ids" => [activity.id], + "comment" => "bad status!", + "forward" => "false" + }) + |> json_response(200) + end + + test "account_id is required", %{ + conn: conn, + reporter: reporter, + activity: activity + } do + assert %{"error" => "Valid `account_id` required"} = + conn + |> assign(:user, reporter) + |> post("/api/v1/reports", %{"status_ids" => [activity.id]}) + |> json_response(400) + end + + test "comment must be up to the size specified in the config", %{ + conn: conn, + reporter: reporter, + target_user: target_user + } do + max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000) + comment = String.pad_trailing("a", max_size + 1, "a") + + error = %{"error" => "Comment must be up to #{max_size} characters"} + + assert ^error = + conn + |> assign(:user, reporter) + |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment}) + |> json_response(400) + end + + test "returns error when account is not exist", %{ + conn: conn, + reporter: reporter, + activity: activity + } do + conn = + conn + |> assign(:user, reporter) + |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"}) + + assert json_response(conn, 400) == %{"error" => "Account not found"} + end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b3acb7a22..d316a61c1 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1380,85 +1380,6 @@ test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do end end - describe "reports" do - setup do - reporter = insert(:user) - target_user = insert(:user) - - {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"}) - - [reporter: reporter, target_user: target_user, activity: activity] - end - - test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do - assert %{"action_taken" => false, "id" => _} = - conn - |> assign(:user, reporter) - |> post("/api/v1/reports", %{"account_id" => target_user.id}) - |> json_response(200) - end - - test "submit a report with statuses and comment", %{ - conn: conn, - reporter: reporter, - target_user: target_user, - activity: activity - } do - assert %{"action_taken" => false, "id" => _} = - conn - |> assign(:user, reporter) - |> post("/api/v1/reports", %{ - "account_id" => target_user.id, - "status_ids" => [activity.id], - "comment" => "bad status!", - "forward" => "false" - }) - |> json_response(200) - end - - test "account_id is required", %{ - conn: conn, - reporter: reporter, - activity: activity - } do - assert %{"error" => "Valid `account_id` required"} = - conn - |> assign(:user, reporter) - |> post("/api/v1/reports", %{"status_ids" => [activity.id]}) - |> json_response(400) - end - - test "comment must be up to the size specified in the config", %{ - conn: conn, - reporter: reporter, - target_user: target_user - } do - max_size = Config.get([:instance, :max_report_comment_size], 1000) - comment = String.pad_trailing("a", max_size + 1, "a") - - error = %{"error" => "Comment must be up to #{max_size} characters"} - - assert ^error = - conn - |> assign(:user, reporter) - |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment}) - |> json_response(400) - end - - test "returns error when account is not exist", %{ - conn: conn, - reporter: reporter, - activity: activity - } do - conn = - conn - |> assign(:user, reporter) - |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"}) - - assert json_response(conn, 400) == %{"error" => "Account not found"} - end - end - describe "link headers" do test "preserves parameters in link headers", %{conn: conn} do user = insert(:user) From 1207e8819507aac55e5725f383987b0078bb1cbe Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 30 Sep 2019 18:30:10 +0700 Subject: [PATCH 6/6] Fix ReportControllerTest --- test/web/mastodon_api/controllers/report_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/controllers/report_controller_test.exs b/test/web/mastodon_api/controllers/report_controller_test.exs index fcece40fb..979ca48f3 100644 --- a/test/web/mastodon_api/controllers/report_controller_test.exs +++ b/test/web/mastodon_api/controllers/report_controller_test.exs @@ -2,7 +2,7 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do +defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Web.CommonAPI