Merge branch 'feature/peertube_2' into 'develop'
rebase/update of feature/peertube See merge request pleroma/pleroma!217
This commit is contained in:
commit
f6b06d2ac8
|
@ -18,18 +18,18 @@ def get_actor(%{"actor" => actor}) when is_binary(actor) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_actor(%{"actor" => actor}) when is_list(actor) do
|
def get_actor(%{"actor" => actor}) when is_list(actor) do
|
||||||
|
if is_binary(Enum.at(actor, 0)) do
|
||||||
Enum.at(actor, 0)
|
Enum.at(actor, 0)
|
||||||
|
else
|
||||||
|
Enum.find(actor, fn %{"type" => type} -> type == "Person" end)
|
||||||
|
|> Map.get("id")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_actor(%{"actor" => actor}) when is_map(actor) do
|
def get_actor(%{"actor" => actor}) when is_map(actor) do
|
||||||
actor["id"]
|
actor["id"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_actor(%{"actor" => actor_list}) do
|
|
||||||
Enum.find(actor_list, fn %{"type" => type} -> type == "Person" end)
|
|
||||||
|> Map.get("id")
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Modifies an incoming AP object (mastodon format) to our internal format.
|
Modifies an incoming AP object (mastodon format) to our internal format.
|
||||||
"""
|
"""
|
||||||
|
@ -42,6 +42,7 @@ def fix_object(object) do
|
||||||
|> fix_emoji
|
|> fix_emoji
|
||||||
|> fix_tag
|
|> fix_tag
|
||||||
|> fix_content_map
|
|> fix_content_map
|
||||||
|
|> fix_likes
|
||||||
|> fix_addressing
|
|> fix_addressing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -67,6 +68,20 @@ def fix_actor(%{"attributedTo" => actor} = object) do
|
||||||
|> Map.put("actor", get_actor(%{"actor" => actor}))
|
|> Map.put("actor", get_actor(%{"actor" => actor}))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fix_likes(%{"likes" => likes} = object)
|
||||||
|
when is_bitstring(likes) do
|
||||||
|
# Check for standardisation
|
||||||
|
# This is what Peertube does
|
||||||
|
# curl -H 'Accept: application/activity+json' $likes | jq .totalItems
|
||||||
|
object
|
||||||
|
|> Map.put("likes", [])
|
||||||
|
|> Map.put("like_count", 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_likes(object) do
|
||||||
|
object
|
||||||
|
end
|
||||||
|
|
||||||
def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object)
|
def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object)
|
||||||
when not is_nil(in_reply_to_id) do
|
when not is_nil(in_reply_to_id) do
|
||||||
case ActivityPub.fetch_object_from_id(in_reply_to_id) do
|
case ActivityPub.fetch_object_from_id(in_reply_to_id) do
|
||||||
|
@ -94,8 +109,11 @@ def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object)
|
||||||
def fix_in_reply_to(object), do: object
|
def fix_in_reply_to(object), do: object
|
||||||
|
|
||||||
def fix_context(object) do
|
def fix_context(object) do
|
||||||
|
context = object["context"] || object["conversation"] || Utils.generate_context_id()
|
||||||
|
|
||||||
object
|
object
|
||||||
|> Map.put("context", object["conversation"])
|
|> Map.put("context", context)
|
||||||
|
|> Map.put("conversation", context)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_attachments(object) do
|
def fix_attachments(object) do
|
||||||
|
@ -163,7 +181,7 @@ def fix_content_map(object), do: object
|
||||||
# - tags
|
# - tags
|
||||||
# - emoji
|
# - emoji
|
||||||
def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data)
|
def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data)
|
||||||
when objtype in ["Article", "Note"] do
|
when objtype in ["Article", "Note", "Video"] do
|
||||||
actor = get_actor(data)
|
actor = get_actor(data)
|
||||||
|
|
||||||
data =
|
data =
|
||||||
|
|
|
@ -128,7 +128,7 @@ def lazy_put_object_defaults(map, activity \\ %{}) do
|
||||||
Inserts a full object if it is contained in an activity.
|
Inserts a full object if it is contained in an activity.
|
||||||
"""
|
"""
|
||||||
def insert_full_object(%{"object" => %{"type" => type} = object_data})
|
def insert_full_object(%{"object" => %{"type" => type} = object_data})
|
||||||
when is_map(object_data) and type in ["Article", "Note"] do
|
when is_map(object_data) and type in ["Article", "Note", "Video"] do
|
||||||
with {:ok, _} <- Object.create(object_data) do
|
with {:ok, _} <- Object.create(object_data) do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
@ -204,13 +204,17 @@ def update_likes_in_object(likes, object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||||
with likes <- [actor | object.data["likes"] || []] |> Enum.uniq() do
|
likes = if is_list(object.data["likes"]), do: object.data["likes"], else: []
|
||||||
|
|
||||||
|
with likes <- [actor | likes] |> Enum.uniq() do
|
||||||
update_likes_in_object(likes, object)
|
update_likes_in_object(likes, object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_like_from_object(%Activity{data: %{"actor" => actor}}, object) do
|
def remove_like_from_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||||
with likes <- (object.data["likes"] || []) |> List.delete(actor) do
|
likes = if is_list(object.data["likes"]), do: object.data["likes"], else: []
|
||||||
|
|
||||||
|
with likes <- likes |> List.delete(actor) do
|
||||||
update_likes_in_object(likes, object)
|
update_likes_in_object(likes, object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -357,13 +361,19 @@ def make_unlike_data(
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||||
with announcements <- [actor | object.data["announcements"] || []] |> Enum.uniq() do
|
announcements =
|
||||||
|
if is_list(object.data["announcements"]), do: object.data["announcements"], else: []
|
||||||
|
|
||||||
|
with announcements <- [actor | announcements] |> Enum.uniq() do
|
||||||
update_element_in_object("announcement", announcements, object)
|
update_element_in_object("announcement", announcements, object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do
|
def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||||
with announcements <- (object.data["announcements"] || []) |> List.delete(actor) do
|
announcements =
|
||||||
|
if is_list(object.data["announcements"]), do: object.data["announcements"], else: []
|
||||||
|
|
||||||
|
with announcements <- announcements |> List.delete(actor) do
|
||||||
update_element_in_object("announcement", announcements, object)
|
update_element_in_object("announcement", announcements, object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView}
|
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.{CommonAPI, OStatus}
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.OAuth.{Authorization, Token, App}
|
alias Pleroma.Web.OAuth.{Authorization, Token, App}
|
||||||
alias Comeonin.Pbkdf2
|
alias Comeonin.Pbkdf2
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
@ -658,12 +658,8 @@ def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
|
||||||
|
|
||||||
fetched =
|
fetched =
|
||||||
if Regex.match?(~r/https?:/, query) do
|
if Regex.match?(~r/https?:/, query) do
|
||||||
with {:ok, activities} <- OStatus.fetch_activity_from_url(query) do
|
with {:ok, object} <- ActivityPub.fetch_object_from_id(query) do
|
||||||
activities
|
[Activity.get_create_activity_by_object_ap_id(object.data["id"])]
|
||||||
|> Enum.filter(fn
|
|
||||||
%{data: %{"type" => "Create"}} -> true
|
|
||||||
_ -> false
|
|
||||||
end)
|
|
||||||
else
|
else
|
||||||
_e -> []
|
_e -> []
|
||||||
end
|
end
|
||||||
|
@ -710,12 +706,8 @@ def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
|
||||||
|
|
||||||
fetched =
|
fetched =
|
||||||
if Regex.match?(~r/https?:/, query) do
|
if Regex.match?(~r/https?:/, query) do
|
||||||
with {:ok, activities} <- OStatus.fetch_activity_from_url(query) do
|
with {:ok, object} <- ActivityPub.fetch_object_from_id(query) do
|
||||||
activities
|
[Activity.get_create_activity_by_object_ap_id(object.data["id"])]
|
||||||
|> Enum.filter(fn
|
|
||||||
%{data: %{"type" => "Create"}} -> true
|
|
||||||
_ -> false
|
|
||||||
end)
|
|
||||||
else
|
else
|
||||||
_e -> []
|
_e -> []
|
||||||
end
|
end
|
||||||
|
|
|
@ -99,8 +99,9 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity}
|
||||||
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
|
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
|
||||||
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
|
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
|
||||||
|
|
||||||
attachments =
|
attachment_data = object["attachment"] || []
|
||||||
render_many(object["attachment"] || [], StatusView, "attachment.json", as: :attachment)
|
attachment_data = attachment_data ++ if object["type"] == "Video", do: [object], else: []
|
||||||
|
attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
|
||||||
|
|
||||||
created_at = Utils.to_masto_date(object["published"])
|
created_at = Utils.to_masto_date(object["published"])
|
||||||
|
|
||||||
|
@ -151,7 +152,9 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity}
|
||||||
end
|
end
|
||||||
|
|
||||||
def render("attachment.json", %{attachment: attachment}) do
|
def render("attachment.json", %{attachment: attachment}) do
|
||||||
[%{"mediaType" => media_type, "href" => href} | _] = attachment["url"]
|
[attachment_url | _] = attachment["url"]
|
||||||
|
media_type = attachment_url["mediaType"] || attachment_url["mimeType"]
|
||||||
|
href = attachment_url["href"]
|
||||||
|
|
||||||
type =
|
type =
|
||||||
cond do
|
cond do
|
||||||
|
@ -208,6 +211,19 @@ def get_visibility(object) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_content(%{"type" => "Video"} = object) do
|
||||||
|
name = object["name"]
|
||||||
|
|
||||||
|
content =
|
||||||
|
if !!name and name != "" do
|
||||||
|
"<p><a href=\"#{object["url"]}\">#{name}</a></p>#{object["content"]}"
|
||||||
|
else
|
||||||
|
object["content"]
|
||||||
|
end
|
||||||
|
|
||||||
|
HtmlSanitizeEx.basic_html(content)
|
||||||
|
end
|
||||||
|
|
||||||
def render_content(%{"type" => "Article"} = object) do
|
def render_content(%{"type" => "Article"} = object) do
|
||||||
summary = object["name"]
|
summary = object["name"]
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,15 @@ def to_map(
|
||||||
HtmlSanitizeEx.basic_html(content)
|
HtmlSanitizeEx.basic_html(content)
|
||||||
|> Formatter.emojify(object["emoji"])
|
|> Formatter.emojify(object["emoji"])
|
||||||
|
|
||||||
|
video =
|
||||||
|
if object["type"] == "Video" do
|
||||||
|
vid = [object]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
attachments = (object["attachment"] || []) ++ video
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"id" => activity.id,
|
"id" => activity.id,
|
||||||
"uri" => activity.data["object"]["id"],
|
"uri" => activity.data["object"]["id"],
|
||||||
|
@ -181,7 +190,7 @@ def to_map(
|
||||||
"created_at" => created_at,
|
"created_at" => created_at,
|
||||||
"in_reply_to_status_id" => object["inReplyToStatusId"],
|
"in_reply_to_status_id" => object["inReplyToStatusId"],
|
||||||
"statusnet_conversation_id" => conversation_id,
|
"statusnet_conversation_id" => conversation_id,
|
||||||
"attachments" => (object["attachment"] || []) |> ObjectRepresenter.enum_to_list(opts),
|
"attachments" => attachments |> ObjectRepresenter.enum_to_list(opts),
|
||||||
"attentions" => attentions,
|
"attentions" => attentions,
|
||||||
"fave_num" => like_count,
|
"fave_num" => like_count,
|
||||||
"repeat_num" => announcement_count,
|
"repeat_num" => announcement_count,
|
||||||
|
|
|
@ -7,7 +7,7 @@ def to_map(%Object{data: %{"url" => [url | _]}} = object, _opts) do
|
||||||
|
|
||||||
%{
|
%{
|
||||||
url: url["href"] |> Pleroma.Web.MediaProxy.url(),
|
url: url["href"] |> Pleroma.Web.MediaProxy.url(),
|
||||||
mimetype: url["mediaType"],
|
mimetype: url["mediaType"] || url["mimeType"],
|
||||||
id: data["uuid"],
|
id: data["uuid"],
|
||||||
oembed: false
|
oembed: false
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ def to_map(%Object{data: %{"url" => [url | _]}} = object, _opts) do
|
||||||
def to_map(%Object{data: %{"url" => url} = data}, _opts) when is_binary(url) do
|
def to_map(%Object{data: %{"url" => url} = data}, _opts) when is_binary(url) do
|
||||||
%{
|
%{
|
||||||
url: url |> Pleroma.Web.MediaProxy.url(),
|
url: url |> Pleroma.Web.MediaProxy.url(),
|
||||||
mimetype: data["mediaType"],
|
mimetype: data["mediaType"] || url["mimeType"],
|
||||||
id: data["uuid"],
|
id: data["uuid"],
|
||||||
oembed: false
|
oembed: false
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"type":"Person","id":"https://peertube.moe/accounts/7even","following":"https://peertube.moe/accounts/7even/following","followers":"https://peertube.moe/accounts/7even/followers","inbox":"https://peertube.moe/accounts/7even/inbox","outbox":"https://peertube.moe/accounts/7even/outbox","preferredUsername":"7even","url":"https://peertube.moe/accounts/7even","name":"7even","endpoints":{"sharedInbox":"https://peertube.moe/inbox"},"uuid":"fd6a914d-0383-4aca-b740-65ed96a0dd63","publicKey":{"id":"https://peertube.moe/accounts/7even#main-key","owner":"https://peertube.moe/accounts/7even","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3vQ2uvYbDprVrq9Ti2wB\nn2J0WkewrzR/+NF4+KVl9s+FMyE4jlmnz+9WEnacKhV1x8a3SrsjLgND55WxNaPj\nabrh6lWmI0SNmHBLi1BejIVAR7CZElF3yCxG0xtNna0Hg6bhtL6I61QxnClhFunu\nDO4i6uyrUu2iXWGQDPzpWkGFrmZdyHOCNIr5PekphR/wcCluwbndO51Ku2RJAblW\nI+QlDG7ailpXyTZGUEO5yfJZX7dkCET1AsNxeBo41aPYzUN5rgRCDB/AdJXxrgZb\nsmtiObB9u+KYk9DuegPpHP3y+dapCSCvStBdPyTaPzsi1y/pOiTVfaxw0NYEJ/Cs\n0QIDAQAB\n-----END PUBLIC KEY-----"},"icon":{"type":"Image","mediaType":"image/png","url":"https://peertube.moe/static/avatars/0815978b-dd71-4797-ae3f-493a3445882a.png"},"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"RsaSignature2017":"https://w3id.org/security#RsaSignature2017","Hashtag":"as:Hashtag","uuid":"http://schema.org/identifier","category":"http://schema.org/category","licence":"http://schema.org/license","sensitive":"as:sensitive","language":"http://schema.org/inLanguage","views":"http://schema.org/Number","size":"http://schema.org/Number","commentsEnabled":"http://schema.org/Boolean","support":"http://schema.org/Text"},{"likes":{"@id":"as:likes","@type":"@id"},"dislikes":{"@id":"as:dislikes","@type":"@id"},"shares":{"@id":"as:shares","@type":"@id"},"comments":{"@id":"as:comments","@type":"@id"}}],"summary":null}
|
File diff suppressed because one or more lines are too long
|
@ -760,6 +760,22 @@ def get("https://baptiste.gelez.xyz/@/BaptisteGelez", _, _) do
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get("https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3", _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Response{
|
||||||
|
status_code: 200,
|
||||||
|
body: File.read!("test/fixtures/httpoison_mock/peertube.moe-vid.json")
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get("https://peertube.moe/accounts/7even", _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Response{
|
||||||
|
status_code: 200,
|
||||||
|
body: File.read!("test/fixtures/httpoison_mock/7even.json")
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
def get(url, body, headers) do
|
def get(url, body, headers) do
|
||||||
{:error,
|
{:error,
|
||||||
"Not implemented the mock response for get #{inspect(url)}, #{inspect(body)}, #{
|
"Not implemented the mock response for get #{inspect(url)}, #{inspect(body)}, #{
|
||||||
|
|
|
@ -506,6 +506,15 @@ test "it creates an update activity with the new user data" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it can fetch peertube videos" do
|
||||||
|
{:ok, object} =
|
||||||
|
ActivityPub.fetch_object_from_id(
|
||||||
|
"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert object
|
||||||
|
end
|
||||||
|
|
||||||
def data_uri do
|
def data_uri do
|
||||||
File.read!("test/fixtures/avatar_data_uri")
|
File.read!("test/fixtures/avatar_data_uri")
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue