defmodule ExWeb do alias Plug.Conn require Logger def render(conn, module, page \\ :index, assigns \\ %{}) def render(%Conn{state: :sent} = conn, _module, _page, _assigns) do Logger.debug "[ExWeb] Response to this request has already been sent" conn end def render(%Conn{} = conn, module, page, assigns) do page = "#{page}" assigns = Map.merge(assigns, %{ex_web_module: module, ex_web_page: page}) links = Map.get(conn.assigns, :ex_web_links) || %{} formdata = Map.get(conn.private, :ex_web_validation) || %{} Logger.debug "[ExWeb] Render #{module}.#{page}" conn |> Plug.Conn.send_resp(200, apply(module, :render, [page, assigns, links, formdata])) |> Plug.Conn.halt end def render_if_failed(conn, module, page \\ :index, assigns \\ %{}) def render_if_failed(%{private: %{ex_web_validation: %{errors: [_|_]}}} = conn, module, page, assigns) do render(conn, module, page, assigns) end def render_if_failed(conn, _module, _page, _assigns) do conn end def render_if_successful(conn, module, page \\ :index, assigns \\ %{}) def render_if_successful(%{private: %{ex_web_validation: %{errors: [_|_]}}} = conn, _module, _page, _assigns) do conn end def render_if_successful(conn, module, page, assigns) do render(conn, module, page, assigns) end def redirect_to_if_successful(conn, url, params \\ %{}, body \\ nil) def redirect_to_if_successful(%{private: %{ex_web_validation: %{errors: [_|_]}}} = conn, _url, _params, _body) do conn end def redirect_to_if_successful(conn, url, params, body) do redirect_to(conn, url, params, body) end def redirect_to_if_failed(conn, url, params \\ %{}, body \\ nil) def redirect_to_if_failed(%{private: %{ex_web_validation: %{errors: [_|_]}}} = conn, url, params, body) do redirect_to(conn, url, params, body) end def redirect_to_if_failed(conn, _url, _params, _body) do conn end def validate(%{body_params: body_params} = conn, module, function, commit_function) do change = %{ attributes: body_params, errors: [] } case apply(module, function, [change]) do %{errors: [_|_] = errors, attributes: attributes} -> conn |> Plug.Conn.put_private(:ex_web_validation, %{errors: errors, attributes: Map.to_list(attributes)}) %{errors: errors, attributes: attributes} -> change = %{errors: errors, attributes: Map.to_list(attributes)} conn |> Plug.Conn.put_private(:ex_web_validation, change) |> commit_function.(Map.to_list(attributes)) end end def forms(conn, module, form) do change = %{ attributes: Map.to_list(apply(module, :form, [form])), errors: [] } conn |> Plug.Conn.put_private(:ex_web_validation, change) end def redirect_to(conn, url, params \\ %{}, body \\ nil) def redirect_to(%Conn{state: :sent} = conn, _url, _params, _body) do Logger.debug "[ExWeb] Response to this request has already been sent" conn end def redirect_to(%Conn{} = conn, url, params, body) do url = merge_params_and_url(url, params) html_url = Plug.HTML.html_escape(url) Logger.debug "[ExWeb] Redirect to #{url}" body = if body == nil do "You are being redirected." else body end conn |> Plug.Conn.put_resp_header("location", url) |> Plug.Conn.send_resp(302, body) |> Plug.Conn.halt end def add_url_for(%{assigns: assigns} = conn, url, opts \\ []) do opts = Map.new(opts) name = Map.get(opts, :name) || String.replace(url, "/", "_") |> String.trim("_") |> String.downcase name = "#{name}_path" |> String.to_atom params = Map.get(opts, :params) || %{} url = merge_params_and_url(url, params) urls = Map.get(assigns, :ex_web_links) || %{} urls = Map.put(urls, name, url) conn |> Plug.Conn.assign(:ex_web_links, urls) end defp generate_params_string(params) do if Enum.count(params) < 1 do "" else str = params |> Enum.map(fn {k,v} -> "#{k}=#{v}" end) |> Enum.join("&") "?#{str}" end end defp merge_params_and_url(url, params) do "#{url}#{generate_params_string(params)}" end end