defmodule Mix.Tasks.Waffle do
defmodule G do
use Mix.Task
import Mix.Generator
import Macro, only: [camelize: 1, underscore: 1]
@shortdoc "For Waffle definition generation code"
@moduledoc """
A task for generating waffle uploader modules.
If generating an uploader in a Phoenix project, your a uploader will be generated in
lib/[APP_NAME]_web/uploaders/
## Example
mix waffle.g avatar # creates lib/[APP_NAME]_web/uploaders/avatar.ex
If not generating an uploader in a Phoenix project, then you must pass the path to where the
uploader should be generated.
## Example
mix waffle.g avatar uploaders/avatar.ex # creates uploaders/avatar.ex
"""
def run([model_name]) do
app_name = Mix.Project.config()[:app]
if File.exists?("lib/#{app_name}_web/") do
project_module_name = camelize(to_string(app_name))
generate_phx_uploader_file(model_name, project_module_name)
else
raise "path must be passed when generating an uploader."
end
end
def run([model_name, path]) do
app_name = Mix.Project.config()[:app]
project_module_name = camelize(to_string(app_name))
generate_uploader_file(model_name, project_module_name, path)
end
def run(_) do
IO.puts "Incorrect syntax. Please try mix waffle.g <model_name>"
end
defp generate_uploader_file(model_name, project_module_name, path) do
model_destination = Path.join(File.cwd!(), "#{path}/#{underscore(model_name)}.ex")
create_uploader(model_name, project_module_name, model_destination)
end
defp generate_phx_uploader_file(model_name, project_module_name) do
app_name = Mix.Project.config()[:app]
model_destination = Path.join(File.cwd!(), "/lib/#{app_name}_web/uploaders/#{underscore(model_name)}.ex")
create_uploader(model_name, project_module_name, model_destination)
end
defp create_uploader(model_name, project_module_name, model_destination) do
create_file model_destination, uploader_template(
model_name: model_name,
uploader_model_name: Module.concat(project_module_name, camelize(model_name))
)
end
embed_template :uploader, """
defmodule <%= inspect @uploader_model_name %> do
use Waffle.Definition
# Include ecto support (requires package waffle_ecto installed):
# use Waffle.Ecto.Definition
@versions [:original]
# To add a thumbnail version:
# @versions [:original, :thumb]
# Override the bucket on a per definition basis:
# def bucket do
# :custom_bucket_name
# end
# def bucket({_file, scope}) do
# scope.bucket || bucket()
# end
# Whitelist file extensions:
# def validate({file, _}) do
# file_extension = file.file_name |> Path.extname() |> String.downcase()
#
# case Enum.member?(~w(.jpg .jpeg .gif .png), file_extension) do
# true -> :ok
# false -> {:error, "invalid file type"}
# end
# end
# Define a thumbnail transformation:
# def transform(:thumb, _) do
# {:convert, "-strip -thumbnail 250x250^ -gravity center -extent 250x250 -format png", :png}
# end
# Override the persisted filenames:
# def filename(version, _) do
# version
# end
# Override the storage directory:
# def storage_dir(version, {file, scope}) do
# "uploads/user/avatars/\#{scope.id}"
# end
# Provide a default URL if there hasn't been a file uploaded
# def default_url(version, scope) do
# "/images/avatars/default_\#{version}.png"
# end
# Specify custom headers for s3 objects
# Available options are [:cache_control, :content_disposition,
# :content_encoding, :content_length, :content_type,
# :expect, :expires, :storage_class, :website_redirect_location]
#
# def s3_object_headers(version, {file, scope}) do
# [content_type: MIME.from_path(file.file_name)]
# end
end
"""
end
end