Skip to main content

lib/controller.ex

defmodule Amur.Controller do
  import Plug.Conn

  def request(conn, %{"provider" => provider}) do
    with {:ok, {_module, config}} <- Amur.Config.resolve(provider),
         strategy = Keyword.fetch!(config, :strategy),
         {:ok, %{url: url, session_params: session_params}} <- strategy.authorize_url(config) do
      conn
      |> put_session(:amur_session_params, session_params)
      |> redirect(url)
    else
      {:error, reason} -> handle_failure(conn, reason)
    end
  end

  def callback(conn, %{"provider" => provider} = params) do
    session_params = get_session(conn, :amur_session_params)

    with {:ok, {module, config}} <- Amur.Config.resolve(provider),
         strategy = Keyword.fetch!(config, :strategy),
         config = Keyword.put(config, :session_params, session_params),
         {:ok, %{user: user, token: _token}} <- strategy.callback(config, params) do
      normalized =
        user
        |> module.normalize_user()
        |> Map.put(:provider, provider)

      on_success = Application.fetch_env!(:amur, :on_success)
      on_success.(conn, normalized)
    else
      {:error, reason} -> handle_failure(conn, reason)
    end
  end

  def logout(conn, _params) do
    conn
    |> Amur.logout()
    |> redirect("/")
  end

  defp handle_failure(conn, reason) do
    on_failure = Application.get_env(:amur, :on_failure, &Amur.Controller.default_failure/2)
    on_failure.(conn, reason)
  end

  def default_failure(conn, _reason) do
    conn
    |> redirect("/")
  end

  defp redirect(conn, to) do
    conn
    |> put_resp_header("location", to)
    |> send_resp(302, "")
    |> halt()
  end
end