aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Chvanikov <chvanikoff@pm.me>2020-12-07 22:37:56 +0300
committerRoman Chvanikov <chvanikoff@pm.me>2020-12-07 22:37:56 +0300
commit193c17cea519f5b12f13122fc6d612e1d9f30e62 (patch)
treef091622c80624626b18c70d3f512e9fbaf20f3c8
parentb3ee618e0d726452248c6fa9a1830d2525b9693b (diff)
downloadpleroma-193c17cea519f5b12f13122fc6d612e1d9f30e62.tar.gz
wip
-rw-r--r--lib/pleroma/media.ex88
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex18
-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.ex31
-rw-r--r--lib/pleroma/web/plugs/uploaded_media.ex2
-rw-r--r--priv/repo/migrations/20201125170429_create_media.exs19
7 files changed, 197 insertions, 13 deletions
diff --git a/lib/pleroma/media.ex b/lib/pleroma/media.ex
new file mode 100644
index 000000000..ed9ed6ed0
--- /dev/null
+++ b/lib/pleroma/media.ex
@@ -0,0 +1,88 @@
+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
+ %Media{}
+ |> changeset(%{
+ href: url["href"],
+ type: url["type"],
+ media_type: url["mediaType"],
+ name: data["name"],
+ blurhash: nil,
+ meta: %{},
+ user_id: user.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
+ }
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 1c91bc074..3a8b17baa 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -119,6 +119,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)
@@ -161,6 +162,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ defp maybe_update_media(%Object{data: %{"attachment" => []}}), do: :ok
+
+ defp maybe_update_media(%Object{id: id, data: %{"attachment" => attachments}}) do
+ Enum.each(attachments, fn %{"id" => media_id} ->
+ media_id
+ |> Pleroma.Media.get_by_id()
+ |> Pleroma.Media.update(%{object_id: id})
+ end)
+ end
+
defp insert_activity_with_expiration(data, local, recipients) do
struct = %Activity{
data: data,
@@ -1190,10 +1201,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/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 1c74ea787..7b814826a 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 161193134..b5283c2a3 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 2301e21cf..d1022f5a1 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -242,8 +242,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
true -> CommonAPI.thread_muted?(opts[:for], activity)
end
- attachment_data = object.data["attachment"] || []
- attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
+ attachment_data = object.data["attachments"] || []
+ # attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
+ attachments = render_many(attachment_data, StatusView, "media.json", as: :media)
created_at = Utils.to_masto_date(object.data["published"])
@@ -436,6 +437,32 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
}
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 402a8bb34..e545b6b18 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),
diff --git a/priv/repo/migrations/20201125170429_create_media.exs b/priv/repo/migrations/20201125170429_create_media.exs
new file mode 100644
index 000000000..a1bd125c3
--- /dev/null
+++ b/priv/repo/migrations/20201125170429_create_media.exs
@@ -0,0 +1,19 @@
+defmodule Pleroma.Repo.Migrations.CreateMedia do
+ use Ecto.Migration
+
+ def change do
+ create_if_not_exists table(:media) do
+ add(:href, :string, null: false)
+ add(:type, :string, null: false)
+ add(:media_type, :string, null: false)
+ add(:name, :string)
+ add(:blurhash, :string)
+ add(:meta, :map)
+ # TODO discuss delete_all option
+ add(:object_id, references(:objects, on_delete: :nothing), null: true)
+ add(:user_id, references(:users, type: :uuid, on_delete: :nothing), null: false)
+
+ timestamps()
+ end
+ end
+end