Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
stavro authored May 10, 2018
2 parents c4f76d0 + 02e0eb0 commit b78245d
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 46 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v0.8.0 (2018-05-10)
* (Enhancement) Use `NaiveDateTime` instead of `Ecto.DateTime`.
* (Dependency Update) Require `ecto ~> 2.1`

## v0.7.0 (2017-03-10)
* (Enhancement) Add `delete` override to the ArcEcto module.
* (Dependency Update) Require `arc ~> 0.8.0`
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Add the latest stable release to your `mix.exs` file:
```elixir
defp deps do
[
{:arc_ecto, "~> 0.7.0"}
{:arc_ecto, "~> 0.8.0"}
]
end

Expand Down
4 changes: 2 additions & 2 deletions lib/arc_ecto/definition.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ defmodule Arc.Ecto.Definition do
url
else
case updated_at do
%Ecto.DateTime{} ->
stamp = :calendar.datetime_to_gregorian_seconds(Ecto.DateTime.to_erl(updated_at))
%NaiveDateTime{} ->
stamp = :calendar.datetime_to_gregorian_seconds(NaiveDateTime.to_erl(updated_at))
case URI.parse(url).query do
nil -> url <> "?v=#{stamp}"
_ -> url <> "&v=#{stamp}"
Expand Down
29 changes: 18 additions & 11 deletions lib/arc_ecto/type.ex
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
defmodule Arc.Ecto.Type do
@moduledoc false
require Logger

def type, do: :string

@filename_with_timestamp ~r{^(.*)\?(\d+)$}

# Support embeds_one/embeds_many
def cast(_definition, %{"file_name" => file, "updated_at" => updated_at}) do
{:ok, %{file_name: file, updated_at: updated_at}}
end

def cast(definition, %{file_name: file, updated_at: updated_at}) do
cast(definition, %{"file_name" => file, "updated_at" => updated_at})
end

def cast(_definition, %{"file_name" => file, "updated_at" => updated_at}) do
{:ok, %{file_name: file, updated_at: updated_at}}
end

def cast(definition, args) do
case definition.store(args) do
{:ok, file} -> {:ok, %{file_name: file, updated_at: Ecto.DateTime.utc}}
_ -> :error
{:ok, file} -> {:ok, %{file_name: file, updated_at: NaiveDateTime.utc_now}}
error ->
Logger.error(inspect(error))
:error
end
end

Expand All @@ -29,9 +35,10 @@ defmodule Arc.Ecto.Type do
updated_at = case gsec do
gsec when is_binary(gsec) ->
gsec
|> String.to_integer()
|> :calendar.gregorian_seconds_to_datetime()
|> Ecto.DateTime.from_erl()
|> String.to_integer
|> :calendar.gregorian_seconds_to_datetime
|> NaiveDateTime.from_erl!

_ ->
nil
end
Expand All @@ -44,7 +51,7 @@ defmodule Arc.Ecto.Type do
end

def dump(_definition, %{file_name: file_name, updated_at: updated_at}) do
gsec = :calendar.datetime_to_gregorian_seconds(Ecto.DateTime.to_erl(updated_at))
gsec = :calendar.datetime_to_gregorian_seconds(NaiveDateTime.to_erl(updated_at))
{:ok, "#{file_name}?#{gsec}"}
end

Expand Down
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Arc.Ecto.Mixfile do
use Mix.Project

@version "0.7.0"
@version "0.8.0"

def project do
[app: :arc_ecto,
Expand Down Expand Up @@ -46,7 +46,7 @@ defmodule Arc.Ecto.Mixfile do
defp deps do
[
{:arc, "~> 0.8.0"},
{:ecto, "~> 2.0"},
{:ecto, "~> 2.1"},
{:mock, "~> 0.1.1", only: :test},
{:ex_doc, ">= 0.0.0", only: :dev}
]
Expand Down
30 changes: 15 additions & 15 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
%{"arc": {:hex, :arc, "0.8.0", "bb7cf8ea50f30f9c2bb357270c074def42a7ec6a3b4605be731cc5faf8fde6fd", [:mix], [{:ex_aws, "~> 1.1", [hex: :ex_aws, optional: true]}, {:httpoison, "~> 0.11", [hex: :httpoison, optional: false]}, {:poison, "~> 2.2 or ~> 3.1", [hex: :poison, optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, optional: true]}]},
"certifi": {:hex, :certifi, "1.0.0", "1c787a85b1855ba354f0b8920392c19aa1d06b0ee1362f9141279620a5be2039", [:rebar3], []},
"decimal": {:hex, :decimal, "1.1.2", "79a769d4657b2d537b51ef3c02d29ab7141d2b486b516c109642d453ee08e00c", [:mix], []},
"earmark": {:hex, :earmark, "1.0.1", "2c2cd903bfdc3de3f189bd9a8d4569a075b88a8981ded9a0d95672f6e2b63141", [:mix], []},
"ecto": {:hex, :ecto, "2.0.5", "7f4c79ac41ffba1a4c032b69d7045489f0069c256de606523c65d9f8188e502d", [:mix], [{:db_connection, "~> 1.0-rc.4", [hex: :db_connection, optional: true]}, {:decimal, "~> 1.1.2 or ~> 1.2", [hex: :decimal, optional: false]}, {:mariaex, "~> 0.7.7", [hex: :mariaex, optional: true]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}, {:postgrex, "~> 0.12.0", [hex: :postgrex, optional: true]}, {:sbroker, "~> 1.0-beta", [hex: :sbroker, optional: true]}]},
%{"arc": {:hex, :arc, "0.8.0", "bb7cf8ea50f30f9c2bb357270c074def42a7ec6a3b4605be731cc5faf8fde6fd", [:mix], [{:ex_aws, "~> 1.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.11", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
"certifi": {:hex, :certifi, "1.0.0", "1c787a85b1855ba354f0b8920392c19aa1d06b0ee1362f9141279620a5be2039", [:rebar3], [], "hexpm"},
"decimal": {:hex, :decimal, "1.4.0", "fac965ce71a46aab53d3a6ce45662806bdd708a4a95a65cde8a12eb0124a1333", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.0.1", "2c2cd903bfdc3de3f189bd9a8d4569a075b88a8981ded9a0d95672f6e2b63141", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.1.4", "d1ba932813ec0e0d9db481ef2c17777f1cefb11fc90fa7c142ff354972dfba7e", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"erlcloud": {:hex, :erlcloud, "0.9.2"},
"ex_doc": {:hex, :ex_doc, "0.13.1", "658dbfc8cc5b0fac192f0f3254efe66ee6294200804a291549e0aeb052053bba", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
"hackney": {:hex, :hackney, "1.7.1", "e238c52c5df3c3b16ce613d3a51c7220a784d734879b1e231c9babd433ac1cb4", [:rebar3], [{:certifi, "1.0.0", [hex: :certifi, optional: false]}, {:idna, "4.0.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},
"httpoison": {:hex, :httpoison, "0.11.1", "d06c571274c0e77b6cc50e548db3fd7779f611fbed6681fd60a331f66c143a0b", [:mix], [{:hackney, "~> 1.7.0", [hex: :hackney, optional: false]}]},
"idna": {:hex, :idna, "4.0.0", "10aaa9f79d0b12cf0def53038547855b91144f1bfcc0ec73494f38bb7b9c4961", [:rebar3], []},
"ex_doc": {:hex, :ex_doc, "0.13.1", "658dbfc8cc5b0fac192f0f3254efe66ee6294200804a291549e0aeb052053bba", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"hackney": {:hex, :hackney, "1.7.1", "e238c52c5df3c3b16ce613d3a51c7220a784d734879b1e231c9babd433ac1cb4", [:rebar3], [{:certifi, "1.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "4.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"httpoison": {:hex, :httpoison, "0.11.1", "d06c571274c0e77b6cc50e548db3fd7779f611fbed6681fd60a331f66c143a0b", [:mix], [{:hackney, "~> 1.7.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "4.0.0", "10aaa9f79d0b12cf0def53038547855b91144f1bfcc0ec73494f38bb7b9c4961", [:rebar3], [], "hexpm"},
"jsx": {:hex, :jsx, "2.1.1"},
"lhttpc": {:hex, :lhttpc, "1.3.0"},
"meck": {:hex, :meck, "0.8.3", "4628a1334c69610c5bd558b04dc78d723d8ec5445c123856de34c77f462b5ee5", [:rebar], []},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
"mock": {:hex, :mock, "0.1.1", "e21469ca27ba32aa7b18b61699db26f7a778171b21c0e5deb6f1218a53278574", [:mix], [{:meck, "~> 0.8.2", [hex: :meck, optional: false]}]},
"meck": {:hex, :meck, "0.8.3", "4628a1334c69610c5bd558b04dc78d723d8ec5445c123856de34c77f462b5ee5", [:rebar], [], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.1.1", "e21469ca27ba32aa7b18b61699db26f7a778171b21c0e5deb6f1218a53278574", [:mix], [{:meck, "~> 0.8.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mogrify": {:hex, :mogrify, "0.1.0"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []}}
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"}}
4 changes: 2 additions & 2 deletions test/definition_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ defmodule ArcTest.Ecto.Definition do
end

test "url appends timestamp to url with no query parameters" do
updated_at = Ecto.DateTime.from_erl({{2015, 1, 1}, {1, 1, 1}})
updated_at = NaiveDateTime.from_erl!({{2015, 1, 1}, {1, 1, 1}})
url = DummyDefinition.url({%{file_name: "test.png", updated_at: updated_at}, :scope}, :original, [])
assert url == "fallback?v=63587293261"
end

test "url appends timestamp to url with query parameters" do
updated_at = Ecto.DateTime.from_erl({{2015, 1, 1}, {1, 1, 1}})
updated_at = NaiveDateTime.from_erl!({{2015, 1, 1}, {1, 1, 1}})
url = DummyDefinition.url({%{file_name: "test.png", updated_at: updated_at}, :scope}, :signed, [])
assert url == "fallback?a=1&b=2&v=63587293261"
end
Expand Down
18 changes: 9 additions & 9 deletions test/schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -48,50 +48,50 @@ defmodule ArcTest.Ecto.Schema do
end

def build_upload(path) do
%{__struct__: Plug.Upload, path: path, file_name: Path.basename(path)}
%{__struct__: Plug.Upload, path: path, filename: Path.basename(path)}
end

test "supports :invalid changeset" do
cs = TestUser.changeset(%TestUser{})
assert cs.valid? == false
assert cs.changes == %{}
assert cs.errors == [avatar: {"can't be blank", []}]
assert cs.errors == [avatar: {"can't be blank", [validation: :required]}]
end

test_with_mock "cascades storage success into a valid change", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:ok, "file.png"} end] do
test_with_mock "cascades storage success into a valid change", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", filename: "file.png"}, %TestUser{}}) -> {:ok, "file.png"} end] do
upload = build_upload("/path/to/my/file.png")
cs = TestUser.changeset(%TestUser{}, %{"avatar" => upload})
assert cs.valid?
%{file_name: "file.png", updated_at: _} = cs.changes.avatar
end

test_with_mock "cascades storage error into an error", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
test_with_mock "cascades storage error into an error", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", filename: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
upload = build_upload("/path/to/my/file.png")
cs = TestUser.changeset(%TestUser{}, %{"avatar" => upload})
assert called DummyDefinition.store({upload, %TestUser{}})
assert cs.valid? == false
assert cs.errors == [avatar: {"is invalid", [type: ArcTest.Ecto.Schema.DummyDefinition.Type]}]
assert cs.errors == [avatar: {"is invalid", [type: ArcTest.Ecto.Schema.DummyDefinition.Type, validation: :cast]}]
end

test_with_mock "converts changeset into schema", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
test_with_mock "converts changeset into schema", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", filename: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
upload = build_upload("/path/to/my/file.png")
TestUser.changeset(%TestUser{}, %{"avatar" => upload})
assert called DummyDefinition.store({upload, %TestUser{}})
end

test_with_mock "applies changes to schema", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
test_with_mock "applies changes to schema", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", filename: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
upload = build_upload("/path/to/my/file.png")
TestUser.changeset(%TestUser{}, %{"avatar" => upload, "first_name" => "test"})
assert called DummyDefinition.store({upload, %TestUser{first_name: "test"}})
end

test_with_mock "converts atom keys", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
test_with_mock "converts atom keys", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", filename: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
upload = build_upload("/path/to/my/file.png")
TestUser.changeset(%TestUser{}, %{avatar: upload})
assert called DummyDefinition.store({upload, %TestUser{}})
end

test_with_mock "casting nil attachments", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:ok, "file.png"} end] do
test_with_mock "casting nil attachments", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", filename: "file.png"}, %TestUser{}}) -> {:ok, "file.png"} end] do
changeset = TestUser.changeset(%TestUser{}, %{"avatar" => build_upload("/path/to/my/file.png")})
changeset = TestUser.changeset2(changeset, %{"avatar" => nil})
assert nil == Ecto.Changeset.get_field(changeset, :avatar)
Expand Down
8 changes: 4 additions & 4 deletions test/type_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ defmodule ArcTest.Ecto.Type do
end

test "dumps filenames with timestamp" do
timestamp = Ecto.DateTime.cast!({{1970, 1, 1}, {0, 0, 0}})
timestamp = NaiveDateTime.from_erl!({{1970, 1, 1}, {0, 0, 0}})
{:ok, value} =
DummyDefinition.Type.dump(%{file_name: "file.png", updated_at: timestamp})
assert value == "file.png?62167219200"
end

test "loads filenames with timestamp" do
timestamp = Ecto.DateTime.cast!({{1970, 1, 1}, {0, 0, 0}})
timestamp = NaiveDateTime.from_erl!({{1970, 1, 1}, {0, 0, 0}})
{:ok, value} = DummyDefinition.Type.load("file.png?62167219200")
assert value == %{file_name: "file.png", updated_at: timestamp}
end

test "loads pathological filenames" do
timestamp = Ecto.DateTime.cast!({{1970, 1, 1}, {0, 0, 0}})
timestamp = NaiveDateTime.from_erl!({{1970, 1, 1}, {0, 0, 0}})
{:ok, value} = DummyDefinition.Type.load("image.php?62167219200")
assert value == %{file_name: "image.php", updated_at: timestamp}
end
Expand All @@ -31,7 +31,7 @@ defmodule ArcTest.Ecto.Type do
end

test "dumps with updated_at" do
timestamp = Ecto.DateTime.cast!({{1970, 1, 1}, {0, 0, 0}})
timestamp = NaiveDateTime.from_erl!({{1970, 1, 1}, {0, 0, 0}})
value = %{file_name: "file.png", updated_at: timestamp}
{:ok, dumped_type} = DummyDefinition.Type.dump(value)
assert dumped_type == "file.png?62167219200"
Expand Down

0 comments on commit b78245d

Please sign in to comment.