Skip to content

Commit

Permalink
allow passing binary data structs as attachments
Browse files Browse the repository at this point in the history
arc allows storing `%{filename: filename, binary: data}`,
and now arc_ecto allows these structs to be accepted in
`cast_attachments`

fixes stavro#54
  • Loading branch information
azhi committed Jan 16, 2018
1 parent a30a3db commit 9c6c9d5
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/arc_ecto/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ defmodule Arc.Ecto.Schema do
# Allow casting Plug.Uploads
{field, upload = %{__struct__: Plug.Upload}}, fields -> [{field, {upload, scope}} | fields]

# Allow casting binary data structs
{field, upload = %{filename: filename, binary: binary}}, fields
when is_binary(filename) and is_binary(binary) ->
[{field, {upload, scope}} | fields]

# If casting a binary (path), ensure we've explicitly allowed paths
{field, path}, fields when is_binary(path) ->
if Keyword.get(options, :allow_paths, false) do
Expand Down
5 changes: 5 additions & 0 deletions test/schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,9 @@ defmodule ArcTest.Ecto.Schema do
changeset = TestUser.path_changeset(%TestUser{}, %{"avatar" => "/path/to/my/file.png"})
assert called DummyDefinition.store({"/path/to/my/file.png", %TestUser{}})
end

test_with_mock "casting binary data struct attachments", DummyDefinition, [store: fn({%{filename: "/path/to/my/file.png", binary: <<1, 2, 3>>}, %TestUser{}}) -> {:ok, "file.png"} end] do
changeset = TestUser.changeset(%TestUser{}, %{"avatar" => %{filename: "/path/to/my/file.png", binary: <<1, 2, 3>>}})
assert called DummyDefinition.store({%{filename: "/path/to/my/file.png", binary: <<1, 2, 3>>}, %TestUser{}})
end
end

3 comments on commit 9c6c9d5

@quantumproducer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azhi can you provide an image test insteadof <<1,2,3>> ?
I am able to write to a file but the result is my image file cannot be opened by a regular image reading program.

@azhi
Copy link
Owner Author

@azhi azhi commented on 9c6c9d5 Feb 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@quantumproducer this fork is used for uploading image files, and it seems to be working fine. Most likely your issue is related to the way you retrieve your image file, or to arc itself.

I would suggest retrieving image files from all possible steps inside your system (e.g. one file retrieved manually to serve as a reference, one file retrieved through elixir client, ..., one file that was uploaded through arc) and comparing them with diff to find where alteration occurred.

@quantumproducer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azhi Thanks for the quick response. Manually reading from the uploads/ folder by my OS fails, which tells me that the write to disk didn't save the image correctly. I tried the sample code from the arc_ecto issue:

   %{"user" => %{"profile_photo" => binary}} = attrs 

    [media_type, binary] = String.split(binary, ";base64,", parts: 2)
    [_, ext] = String.split(media_type, "/", parts: 2)
    [_, content_type] = String.split(media_type, ":", parts: 2)

    name = random_filename()
    filepath = Application.get_env(:api, :images)
             |> Keyword.fetch!(:path)
    filepath = filepath <> "#{name}.#{ext}"

    case File.write!("#{filepath}", Base.decode64!(binary), [:binary]) do
      :ok ->
        %Plug.Upload{
          content_type: content_type,
          filename: "#{name}.#{ext}",
          path: Path.expand("#{filepath}") |> Path.absname()
        }

      {:error, reason} ->
        {:error, reason}
    end

    formatted_data = %{user: %{email: user.email, profile_photo: %{binary: binary, filename: random_filename()}}}
    User.photo_update_changeset(user, formatted_data))
  def photo_update_changeset(user, attrs) do
    IO.inspect(user)
    IO.inspect(attrs)
    IO.inspect("changeset")
    user
    |> cast(attrs[:user], @allowed_update_photo_fields)
    |> cast_attachments(attrs, @required_update_photo_attachment_fields)
    |> validate_required(@required_update_photo_fields)
  end

and when it saves to my hard disk, I cannot open the image.

Please sign in to comment.