Skip to content

Commit

Permalink
allow storage path to be different from url
Browse files Browse the repository at this point in the history
  • Loading branch information
achempion committed Sep 4, 2019
1 parent afab270 commit 3c317e6
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ erl_crash.dump
/waffletest
/doc
.env
/priv
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,22 @@ Waffle currently supports Amazon S3 and local destinations for file uploads.

### Local Configuration

```elixir
config :waffle,
storage: Waffle.Storage.Local,
# in order to have a different storage directory from url
starage_dir_prefix: "priv/waffle/private"
```

To store your attachments locally, override the `__storage` function in your definition module to `Waffle.Storage.Local`. You may wish to optionally override the storage directory as well, as outlined below.


```elixir
defmodule Avatar do
use Waffle.Definition
def __storage, do: Waffle.Storage.Local # Add this
# in order to have a different storage directory from url
def starage_dir_prefix(), do: "priv/waffle/private"
end
```

Expand Down
3 changes: 2 additions & 1 deletion lib/waffle/definition/storage.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ defmodule Waffle.Definition.Storage do
def bucket, do: Application.fetch_env!(:waffle, :bucket)
def asset_host, do: Application.get_env(:waffle, :asset_host)
def filename(_, {file, _}), do: Path.basename(file.file_name, Path.extname(file.file_name))
def storage_dir_prefix(), do: Application.get_env(:waffle, :storage_dir_prefix, "")
def storage_dir(_, _), do: Application.get_env(:waffle, :storage_dir, "uploads")
def validate(_), do: true
def default_url(version, _), do: default_url(version)
def default_url(_), do: nil
def __storage, do: Application.get_env(:waffle, :storage, Waffle.Storage.S3)

defoverridable [storage_dir: 2, filename: 2, validate: 1, default_url: 1, default_url: 2, __storage: 0, bucket: 0, asset_host: 0]
defoverridable [storage_dir_prefix: 0, storage_dir: 2, filename: 2, validate: 1, default_url: 1, default_url: 2, __storage: 0, bucket: 0, asset_host: 0]

@before_compile Waffle.Definition.Storage
end
Expand Down
26 changes: 15 additions & 11 deletions lib/waffle/storage/local.ex
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
defmodule Waffle.Storage.Local do

def put(definition, version, {file, scope}) do
destination_dir = definition.storage_dir(version, {file, scope})
path = Path.join(destination_dir, file.file_name)
path |> Path.dirname() |> File.mkdir_p!()
destination_path = Path.join([
definition.storage_dir_prefix(),
definition.storage_dir(version, {file, scope}),
file.file_name
])
destination_path |> Path.dirname() |> File.mkdir_p!()

if binary = file.binary do
File.write!(path, binary)
File.write!(destination_path, binary)
else
File.copy!(file.path, path)
File.copy!(file.path, destination_path)
end

{:ok, file.file_name}
end

def url(definition, version, file_and_scope, _options \\ []) do
local_path = build_local_path(definition, version, file_and_scope)
local_path = Path.join([
definition.storage_dir(version, file_and_scope),
Waffle.Definition.Versioning.resolve_file_name(definition, version, file_and_scope)
])

url = if String.starts_with?(local_path, "/") do
local_path
Expand All @@ -26,14 +33,11 @@ defmodule Waffle.Storage.Local do
end

def delete(definition, version, file_and_scope) do
build_local_path(definition, version, file_and_scope)
|> File.rm()
end

defp build_local_path(definition, version, file_and_scope) do
Path.join([
definition.storage_dir_prefix(),
definition.storage_dir(version, file_and_scope),
Waffle.Definition.Versioning.resolve_file_name(definition, version, file_and_scope)
])
|> File.rm()
end
end
32 changes: 31 additions & 1 deletion test/storage/local_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ defmodule WaffleTest.Storage.Local do
defmodule DummyDefinition do
use Waffle.Definition

@acl :public_read
@versions [:original, :thumb, :skipped]

def transform(:thumb, _), do: {:convert, "-strip -thumbnail 10x10"}
Expand All @@ -33,6 +32,21 @@ defmodule WaffleTest.Storage.Local do
def filename(:skipped, {file, _}), do: "1/skipped-#{Path.basename(file.file_name, Path.extname(file.file_name))}"
end

defmodule DummyDefinitionWithPrefix do
use Waffle.Definition

@versions [:original, :thumb]

def transform(:thumb, _), do: {:convert, "-strip -thumbnail 10x10"}

def storage_dir_prefix(), do: "priv/waffle/private"
def storage_dir(_, _), do: "waffletest/uploads"
def __storage, do: Waffle.Storage.Local

def filename(:original, {file, _}), do: "original-#{Path.basename(file.file_name, Path.extname(file.file_name))}"
def filename(:thumb, {file, _}), do: "1/thumb-#{Path.basename(file.file_name, Path.extname(file.file_name))}"
end

test "put, delete, get" do
assert {:ok, "original-image.png"} == Waffle.Storage.Local.put(DummyDefinition, :original, {Waffle.File.new(%{filename: "original-image.png", path: @img}), nil})
assert {:ok, "1/thumb-image.png"} == Waffle.Storage.Local.put(DummyDefinition, :thumb, {Waffle.File.new(%{filename: "1/thumb-image.png", path: @img}), nil})
Expand All @@ -48,6 +62,22 @@ defmodule WaffleTest.Storage.Local do
refute File.exists?("waffletest/uploads/1/thumb-image.png")
end

test "put, delete, get with storage prefix" do
assert {:ok, "original-image.png"} == Waffle.Storage.Local.put(DummyDefinitionWithPrefix, :original, {Waffle.File.new(%{filename: "original-image.png", path: @img}), nil})
assert {:ok, "1/thumb-image.png"} == Waffle.Storage.Local.put(DummyDefinitionWithPrefix, :thumb, {Waffle.File.new(%{filename: "1/thumb-image.png", path: @img}), nil})

assert File.exists?("priv/waffle/private/waffletest/uploads/original-image.png")
assert File.exists?("priv/waffle/private/waffletest/uploads/1/thumb-image.png")
assert "/waffletest/uploads/original-image.png" == DummyDefinitionWithPrefix.url("image.png", :original)
assert "/waffletest/uploads/1/thumb-image.png" == DummyDefinitionWithPrefix.url("1/image.png", :thumb)

:ok = Waffle.Storage.Local.delete(DummyDefinitionWithPrefix, :original, {%{file_name: "image.png"}, nil})
:ok = Waffle.Storage.Local.delete(DummyDefinitionWithPrefix, :thumb, {%{file_name: "image.png"}, nil})
refute File.exists?("priv/waffle/private/waffletest/uploads/original-image.png")
refute File.exists?("priv/waffle/private/waffletest/uploads/1/thumb-image.png")
end


test "deleting when there's a skipped version" do
DummyDefinition.store(@img)
assert :ok = DummyDefinition.delete(@img)
Expand Down

0 comments on commit 3c317e6

Please sign in to comment.