Current section

Files

Jump to
ex_admin_runtime web controllers admin_resource_controller.ex
Raw

web/controllers/admin_resource_controller.ex

defmodule ExAdmin.AdminResourceController do
@moduledoc false
@resource nil
use ExAdmin.Web, :resource_controller
def index(conn, defn, params) do
model = defn.__struct__
page = case conn.assigns[:page] do
nil ->
id = params |> Map.to_list
query = model.run_query(repo(), defn, :index, id)
Authorization.authorize_query(conn.assigns.resource, conn, query, :index, id)
|> ExAdmin.Query.execute_query(repo(), :index, id)
page ->
page
end
scope_counts = model.run_query_counts repo(), defn, :index, params |> Map.to_list
{conn, _params, page} = handle_after_filter(conn, :index, defn, params, page)
contents = if function_exported? model, :index_view, 3 do
apply(model, :index_view, [conn, page, scope_counts])
else
ExAdmin.Index.default_index_view(conn, page, scope_counts)
end
assign(conn, :scope_counts, scope_counts)
|> render("admin.html", html: contents, page: page,
filters: (if false in defn.index_filters, do: false, else: defn.index_filters))
end
def show(conn, defn, params) do
model = defn.__struct__
resource = conn.assigns.resource
{conn, _params, resource} = handle_after_filter(conn, :show, defn, params, resource)
contents = if function_exported? model, :show_view, 2 do
apply(model, :show_view, [conn, resource])
else
ExAdmin.Show.default_show_view(conn, resource)
end
render conn, "admin.html", html: contents, filters: nil
end
def edit(conn, defn, params) do
model = defn.__struct__
resource = conn.assigns.resource
changeset_fn = model.changeset_fn(defn, :update)
changeset = ExAdmin.Repo.changeset(changeset_fn, resource, params[defn.resource_name])
conn = Plug.Conn.assign(conn, :ea_required, changeset.required)
{conn, params, resource} = handle_after_filter(conn, :edit, defn, params, resource)
contents = do_form_view(conn, resource, params)
render conn, "admin.html", html: contents, filters: nil
end
def new(conn, defn, params) do
model = defn.__struct__
resource = conn.assigns.resource
changeset_fn = model.changeset_fn(defn, :create)
changeset = ExAdmin.Repo.changeset(changeset_fn, resource, params[defn.resource_name])
conn = Plug.Conn.assign(conn, :ea_required, changeset.required)
{conn, params, resource} = handle_after_filter(conn, :new, defn, params, resource)
contents = do_form_view(conn, resource, params)
render conn, "admin.html", html: contents, filters: nil
end
def create(conn, defn, params) do
model = defn.__struct__
resource = conn.assigns.resource
changeset_fn = model.changeset_fn(defn, :create)
changeset = ExAdmin.Repo.changeset(changeset_fn, resource, params[defn.resource_name])
case ExAdmin.Repo.insert(changeset) do
{:error, changeset} ->
conn |> handle_changeset_error(defn, changeset, params)
resource ->
{conn, _, resource} = handle_after_filter(conn, :create, defn, params, resource)
put_flash(conn, :notice, (gettext "%{model_name} was successfully created.", model_name: (model |> base_name |> titleize) ))
|> redirect(to: admin_resource_path(resource, :show))
end
end
def update(conn, defn, params) do
model = defn.__struct__
resource = conn.assigns.resource
changeset_fn = model.changeset_fn(defn, :update)
changeset = ExAdmin.Repo.changeset(changeset_fn, resource, params[defn.resource_name])
case ExAdmin.Repo.update(changeset) do
{:error, changeset} ->
conn |> handle_changeset_error(defn, changeset, params)
resource ->
{conn, _, resource} = handle_after_filter(conn, :update, defn, params, resource)
put_flash(conn, :notice, "#{model |> base_name |> titleize} " <> (gettext "was successfully updated."))
|> redirect(to: admin_resource_path(resource, :show))
end
end
def toggle_attr(conn, defn, %{attr_name: attr_name, attr_value: attr_value}) do
resource = conn.assigns.resource
attr_name_atom = String.to_existing_atom(attr_name)
resource = resource
|> defn.resource_model.changeset(%{attr_name => attr_value})
|> repo().update!
render conn, "toggle_attr.js", attr_name: attr_name, attr_value: Map.get(resource, attr_name_atom), id: ExAdmin.Schema.get_id(resource)
end
def destroy(conn, defn, params) do
model = defn.__struct__
resource = conn.assigns.resource
ExAdmin.Repo.delete(resource, params[defn.resource_name])
model_name = model |> base_name |> titleize
{conn, _, _resource} = handle_after_filter(conn, :destroy, defn, params, resource)
if conn.assigns.xhr do
render conn, "destroy.js", tr_id: String.downcase("#{model_name}_#{params[:id]}")
else
put_flash(conn, :notice, "#{model_name} " <> (gettext "was successfully destroyed."))
|> redirect(to: admin_resource_path(defn.resource_model, :index))
end
end
def batch_action(conn, defn, %{batch_action: "destroy"} = params) do
resource_model = defn.resource_model
type = case ExAdmin.Schema.primary_key(resource_model) do
nil -> :integer
key -> resource_model.__schema__(:type, key)
end
ids = params[:collection_selection]
count = Enum.count ids
ids
|> Enum.map(&(to_integer(type, &1)))
|> Enum.each(fn(id) ->
repo().delete repo().get(resource_model, id)
end)
put_flash(conn, :notice, "#{count} #{pluralize params[:resource], count} "
<> (ngettext "was successfully destroyed.", "were successfully destroyed.", count))
|> redirect(to: admin_resource_path(resource_model, :index))
end
defp to_integer(:id, string), do: string
defp to_integer(:string, string), do: string
defp to_integer(:integer, string) do
case Integer.parse string do
{int, ""} -> int
_ -> string
end
end
def csv(conn, defn, params) do
model = defn.__struct__
id = params |> Map.to_list
query = model.run_query(repo(), defn, :csv, id)
csv = Authorization.authorize_query(conn.assigns.resource, conn, query, :csv, id)
|> ExAdmin.Query.execute_query(repo(), :csv, id)
|> case do
[] -> []
resources ->
if function_exported? model, :build_csv, 1 do
model.build_csv(resources)
else
ExAdmin.CSV.build_csv(resources)
end
end
conn
|> put_resp_content_type("text/csv")
|> put_resp_header("Content-Disposition", "inline; filename=\"#{params[:resource]}.csv\"")
|> send_resp(conn.status || 200, csv)
end
# Can't remember why this is here
# @nested_key_list for i <- 1..5, do: {String.to_atom("nested#{i}"), String.to_atom("id#{i}")}
def nested(conn, defn, params) do
model = defn.__struct__
resource = case conn.assigns.resource do
[res] -> res
other -> other
end
items = apply(model, :get_blocks, [conn, defn.resource_model.__struct__, params])
block = deep_find(items, String.to_atom(params[:field_name]))
resources = case block[:opts][:collection] do
list when is_list(list) ->
list
fun when is_function(fun) ->
fun.(conn, defn.resource_model.__struct__)
end
contents = apply(model, :ajax_view, [conn, params, resource, resources, block])
send_resp(conn, conn.status || 200, "text/javascript", contents)
end
def deep_find(items, name) do
Enum.reduce items, nil, fn(item, acc) ->
case item do
%{inputs: inputs} ->
case Enum.find inputs, &(&1[:name] == name) do
nil -> acc
found -> found
end
_ -> acc
end
end
end
defp send_resp(conn, default_status, default_content_type, body) do
conn
|> ensure_resp_content_type(default_content_type)
|> Plug.Conn.send_resp(conn.status || default_status, body)
end
defp ensure_resp_content_type(%{resp_headers: resp_headers} = conn, content_type) do
if List.keyfind(resp_headers, "content-type", 0) do
conn
else
content_type = content_type <> "; charset=utf-8"
%{conn | resp_headers: [{"content-type", content_type}|resp_headers]}
end
end
end