Expose posts media through AP
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
4e7ab231ad
commit
d1472d94de
|
@ -10,7 +10,6 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
alias Mobilizon.Addresses
|
alias Mobilizon.Addresses
|
||||||
alias Mobilizon.Addresses.Address
|
alias Mobilizon.Addresses.Address
|
||||||
alias Mobilizon.Events.Event, as: EventModel
|
alias Mobilizon.Events.Event, as: EventModel
|
||||||
alias Mobilizon.Medias.Media
|
|
||||||
|
|
||||||
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
||||||
alias Mobilizon.Federation.ActivityStream.Converter.Address, as: AddressConverter
|
alias Mobilizon.Federation.ActivityStream.Converter.Address, as: AddressConverter
|
||||||
|
@ -21,7 +20,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
fetch_tags: 1,
|
fetch_tags: 1,
|
||||||
fetch_mentions: 1,
|
fetch_mentions: 1,
|
||||||
build_tags: 1,
|
build_tags: 1,
|
||||||
maybe_fetch_actor_and_attributed_to_id: 1
|
maybe_fetch_actor_and_attributed_to_id: 1,
|
||||||
|
process_pictures: 2
|
||||||
]
|
]
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
@ -34,6 +34,9 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
defdelegate model_to_as(event), to: EventConverter
|
defdelegate model_to_as(event), to: EventConverter
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@online_address_name "Website"
|
||||||
|
@banner_picture_name "Banner"
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Converts an AP object data to our internal data structure.
|
Converts an AP object data to our internal data structure.
|
||||||
"""
|
"""
|
||||||
|
@ -47,30 +50,16 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
{:tags, tags} <- {:tags, fetch_tags(object["tag"])},
|
{:tags, tags} <- {:tags, fetch_tags(object["tag"])},
|
||||||
{:mentions, mentions} <- {:mentions, fetch_mentions(object["tag"])},
|
{:mentions, mentions} <- {:mentions, fetch_mentions(object["tag"])},
|
||||||
{:visibility, visibility} <- {:visibility, get_visibility(object)},
|
{:visibility, visibility} <- {:visibility, get_visibility(object)},
|
||||||
{:options, options} <- {:options, get_options(object)} do
|
{:options, options} <- {:options, get_options(object)},
|
||||||
attachments =
|
[description: description, picture_id: picture_id, medias: medias] <-
|
||||||
object
|
process_pictures(object, actor_id) do
|
||||||
|> Map.get("attachment", [])
|
|
||||||
|> Enum.filter(fn attachment -> Map.get(attachment, "type", "Document") == "Document" end)
|
|
||||||
|
|
||||||
picture_id =
|
|
||||||
with true <- length(attachments) > 0,
|
|
||||||
{:ok, %Media{id: picture_id}} <-
|
|
||||||
attachments
|
|
||||||
|> hd()
|
|
||||||
|> MediaConverter.find_or_create_media(actor_id) do
|
|
||||||
picture_id
|
|
||||||
else
|
|
||||||
_err ->
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
title: object["name"],
|
title: object["name"],
|
||||||
description: object["content"],
|
description: description,
|
||||||
organizer_actor_id: actor_id,
|
organizer_actor_id: actor_id,
|
||||||
attributed_to_id: if(is_nil(attributed_to), do: nil, else: attributed_to.id),
|
attributed_to_id: if(is_nil(attributed_to), do: nil, else: attributed_to.id),
|
||||||
picture_id: picture_id,
|
picture_id: picture_id,
|
||||||
|
medias: medias,
|
||||||
begins_on: object["startTime"],
|
begins_on: object["startTime"],
|
||||||
ends_on: object["endTime"],
|
ends_on: object["endTime"],
|
||||||
category: object["category"],
|
category: object["category"],
|
||||||
|
@ -143,6 +132,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
|> maybe_add_physical_address(event)
|
|> maybe_add_physical_address(event)
|
||||||
|> maybe_add_event_picture(event)
|
|> maybe_add_event_picture(event)
|
||||||
|> maybe_add_online_address(event)
|
|> maybe_add_online_address(event)
|
||||||
|
|> maybe_add_inline_media(event)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get only elements that we have in EventOptions
|
# Get only elements that we have in EventOptions
|
||||||
|
@ -213,7 +203,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
"type" => "Link",
|
"type" => "Link",
|
||||||
"href" => url,
|
"href" => url,
|
||||||
"mediaType" => "text/html",
|
"mediaType" => "text/html",
|
||||||
"name" => "Website"
|
"name" => @online_address_name
|
||||||
} ->
|
} ->
|
||||||
url
|
url
|
||||||
|
|
||||||
|
@ -239,7 +229,12 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
res,
|
res,
|
||||||
"attachment",
|
"attachment",
|
||||||
[],
|
[],
|
||||||
&(&1 ++ [MediaConverter.model_to_as(event.picture)])
|
&(&1 ++
|
||||||
|
[
|
||||||
|
event.picture
|
||||||
|
|> MediaConverter.model_to_as()
|
||||||
|
|> Map.put("name", @banner_picture_name)
|
||||||
|
])
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -258,9 +253,21 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
"type" => "Link",
|
"type" => "Link",
|
||||||
"href" => event.online_address,
|
"href" => event.online_address,
|
||||||
"mediaType" => "text/html",
|
"mediaType" => "text/html",
|
||||||
"name" => "Website"
|
"name" => @online_address_name
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec maybe_add_inline_media(map(), Event.t()) :: map()
|
||||||
|
defp maybe_add_inline_media(res, event) do
|
||||||
|
medias = Enum.map(event.media, &MediaConverter.model_to_as/1)
|
||||||
|
|
||||||
|
Map.update(
|
||||||
|
res,
|
||||||
|
"attachment",
|
||||||
|
[],
|
||||||
|
&(&1 ++ medias)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,9 +9,15 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||||
alias Mobilizon.Federation.ActivityPub
|
alias Mobilizon.Federation.ActivityPub
|
||||||
alias Mobilizon.Federation.ActivityPub.Utils
|
alias Mobilizon.Federation.ActivityPub.Utils
|
||||||
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
||||||
|
alias Mobilizon.Federation.ActivityStream.Converter.Media, as: MediaConverter
|
||||||
alias Mobilizon.Posts.Post
|
alias Mobilizon.Posts.Post
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
import Mobilizon.Federation.ActivityStream.Converter.Utils,
|
||||||
|
only: [
|
||||||
|
process_pictures: 2
|
||||||
|
]
|
||||||
|
|
||||||
@behaviour Converter
|
@behaviour Converter
|
||||||
|
|
||||||
defimpl Convertible, for: Post do
|
defimpl Convertible, for: Post do
|
||||||
|
@ -20,6 +26,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||||
defdelegate model_to_as(post), to: PostConverter
|
defdelegate model_to_as(post), to: PostConverter
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@banner_picture_name "Banner"
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Convert an post struct to an ActivityStream representation
|
Convert an post struct to an ActivityStream representation
|
||||||
"""
|
"""
|
||||||
|
@ -35,8 +43,11 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||||
"name" => post.title,
|
"name" => post.title,
|
||||||
"content" => post.body,
|
"content" => post.body,
|
||||||
"attributedTo" => creator_url,
|
"attributedTo" => creator_url,
|
||||||
"published" => (post.publish_at || post.inserted_at) |> to_date()
|
"published" => (post.publish_at || post.inserted_at) |> to_date(),
|
||||||
|
"attachment" => []
|
||||||
}
|
}
|
||||||
|
|> maybe_add_post_picture(post)
|
||||||
|
|> maybe_add_inline_media(post)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -48,15 +59,19 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||||
%{"type" => "Article", "actor" => creator, "attributedTo" => group} = object
|
%{"type" => "Article", "actor" => creator, "attributedTo" => group} = object
|
||||||
) do
|
) do
|
||||||
with {:ok, %Actor{id: attributed_to_id}} <- get_actor(group),
|
with {:ok, %Actor{id: attributed_to_id}} <- get_actor(group),
|
||||||
{:ok, %Actor{id: author_id}} <- get_actor(creator) do
|
{:ok, %Actor{id: author_id}} <- get_actor(creator),
|
||||||
|
[description: description, picture_id: picture_id, medias: medias] <-
|
||||||
|
process_pictures(object, attributed_to_id) do
|
||||||
%{
|
%{
|
||||||
title: object["name"],
|
title: object["name"],
|
||||||
body: object["content"],
|
body: description,
|
||||||
url: object["id"],
|
url: object["id"],
|
||||||
attributed_to_id: attributed_to_id,
|
attributed_to_id: attributed_to_id,
|
||||||
author_id: author_id,
|
author_id: author_id,
|
||||||
local: false,
|
local: false,
|
||||||
publish_at: object["published"]
|
publish_at: object["published"],
|
||||||
|
picture_id: picture_id,
|
||||||
|
medias: medias
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{:error, err} -> {:error, err}
|
{:error, err} -> {:error, err}
|
||||||
|
@ -70,4 +85,34 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Post do
|
||||||
|
|
||||||
defp to_date(%DateTime{} = date), do: DateTime.to_iso8601(date)
|
defp to_date(%DateTime{} = date), do: DateTime.to_iso8601(date)
|
||||||
defp to_date(%NaiveDateTime{} = date), do: NaiveDateTime.to_iso8601(date)
|
defp to_date(%NaiveDateTime{} = date), do: NaiveDateTime.to_iso8601(date)
|
||||||
|
|
||||||
|
@spec maybe_add_post_picture(map(), Post.t()) :: map()
|
||||||
|
defp maybe_add_post_picture(res, post) do
|
||||||
|
if is_nil(post.picture),
|
||||||
|
do: res,
|
||||||
|
else:
|
||||||
|
Map.update(
|
||||||
|
res,
|
||||||
|
"attachment",
|
||||||
|
[],
|
||||||
|
&(&1 ++
|
||||||
|
[
|
||||||
|
post.picture
|
||||||
|
|> MediaConverter.model_to_as()
|
||||||
|
|> Map.put("name", @banner_picture_name)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec maybe_add_inline_media(map(), Post.t()) :: map()
|
||||||
|
defp maybe_add_inline_media(res, post) do
|
||||||
|
medias = Enum.map(post.media, &MediaConverter.model_to_as/1)
|
||||||
|
|
||||||
|
Map.update(
|
||||||
|
res,
|
||||||
|
"attachment",
|
||||||
|
[],
|
||||||
|
&(&1 ++ medias)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,15 +6,19 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
|
||||||
alias Mobilizon.{Actors, Events}
|
alias Mobilizon.{Actors, Events}
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Events.Tag
|
alias Mobilizon.Events.Tag
|
||||||
|
alias Mobilizon.Medias.Media
|
||||||
alias Mobilizon.Mention
|
alias Mobilizon.Mention
|
||||||
alias Mobilizon.Storage.Repo
|
alias Mobilizon.Storage.Repo
|
||||||
|
|
||||||
alias Mobilizon.Federation.ActivityPub
|
alias Mobilizon.Federation.ActivityPub
|
||||||
|
alias Mobilizon.Federation.ActivityStream.Converter.Media, as: MediaConverter
|
||||||
|
|
||||||
alias Mobilizon.Web.Endpoint
|
alias Mobilizon.Web.Endpoint
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@banner_picture_name "Banner"
|
||||||
|
|
||||||
@spec fetch_tags([String.t()]) :: [Tag.t()]
|
@spec fetch_tags([String.t()]) :: [Tag.t()]
|
||||||
def fetch_tags(tags) when is_list(tags) do
|
def fetch_tags(tags) when is_list(tags) do
|
||||||
Logger.debug("fetching tags")
|
Logger.debug("fetching tags")
|
||||||
|
@ -169,4 +173,62 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
|
||||||
actor
|
actor
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec process_pictures(map(), integer()) :: Keyword.t()
|
||||||
|
def process_pictures(object, actor_id) do
|
||||||
|
attachements = Map.get(object, "attachment", [])
|
||||||
|
|
||||||
|
media_attachements = get_medias(attachements)
|
||||||
|
|
||||||
|
media_attachements_map =
|
||||||
|
media_attachements
|
||||||
|
|> Enum.map(fn media_attachement ->
|
||||||
|
{media_attachement["url"],
|
||||||
|
MediaConverter.find_or_create_media(media_attachement, actor_id)}
|
||||||
|
end)
|
||||||
|
|> Enum.reduce(%{}, fn {old_url, media}, acc ->
|
||||||
|
case media do
|
||||||
|
{:ok, %Media{} = media} ->
|
||||||
|
Map.put(acc, old_url, media)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
acc
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
media_attachements_map_urls =
|
||||||
|
media_attachements_map
|
||||||
|
|> Enum.map(fn {old_url, new_media} -> {old_url, new_media.file.url} end)
|
||||||
|
|> Map.new()
|
||||||
|
|
||||||
|
picture_id =
|
||||||
|
with banner when is_map(banner) <- get_banner_picture(attachements),
|
||||||
|
{:ok, %Media{id: picture_id}} <-
|
||||||
|
MediaConverter.find_or_create_media(banner, actor_id) do
|
||||||
|
picture_id
|
||||||
|
else
|
||||||
|
_err ->
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
description = replace_media_urls_in_body(object["content"], media_attachements_map_urls)
|
||||||
|
[description: description, picture_id: picture_id, medias: Map.values(media_attachements_map)]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp replace_media_urls_in_body(body, media_urls),
|
||||||
|
do:
|
||||||
|
Enum.reduce(media_urls, body, fn media_url, body ->
|
||||||
|
replace_media_url_in_body(body, media_url)
|
||||||
|
end)
|
||||||
|
|
||||||
|
defp replace_media_url_in_body(body, {old_url, new_url}),
|
||||||
|
do: String.replace(body, old_url, new_url)
|
||||||
|
|
||||||
|
defp get_medias(attachments) do
|
||||||
|
Enum.filter(attachments, &(&1["type"] == "Document" && &1["name"] != @banner_picture_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_banner_picture(attachments) do
|
||||||
|
Enum.find(attachments, &(&1["type"] == "Document" && &1["name"] == @banner_picture_name))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,7 +10,7 @@ defmodule Mobilizon.Posts do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@post_preloads [:author, :attributed_to, :picture]
|
@post_preloads [:author, :attributed_to, :picture, :media]
|
||||||
|
|
||||||
import EctoEnum
|
import EctoEnum
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Mobilizon.Web.PageView do
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Discussions.{Comment, Discussion}
|
alias Mobilizon.Discussions.{Comment, Discussion}
|
||||||
alias Mobilizon.Events.Event
|
alias Mobilizon.Events.Event
|
||||||
|
alias Mobilizon.Posts.Post
|
||||||
alias Mobilizon.Resources.Resource
|
alias Mobilizon.Resources.Resource
|
||||||
alias Mobilizon.Tombstone
|
alias Mobilizon.Tombstone
|
||||||
|
|
||||||
|
@ -54,6 +55,12 @@ defmodule Mobilizon.Web.PageView do
|
||||||
|> Map.merge(Utils.make_json_ld_header())
|
|> Map.merge(Utils.make_json_ld_header())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render("post.activity-json", %{conn: %{assigns: %{object: %Post{} = post}}}) do
|
||||||
|
post
|
||||||
|
|> Convertible.model_to_as()
|
||||||
|
|> Map.merge(Utils.make_json_ld_header())
|
||||||
|
end
|
||||||
|
|
||||||
def render(page, %{object: object, conn: conn} = _assigns)
|
def render(page, %{object: object, conn: conn} = _assigns)
|
||||||
when page in ["actor.html", "event.html", "comment.html", "post.html"] do
|
when page in ["actor.html", "event.html", "comment.html", "post.html"] do
|
||||||
locale = get_locale(conn)
|
locale = get_locale(conn)
|
||||||
|
|
Loading…
Reference in a new issue