defmodule Uploadex.Definition do @moduledoc """ An Uploader definition. This is a wrapper on top of the [Arc.Definition](https://github.com/stavro/arc/blob/master/lib/arc/definition.ex), adding some extra functionalities to it. ## Usage defmodule MyApp.MyUploader do use Uploadex.Definition, repo: MyApp.Repo ## Functions required for Uploadex.Definition def base_directory do Path.join(:code.priv_dir(:my_app), "static/") end def get_files(%MyApp.User{photo: photo}), do: photo def get_files(%MyApp.Company{} = company) do company |> MyApp.Repo.preload(:photos) |> Map.get(:photos) |> Enum.map(& &1.file) end ## We can also define the functions for Arc.Definition here def storage_dir(_version, {_file, %User{id: user_id}}) do Path.join(base_directory(), "/uploads/users/\#{user_id}") end def storage_dir(_version, {_file, %Company{id: id}}) do Path.join(base_directory(), "/uploads/companies/\#{id}") end end """ alias Uploadex.Uploader defmacro __using__(opts \\ []) do repo = Keyword.fetch!(opts, :repo) quote do @behaviour Uploader use Arc.Definition def repo, do: unquote(repo) @doc """ Wraps the user defined `get_files` function to always return a list """ def do_get_files(record) do record |> get_files() |> List.wrap() |> Enum.reject(&is_nil/1) end def url(file), do: url(file, nil) def url(file, options) when is_list(options), do: url(file, nil, options) def url(file, version), do: url(file, version, []) def url(file_and_scope, version, _options) do filename = resolve_file_name(version, file_and_scope) Path.join(storage_dir(version, file_and_scope), filename) end def filename(_version, {%{file_name: file_name}, _record}), do: Path.basename(file_name, Path.extname(file_name)) def filename(_version, {%{filename: filename}, _record}), do: Path.basename(filename, Path.extname(filename)) def filename(_version, {filename, _record}) when is_binary(filename), do: Path.basename(filename, Path.extname(filename)) def extension(_version, {%{file_name: file_name}, _record}), do: Path.extname(file_name) def extension(_version, {%{filename: filename}, _record}), do: Path.extname(filename) def extension(_version, {filename, _record}) when is_binary(filename), do: Path.extname(filename) # Using this as a fixed version of Arc.Definition.Versioning.resolve_file_name def resolve_file_name(version, {file, scope}) do filename = filename(version, {file, scope}) extension = extension(version, {file, scope}) conversion = transform(version, {file, scope}) case conversion do :skip -> nil {_, _, ext} -> "#{filename}.#{ext}" _ -> "#{filename}#{extension}" end end defoverridable Uploader end end end