fix(mastodon-api): finish preview card compatibility
This commit is contained in:
parent
7a741736ea
commit
c591ca518c
6 changed files with 174 additions and 115 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
defmodule Pleroma.Web.ApiSpec.Schemas.ChatMessage do
|
defmodule Pleroma.Web.ApiSpec.Schemas.ChatMessage do
|
||||||
alias OpenApiSpex.Schema
|
alias OpenApiSpex.Schema
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Emoji
|
alias Pleroma.Web.ApiSpec.Schemas.Emoji
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.PreviewCard
|
||||||
|
|
||||||
require OpenApiSpex
|
require OpenApiSpex
|
||||||
|
|
||||||
|
|
@ -22,36 +23,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.ChatMessage do
|
||||||
emojis: %Schema{type: :array, items: Emoji},
|
emojis: %Schema{type: :array, items: Emoji},
|
||||||
attachment: %Schema{type: :object, nullable: true},
|
attachment: %Schema{type: :object, nullable: true},
|
||||||
card: %Schema{
|
card: %Schema{
|
||||||
type: :object,
|
allOf: [PreviewCard],
|
||||||
nullable: true,
|
nullable: true
|
||||||
description: "Preview card for links included within status content",
|
|
||||||
required: [:url, :title, :description, :type],
|
|
||||||
properties: %{
|
|
||||||
type: %Schema{
|
|
||||||
type: :string,
|
|
||||||
enum: ["link", "photo", "video", "rich"],
|
|
||||||
description: "The type of the preview card"
|
|
||||||
},
|
|
||||||
provider_name: %Schema{
|
|
||||||
type: :string,
|
|
||||||
nullable: true,
|
|
||||||
description: "The provider of the original resource"
|
|
||||||
},
|
|
||||||
provider_url: %Schema{
|
|
||||||
type: :string,
|
|
||||||
format: :uri,
|
|
||||||
description: "A link to the provider of the original resource"
|
|
||||||
},
|
|
||||||
url: %Schema{type: :string, format: :uri, description: "Location of linked resource"},
|
|
||||||
image: %Schema{
|
|
||||||
type: :string,
|
|
||||||
nullable: true,
|
|
||||||
format: :uri,
|
|
||||||
description: "Preview thumbnail"
|
|
||||||
},
|
|
||||||
title: %Schema{type: :string, description: "Title of linked resource"},
|
|
||||||
description: %Schema{type: :string, description: "Description of preview"}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
unread: %Schema{type: :boolean, description: "Whether a message has been marked as read."}
|
unread: %Schema{type: :boolean, description: "Whether a message has been marked as read."}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
109
lib/pleroma/web/api_spec/schemas/preview_card.ex
Normal file
109
lib/pleroma/web/api_spec/schemas/preview_card.ex
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ApiSpec.Schemas.PreviewCard do
|
||||||
|
alias OpenApiSpex.Schema
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.Account
|
||||||
|
|
||||||
|
require OpenApiSpex
|
||||||
|
|
||||||
|
OpenApiSpex.schema(%{
|
||||||
|
title: "PreviewCard",
|
||||||
|
description: "Preview card for a link included within status or chat message content",
|
||||||
|
type: :object,
|
||||||
|
required: [
|
||||||
|
:url,
|
||||||
|
:title,
|
||||||
|
:description,
|
||||||
|
:language,
|
||||||
|
:type,
|
||||||
|
:authors,
|
||||||
|
:author_name,
|
||||||
|
:author_url,
|
||||||
|
:provider_name,
|
||||||
|
:provider_url,
|
||||||
|
:html,
|
||||||
|
:width,
|
||||||
|
:height,
|
||||||
|
:image,
|
||||||
|
:image_description,
|
||||||
|
:embed_url,
|
||||||
|
:blurhash,
|
||||||
|
:published_at
|
||||||
|
],
|
||||||
|
properties: %{
|
||||||
|
url: %Schema{type: :string, format: :uri, description: "Location of linked resource"},
|
||||||
|
title: %Schema{type: :string, description: "Title of linked resource"},
|
||||||
|
description: %Schema{type: :string, description: "Description of preview"},
|
||||||
|
language: %Schema{
|
||||||
|
type: :string,
|
||||||
|
nullable: true,
|
||||||
|
description: "Language of the linked resource"
|
||||||
|
},
|
||||||
|
type: %Schema{
|
||||||
|
type: :string,
|
||||||
|
enum: ["link", "photo", "video", "rich"],
|
||||||
|
description: "The type of the preview card"
|
||||||
|
},
|
||||||
|
authors: %Schema{
|
||||||
|
type: :array,
|
||||||
|
description: "Fediverse accounts of the authors of the original resource",
|
||||||
|
items: %Schema{
|
||||||
|
type: :object,
|
||||||
|
required: [:name, :url, :account],
|
||||||
|
properties: %{
|
||||||
|
name: %Schema{type: :string},
|
||||||
|
url: %Schema{type: :string},
|
||||||
|
account: %Schema{allOf: [Account], nullable: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
author_name: %Schema{type: :string, description: "Author of the original resource"},
|
||||||
|
author_url: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "Link to the author of the original resource"
|
||||||
|
},
|
||||||
|
provider_name: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "The provider of the original resource"
|
||||||
|
},
|
||||||
|
provider_url: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "A link to the provider of the original resource"
|
||||||
|
},
|
||||||
|
html: %Schema{
|
||||||
|
type: :string,
|
||||||
|
format: :html,
|
||||||
|
description: "HTML to be used for generating the preview card"
|
||||||
|
},
|
||||||
|
width: %Schema{type: :integer, description: "Width of preview, in pixels"},
|
||||||
|
height: %Schema{type: :integer, description: "Height of preview, in pixels"},
|
||||||
|
image: %Schema{
|
||||||
|
type: :string,
|
||||||
|
nullable: true,
|
||||||
|
format: :uri,
|
||||||
|
description: "Preview thumbnail"
|
||||||
|
},
|
||||||
|
image_description: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "Alternate text that describes what is in the thumbnail"
|
||||||
|
},
|
||||||
|
embed_url: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "Used for photo embeds, instead of custom `html`"
|
||||||
|
},
|
||||||
|
blurhash: %Schema{
|
||||||
|
type: :string,
|
||||||
|
nullable: true,
|
||||||
|
description:
|
||||||
|
"A hash computed by the [BlurHash algorithm](https://github.com/woltapp/blurhash), for generating colorful preview thumbnails when media has not been downloaded yet."
|
||||||
|
},
|
||||||
|
published_at: %Schema{
|
||||||
|
type: :string,
|
||||||
|
nullable: true,
|
||||||
|
description: "Publication date of the linked resource"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Emoji
|
alias Pleroma.Web.ApiSpec.Schemas.Emoji
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Poll
|
alias Pleroma.Web.ApiSpec.Schemas.Poll
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.PreviewCard
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Tag
|
alias Pleroma.Web.ApiSpec.Schemas.Tag
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
||||||
|
|
||||||
|
|
@ -31,79 +32,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
|
||||||
},
|
},
|
||||||
bookmarked: %Schema{type: :boolean, description: "Have you bookmarked this status?"},
|
bookmarked: %Schema{type: :boolean, description: "Have you bookmarked this status?"},
|
||||||
card: %Schema{
|
card: %Schema{
|
||||||
type: :object,
|
allOf: [PreviewCard],
|
||||||
nullable: true,
|
nullable: true
|
||||||
description: "Preview card for links included within status content",
|
|
||||||
# Yeah, it's effectivelly all required in MastoAPI so far
|
|
||||||
required: [
|
|
||||||
:url,
|
|
||||||
:title,
|
|
||||||
:description,
|
|
||||||
:type,
|
|
||||||
:author_name,
|
|
||||||
:author_url,
|
|
||||||
:provider_name,
|
|
||||||
:provider_url,
|
|
||||||
:html,
|
|
||||||
:width,
|
|
||||||
:height,
|
|
||||||
:image,
|
|
||||||
:embed_url,
|
|
||||||
:blurhash
|
|
||||||
],
|
|
||||||
properties: %{
|
|
||||||
url: %Schema{type: :string, format: :uri, description: "Location of linked resource"},
|
|
||||||
title: %Schema{type: :string, description: "Title of linked resource"},
|
|
||||||
description: %Schema{type: :string, description: "Description of preview"},
|
|
||||||
type: %Schema{
|
|
||||||
type: :string,
|
|
||||||
enum: ["link", "photo", "video", "rich"],
|
|
||||||
description: "The type of the preview card"
|
|
||||||
},
|
|
||||||
author_name: %Schema{type: :string, description: "author of the original resource"},
|
|
||||||
author_url: %Schema{
|
|
||||||
type: :string,
|
|
||||||
format: :uri,
|
|
||||||
description: "link to the author of the original resource"
|
|
||||||
},
|
|
||||||
provider_name: %Schema{
|
|
||||||
type: :string,
|
|
||||||
description: "The provider of the original resource"
|
|
||||||
},
|
|
||||||
provider_url: %Schema{
|
|
||||||
type: :string,
|
|
||||||
format: :uri,
|
|
||||||
description: "A link to the provider of the original resource"
|
|
||||||
},
|
|
||||||
html: %Schema{
|
|
||||||
type: :string,
|
|
||||||
format: :html,
|
|
||||||
description: "HTML to be used for generating the preview card"
|
|
||||||
},
|
|
||||||
width: %Schema{type: :integer, description: "Width of preview, in pixels"},
|
|
||||||
height: %Schema{type: :integer, description: "Height of preview, in pixels"},
|
|
||||||
image: %Schema{
|
|
||||||
type: :string,
|
|
||||||
nullable: true,
|
|
||||||
format: :uri,
|
|
||||||
description: "Preview thumbnail"
|
|
||||||
},
|
|
||||||
image_description: %Schema{
|
|
||||||
type: :string,
|
|
||||||
description: "Alternate text that describes what is in the thumbnail"
|
|
||||||
},
|
|
||||||
embed_url: %Schema{
|
|
||||||
type: :string,
|
|
||||||
format: :uri,
|
|
||||||
description: "Used for photo embeds, instead of custom `html`"
|
|
||||||
},
|
|
||||||
blurhash: %Schema{
|
|
||||||
type: :string,
|
|
||||||
nullable: true,
|
|
||||||
description:
|
|
||||||
"A hash computed by the (BlurHash algorithm)[https://github.com/woltapp/blurhash], for generating colorful preview thumbnails when media has not been downloaded yet."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
content: %Schema{type: :string, format: :html, description: "HTML-encoded status content"},
|
content: %Schema{type: :string, format: :html, description: "HTML-encoded status content"},
|
||||||
text: %Schema{
|
text: %Schema{
|
||||||
|
|
|
||||||
|
|
@ -587,21 +587,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
video_url = proxied_url(rich_media["video"], page_url_data)
|
video_url = proxied_url(rich_media["video"], page_url_data)
|
||||||
|
|
||||||
%{
|
%{
|
||||||
type: "link",
|
type: card_type(rich_media["type"]),
|
||||||
provider_name: page_url_data.host,
|
provider_name: rich_media["provider_name"] || page_url_data.host,
|
||||||
provider_url: page_url_data.scheme <> "://" <> page_url_data.host,
|
provider_url:
|
||||||
|
rich_media["provider_url"] || page_url_data.scheme <> "://" <> page_url_data.host,
|
||||||
url: page_url,
|
url: page_url,
|
||||||
image: image_url,
|
image: image_url,
|
||||||
image_description: rich_media["image:alt"] || "",
|
image_description: rich_media["image:alt"] || "",
|
||||||
title: rich_media["title"] || "",
|
title: rich_media["title"] || "",
|
||||||
description: rich_media["description"] || "",
|
description: rich_media["description"] || "",
|
||||||
author_name: "",
|
language: nil,
|
||||||
author_url: "",
|
authors: [],
|
||||||
html: "",
|
author_name: rich_media["author_name"] || "",
|
||||||
width: 0,
|
author_url: rich_media["author_url"] || "",
|
||||||
height: 0,
|
html: rich_media["html"] || "",
|
||||||
embed_url: "",
|
width: card_dimension(rich_media["width"]),
|
||||||
|
height: card_dimension(rich_media["height"]),
|
||||||
|
embed_url: rich_media["embed_url"] || "",
|
||||||
blurhash: nil,
|
blurhash: nil,
|
||||||
|
published_at: nil,
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
opengraph:
|
opengraph:
|
||||||
rich_media
|
rich_media
|
||||||
|
|
@ -706,6 +710,20 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
%{content: content, detected_source_language: detected_source_language, provider: provider}
|
%{content: content, detected_source_language: detected_source_language, provider: provider}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp card_type(type) when type in ["link", "photo", "video", "rich"], do: type
|
||||||
|
defp card_type(_), do: "link"
|
||||||
|
|
||||||
|
defp card_dimension(value) when is_integer(value) and value >= 0, do: value
|
||||||
|
|
||||||
|
defp card_dimension(value) when is_binary(value) do
|
||||||
|
case Integer.parse(value) do
|
||||||
|
{dimension, ""} when dimension >= 0 -> dimension
|
||||||
|
_ -> 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp card_dimension(_), do: 0
|
||||||
|
|
||||||
def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
|
def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
|
||||||
object = Object.normalize(activity, fetch: false)
|
object = Object.normalize(activity, fetch: false)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2430,6 +2430,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
|
|
||||||
describe "cards" do
|
describe "cards" do
|
||||||
setup do
|
setup do
|
||||||
|
clear_config([:rich_media, :enabled], true)
|
||||||
|
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
|
||||||
|
|
||||||
Pleroma.StaticStubbedConfigMock
|
Pleroma.StaticStubbedConfigMock
|
||||||
|> stub(:get, fn
|
|> stub(:get, fn
|
||||||
[:rich_media, :enabled] -> true
|
[:rich_media, :enabled] -> true
|
||||||
|
|
@ -2443,6 +2446,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp"})
|
||||||
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
card_data = %{
|
card_data = %{
|
||||||
"image" => "http://ia.media-imdb.com/images/rock.jpg",
|
"image" => "http://ia.media-imdb.com/images/rock.jpg",
|
||||||
|
|
@ -2465,10 +2469,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
},
|
},
|
||||||
"author_name" => "",
|
"author_name" => "",
|
||||||
"author_url" => "",
|
"author_url" => "",
|
||||||
|
"authors" => [],
|
||||||
"blurhash" => nil,
|
"blurhash" => nil,
|
||||||
"embed_url" => "",
|
"embed_url" => "",
|
||||||
"height" => 0,
|
"height" => 0,
|
||||||
"html" => "",
|
"html" => "",
|
||||||
|
"image_description" => "",
|
||||||
|
"language" => nil,
|
||||||
|
"published_at" => nil,
|
||||||
"width" => 0
|
"width" => 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2495,6 +2503,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp-missing-data"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp-missing-data"})
|
||||||
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
response =
|
response =
|
||||||
conn
|
conn
|
||||||
|
|
@ -2518,10 +2527,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
},
|
},
|
||||||
"author_name" => "",
|
"author_name" => "",
|
||||||
"author_url" => "",
|
"author_url" => "",
|
||||||
|
"authors" => [],
|
||||||
"blurhash" => nil,
|
"blurhash" => nil,
|
||||||
"embed_url" => "",
|
"embed_url" => "",
|
||||||
"height" => 0,
|
"height" => 0,
|
||||||
"html" => "",
|
"html" => "",
|
||||||
|
"image_description" => "",
|
||||||
|
"language" => nil,
|
||||||
|
"published_at" => nil,
|
||||||
"width" => 0
|
"width" => 0
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -845,15 +845,31 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|
||||||
|
|
||||||
fields = %{
|
fields = %{
|
||||||
"url" => page_url,
|
"url" => page_url,
|
||||||
"site_name" => "Example site name",
|
"type" => "photo",
|
||||||
"title" => "Example website",
|
"title" => "Example website",
|
||||||
"image" => page_url <> "/example.jpg",
|
"image" => page_url <> "/example.jpg",
|
||||||
"description" => "Example description"
|
"description" => "Example description",
|
||||||
|
"author_name" => "Example author",
|
||||||
|
"author_url" => page_url <> "/author",
|
||||||
|
"provider_name" => "Example provider",
|
||||||
|
"provider_url" => page_url <> "/provider",
|
||||||
|
"html" => "<img src=\"#{page_url}/example.jpg\">",
|
||||||
|
"width" => "1024",
|
||||||
|
"height" => 768
|
||||||
}
|
}
|
||||||
|
|
||||||
{:ok, card} = Card.create(page_url, fields)
|
{:ok, card} = Card.create(page_url, fields)
|
||||||
|
|
||||||
assert match?(%{provider_name: "example.com"}, StatusView.render("card.json", card))
|
assert %{
|
||||||
|
type: "photo",
|
||||||
|
author_name: "Example author",
|
||||||
|
author_url: "https://example.com/author",
|
||||||
|
provider_name: "Example provider",
|
||||||
|
provider_url: "https://example.com/provider",
|
||||||
|
html: "<img src=\"https://example.com/example.jpg\">",
|
||||||
|
width: 1024,
|
||||||
|
height: 768
|
||||||
|
} = StatusView.render("card.json", card)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "a rich media card has all media proxied" do
|
test "a rich media card has all media proxied" do
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue