Packages

An Elixir Phoenix Auto Administration Package.

Retired package: Release invalid

Current section

Files

Jump to
ex_admin_runtime web ex_admin resource_controller.ex
Raw

web/ex_admin/resource_controller.ex

defmodule ExAdmin.ResourceController do
@moduledoc false
defmacro __using__(_opts) do
quote do
alias ExAdmin.Authorization
import ExAdmin.Utils
import ExAdmin.ParamsToAtoms
def action(%{private: %{phoenix_action: action}} = conn, _options) do
conn = conn |> assign(:xhr, get_req_header(conn, "x-requested-with") == ["XMLHttpRequest"])
resource = Macro.expand(@resource, __ENV__) || conn.params["resource"]
conn = scrub_params(conn, resource, action)
defn = get_registered_by_controller_route!(conn, resource)
params = filter_params(conn.params, defn.resource_model)
if !restricted_action?(action, defn) do
conn
|> assign(:defn, defn)
|> load_resource(action, defn, params[:id])
|> authorize_action(action)
|> handle_plugs(action, defn)
|> handle_before_filter(action, defn, params)
|> handle_custom_actions(action, defn, params)
else
render_403 conn
end
end
defp do_form_view(conn, resource, params) do
model = conn.assigns.defn.__struct__
if function_exported? model, :form_view, 3 do
apply(model, :form_view, [conn, resource, params])
else
ExAdmin.Form.default_form_view conn, resource, params
end
end
defp handle_changeset_error(conn, defn, changeset, params) do
conn = put_flash(conn, :inline_error, changeset.errors)
|> Plug.Conn.assign(:changeset, changeset)
|> Plug.Conn.assign(:ea_required, changeset.required)
contents = do_form_view(conn, ExAdmin.Changeset.get_data(changeset), params)
render(conn, "admin.html", html: contents, filters: nil)
end
defp render_403(conn) do
conn
|> put_layout(false)
|> put_status(403)
|> render(ExAdmin.ErrorView, "403.html")
|> halt
end
defp restricted_action?(:destroy, defn), do: restricted_action?(:delete, defn)
defp restricted_action?(:create, defn), do: restricted_action?(:new, defn)
defp restricted_action?(:update, defn), do: restricted_action?(:edit, defn)
defp restricted_action?(action, defn) do
if action in [:show, :edit, :update, :new, :destroy, :delete] do
not action in defn.actions
else
false
end
end
def authorize_action(conn, action) do
if ExAdmin.Authorization.authorize_action(conn.assigns[:resource], conn, action) do
conn
else
render_403(conn)
end
end
defp scrub_params(conn, required_key, action) when action in [:create, :update] do
if conn.params[required_key] do
Phoenix.Controller.scrub_params conn, required_key
else
conn
end
end
defp scrub_params(conn, _required_key, _action), do: conn
defp load_resource(conn, _action, defn, nil) do
resource = defn.resource_model.__struct__
assign(conn, :resource, resource)
end
defp load_resource(conn, action, defn, resource_id) do
model = defn.__struct__
query = model.run_query(repo(), defn, action, resource_id)
resource =
Authorization.authorize_query(defn.resource_model.__struct__, conn, query, action, resource_id)
|> ExAdmin.Query.execute_query(repo(), action, resource_id)
if resource == nil do
raise Phoenix.Router.NoRouteError, conn: conn, router: __MODULE__
end
assign(conn, :resource, resource)
end
defp handle_custom_actions(%{halted: true} = conn, _, _, _), do: conn
defp handle_custom_actions({conn, params}, action, defn, _) do
handle_custom_actions(conn, action, defn, params)
end
defp handle_custom_actions(conn, :member, defn, params) do
%{member_actions: member_actions} = defn
action = String.to_atom params[:action]
cond do
member_action = Keyword.get(member_actions, action) ->
member_action[:fun].(conn, params)
true ->
render_403 conn
end
end
defp handle_custom_actions(conn, :collection, defn, params) do
%{collection_actions: collection_actions} = defn
action = String.to_atom params[:action]
cond do
collection_action = Keyword.get(collection_actions, action) ->
collection_action[:fun].(conn, params)
true ->
render_403 conn
end
end
defp handle_custom_actions(conn, action, defn, params) do
apply(__MODULE__, action, [conn, defn, params])
end
defp handle_before_filter(%{halted: true} = conn, _, _, _), do: conn
defp handle_before_filter(conn, action, defn, params) do
_handle_before_filter(conn, action, defn, params, defn.controller_filters[:before_filter])
end
defp _handle_before_filter(conn, action, defn, params, [{name, opts} | t]) do
filter = cond do
opts[:only] ->
if action in opts[:only], do: true, else: false
opts[:except] ->
if not action in opts[:except], do: true, else: false
true -> true
end
if filter do
apply(defn.__struct__, name, [conn, params])
else
conn
end
|> _handle_before_filter(action, defn, params, t)
end
defp _handle_before_filter(conn, _action, _defn, _params, _), do: conn
defp handle_after_filter(conn, action, defn, params, resource) do
_handle_after_filter({conn, params, resource}, action, defn, defn.controller_filters[:after_filter])
end
defp _handle_after_filter({conn, params, resource}, action, defn, [{name, opts} | t]) do
filter = cond do
opts[:only] ->
if action in opts[:only], do: true, else: false
opts[:except] ->
if not action in opts[:except], do: true, else: false
true -> true
end
if filter do
case apply(defn.__struct__, name, [conn, params, resource, action]) do
{_, _, _} = tuple -> tuple
%Plug.Conn{} = conn -> {conn, params, resource}
error ->
raise ExAdmin.RuntimeError, message: (gettext "invalid after_filter return:") <> " #{inspect error}"
end
else
{conn, params, resource}
end
|> _handle_after_filter(action, defn, t)
end
defp _handle_after_filter(args, _action, _defn, _), do: args
defp handle_plugs(%{halted: true} = conn, _, _), do: conn
defp handle_plugs(conn, :nested, _defn), do: conn
defp handle_plugs(conn, _action, defn) do
case Application.get_env(:ex_admin_runtime, :plug, []) do
list when is_list(list) -> list
item -> [{item, []}]
end
|> Keyword.merge(defn.plugs)
|> Enum.reduce(conn, fn({name, opts}, conn) ->
apply(name, :call, [conn, opts])
end)
|> authorized?
end
defp authorized?(%{assigns: %{authorized: true}} = conn), do: conn
defp authorized?(%{assigns: %{authorized: false}}) do
throw :unauthorized
end
defp authorized?(conn), do: conn
defp repo, do: Application.get_env(:ex_admin_runtime, :repo)
end
end
end