[#210] [TwitterAPI] Made actor be stored for uploads. Added ownership check

to `update_media` action. Added controller tests for `upload` and `update_media` actions.
Refactoring.
This commit is contained in:
Ivan Tashkinov 2018-12-05 13:37:06 +03:00
parent 53797d19c5
commit 848151f7cb
8 changed files with 120 additions and 40 deletions

View file

@ -574,7 +574,8 @@ def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do
def upload(file, opts \\ []) do def upload(file, opts \\ []) do
with {:ok, data} <- Upload.store(file, opts) do with {:ok, data} <- Upload.store(file, opts) do
Repo.insert(%Object{data: data}) obj_data = if opts[:actor], do: Map.put(data, "actor", opts[:actor]), else: data
Repo.insert(%Object{data: obj_data})
end end
end end

View file

@ -93,8 +93,12 @@ def unfav(%User{} = user, ap_id_or_id) do
end end
end end
def upload(%Plug.Upload{} = file, format \\ "xml") do def ap_upload(%Plug.Upload{} = file, %User{} = user) do
{:ok, object} = ActivityPub.upload(file) ActivityPub.upload(file, actor: User.ap_id(user))
end
def upload(%Plug.Upload{} = file, %User{} = user, format \\ "xml") do
{:ok, object} = ap_upload(file, user)
url = List.first(object.data["url"]) url = List.first(object.data["url"])
href = url["href"] href = url["href"]

View file

@ -230,34 +230,47 @@ def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
Updates metadata of uploaded media object. Updates metadata of uploaded media object.
Derived from [Twitter API endpoint](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create). Derived from [Twitter API endpoint](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create).
""" """
def update_media(%{assigns: %{user: _}} = conn, %{"media_id" => id} = data) do def update_media(%{assigns: %{user: user}} = conn, %{"media_id" => id} = data) do
object = Repo.get(Object, id)
description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"] description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"]
with %Object{} = object <- Repo.get(Object, id), {conn, status, response_body} =
is_binary(description) do cond do
new_data = Map.put(object.data, "name", description) !object ->
{halt(conn), :not_found, ""}
{:ok, _} = object.data["actor"] != User.ap_id(user) ->
object {halt(conn), :forbidden, "You can only update your own uploads."}
|> Object.change(%{data: new_data})
|> Repo.update() !is_binary(description) ->
end {conn, :not_modified, ""}
true ->
new_data = Map.put(object.data, "name", description)
{:ok, _} =
object
|> Object.change(%{data: new_data})
|> Repo.update()
{conn, :no_content, ""}
end
conn conn
|> put_status(:no_content) |> put_status(status)
|> json("") |> json(response_body)
end end
def upload(conn, %{"media" => media}) do def upload(%{assigns: %{user: user}} = conn, %{"media" => media}) do
response = TwitterAPI.upload(media) response = TwitterAPI.upload(media, user)
conn conn
|> put_resp_content_type("application/atom+xml") |> put_resp_content_type("application/atom+xml")
|> send_resp(200, response) |> send_resp(200, response)
end end
def upload_json(conn, %{"media" => media}) do def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do
response = TwitterAPI.upload(media, "json") response = TwitterAPI.upload(media, user, "json")
conn conn
|> json_reply(200, response) |> json_reply(200, response)

View file

@ -36,6 +36,23 @@ defmodule Pleroma.DataCase do
:ok :ok
end end
def ensure_local_uploader(_context) do
uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
filters = Pleroma.Config.get([Pleroma.Upload, :filters])
unless uploader == Pleroma.Uploaders.Local || filters != [] do
Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
Pleroma.Config.put([Pleroma.Upload, :filters], [])
on_exit(fn ->
Pleroma.Config.put([Pleroma.Upload, :uploader], uploader)
Pleroma.Config.put([Pleroma.Upload, :filters], filters)
end)
end
:ok
end
@doc """ @doc """
A helper that transform changeset errors to a map of messages. A helper that transform changeset errors to a map of messages.

View file

@ -3,22 +3,7 @@ defmodule Pleroma.UploadTest do
use Pleroma.DataCase use Pleroma.DataCase
describe "Storing a file with the Local uploader" do describe "Storing a file with the Local uploader" do
setup do setup [:ensure_local_uploader]
uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
filters = Pleroma.Config.get([Pleroma.Upload, :filters])
unless uploader == Pleroma.Uploaders.Local || filters != [] do
Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
Pleroma.Config.put([Pleroma.Upload, :filters], [])
on_exit(fn ->
Pleroma.Config.put([Pleroma.Upload, :uploader], uploader)
Pleroma.Config.put([Pleroma.Upload, :filters], filters)
end)
end
:ok
end
test "returns a media url" do test "returns a media url" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")

View file

@ -804,7 +804,7 @@ test "gets an users media", %{conn: conn} do
} }
media = media =
TwitterAPI.upload(file, "json") TwitterAPI.upload(file, user, "json")
|> Poison.decode!() |> Poison.decode!()
{:ok, image_post} = {:ok, image_post} =

View file

@ -1254,15 +1254,74 @@ test "it returns users, ordered by similarity", %{conn: conn} do
end end
end end
describe "POST /api/media/metadata/create" do describe "POST /api/media/upload" do
test "it updates `data[name]` of referenced Object with provided value", %{conn: conn} do setup context do
Pleroma.DataCase.ensure_local_uploader(context)
end
test "it performs the upload and sets `data[actor]` with AP id of uploader user", %{
conn: conn
} do
user = insert(:user) user = insert(:user)
upload_filename = "test/fixtures/image_tmp.jpg"
File.cp!("test/fixtures/image.jpg", upload_filename)
file = %Plug.Upload{
content_type: "image/jpg",
path: Path.absname(upload_filename),
filename: "image.jpg"
}
response =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/octet-stream")
|> post("/api/media/upload", %{
"media" => file
})
|> json_response(:ok)
assert response["media_id"]
object = Repo.get(Object, response["media_id"])
assert object
assert object.data["actor"] == User.ap_id(user)
end
end
describe "POST /api/media/metadata/create" do
setup do
object = insert(:note) object = insert(:note)
description = "Informative description of the image. Initial: #{object.data["name"]}}" user = User.get_by_ap_id(object.data["actor"])
%{object: object, user: user}
end
test "it returns :forbidden status on attempt to modify someone else's upload", %{
conn: conn,
object: object
} do
initial_description = object.data["name"]
another_user = insert(:user)
conn
|> assign(:user, another_user)
|> post("/api/media/metadata/create", %{"media_id" => object.id})
|> json_response(:forbidden)
object = Repo.get(Object, object.id)
assert object.data["name"] == initial_description
end
test "it updates `data[name]` of referenced Object with provided value", %{
conn: conn,
object: object,
user: user
} do
description = "Informative description of the image. Initial value: #{object.data["name"]}}"
conn conn
|> assign(:user, user) |> assign(:user, user)
|> post("/api/media/metadata/create.json", %{ |> post("/api/media/metadata/create", %{
"media_id" => object.id, "media_id" => object.id,
"alt_text" => %{"text" => description} "alt_text" => %{"text" => description}
}) })

View file

@ -182,13 +182,14 @@ test "Unblock another user using screen_name" do
end end
test "upload a file" do test "upload a file" do
user = insert(:user)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
response = TwitterAPI.upload(file) response = TwitterAPI.upload(file, user)
assert is_binary(response) assert is_binary(response)
end end