defmodule Mix.Tasks.Passport.Install do use Mix.Task @shortdoc "Generates controller, model and views for authentication resource" @moduledoc """ Generates a Phoenix resource for user authentication. mix passport.install or mix passport.install Admin admins The first argument is the module name for the user and the second argument is the plural form of the module name. If omitted, it uses default module name as User and its plural form users. The generated resource will contain: * a model in web/models * a controller, a view, and templates for User registration * a controller, a view, and templates for Session management * a controller, a view, and templates for Password reset * a migration file for the repository """ def run(args) do {_, parsed, _} = OptionParser.parse(args) [singular, plural] = validate_args!(parsed) binding = Mix.Phoenix.inflect(singular) path = binding[:path] migration = String.replace(path, "/", "_") binding = binding ++ [plural: plural, template_singular: String.replace(binding[:singular], "_", " "), template_plural: String.replace(plural, "_", " ")] IO.puts inspect binding Mix.Phoenix.check_module_name_availability!(binding[:module] <> "Controller") Mix.Phoenix.check_module_name_availability!(binding[:module] <> "View") files = [ {:eex, "model.ex", "web/models/#{path}.ex"}, {:eex, "migration.exs", "priv/repo/migrations/#{timestamp()}_create_#{migration}.exs"}, {:eex, "session_view.ex", "web/views/session_view.ex"}, {:eex, "registration_view.ex", "web/views/registration_view.ex"}, {:eex, "password_view.ex", "web/views/password_view.ex"}, {:eex, "registration_controller.ex", "web/controllers/registration_controller.ex"}, {:eex, "session_controller.ex", "web/controllers/session_controller.ex"}, {:eex, "password_controller.ex", "web/controllers/password_controller.ex"}, {:eex, "session_new.html.eex", "web/templates/session/new.html.eex"}, {:eex, "registration_new.html.eex", "web/templates/registration/new.html.eex"}, {:eex, "password_reset.html.eex", "web/templates/password/forget_password.html.eex"}, ] Mix.Phoenix.copy_from paths(), "priv/templates/passport.install", "", binding, files instructions = """ Use Passport in your web/router.ex use Passport add the plug `:current_user` in your browser pipeline pipeline :browser do ... plug :current_user end Add the following routes to your browser scope in web/router.ex: get "/login", SessionController, :new post "/login", SessionController, :create get "/logout", SessionController, :delete get "/register", RegistrationController, :new post "/register", RegistrationController, :create get "/forget-password", PasswordController, :forget_password post "/reset-password", PasswordController, :reset_password Add Passport configuration in your config.exs like below: config :passport, resource: #{binding[:module]}, repo: #{binding[:base]}.Repo Optionally, in your navigation you may to include this: """ Mix.shell.info instructions end defp validate_args!([singular, plural] = args) do cond do plural != Phoenix.Naming.underscore(plural) -> Mix.raise "expected the second argument, #{inspect plural}, to be all lowercase using snake_case convention" true -> args end end defp validate_args!([]) do ["User", "users"] end defp validate_args!(_) do raise_with_help end defp raise_with_help do Mix.raise """ mix passport.install expects both singular and plural names mix passport.install User users or just type without any arguments to create a User resource mix passport.install """ end defp timestamp do {{y, m, d}, {hh, mm, ss}} = :calendar.universal_time() "#{y}#{pad(m)}#{pad(d)}#{pad(hh)}#{pad(mm)}#{pad(ss)}" end defp pad(i) when i < 10, do: << ?0, ?0 + i >> defp pad(i), do: to_string(i) defp paths do [".", :passport] end end