diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index f5c6e5033..fb602d6b6 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -58,6 +58,20 @@ defmodule Pleroma.HTML do "#{signature}#{to_string(scrubber)}" end) end + + def extract_first_external_url(object, content) do + key = "URL|#{object.id}" + + Cachex.fetch!(:scrubber_cache, key, fn _key -> + result = + content + |> Floki.filter_out("a.mention") + |> Floki.attribute("a", "href") + |> Enum.at(0) + + {:commit, result} + end) + end end defmodule Pleroma.HTML.Scrubber.TwitterText do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index f4736fcb5..a60532b55 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller alias Pleroma.{Repo, Object, Activity, User, Notification, Stats} alias Pleroma.Web + alias Pleroma.HTML alias Pleroma.Web.MastodonAPI.{ StatusView, @@ -1322,6 +1323,29 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def get_status_card(status_id) do + with %Activity{} = activity <- Repo.get(Activity, status_id), + true <- ActivityPub.is_public?(activity), + %Object{} = object <- Object.normalize(activity.data["object"]), + page_url <- HTML.extract_first_external_url(object, object.data["content"]), + {:ok, rich_media} <- Pleroma.Web.RichMedia.Parser.parse(page_url) do + page_url = rich_media[:url] || page_url + site_name = rich_media[:site_name] || URI.parse(page_url).host + + rich_media + |> Map.take([:image, :title, :description]) + |> Map.put(:type, "link") + |> Map.put(:provider_name, site_name) + |> Map.put(:url, page_url) + else + _ -> %{} + end + end + + def status_card(conn, %{"id" => status_id}) do + json(conn, get_status_card(status_id)) + end + def try_render(conn, target, params) when is_binary(target) do res = render(conn, target, params) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b83790858..e749aa834 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -258,7 +258,7 @@ defmodule Pleroma.Web.Router do get("/statuses/:id", MastodonAPIController, :get_status) get("/statuses/:id/context", MastodonAPIController, :get_context) - get("/statuses/:id/card", MastodonAPIController, :empty_object) + get("/statuses/:id/card", MastodonAPIController, :status_card) get("/statuses/:id/favourited_by", MastodonAPIController, :favourited_by) get("/statuses/:id/reblogged_by", MastodonAPIController, :reblogged_by) diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index e4279e14d..3043d2be6 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -653,6 +653,14 @@ defmodule HttpRequestMock do {:ok, Tesla.Mock.json(%{"id" => "https://social.heldscal.la/user/23211"}, status: 200)} end + def get("http://example.com/ogp", _, _, _) do + {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}} + end + + def get("http://example.com/empty", _, _, _) do + {:ok, %Tesla.Env{status: 200, body: "hello"}} + end + def get(url, query, body, headers) do {:error, "Not implemented the mock response for get #{inspect(url)}, #{query}, #{inspect(body)}, #{ diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 6004285d6..55e778e4f 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1623,5 +1623,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do |> post("/api/v1/statuses/#{activity_two.id}/pin") |> json_response(400) end + + test "Status rich-media Card", %{conn: conn, user: user} do + {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"}) + + response = + conn + |> get("/api/v1/statuses/#{activity.id}/card") + |> json_response(200) + + assert response == %{ + "image" => "http://ia.media-imdb.com/images/rock.jpg", + "provider_name" => "www.imdb.com", + "title" => "The Rock", + "type" => "link", + "url" => "http://www.imdb.com/title/tt0117500/" + } + end end end diff --git a/test/web/rich_media/controllers/rich_media_controller_test.exs b/test/web/rich_media/controllers/rich_media_controller_test.exs index 37c82631f..fef126513 100644 --- a/test/web/rich_media/controllers/rich_media_controller_test.exs +++ b/test/web/rich_media/controllers/rich_media_controller_test.exs @@ -1,19 +1,14 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.RichMedia.RichMediaControllerTest do use Pleroma.Web.ConnCase import Pleroma.Factory + import Tesla.Mock setup do - Tesla.Mock.mock(fn - %{ - method: :get, - url: "http://example.com/ogp" - } -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")} - - %{method: :get, url: "http://example.com/empty"} -> - %Tesla.Env{status: 200, body: "hello"} - end) - + mock(fn env -> apply(HttpRequestMock, :request, [env]) end) :ok end