diff --git a/lib/mobilizon/media/file.ex b/lib/mobilizon/media/file.ex index a424b8c63..2574a012b 100644 --- a/lib/mobilizon/media/file.ex +++ b/lib/mobilizon/media/file.ex @@ -9,6 +9,7 @@ defmodule Mobilizon.Media.File do field(:name, :string) field(:url, :string) field(:content_type, :string) + field(:size, :integer) timestamps() end @@ -16,7 +17,7 @@ defmodule Mobilizon.Media.File do @doc false def changeset(picture, attrs) do picture - |> cast(attrs, [:name, :url, :content_type]) + |> cast(attrs, [:name, :url, :content_type, :size]) |> validate_required([:name, :url]) end end diff --git a/lib/mobilizon_web/resolvers/picture.ex b/lib/mobilizon_web/resolvers/picture.ex index 18c0caa59..c98a0346a 100644 --- a/lib/mobilizon_web/resolvers/picture.ex +++ b/lib/mobilizon_web/resolvers/picture.ex @@ -36,7 +36,8 @@ defmodule MobilizonWeb.Resolvers.Picture do @spec do_fetch_picture(String.t()) :: {:ok, Picture.t()} | {:error, :not_found} defp do_fetch_picture(picture_id) do with %Picture{id: id, file: file} = _pic <- Media.get_picture(picture_id) do - {:ok, %{name: file.name, url: file.url, id: id}} + {:ok, + %{name: file.name, url: file.url, id: id, content_type: file.content_type, size: file.size}} else _err -> {:error, "Picture with ID #{picture_id} was not found"} @@ -50,11 +51,23 @@ defmodule MobilizonWeb.Resolvers.Picture do } }) do with {:is_owned, true, _actor} <- User.owns_actor(user, actor_id), - {:ok, %{"url" => [%{"href" => url}]}} <- MobilizonWeb.Upload.store(file), - args <- Map.put(args, :url, url), + {:ok, %{"url" => [%{"href" => url, "mediaType" => content_type}], "size" => size}} <- + MobilizonWeb.Upload.store(file), + args <- + args + |> Map.put(:url, url) + |> Map.put(:size, size) + |> Map.put(:content_type, content_type), {:ok, picture = %Picture{}} <- Media.create_picture(%{"file" => args, "actor_id" => actor_id}) do - {:ok, %{name: picture.file.name, url: picture.file.url, id: picture.id}} + {:ok, + %{ + name: picture.file.name, + url: picture.file.url, + id: picture.id, + content_type: picture.file.content_type, + size: picture.file.size + }} else {:is_owned, false} -> {:error, "Actor id is not owned by authenticated user"} diff --git a/lib/mobilizon_web/schema/picture.ex b/lib/mobilizon_web/schema/picture.ex index d14b3ebf3..e241ace92 100644 --- a/lib/mobilizon_web/schema/picture.ex +++ b/lib/mobilizon_web/schema/picture.ex @@ -11,6 +11,8 @@ defmodule MobilizonWeb.Schema.PictureType do field(:alt, :string, description: "The picture's alternative text") field(:name, :string, description: "The picture's name") field(:url, :string, description: "The picture's full URL") + field(:content_type, :string, description: "The picture's detected content type") + field(:size, :integer, description: "The picture's size") end @desc "An attached picture or a link to a picture" diff --git a/lib/mobilizon_web/upload.ex b/lib/mobilizon_web/upload.ex index fac4fffbc..24ad765eb 100644 --- a/lib/mobilizon_web/upload.ex +++ b/lib/mobilizon_web/upload.ex @@ -52,9 +52,10 @@ defmodule MobilizonWeb.Upload do name: String.t(), tempfile: String.t(), content_type: String.t(), - path: String.t() + path: String.t(), + size: integer() } - defstruct [:id, :name, :tempfile, :content_type, :path] + defstruct [:id, :name, :tempfile, :content_type, :path, :size] @spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()} def store(upload, opts \\ []) do @@ -66,7 +67,7 @@ defmodule MobilizonWeb.Upload do {:ok, url_spec} <- MobilizonWeb.Uploaders.Uploader.put_file(opts.uploader, upload) do {:ok, %{ - "type" => opts.activity_type, + "type" => opts.activity_type || get_type(upload.content_type), "url" => [ %{ "type" => "Link", @@ -74,6 +75,7 @@ defmodule MobilizonWeb.Upload do "href" => url_from_spec(upload, opts.base_url, url_spec) } ], + "size" => upload.size, "name" => Map.get(opts, :description) || upload.name }} else @@ -100,7 +102,7 @@ defmodule MobilizonWeb.Upload do {Mobilizon.CommonConfig.get!([:instance, :avatar_upload_limit]), "Image"} _ -> - {Mobilizon.CommonConfig.get!([:instance, :upload_limit]), "Document"} + {Mobilizon.CommonConfig.get!([:instance, :upload_limit]), nil} end %{ @@ -119,14 +121,15 @@ defmodule MobilizonWeb.Upload do end defp prepare_upload(%Plug.Upload{} = file, opts) do - with :ok <- check_file_size(file.path, opts.size_limit), + with {:ok, size} <- check_file_size(file.path, opts.size_limit), {:ok, content_type, name} <- Mobilizon.MIME.file_mime_type(file.path, file.filename) do {:ok, %__MODULE__{ id: UUID.generate(), name: name, tempfile: file.path, - content_type: content_type + content_type: content_type, + size: size }} end end @@ -134,7 +137,7 @@ defmodule MobilizonWeb.Upload do defp check_file_size(path, size_limit) when is_integer(size_limit) and size_limit > 0 do with {:ok, %{size: size}} <- File.stat(path), true <- size <= size_limit do - :ok + {:ok, size} else false -> {:error, :file_too_large} error -> error @@ -143,6 +146,16 @@ defmodule MobilizonWeb.Upload do defp check_file_size(_, _), do: :ok + @picture_content_types ["image/png", "image/jpg", "image/jpeg", "image/webp"] + # Return whether the upload is a picture or not + defp get_type(content_type) do + if content_type in @picture_content_types do + "Image" + else + "Document" + end + end + defp url_from_spec(%__MODULE__{name: name}, base_url, {:file, path}) do path = URI.encode(path, &char_unescaped?/1) <> diff --git a/lib/service/activity_pub/utils.ex b/lib/service/activity_pub/utils.ex index 1e81d1291..fdd469eee 100644 --- a/lib/service/activity_pub/utils.ex +++ b/lib/service/activity_pub/utils.ex @@ -209,12 +209,15 @@ defmodule Mobilizon.Service.ActivityPub.Utils do Save picture data from raw data and return AS Link data. """ def make_picture_data(%{picture: picture}) do - with {:ok, %{"url" => [%{"href" => url}]}} <- MobilizonWeb.Upload.store(picture.file), + with {:ok, %{"url" => [%{"href" => url, "mediaType" => content_type}], "size" => size}} <- + MobilizonWeb.Upload.store(picture.file), {:ok, %Picture{file: _file} = pic} <- Mobilizon.Media.create_picture(%{ "file" => %{ "url" => url, - "name" => picture.name + "name" => picture.name, + "content_type" => content_type, + "size" => size }, "actor_id" => picture.actor_id }) do diff --git a/test/mobilizon_web/resolvers/picture_resolver_test.exs b/test/mobilizon_web/resolvers/picture_resolver_test.exs index 63e71dea0..e1dde528d 100644 --- a/test/mobilizon_web/resolvers/picture_resolver_test.exs +++ b/test/mobilizon_web/resolvers/picture_resolver_test.exs @@ -21,7 +21,9 @@ defmodule MobilizonWeb.Resolvers.PictureResolverTest do picture(id: "#{id}") { name, alt, - url + url, + content_type, + size } } """ @@ -32,6 +34,11 @@ defmodule MobilizonWeb.Resolvers.PictureResolverTest do assert json_response(res, 200)["data"]["picture"]["name"] == picture.file.name + assert json_response(res, 200)["data"]["picture"]["content_type"] == + picture.file.content_type + + assert json_response(res, 200)["data"]["picture"]["size"] == 13_120 + assert json_response(res, 200)["data"]["picture"]["url"] =~ MobilizonWeb.Endpoint.url() end @@ -68,7 +75,9 @@ defmodule MobilizonWeb.Resolvers.PictureResolverTest do actor_id: #{actor.id} ) { url, - name + name, + content_type, + size } } """ @@ -91,6 +100,8 @@ defmodule MobilizonWeb.Resolvers.PictureResolverTest do ) assert json_response(res, 200)["data"]["uploadPicture"]["name"] == picture.name + assert json_response(res, 200)["data"]["uploadPicture"]["content_type"] == "image/png" + assert json_response(res, 200)["data"]["uploadPicture"]["size"] == 10_097 assert json_response(res, 200)["data"]["uploadPicture"]["url"] end diff --git a/test/mobilizon_web/upload_test.exs b/test/mobilizon_web/upload_test.exs index d9ebe606d..39f1bb656 100644 --- a/test/mobilizon_web/upload_test.exs +++ b/test/mobilizon_web/upload_test.exs @@ -21,7 +21,11 @@ defmodule Mobilizon.UploadTest do {:ok, data} = Upload.store(file) - assert %{"url" => [%{"href" => url}]} = data + assert %{ + "url" => [%{"href" => url, "mediaType" => "image/jpeg"}], + "size" => 13_227, + "type" => "Image" + } = data assert String.starts_with?(url, MobilizonWeb.Endpoint.url() <> "/media/") end diff --git a/test/support/factory.ex b/test/support/factory.ex index 65804f631..5362bbe9c 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -174,7 +174,8 @@ defmodule Mobilizon.Factory do %Mobilizon.Media.File{ name: "My Picture", url: MobilizonWeb.Endpoint.url() <> "/uploads/something", - content_type: "image/png" + content_type: "image/png", + size: 13_120 } end