Merge branch 'add-filesize-to-files' into 'master'
Add filesize to file entity, expose it to GraphQL API Closes #128 See merge request framasoft/mobilizon!148
This commit is contained in:
commit
10dbe14a52
|
@ -9,6 +9,7 @@ defmodule Mobilizon.Media.File do
|
||||||
field(:name, :string)
|
field(:name, :string)
|
||||||
field(:url, :string)
|
field(:url, :string)
|
||||||
field(:content_type, :string)
|
field(:content_type, :string)
|
||||||
|
field(:size, :integer)
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
@ -16,7 +17,7 @@ defmodule Mobilizon.Media.File do
|
||||||
@doc false
|
@doc false
|
||||||
def changeset(picture, attrs) do
|
def changeset(picture, attrs) do
|
||||||
picture
|
picture
|
||||||
|> cast(attrs, [:name, :url, :content_type])
|
|> cast(attrs, [:name, :url, :content_type, :size])
|
||||||
|> validate_required([:name, :url])
|
|> validate_required([:name, :url])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,7 +36,8 @@ defmodule MobilizonWeb.Resolvers.Picture do
|
||||||
@spec do_fetch_picture(String.t()) :: {:ok, Picture.t()} | {:error, :not_found}
|
@spec do_fetch_picture(String.t()) :: {:ok, Picture.t()} | {:error, :not_found}
|
||||||
defp do_fetch_picture(picture_id) do
|
defp do_fetch_picture(picture_id) do
|
||||||
with %Picture{id: id, file: file} = _pic <- Media.get_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
|
else
|
||||||
_err ->
|
_err ->
|
||||||
{:error, "Picture with ID #{picture_id} was not found"}
|
{:error, "Picture with ID #{picture_id} was not found"}
|
||||||
|
@ -50,11 +51,23 @@ defmodule MobilizonWeb.Resolvers.Picture do
|
||||||
}
|
}
|
||||||
}) do
|
}) do
|
||||||
with {:is_owned, true, _actor} <- User.owns_actor(user, actor_id),
|
with {:is_owned, true, _actor} <- User.owns_actor(user, actor_id),
|
||||||
{:ok, %{"url" => [%{"href" => url}]}} <- MobilizonWeb.Upload.store(file),
|
{:ok, %{"url" => [%{"href" => url, "mediaType" => content_type}], "size" => size}} <-
|
||||||
args <- Map.put(args, :url, url),
|
MobilizonWeb.Upload.store(file),
|
||||||
|
args <-
|
||||||
|
args
|
||||||
|
|> Map.put(:url, url)
|
||||||
|
|> Map.put(:size, size)
|
||||||
|
|> Map.put(:content_type, content_type),
|
||||||
{:ok, picture = %Picture{}} <-
|
{:ok, picture = %Picture{}} <-
|
||||||
Media.create_picture(%{"file" => args, "actor_id" => actor_id}) do
|
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
|
else
|
||||||
{:is_owned, false} ->
|
{:is_owned, false} ->
|
||||||
{:error, "Actor id is not owned by authenticated user"}
|
{:error, "Actor id is not owned by authenticated user"}
|
||||||
|
|
|
@ -11,6 +11,8 @@ defmodule MobilizonWeb.Schema.PictureType do
|
||||||
field(:alt, :string, description: "The picture's alternative text")
|
field(:alt, :string, description: "The picture's alternative text")
|
||||||
field(:name, :string, description: "The picture's name")
|
field(:name, :string, description: "The picture's name")
|
||||||
field(:url, :string, description: "The picture's full URL")
|
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
|
end
|
||||||
|
|
||||||
@desc "An attached picture or a link to a picture"
|
@desc "An attached picture or a link to a picture"
|
||||||
|
|
|
@ -52,9 +52,10 @@ defmodule MobilizonWeb.Upload do
|
||||||
name: String.t(),
|
name: String.t(),
|
||||||
tempfile: String.t(),
|
tempfile: String.t(),
|
||||||
content_type: 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()}
|
@spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()}
|
||||||
def store(upload, opts \\ []) do
|
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, url_spec} <- MobilizonWeb.Uploaders.Uploader.put_file(opts.uploader, upload) do
|
||||||
{:ok,
|
{:ok,
|
||||||
%{
|
%{
|
||||||
"type" => opts.activity_type,
|
"type" => opts.activity_type || get_type(upload.content_type),
|
||||||
"url" => [
|
"url" => [
|
||||||
%{
|
%{
|
||||||
"type" => "Link",
|
"type" => "Link",
|
||||||
|
@ -74,6 +75,7 @@ defmodule MobilizonWeb.Upload do
|
||||||
"href" => url_from_spec(upload, opts.base_url, url_spec)
|
"href" => url_from_spec(upload, opts.base_url, url_spec)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"size" => upload.size,
|
||||||
"name" => Map.get(opts, :description) || upload.name
|
"name" => Map.get(opts, :description) || upload.name
|
||||||
}}
|
}}
|
||||||
else
|
else
|
||||||
|
@ -100,7 +102,7 @@ defmodule MobilizonWeb.Upload do
|
||||||
{Mobilizon.CommonConfig.get!([:instance, :avatar_upload_limit]), "Image"}
|
{Mobilizon.CommonConfig.get!([:instance, :avatar_upload_limit]), "Image"}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
{Mobilizon.CommonConfig.get!([:instance, :upload_limit]), "Document"}
|
{Mobilizon.CommonConfig.get!([:instance, :upload_limit]), nil}
|
||||||
end
|
end
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
@ -119,14 +121,15 @@ defmodule MobilizonWeb.Upload do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp prepare_upload(%Plug.Upload{} = file, opts) do
|
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, content_type, name} <- Mobilizon.MIME.file_mime_type(file.path, file.filename) do
|
||||||
{:ok,
|
{:ok,
|
||||||
%__MODULE__{
|
%__MODULE__{
|
||||||
id: UUID.generate(),
|
id: UUID.generate(),
|
||||||
name: name,
|
name: name,
|
||||||
tempfile: file.path,
|
tempfile: file.path,
|
||||||
content_type: content_type
|
content_type: content_type,
|
||||||
|
size: size
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
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
|
defp check_file_size(path, size_limit) when is_integer(size_limit) and size_limit > 0 do
|
||||||
with {:ok, %{size: size}} <- File.stat(path),
|
with {:ok, %{size: size}} <- File.stat(path),
|
||||||
true <- size <= size_limit do
|
true <- size <= size_limit do
|
||||||
:ok
|
{:ok, size}
|
||||||
else
|
else
|
||||||
false -> {:error, :file_too_large}
|
false -> {:error, :file_too_large}
|
||||||
error -> error
|
error -> error
|
||||||
|
@ -143,6 +146,16 @@ defmodule MobilizonWeb.Upload do
|
||||||
|
|
||||||
defp check_file_size(_, _), do: :ok
|
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
|
defp url_from_spec(%__MODULE__{name: name}, base_url, {:file, path}) do
|
||||||
path =
|
path =
|
||||||
URI.encode(path, &char_unescaped?/1) <>
|
URI.encode(path, &char_unescaped?/1) <>
|
||||||
|
|
|
@ -209,12 +209,15 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||||
Save picture data from raw data and return AS Link data.
|
Save picture data from raw data and return AS Link data.
|
||||||
"""
|
"""
|
||||||
def make_picture_data(%{picture: picture}) do
|
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} <-
|
{:ok, %Picture{file: _file} = pic} <-
|
||||||
Mobilizon.Media.create_picture(%{
|
Mobilizon.Media.create_picture(%{
|
||||||
"file" => %{
|
"file" => %{
|
||||||
"url" => url,
|
"url" => url,
|
||||||
"name" => picture.name
|
"name" => picture.name,
|
||||||
|
"content_type" => content_type,
|
||||||
|
"size" => size
|
||||||
},
|
},
|
||||||
"actor_id" => picture.actor_id
|
"actor_id" => picture.actor_id
|
||||||
}) do
|
}) do
|
||||||
|
|
|
@ -21,7 +21,9 @@ defmodule MobilizonWeb.Resolvers.PictureResolverTest do
|
||||||
picture(id: "#{id}") {
|
picture(id: "#{id}") {
|
||||||
name,
|
name,
|
||||||
alt,
|
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"]["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"] =~
|
assert json_response(res, 200)["data"]["picture"]["url"] =~
|
||||||
MobilizonWeb.Endpoint.url()
|
MobilizonWeb.Endpoint.url()
|
||||||
end
|
end
|
||||||
|
@ -68,7 +75,9 @@ defmodule MobilizonWeb.Resolvers.PictureResolverTest do
|
||||||
actor_id: #{actor.id}
|
actor_id: #{actor.id}
|
||||||
) {
|
) {
|
||||||
url,
|
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"]["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"]
|
assert json_response(res, 200)["data"]["uploadPicture"]["url"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,11 @@ defmodule Mobilizon.UploadTest do
|
||||||
|
|
||||||
{:ok, data} = Upload.store(file)
|
{: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/")
|
assert String.starts_with?(url, MobilizonWeb.Endpoint.url() <> "/media/")
|
||||||
end
|
end
|
||||||
|
|
|
@ -174,7 +174,8 @@ defmodule Mobilizon.Factory do
|
||||||
%Mobilizon.Media.File{
|
%Mobilizon.Media.File{
|
||||||
name: "My Picture",
|
name: "My Picture",
|
||||||
url: MobilizonWeb.Endpoint.url() <> "/uploads/something",
|
url: MobilizonWeb.Endpoint.url() <> "/uploads/something",
|
||||||
content_type: "image/png"
|
content_type: "image/png",
|
||||||
|
size: 13_120
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue