Compare commits

...

13 Commits

Author SHA1 Message Date
Ivan Tashkinov
4ade12bf82 [#3259] Media.create_from_object_data/_ fix (data handling). 2021-01-23 22:29:00 +03:00
Roman Chvanikov
093649509e Add forgotten migration 2021-01-21 17:24:56 +03:00
Roman Chvanikov
5afdca7ddf Replaced Media.user_id with Media.actor 2021-01-21 16:15:53 +03:00
Roman Chvanikov
a35299dd96 Dev patch applied 2021-01-18 12:46:43 +03:00
Roman Chvanikov
2289a1d587 Merge branch 'develop' into refactor/uploads 2021-01-18 11:56:40 +03:00
Roman Chvanikov
dbaa15232b wip 2020-12-09 01:18:05 +03:00
Roman Chvanikov
8a7b081966 wip 2020-12-09 01:17:37 +03:00
Roman Chvanikov
d960d926a0 wip 2020-12-09 00:49:28 +03:00
Roman Chvanikov
07e80e39b1 wip 2020-12-09 00:11:38 +03:00
Roman Chvanikov
8553df904a wip 2020-12-08 23:56:03 +03:00
Roman Chvanikov
81913e3a1a wip 2020-12-08 23:48:26 +03:00
Roman Chvanikov
cf1c101849 Merge branch 'develop' into refactor/uploads 2020-12-07 23:20:18 +03:00
Roman Chvanikov
193c17cea5 wip 2020-12-07 22:37:56 +03:00
30 changed files with 529 additions and 253 deletions

95
lib/pleroma/media.ex Normal file
View File

@ -0,0 +1,95 @@
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, :actor]}
@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)
field(:actor, :string)
field(:removable, :boolean, virtual: true, default: false)
belongs_to(:object, Pleroma.Object)
timestamps()
end
def create_from_object_data(%{"url" => [url]} = data, %{actor: actor} = opts) do
object_id = get_in(opts, [:object, "id"]) || Map.get(opts, :object_id)
%Media{}
|> changeset(%{
href: url["href"],
type: data["type"],
media_type: url["mediaType"],
name: data["name"],
blurhash: nil,
meta: %{},
actor: actor,
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{actor: ap_id}, %User{ap_id: ap_id}), do: :ok
def authorize_access(_media, %User{is_admin: is_admin?, is_moderator: is_moderator?})
when true in [is_admin?, is_moderator?],
do: :ok
def authorize_access(_media, _user), do: {:error, :forbidden}
def update(%Media{} = media, attrs \\ %{}) do
media
|> changeset(attrs)
|> Repo.update()
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, :actor, :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" => media.actor
}
end
end

View File

@ -10,6 +10,7 @@ defmodule Pleroma.Object do
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.Object.Fetcher
alias Pleroma.ObjectTombstone
@ -51,6 +52,7 @@ defmodule Pleroma.Object do
def create(data) do
Object.change(%Object{}, %{data: data})
|> Repo.insert()
|> maybe_set_media_object_id()
end
def change(struct, params \\ %{}) do
@ -58,6 +60,7 @@ defmodule Pleroma.Object do
|> cast(params, [:data])
|> validate_required([:data])
|> unique_constraint(:ap_id, name: :objects_unique_apid_index)
|> maybe_create_media()
end
def get_by_id(nil), do: nil
@ -349,4 +352,46 @@ defmodule Pleroma.Object do
def self_replies(object, opts \\ []),
do: replies(object, Keyword.put(opts, :self_only, true))
defp maybe_create_media(
%{
valid?: true,
changes: %{data: %{"actor" => actor, "attachment" => [_ | _] = attachments}}
} = changeset
) do
new_attachments =
Enum.map(attachments, fn attachment ->
if is_nil(attachment["id"]) do
{:ok, media} = Media.create_from_object_data(attachment, %{actor: actor})
Map.put(attachment, "id", media.id)
else
attachment
end
end)
%{
changeset
| changes: %{
changeset.changes
| data: %{changeset.changes.data | "attachment" => new_attachments}
}
}
end
defp maybe_create_media(changeset), do: changeset
defp maybe_set_media_object_id(
{:ok, %Object{id: object_id, data: %{"attachment" => [_ | _] = attachments}}} = result
) do
Enum.each(attachments, fn %{"id" => media_id} ->
media_id
|> Media.get_by_id()
|> Media.update(%{object_id: object_id})
end)
result
end
defp maybe_set_media_object_id(result), do: result
end

View File

@ -1200,10 +1200,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{} = user <- opts[:user] do
Pleroma.Media.create_from_object_data(data, %{actor: user.ap_id})
end
end

View File

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Activity
alias Pleroma.Delivery
alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.Object.Fetcher
alias Pleroma.User
@ -532,17 +533,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
def upload_media(%{assigns: %{user: %User{} = user}} = conn, %{"file" => file} = data) do
with {:ok, object} <-
with {:ok, media} <-
ActivityPub.upload(
file,
actor: User.ap_id(user),
user: user,
description: Map.get(data, "description")
) do
Logger.debug(inspect(object))
Logger.debug(inspect(media))
conn
|> put_status(:created)
|> json(object.data)
|> json(Media.to_object_form(media))
end
end
end

View File

@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
"""
alias Pleroma.Emoji
alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
@ -137,6 +138,9 @@ defmodule Pleroma.Web.ActivityPub.Builder do
}
case opts[:attachment] do
%Media{} = media ->
{:ok, Map.put(basic, "attachment", Media.to_object_form(media)), []}
%Object{data: attachment_data} ->
{
:ok,

View File

@ -32,18 +32,18 @@ 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_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

View File

@ -6,6 +6,7 @@ defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Activity
alias Pleroma.Conversation.Participation
alias Pleroma.Formatter
alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.ThreadMute
alias Pleroma.User
@ -31,7 +32,7 @@ defmodule Pleroma.Web.CommonAPI do
end
def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
with maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
with maybe_attachment <- opts[:media_id] && Media.get_by_id(opts[:media_id]),
:ok <- validate_chat_content_length(content, !!maybe_attachment),
{_, {:ok, chat_message_data, _meta}} <-
{:build_object,

View File

@ -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)

View File

@ -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,15 +23,14 @@ 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, object} <-
with {:ok, media} <-
ActivityPub.upload(
file,
user: user,
actor: User.ap_id(user),
description: Map.get(data, :description)
) do
attachment_data = Map.put(object.data, "id", object.id)
render(conn, "attachment.json", %{attachment: attachment_data})
render(conn, "media.json", %{media: media})
end
end
@ -38,17 +38,15 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
@doc "POST /api/v2/media"
def create2(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
with {:ok, object} <-
with {:ok, media} <-
ActivityPub.upload(
file,
actor: User.ap_id(user),
user: user,
description: Map.get(data, :description)
) do
attachment_data = Map.put(object.data, "id", object.id)
conn
|> put_status(202)
|> render("attachment.json", %{attachment: attachment_data})
|> render("media.json", %{media: media})
end
end
@ -56,6 +54,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 +75,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 +96,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

View File

@ -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

View File

@ -24,8 +24,8 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do
@doc "PUT /api/v1/pleroma/mascot"
def update(%{assigns: %{user: user}, body_params: %{file: file}} = conn, _) do
with {:content_type, "image" <> _} <- {:content_type, file.content_type},
{:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)) do
attachment = render_attachment(object)
{:ok, media} <- ActivityPub.upload(file, user: user) do
attachment = Pleroma.Web.MastodonAPI.StatusView.render("media.json", %{media: media})
{:ok, _user} = User.mascot_update(user, attachment)
json(conn, attachment)
@ -34,9 +34,4 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do
render_error(conn, :unsupported_media_type, "mascots can only be images")
end
end
defp render_attachment(object) do
attachment_data = Map.put(object.data, "id", object.id)
Pleroma.Web.MastodonAPI.StatusView.render("attachment.json", %{attachment: attachment_data})
end
end

View File

@ -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),

View File

@ -5,7 +5,7 @@
defmodule Pleroma.Workers.AttachmentsCleanupWorker do
import Ecto.Query
alias Pleroma.Object
alias Pleroma.Media
alias Pleroma.Repo
use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup"
@ -14,22 +14,21 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do
def perform(%Job{
args: %{
"op" => "cleanup_attachments",
"object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}}
"object" => %{"data" => %{"attachment" => [_ | _] = attachments}}
}
}) do
attachments
|> Enum.flat_map(fn item -> Enum.map(item["url"], & &1["href"]) end)
|> fetch_objects
|> prepare_objects(actor, Enum.map(attachments, & &1["name"]))
|> filter_objects
|> do_clean
|> Enum.map(& &1["id"])
|> get_media()
|> set_removable()
|> do_clean()
{:ok, :success}
end
def perform(%Job{args: %{"op" => "cleanup_attachments", "object" => _object}}), do: {:ok, :skip}
defp do_clean({object_ids, attachment_urls}) do
defp do_clean(medias) do
uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
base_url =
@ -38,70 +37,38 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do
"/"
)
Enum.each(attachment_urls, fn href ->
href
|> String.trim_leading("#{base_url}")
|> uploader.delete_file()
Enum.each(medias, fn media ->
with true <- media.removable do
media.href
|> String.trim_leading("#{base_url}")
|> uploader.delete_file()
end
Repo.delete(media)
end)
delete_objects(object_ids)
end
defp delete_objects([_ | _] = object_ids) do
Repo.delete_all(from(o in Object, where: o.id in ^object_ids))
defp get_media(ids) do
from(m in Media,
where: m.id in ^ids
)
|> Repo.all()
end
defp delete_objects(_), do: :ok
defp set_removable(medias) do
Enum.map(medias, fn media ->
from(m in Media,
where: m.href == ^media.href,
select: count(m.id)
)
|> Repo.one!()
|> case do
1 ->
%Media{media | removable: true}
# we should delete 1 object for any given attachment, but don't delete
# files if there are more than 1 object for it
defp filter_objects(objects) do
Enum.reduce(objects, {[], []}, fn {href, %{id: id, count: count}}, {ids, hrefs} ->
with 1 <- count do
{ids ++ [id], hrefs ++ [href]}
else
_ -> {ids ++ [id], hrefs}
_ ->
%Media{media | removable: false}
end
end)
end
defp prepare_objects(objects, actor, names) do
objects
|> Enum.reduce(%{}, fn %{
id: id,
data: %{
"url" => [%{"href" => href}],
"actor" => obj_actor,
"name" => name
}
},
acc ->
Map.update(acc, href, %{id: id, count: 1}, fn val ->
case obj_actor == actor and name in names do
true ->
# set id of the actor's object that will be deleted
%{val | id: id, count: val.count + 1}
false ->
# another actor's object, just increase count to not delete file
%{val | count: val.count + 1}
end
end)
end)
end
defp fetch_objects(hrefs) do
from(o in Object,
where:
fragment(
"to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)",
o.data,
o.data,
^hrefs
)
)
# The query above can be time consumptive on large instances until we
# refactor how uploads are stored
|> Repo.all(timeout: :infinity)
end
end

View File

@ -0,0 +1,19 @@
defmodule Pleroma.Repo.Migrations.CreateMedia do
use Ecto.Migration
def change do
create_if_not_exists table(:media) do
add(:actor, :string)
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)
add(:object_id, references(:objects, on_delete: :delete_all), null: true)
timestamps()
end
end
end

View File

@ -5,10 +5,13 @@
defmodule Pleroma.ObjectTest do
use Pleroma.DataCase
use Oban.Testing, repo: Pleroma.Repo
import ExUnit.CaptureLog
import Pleroma.Factory
import Tesla.Mock
alias Pleroma.Activity
alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
@ -89,11 +92,11 @@ defmodule Pleroma.ObjectTest do
user = insert(:user)
{:ok, %Object{} = attachment} =
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
{:ok, %Media{} = media} = Pleroma.Web.ActivityPub.ActivityPub.upload(file, user: user)
%{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
note =
insert(:note, %{user: user, data: %{"attachment" => [Media.to_object_form(media)]}})
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
@ -106,7 +109,7 @@ defmodule Pleroma.ObjectTest do
ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker))
assert Object.get_by_id(note.id).data["deleted"]
refute Object.get_by_id(attachment.id) == nil
refute Media.get_by_id(media.id) == nil
assert {:ok, ["an_image.jpg"]} == File.ls("#{uploads_dir}/#{path}")
end
@ -123,11 +126,11 @@ defmodule Pleroma.ObjectTest do
user = insert(:user)
{:ok, %Object{} = attachment} =
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
{:ok, %Media{} = media} = Pleroma.Web.ActivityPub.ActivityPub.upload(file, user: user)
%{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
note =
insert(:note, %{user: user, data: %{"attachment" => [Media.to_object_form(media)]}})
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
@ -140,7 +143,7 @@ defmodule Pleroma.ObjectTest do
ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker))
assert Object.get_by_id(note.id).data["deleted"]
assert Object.get_by_id(attachment.id) == nil
assert Media.get_by_id(media.id) == nil
assert {:ok, []} == File.ls("#{uploads_dir}/#{path}")
end
@ -162,11 +165,11 @@ defmodule Pleroma.ObjectTest do
user = insert(:user)
{:ok, %Object{} = attachment} =
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
{:ok, %Media{} = media} = Pleroma.Web.ActivityPub.ActivityPub.upload(file, user: user)
%{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
note =
insert(:note, %{user: user, data: %{"attachment" => [Media.to_object_form(media)]}})
filename = Path.basename(href)
@ -178,7 +181,7 @@ defmodule Pleroma.ObjectTest do
ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker))
assert Object.get_by_id(note.id).data["deleted"]
assert Object.get_by_id(attachment.id) == nil
assert Media.get_by_id(media.id) == nil
assert {:ok, files} = File.ls(uploads_dir)
refute filename in files
end
@ -195,13 +198,13 @@ defmodule Pleroma.ObjectTest do
user = insert(:user)
{:ok, %Object{} = attachment} =
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
{:ok, %Media{} = media} = Pleroma.Web.ActivityPub.ActivityPub.upload(file, user: user)
{:ok, %Object{}} = Object.create(%{url: "https://google.com", actor: user.ap_id})
%{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
note =
insert(:note, %{user: user, data: %{"attachment" => [Media.to_object_form(media)]}})
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
@ -214,7 +217,7 @@ defmodule Pleroma.ObjectTest do
ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker))
assert Object.get_by_id(note.id).data["deleted"]
assert Object.get_by_id(attachment.id) == nil
assert Media.get_by_id(media.id) == nil
assert {:ok, []} == File.ls("#{uploads_dir}/#{path}")
end
@ -232,11 +235,11 @@ defmodule Pleroma.ObjectTest do
user = insert(:user)
{:ok, %Object{} = attachment} =
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
{:ok, %Media{} = media} = Pleroma.Web.ActivityPub.ActivityPub.upload(file, user: user)
%{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
note =
insert(:note, %{user: user, data: %{"attachment" => [Media.to_object_form(media)]}})
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
@ -249,7 +252,7 @@ defmodule Pleroma.ObjectTest do
ObanHelpers.perform(all_enqueued(worker: Pleroma.Workers.AttachmentsCleanupWorker))
assert Object.get_by_id(note.id).data["deleted"]
assert Object.get_by_id(attachment.id) == nil
assert Media.get_by_id(media.id) == nil
assert {:ok, []} == File.ls("#{uploads_dir}/#{path}")
end

View File

@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
alias Pleroma.Activity
alias Pleroma.Builders.ActivityBuilder
alias Pleroma.Config
alias Pleroma.Media
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.User
@ -1068,42 +1069,47 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
filename: "an_image.jpg"
}
%{test_file: test_file}
user = insert(:user)
%{test_file: test_file, user: user}
end
test "sets a description if given", %{test_file: file} do
{:ok, %Object{} = object} = ActivityPub.upload(file, description: "a cool file")
assert object.data["name"] == "a cool file"
test "sets a description if given", %{test_file: file, user: user} do
{:ok, %Media{} = media} = ActivityPub.upload(file, description: "a cool file", user: user)
assert media.name == "a cool file"
end
test "it sets the default description depending on the configuration", %{test_file: file} do
test "it sets the default description depending on the configuration", %{
test_file: file,
user: user
} do
clear_config([Pleroma.Upload, :default_description])
Pleroma.Config.put([Pleroma.Upload, :default_description], nil)
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == ""
{:ok, %Media{} = media} = ActivityPub.upload(file, user: user)
assert media.name == nil
Pleroma.Config.put([Pleroma.Upload, :default_description], :filename)
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "an_image.jpg"
{:ok, %Media{} = media} = ActivityPub.upload(file, user: user)
assert media.name == "an_image.jpg"
Pleroma.Config.put([Pleroma.Upload, :default_description], "unnamed attachment")
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "unnamed attachment"
{:ok, %Media{} = media} = ActivityPub.upload(file, user: user)
assert media.name == "unnamed attachment"
end
test "copies the file to the configured folder", %{test_file: file} do
test "copies the file to the configured folder", %{test_file: file, user: user} do
clear_config([Pleroma.Upload, :default_description], :filename)
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "an_image.jpg"
{:ok, %Media{} = media} = ActivityPub.upload(file, user: user)
assert media.name == "an_image.jpg"
end
test "works with base64 encoded images" do
test "works with base64 encoded images", %{user: user} do
file = %{
img: data_uri()
}
{:ok, %Object{}} = ActivityPub.upload(file)
{:ok, %Media{}} = ActivityPub.upload(file, user: user)
end
end

View File

@ -63,10 +63,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
filename: "an_image.jpg"
}
{:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, attachment} = ActivityPub.upload(file, user: user)
{:ok, attachment} =
attachment.data
attachment
|> AttachmentValidator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert)

View File

@ -4,6 +4,8 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
use Pleroma.DataCase
alias Pleroma.Media
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
@ -82,11 +84,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
filename: "an_image.jpg"
}
{:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, media} = ActivityPub.upload(file, user: user)
valid_chat_message =
valid_chat_message
|> Map.put("attachment", attachment.data)
|> Map.put("attachment", Media.to_object_form(media))
assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
@ -103,11 +105,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
filename: "an_image.jpg"
}
{:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, media} = ActivityPub.upload(file, user: user)
valid_chat_message =
valid_chat_message
|> Map.put("attachment", [attachment.data])
|> Map.put("attachment", [Media.to_object_form(media)])
assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
@ -124,11 +126,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
filename: "an_image.jpg"
}
{:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, media} = ActivityPub.upload(file, user: user)
valid_chat_message =
valid_chat_message
|> Map.put("attachment", attachment.data)
|> Map.put("attachment", Media.to_object_form(media))
|> Map.delete("content")
assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])

View File

@ -65,21 +65,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
assert object.data["url"] == "https://channels.tests.funkwhale.audio/library/tracks/74"
assert object.data["attachment"] == [
%{
"mediaType" => "audio/ogg",
"type" => "Link",
"name" => nil,
"blurhash" => nil,
"url" => [
%{
"href" =>
"https://channels.tests.funkwhale.audio/api/v1/listen/3901e5d8-0445-49d5-9711-e096cf32e515/?upload=42342395-0208-4fee-a38d-259a6dae0871&download=false",
"mediaType" => "audio/ogg",
"type" => "Link"
}
]
}
]
assert match?(
[
%{
"mediaType" => "audio/ogg",
"type" => "Link",
"name" => nil,
"blurhash" => nil,
"url" => [
%{
"href" =>
"https://channels.tests.funkwhale.audio/api/v1/listen/3901e5d8-0445-49d5-9711-e096cf32e515/?upload=42342395-0208-4fee-a38d-259a6dae0871&download=false",
"mediaType" => "audio/ogg",
"type" => "Link"
}
]
}
],
object.data["attachment"]
)
end
end

View File

@ -49,22 +49,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do
assert object.data["url"] ==
"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
assert object.data["attachment"] == [
%{
"type" => "Link",
"mediaType" => "video/mp4",
"name" => nil,
"blurhash" => nil,
"url" => [
%{
"href" =>
"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
"mediaType" => "video/mp4",
"type" => "Link"
}
]
}
]
assert match?(
[
%{
"type" => "Link",
"mediaType" => "video/mp4",
"name" => nil,
"blurhash" => nil,
"url" => [
%{
"href" =>
"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
"mediaType" => "video/mp4",
"type" => "Link"
}
]
}
],
object.data["attachment"]
)
data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!()
@ -72,22 +75,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do
assert object = Object.normalize(activity, fetch: false)
assert object.data["attachment"] == [
%{
"type" => "Link",
"mediaType" => "video/mp4",
"name" => nil,
"blurhash" => nil,
"url" => [
%{
"href" =>
"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4",
"mediaType" => "video/mp4",
"type" => "Link"
}
]
}
]
assert match?(
[
%{
"type" => "Link",
"mediaType" => "video/mp4",
"name" => nil,
"blurhash" => nil,
"url" => [
%{
"href" =>
"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4",
"mediaType" => "video/mp4",
"type" => "Link"
}
]
}
],
object.data["attachment"]
)
assert object.data["url"] ==
"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"

View File

@ -511,31 +511,76 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
end
test "returns list attachments with desc" do
object = insert(:note)
desc = Jason.encode!(%{object.id => "test-desc"})
media = insert(:media)
desc = Jason.encode!(%{media.id => "test-desc"})
assert Utils.attachments_from_ids_descs(["#{object.id}", "34"], desc) == [
Map.merge(object.data, %{"name" => "test-desc"})
]
assert match?(
[
%{
"mediaType" => "image/png",
"name" => "test-desc",
"type" => "Document",
"url" => [
%{
"href" => "https://pleroma.social/images/pleroma_tan_2.1_cofe.png",
"mediaType" => "image/png",
"type" => "Link"
}
]
}
],
Utils.attachments_from_ids_descs(["#{media.id}", "34"], desc)
)
end
end
describe "attachments_from_ids/1" do
test "returns attachments with descs" do
object = insert(:note)
desc = Jason.encode!(%{object.id => "test-desc"})
media = insert(:media)
desc = Jason.encode!(%{media.id => "test-desc"})
assert Utils.attachments_from_ids(%{
media_ids: ["#{object.id}"],
descriptions: desc
}) == [
Map.merge(object.data, %{"name" => "test-desc"})
]
assert match?(
[
%{
"mediaType" => "image/png",
"name" => "test-desc",
"type" => "Document",
"url" => [
%{
"href" => "https://pleroma.social/images/pleroma_tan_2.1_cofe.png",
"mediaType" => "image/png",
"type" => "Link"
}
]
}
],
Utils.attachments_from_ids(%{
media_ids: ["#{media.id}"],
descriptions: desc
})
)
end
test "returns attachments without descs" do
object = insert(:note)
assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}) == [object.data]
media = insert(:media)
assert match?(
[
%{
"mediaType" => "image/png",
"name" => nil,
"type" => "Document",
"url" => [
%{
"href" => "https://pleroma.social/images/pleroma_tan_2.1_cofe.png",
"mediaType" => "image/png",
"type" => "Link"
}
]
}
],
Utils.attachments_from_ids(%{media_ids: ["#{media.id}"]})
)
end
test "returns [] when not pass media_ids" do

View File

@ -119,7 +119,7 @@ defmodule Pleroma.Web.CommonAPITest do
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: author.ap_id)
{:ok, upload} = ActivityPub.upload(file, user: author)
with_mocks([
{

View File

@ -385,11 +385,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
filename: "an_image.jpg"
}
{:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, %{id: media_id}} = ActivityPub.upload(file, user: user)
{:ok, %{id: image_post_id}} = CommonAPI.post(user, %{status: "cofe", media_ids: [media_id]})
{:ok, %{id: media_id}} = ActivityPub.upload(file, actor: other_user.ap_id)
{:ok, %{id: media_id}} = ActivityPub.upload(file, user: other_user)
{:ok, %{id: other_image_post_id}} =
CommonAPI.post(other_user, %{status: "cofe2", media_ids: [media_id]})

View File

@ -5,8 +5,7 @@
defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Media
alias Pleroma.Web.ActivityPub.ActivityPub
describe "Upload media" do
@ -38,8 +37,8 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
assert media["description"] == desc
assert media["id"]
object = Object.get_by_id(media["id"])
assert object.data["actor"] == User.ap_id(conn.assigns[:user])
media = Media.get_by_id(media["id"])
assert media.actor == conn.assigns[:user].ap_id
end
test "/api/v2/media", %{conn: conn, user: user, image: image} do
@ -64,8 +63,8 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
assert media["description"] == desc
assert media["id"]
object = Object.get_by_id(media["id"])
assert object.data["actor"] == user.ap_id
media = Media.get_by_id(media["id"])
assert media.actor == user.ap_id
end
end
@ -79,25 +78,25 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
filename: "an_image.jpg"
}
{:ok, %Object{} = object} =
{:ok, %Media{} = media} =
ActivityPub.upload(
file,
actor: User.ap_id(actor),
user: actor,
description: "test-m"
)
[object: object]
[media: media]
end
test "/api/v1/media/:id good request", %{conn: conn, object: object} do
media =
test "/api/v1/media/:id good request", %{conn: conn, media: media} do
media2 =
conn
|> put_req_header("content-type", "multipart/form-data")
|> put("/api/v1/media/#{object.id}", %{"description" => "test-media"})
|> put("/api/v1/media/#{media.id}", %{"description" => "test-media"})
|> json_response_and_validate_schema(:ok)
assert media["description"] == "test-media"
assert refresh_record(object).data["name"] == "test-media"
assert media2["description"] == "test-media"
assert refresh_record(media).name == "test-media"
end
end
@ -111,35 +110,35 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
filename: "an_image.jpg"
}
{:ok, %Object{} = object} =
{:ok, %Media{} = media} =
ActivityPub.upload(
file,
actor: User.ap_id(actor),
user: actor,
description: "test-media"
)
[object: object]
[media: media]
end
test "it returns media object when requested by owner", %{conn: conn, object: object} do
media =
test "it returns media object when requested by owner", %{conn: conn, media: media} do
media2 =
conn
|> get("/api/v1/media/#{object.id}")
|> get("/api/v1/media/#{media.id}")
|> json_response_and_validate_schema(:ok)
assert media["description"] == "test-media"
assert media["type"] == "image"
assert media["id"]
assert media2["description"] == "test-media"
assert media2["type"] == "image"
assert media2["id"]
end
test "it returns 403 if media object requested by non-owner", %{object: object, user: user} do
test "it returns 403 if media object requested by non-owner", %{media: media, user: user} do
%{conn: conn, user: other_user} = oauth_access(["read:media"])
assert object.data["actor"] == user.ap_id
assert media.actor == user.ap_id
refute user.id == other_user.id
conn
|> get("/api/v1/media/#{object.id}")
|> get("/api/v1/media/#{media.id}")
|> json_response(403)
end
end

View File

@ -168,7 +168,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, upload} = ActivityPub.upload(file, user: user)
conn =
conn
@ -409,7 +409,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, upload} = ActivityPub.upload(file, user: user)
conn =
conn

View File

@ -27,11 +27,11 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, media} = ActivityPub.upload(file, user: user)
attrs = %{
params: %{
"media_ids" => [upload.id],
"media_ids" => [media.id],
"status" => "hi",
"sensitive" => true,
"spoiler_text" => "spoiler",
@ -47,12 +47,12 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
expected = %{
id: to_string(scheduled_activity.id),
media_attachments:
%{media_ids: [upload.id]}
%{media_ids: [media.id]}
|> Utils.attachments_from_ids()
|> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})),
params: %{
in_reply_to_id: to_string(activity.id),
media_ids: [upload.id],
media_ids: [media.id],
poll: nil,
scheduled_at: nil,
sensitive: true,

View File

@ -112,7 +112,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, upload} = ActivityPub.upload(file, user: user)
other_user = insert(:user)

View File

@ -24,7 +24,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, upload} = ActivityPub.upload(file, user: user)
{:ok, activity} =
CommonAPI.post_chat_message(user, recipient, "kippis :firefox:", idempotency_key: "123")

View File

@ -242,7 +242,7 @@ defmodule Pleroma.Web.Push.ImplTest do
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, upload} = ActivityPub.upload(file, user: user)
{:ok, chat} = CommonAPI.post_chat_message(user, recipient, nil, media_id: upload.id)
object = Object.normalize(chat, fetch: false)

View File

@ -458,4 +458,13 @@ defmodule Pleroma.Factory do
phrase: "cofe"
}
end
def media_factory do
%Pleroma.Media{
href: "https://pleroma.social/images/pleroma_tan_2.1_cofe.png",
type: "Link",
media_type: "image/png",
actor: build(:user).ap_id
}
end
end