aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/pleroma/media.ex92
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex20
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex11
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex35
-rw-r--r--lib/pleroma/web/common_api/utils.ex10
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/media_controller.ex42
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex56
-rw-r--r--lib/pleroma/web/plugs/uploaded_media.ex2
8 files changed, 242 insertions, 26 deletions
diff --git a/lib/pleroma/media.ex b/lib/pleroma/media.ex
new file mode 100644
index 000000000..431c06bb5
--- /dev/null
+++ b/lib/pleroma/media.ex
@@ -0,0 +1,92 @@
+defmodule Pleroma.Media do
+ use Ecto.Schema
+
+ import Ecto.Changeset
+
+ alias Pleroma.Media
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ @derive {Jason.Encoder,
+ only: [:href, :type, :media_type, :name, :blurhash, :meta, :object_id, :user_id]}
+
+ @type t() :: %__MODULE__{}
+
+ schema "media" do
+ field(:href, :string)
+ field(:type, :string)
+ field(:media_type, :string)
+ field(:name, :string)
+ field(:blurhash, :string)
+ field(:meta, :map)
+
+ belongs_to(:object, Pleroma.Object)
+ belongs_to(:user, Pleroma.User, type: FlakeId.Ecto.CompatType)
+
+ timestamps()
+ end
+
+ def create_from_object_data(%{"url" => [url]} = data, %{user: user} = opts) do
+ object_id = get_in(opts, [:object, "id"])
+
+ %Media{}
+ |> changeset(%{
+ href: url["href"],
+ type: url["type"],
+ media_type: url["mediaType"],
+ name: data["name"],
+ blurhash: nil,
+ meta: %{},
+ user_id: user.id,
+ object_id: object_id
+ })
+ |> Repo.insert()
+ end
+
+ def get_by_id(nil), do: nil
+ def get_by_id(id), do: Repo.get(Media, id)
+
+ @spec authorize_access(Media.t(), User.t()) :: :ok | {:error, :forbidden}
+ def authorize_access(%Media{user_id: user_id}, %User{id: user_id}), do: :ok
+ def authorize_access(%Media{user_id: user_id}, %User{id: user_id}), do: {:error, :forbidden}
+
+ def update(%Media{} = media, attrs \\ %{}) do
+ media
+ |> changeset(attrs)
+ |> Repo.update()
+ end
+
+ def from_object(%Pleroma.Object{data: data}, %{user: user}) do
+ %Media{href: data["href"], user_id: user.id}
+ end
+
+ def insert(%Media{} = media) do
+ media
+ |> changeset()
+ |> Repo.insert()
+ end
+
+ def changeset(struct, params \\ %{}) do
+ struct
+ |> cast(params, [:href, :type, :media_type, :name, :blurhash, :meta, :user_id, :object_id])
+ |> validate_required([:href, :type, :media_type])
+ end
+
+ def to_object_form(%Media{} = media) do
+ %{
+ "id" => media.id,
+ "url" => [
+ %{
+ "href" => media.href,
+ "type" => media.type,
+ "mediaType" => media.media_type
+ }
+ ],
+ "name" => media.name,
+ "type" => "Document",
+ "blurhash" => media.blurhash,
+ "mediaType" => media.media_type,
+ "actor" => User.get_by_id(media.user_id).ap_id
+ }
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index c5bc08153..c2948fd52 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -123,6 +123,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:fake, false, map, recipients} <- {:fake, fake, map, recipients},
{:containment, :ok} <- {:containment, Containment.contain_child(map)},
{:ok, map, object} <- insert_full_object(map),
+ :ok <- maybe_update_media(object),
{:ok, activity} <- insert_activity_with_expiration(map, local, recipients) do
# Splice in the child object if we have one.
activity = Maps.put_if_present(activity, :object, object)
@@ -165,6 +166,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ defp maybe_update_media(%Object{data: %{"attachment" => []}}), do: :ok
+
+ defp maybe_update_media(%Object{data: %{"id" => id, "attachment" => attachments}}) do
+ Enum.each(attachments, fn data ->
+ with %{"id" => media_id} <- data do
+ media_id
+ |> Pleroma.Media.get_by_id()
+ |> Pleroma.Media.update(%{object_id: id})
+ end
+ end)
+ end
+
defp insert_activity_with_expiration(data, local, recipients) do
struct = %Activity{
data: data,
@@ -1200,10 +1213,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
@spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
def upload(file, opts \\ []) do
- with {:ok, data} <- Upload.store(file, opts) do
- obj_data = Maps.put_if_present(data, "actor", opts[:actor])
-
- Repo.insert(%Object{data: obj_data})
+ with {:ok, data} <- Upload.store(file, opts),
+ %User{} <- opts[:user] do
+ Pleroma.Media.create_from_object_data(data, %{user: opts[:user]})
end
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index eb9e119f7..2e5069cb5 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -271,7 +271,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
+ def inbox(conn, params) do
+ IO.inspect(%{conn: conn, params: params})
+ inbox2(conn, params)
+ end
+
+ def inbox2(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
with %User{} = recipient <- User.get_cached_by_nickname(nickname),
{:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(params["actor"]),
true <- Utils.recipient_in_message(recipient, actor, params),
@@ -281,13 +286,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
+ def inbox2(%{assigns: %{valid_signature: true}} = conn, params) do
Federator.incoming_ap_doc(params)
json(conn, "ok")
end
# POST /relay/inbox -or- POST /internal/fetch/inbox
- def inbox(conn, params) do
+ def inbox2(conn, params) do
if params["type"] == "Create" && FederatingPlug.federating?() do
post_inbox_relayed_create(conn, params)
else
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 4d9a5617e..7f7387c31 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Activity
alias Pleroma.EctoType.ActivityPub.ObjectValidators
alias Pleroma.Maps
+ alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.Repo
@@ -32,18 +33,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
"""
def fix_object(object, options \\ []) do
object
- |> strip_internal_fields
- |> fix_actor
- |> fix_url
- |> fix_attachments
- |> fix_context
+ |> strip_internal_fields()
+ |> fix_actor()
+ |> fix_url()
+ |> fix_attachments()
+ |> fix_media()
+ |> fix_context()
|> fix_in_reply_to(options)
- |> fix_emoji
- |> fix_tag
- |> set_sensitive
- |> fix_content_map
- |> fix_addressing
- |> fix_summary
+ |> fix_emoji()
+ |> fix_tag()
+ |> set_sensitive()
+ |> fix_content_map()
+ |> fix_addressing()
+ |> fix_summary()
|> fix_type(options)
end
@@ -270,6 +272,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_attachments(object), do: object
+ def fix_media(%{"attachment" => [_ | _] = attachments} = object) do
+ Enum.each(
+ attachments,
+ &Media.create_from_object_data(&1, %{user: User.get_by_ap_id(object.actor), object: object})
+ )
+
+ object
+ end
+
+ def fix_media(object), do: object
+
def fix_url(%{"url" => url} = object) when is_map(url) do
Map.put(object, "url", url["href"])
end
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 9587dfa25..6a4e22f27 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Config
alias Pleroma.Conversation.Participation
alias Pleroma.Formatter
+ alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
@@ -37,8 +38,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def attachments_from_ids_no_descs(ids) do
Enum.map(ids, fn media_id ->
- case Repo.get(Object, media_id) do
- %Object{data: data} -> data
+ case Repo.get(Media, media_id) do
+ %Media{} = media -> Media.to_object_form(media)
_ -> nil
end
end)
@@ -51,8 +52,9 @@ defmodule Pleroma.Web.CommonAPI.Utils do
{_, descs} = Jason.decode(descs_str)
Enum.map(ids, fn media_id ->
- with %Object{data: data} <- Repo.get(Object, media_id) do
- Map.put(data, "name", descs[media_id])
+ with %Media{} = media <- Repo.get(Media, media_id) do
+ %Media{media | name: descs[media_id]}
+ |> Media.to_object_form()
end
end)
|> Enum.reject(&is_nil/1)
diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
index d6949ed80..1bd521460 100644
--- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.MastodonAPI.MediaController do
use Pleroma.Web, :controller
+ alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -22,6 +23,20 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
@doc "POST /api/v1/media"
def create(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
+ with {:ok, media} <-
+ ActivityPub.upload(
+ file,
+ user: user,
+ actor: User.ap_id(user),
+ description: Map.get(data, :description)
+ ) do
+ render(conn, "media.json", %{media: media})
+ end
+ end
+
+ def create(_conn, _data), do: {:error, :bad_request}
+
+ def _create(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
with {:ok, object} <-
ActivityPub.upload(
file,
@@ -34,7 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
end
end
- def create(_conn, _data), do: {:error, :bad_request}
+ def _create(_conn, _data), do: {:error, :bad_request}
@doc "POST /api/v2/media"
def create2(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
@@ -56,6 +71,18 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
@doc "PUT /api/v1/media/:id"
def update(%{assigns: %{user: user}, body_params: %{description: description}} = conn, %{id: id}) do
+ with %Media{} = media <- Media.get_by_id(id),
+ :ok <- Media.authorize_access(media, user),
+ {:ok, %Media{} = media} <- Media.update(media, %{"name" => description}) do
+ render(conn, "media.json", %{media: media})
+ end
+ end
+
+ def update(conn, data), do: show(conn, data)
+
+ def _update(%{assigns: %{user: user}, body_params: %{description: description}} = conn, %{
+ id: id
+ }) do
with %Object{} = object <- Object.get_by_id(id),
:ok <- Object.authorize_access(object, user),
{:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do
@@ -65,10 +92,19 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
end
end
- def update(conn, data), do: show(conn, data)
+ def _update(conn, data), do: show(conn, data)
@doc "GET /api/v1/media/:id"
def show(%{assigns: %{user: user}} = conn, %{id: id}) do
+ with %Pleroma.Media{} = media <- Pleroma.Media.get_by_id(id),
+ :ok <- Pleroma.Media.authorize_access(media, user) do
+ render(conn, "media.json", %{media: media})
+ end
+ end
+
+ def show(_conn, _data), do: {:error, :bad_request}
+
+ def _show(%{assigns: %{user: user}} = conn, %{id: id}) do
with %Object{data: data, id: object_id} = object <- Object.get_by_id(id),
:ok <- Object.authorize_access(object, user) do
attachment_data = Map.put(data, "id", object_id)
@@ -77,5 +113,5 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
end
end
- def show(_conn, _data), do: {:error, :bad_request}
+ def _show(_conn, _data), do: {:error, :bad_request}
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index cd1a85088..8c6d56e0f 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -243,7 +243,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
attachment_data = object.data["attachment"] || []
- attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
+ # attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
+ attachments = render_many(attachment_data, StatusView, "object_media.json", as: :media)
created_at = Utils.to_masto_date(object.data["published"])
@@ -436,6 +437,59 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
}
end
+ def render("object_media.json", %{media: media}) do
+ [url] = media["url"]
+ media_type = media["mediaType"] || "image"
+ href = MediaProxy.url(url["href"])
+ href_preview = MediaProxy.preview_url(url["href"])
+
+ type =
+ cond do
+ String.contains?(media_type, "image") -> "image"
+ String.contains?(media_type, "video") -> "video"
+ String.contains?(media_type, "audio") -> "audio"
+ true -> "unknown"
+ end
+
+ %{
+ id: to_string(media["id"]),
+ url: href,
+ remote_url: href,
+ preview_url: href_preview,
+ text_url: href,
+ type: type,
+ description: media["name"],
+ pleroma: %{mime_type: media_type},
+ blurhash: media["blurhash"]
+ }
+ end
+
+ def render("media.json", %{media: media}) do
+ media_type = media.media_type || media.mime_type || "image"
+ href = MediaProxy.url(media.href)
+ href_preview = MediaProxy.preview_url(media.href)
+
+ type =
+ cond do
+ String.contains?(media_type, "image") -> "image"
+ String.contains?(media_type, "video") -> "video"
+ String.contains?(media_type, "audio") -> "audio"
+ true -> "unknown"
+ end
+
+ %{
+ id: to_string(media.id),
+ url: href,
+ remote_url: href,
+ preview_url: href_preview,
+ text_url: href,
+ type: type,
+ description: media.name,
+ pleroma: %{mime_type: media_type},
+ blurhash: media.blurhash
+ }
+ end
+
def render("context.json", %{activity: activity, activities: activities, user: user}) do
%{ancestors: ancestors, descendants: descendants} =
activities
diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex
index 2378e98d2..0350fdfbf 100644
--- a/lib/pleroma/web/plugs/uploaded_media.ex
+++ b/lib/pleroma/web/plugs/uploaded_media.ex
@@ -46,6 +46,8 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
config = Pleroma.Config.get(Pleroma.Upload)
+ # https://pleroma.local/media/cf61935ec407b4df8fd3dcf58352948eb6231bdfe12fcbf5270e653c20da9860.jpeg
+
with uploader <- Keyword.fetch!(config, :uploader),
proxy_remote = Keyword.get(config, :proxy_remote, false),
{:ok, get_method} <- uploader.get_file(file),