Compare commits
15 Commits
feature/sa
...
3259-objec
Author | SHA1 | Date | |
---|---|---|---|
|
90c60993c1 | ||
|
4b10d15e62 | ||
|
4ade12bf82 | ||
|
093649509e | ||
|
5afdca7ddf | ||
|
a35299dd96 | ||
|
2289a1d587 | ||
|
dbaa15232b | ||
|
8a7b081966 | ||
|
d960d926a0 | ||
|
07e80e39b1 | ||
|
8553df904a | ||
|
81913e3a1a | ||
|
cf1c101849 | ||
|
193c17cea5 |
@ -104,7 +104,8 @@ defmodule Pleroma.Application do
|
||||
chat_child(chat_enabled?()) ++
|
||||
[
|
||||
Pleroma.Web.Endpoint,
|
||||
Pleroma.Gopher.Server
|
||||
Pleroma.Gopher.Server,
|
||||
Pleroma.Migrators.MediaTableMigrator
|
||||
]
|
||||
|
||||
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
|
||||
|
46
lib/pleroma/data_migration.ex
Normal file
46
lib/pleroma/data_migration.ex
Normal file
@ -0,0 +1,46 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.DataMigration do
|
||||
use Ecto.Schema
|
||||
|
||||
alias Pleroma.DataMigration
|
||||
alias Pleroma.DataMigration.State
|
||||
alias Pleroma.Repo
|
||||
|
||||
import Ecto.Changeset
|
||||
|
||||
schema "data_migrations" do
|
||||
field(:name, :string)
|
||||
field(:state, State, default: :pending)
|
||||
field(:feature_lock, :boolean, default: false)
|
||||
field(:params, :map, default: %{})
|
||||
field(:data, :map, default: %{})
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
def changeset(data_migration, params \\ %{}) do
|
||||
data_migration
|
||||
|> cast(params, [:name, :state, :feature_lock, :params, :data])
|
||||
|> validate_required([:name])
|
||||
|> unique_constraint(:name)
|
||||
end
|
||||
|
||||
def update(data_migration, params \\ %{}) do
|
||||
data_migration
|
||||
|> changeset(params)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
def update_state(data_migration, new_state) do
|
||||
update(data_migration, %{state: new_state})
|
||||
end
|
||||
|
||||
def get_by_name(name) do
|
||||
Repo.get_by(DataMigration, name: name)
|
||||
end
|
||||
|
||||
def populate_media_table, do: get_by_name("populate_media_table")
|
||||
end
|
@ -17,3 +17,11 @@ defenum(Pleroma.FollowingRelationship.State,
|
||||
follow_accept: 2,
|
||||
follow_reject: 3
|
||||
)
|
||||
|
||||
defenum(Pleroma.DataMigration.State,
|
||||
pending: 1,
|
||||
running: 2,
|
||||
complete: 3,
|
||||
failed: 4,
|
||||
manual: 5
|
||||
)
|
||||
|
95
lib/pleroma/media.ex
Normal file
95
lib/pleroma/media.ex
Normal 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
|
301
lib/pleroma/migrators/media_table_migrator.ex
Normal file
301
lib/pleroma/migrators/media_table_migrator.ex
Normal file
@ -0,0 +1,301 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Migrators.MediaTableMigrator do
|
||||
use GenServer
|
||||
|
||||
require Logger
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
alias __MODULE__.State
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.DataMigration
|
||||
alias Pleroma.Media
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
|
||||
defdelegate state(), to: State, as: :get
|
||||
defdelegate put_stat(key, value), to: State, as: :put
|
||||
defdelegate increment_stat(key, increment), to: State, as: :increment
|
||||
|
||||
defdelegate data_migration(), to: DataMigration, as: :populate_media_table
|
||||
|
||||
@reg_name {:global, __MODULE__}
|
||||
|
||||
def whereis, do: GenServer.whereis(@reg_name)
|
||||
|
||||
def start_link(_) do
|
||||
case whereis() do
|
||||
nil ->
|
||||
GenServer.start_link(__MODULE__, nil, name: @reg_name)
|
||||
|
||||
pid ->
|
||||
{:ok, pid}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_) do
|
||||
{:ok, nil, {:continue, :init_state}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_continue(:init_state, _state) do
|
||||
{:ok, _} = State.start_link(nil)
|
||||
|
||||
update_status(:init)
|
||||
|
||||
data_migration = data_migration()
|
||||
manual_migrations = Config.get([:instance, :manual_data_migrations], [])
|
||||
|
||||
cond do
|
||||
Config.get(:env) == :test ->
|
||||
update_status(:noop)
|
||||
|
||||
is_nil(data_migration) ->
|
||||
update_status(:halt, "Data migration does not exist.")
|
||||
|
||||
data_migration.state == :manual or data_migration.name in manual_migrations ->
|
||||
update_status(:noop, "Data migration is in manual execution state.")
|
||||
|
||||
data_migration.state == :complete ->
|
||||
handle_success(data_migration)
|
||||
|
||||
true ->
|
||||
send(self(), :process_attachments)
|
||||
end
|
||||
|
||||
{:noreply, nil}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(:process_attachments, state) do
|
||||
State.clear()
|
||||
|
||||
data_migration = data_migration()
|
||||
|
||||
persistent_data = Map.take(data_migration.data, ["max_processed_id"])
|
||||
|
||||
{:ok, data_migration} =
|
||||
DataMigration.update(data_migration, %{state: :running, data: persistent_data})
|
||||
|
||||
update_status(:running)
|
||||
put_stat(:started_at, NaiveDateTime.utc_now())
|
||||
|
||||
Logger.info("Starting creating `media` records for objects' attachments...")
|
||||
|
||||
max_processed_id = data_migration.data["max_processed_id"] || 0
|
||||
|
||||
query()
|
||||
|> where([object], object.id > ^max_processed_id)
|
||||
|> Repo.chunk_stream(100, :batches, timeout: :infinity)
|
||||
|> Stream.each(fn objects ->
|
||||
object_ids = Enum.map(objects, & &1.id)
|
||||
|
||||
failed_ids =
|
||||
objects
|
||||
|> Enum.map(&process_object_attachments(&1))
|
||||
|> Enum.filter(&(elem(&1, 0) == :error))
|
||||
|> Enum.map(&elem(&1, 1))
|
||||
|
||||
for failed_id <- failed_ids do
|
||||
_ =
|
||||
Repo.query(
|
||||
"INSERT INTO data_migration_failed_ids(data_migration_id, record_id) " <>
|
||||
"VALUES ($1, $2) ON CONFLICT DO NOTHING;",
|
||||
[data_migration.id, failed_id]
|
||||
)
|
||||
end
|
||||
|
||||
_ =
|
||||
Repo.query(
|
||||
"DELETE FROM data_migration_failed_ids " <>
|
||||
"WHERE data_migration_id = $1 AND record_id = ANY($2)",
|
||||
[data_migration.id, object_ids -- failed_ids]
|
||||
)
|
||||
|
||||
max_object_id = Enum.at(object_ids, -1)
|
||||
|
||||
put_stat(:max_processed_id, max_object_id)
|
||||
increment_stat(:processed_count, length(object_ids))
|
||||
increment_stat(:failed_count, length(failed_ids))
|
||||
|
||||
put_stat(
|
||||
:records_per_second,
|
||||
state()[:processed_count] /
|
||||
Enum.max([NaiveDateTime.diff(NaiveDateTime.utc_now(), state()[:started_at]), 1])
|
||||
)
|
||||
|
||||
persist_stats(data_migration)
|
||||
|
||||
# A quick and dirty approach to controlling the load this background migration imposes
|
||||
sleep_interval = Config.get([:populate_media_table, :sleep_interval_ms], 0)
|
||||
Process.sleep(sleep_interval)
|
||||
end)
|
||||
|> Stream.run()
|
||||
|
||||
with 0 <- failures_count(data_migration.id) do
|
||||
{:ok, data_migration} = DataMigration.update_state(data_migration, :complete)
|
||||
|
||||
handle_success(data_migration)
|
||||
else
|
||||
_ ->
|
||||
_ = DataMigration.update_state(data_migration, :failed)
|
||||
|
||||
update_status(:failed, "Please check data_migration_failed_ids records.")
|
||||
end
|
||||
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def query do
|
||||
from(
|
||||
object in Object,
|
||||
where:
|
||||
fragment(
|
||||
"(?)->'attachment' IS NOT NULL AND \
|
||||
(?)->'attachment' != ANY(ARRAY['null'::jsonb, '[]'::jsonb])",
|
||||
object.data,
|
||||
object.data
|
||||
),
|
||||
select: %{
|
||||
id: object.id,
|
||||
attachment: fragment("(?)->'attachment'", object.data),
|
||||
actor: fragment("(?)->'actor'", object.data)
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
defp process_object_attachments(object) do
|
||||
attachments =
|
||||
if Map.has_key?(object, :attachment), do: object.attachment, else: object.data["attachment"]
|
||||
|
||||
actor = if Map.has_key?(object, :actor), do: object.actor, else: object.data["actor"]
|
||||
|
||||
Repo.transaction(fn ->
|
||||
with {_, true} <- {:any, Enum.any?(attachments || [], &is_nil(&1["id"]))},
|
||||
updated_attachments =
|
||||
Enum.map(attachments, fn attachment ->
|
||||
if is_nil(attachment["id"]) do
|
||||
with {:ok, media} <-
|
||||
Media.create_from_object_data(attachment, %{
|
||||
actor: actor,
|
||||
object_id: object.id
|
||||
}) do
|
||||
Map.put(attachment, "id", media.id)
|
||||
else
|
||||
{:error, e} ->
|
||||
error =
|
||||
"ERROR: could not process attachment of object #{object.id}: " <>
|
||||
"#{attachment["href"]}: #{inspect(e)}"
|
||||
|
||||
Logger.error(error)
|
||||
Repo.rollback(object.id)
|
||||
end
|
||||
else
|
||||
attachment
|
||||
end
|
||||
end),
|
||||
{:ok, _} <-
|
||||
Object.update_data(%Object{id: object.id}, %{"attachment" => updated_attachments}) do
|
||||
object.id
|
||||
else
|
||||
{:any, false} ->
|
||||
object.id
|
||||
|
||||
{:error, e} ->
|
||||
error = "ERROR: could not update attachments of object #{object.id}: #{inspect(e)}"
|
||||
|
||||
Logger.error(error)
|
||||
Repo.rollback(object.id)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@doc "Approximate count for current iteration (including processed records count)"
|
||||
def count(force \\ false, timeout \\ :infinity) do
|
||||
stored_count = state()[:count]
|
||||
|
||||
if stored_count && !force do
|
||||
stored_count
|
||||
else
|
||||
processed_count = state()[:processed_count] || 0
|
||||
max_processed_id = data_migration().data["max_processed_id"] || 0
|
||||
query = where(query(), [object], object.id > ^max_processed_id)
|
||||
|
||||
count = Repo.aggregate(query, :count, :id, timeout: timeout) + processed_count
|
||||
put_stat(:count, count)
|
||||
count
|
||||
end
|
||||
end
|
||||
|
||||
defp persist_stats(data_migration) do
|
||||
runner_state = Map.drop(state(), [:status])
|
||||
_ = DataMigration.update(data_migration, %{data: runner_state})
|
||||
end
|
||||
|
||||
defp handle_success(_data_migration) do
|
||||
update_status(:complete)
|
||||
end
|
||||
|
||||
def failed_objects_query do
|
||||
from(o in Object)
|
||||
|> join(:inner, [o], dmf in fragment("SELECT * FROM data_migration_failed_ids"),
|
||||
on: dmf.record_id == o.id
|
||||
)
|
||||
|> where([_o, dmf], dmf.data_migration_id == ^data_migration().id)
|
||||
|> order_by([o], asc: o.id)
|
||||
end
|
||||
|
||||
def failures_count(data_migration_id \\ nil) do
|
||||
data_migration_id = data_migration_id || data_migration().id
|
||||
|
||||
with {:ok, %{rows: [[count]]}} <-
|
||||
Repo.query(
|
||||
"SELECT COUNT(record_id) FROM data_migration_failed_ids WHERE data_migration_id = $1;",
|
||||
[data_migration_id]
|
||||
) do
|
||||
count
|
||||
end
|
||||
end
|
||||
|
||||
def retry_failed do
|
||||
data_migration = data_migration()
|
||||
|
||||
failed_objects_query()
|
||||
|> Repo.chunk_stream(100, :one)
|
||||
|> Stream.each(fn object ->
|
||||
with {:ok, _} <- process_object_attachments(object) do
|
||||
_ =
|
||||
Repo.query(
|
||||
"DELETE FROM data_migration_failed_ids " <>
|
||||
"WHERE data_migration_id = $1 AND record_id = $2",
|
||||
[data_migration.id, object.id]
|
||||
)
|
||||
end
|
||||
end)
|
||||
|> Stream.run()
|
||||
end
|
||||
|
||||
def force_continue do
|
||||
send(whereis(), :process_attachments)
|
||||
end
|
||||
|
||||
def force_restart do
|
||||
{:ok, _} = DataMigration.update(data_migration(), %{state: :pending, data: %{}})
|
||||
force_continue()
|
||||
end
|
||||
|
||||
def force_complete do
|
||||
{:ok, data_migration} = DataMigration.update_state(data_migration(), :complete)
|
||||
|
||||
handle_success(data_migration)
|
||||
end
|
||||
|
||||
defp update_status(status, message \\ nil) do
|
||||
put_stat(:status, status)
|
||||
put_stat(:message, message)
|
||||
end
|
||||
end
|
35
lib/pleroma/migrators/media_table_migrator/state.ex
Normal file
35
lib/pleroma/migrators/media_table_migrator/state.ex
Normal file
@ -0,0 +1,35 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Migrators.MediaTableMigrator.State do
|
||||
use Agent
|
||||
|
||||
@init_state %{}
|
||||
@reg_name {:global, __MODULE__}
|
||||
|
||||
def start_link(_) do
|
||||
Agent.start_link(fn -> @init_state end, name: @reg_name)
|
||||
end
|
||||
|
||||
def clear do
|
||||
Agent.update(@reg_name, fn _state -> @init_state end)
|
||||
end
|
||||
|
||||
def get do
|
||||
Agent.get(@reg_name, & &1)
|
||||
end
|
||||
|
||||
def put(key, value) do
|
||||
Agent.update(@reg_name, fn state ->
|
||||
Map.put(state, key, value)
|
||||
end)
|
||||
end
|
||||
|
||||
def increment(key, increment \\ 1) do
|
||||
Agent.update(@reg_name, fn state ->
|
||||
updated_value = (state[key] || 0) + increment
|
||||
Map.put(state, key, updated_value)
|
||||
end)
|
||||
end
|
||||
end
|
@ -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
|
||||
|
@ -63,8 +63,8 @@ defmodule Pleroma.Repo do
|
||||
iex> Pleroma.Repo.chunk_stream(Pleroma.Activity.Queries.by_actor(ap_id), 500, :batches)
|
||||
"""
|
||||
@spec chunk_stream(Ecto.Query.t(), integer(), atom()) :: Enumerable.t()
|
||||
def chunk_stream(query, chunk_size, returns_as \\ :one) do
|
||||
# We don't actually need start and end funcitons of resource streaming,
|
||||
def chunk_stream(query, chunk_size, returns_as \\ :one, query_options \\ []) do
|
||||
# We don't actually need start and end functions of resource streaming,
|
||||
# but it seems to be the only way to not fetch records one-by-one and
|
||||
# have individual records be the elements of the stream, instead of
|
||||
# lists of records
|
||||
@ -76,7 +76,7 @@ defmodule Pleroma.Repo do
|
||||
|> order_by(asc: :id)
|
||||
|> where([r], r.id > ^last_id)
|
||||
|> limit(^chunk_size)
|
||||
|> all()
|
||||
|> all(query_options)
|
||||
|> case do
|
||||
[] ->
|
||||
{:halt, last_id}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
19
priv/repo/migrations/20201125170429_create_media.exs
Normal file
19
priv/repo/migrations/20201125170429_create_media.exs
Normal 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
|
@ -0,0 +1,17 @@
|
||||
defmodule Pleroma.Repo.Migrations.CreateDataMigrations do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create_if_not_exists table(:data_migrations) do
|
||||
add(:name, :string, null: false)
|
||||
add(:state, :integer, default: 1)
|
||||
add(:feature_lock, :boolean, default: false)
|
||||
add(:params, :map, default: %{})
|
||||
add(:data, :map, default: %{})
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
create_if_not_exists(unique_index(:data_migrations, [:name]))
|
||||
end
|
||||
end
|
@ -0,0 +1,14 @@
|
||||
defmodule Pleroma.Repo.Migrations.CreateDataMigrationFailedIds do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create_if_not_exists table(:data_migration_failed_ids, primary_key: false) do
|
||||
add(:data_migration_id, references(:data_migrations), null: false)
|
||||
add(:record_id, :bigint, null: false)
|
||||
end
|
||||
|
||||
create_if_not_exists(
|
||||
unique_index(:data_migration_failed_ids, [:data_migration_id, :record_id])
|
||||
)
|
||||
end
|
||||
end
|
@ -0,0 +1,14 @@
|
||||
defmodule Pleroma.Repo.Migrations.DataMigrationCreatePopulateMediaTable do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
dt = NaiveDateTime.utc_now()
|
||||
|
||||
execute(
|
||||
"INSERT INTO data_migrations(name, inserted_at, updated_at) " <>
|
||||
"VALUES ('populate_media_table', '#{dt}', '#{dt}') ON CONFLICT DO NOTHING;"
|
||||
)
|
||||
end
|
||||
|
||||
def down, do: :ok
|
||||
end
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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, [])
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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([
|
||||
{
|
||||
|
@ -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]})
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user