Current section

Files

Jump to
kaffy lib kaffy_web controllers resource_controller.ex
Raw

lib/kaffy_web/controllers/resource_controller.ex

defmodule KaffyWeb.ResourceController do
@moduledoc false
use Phoenix.Controller, formats: [html: "View"]
alias Kaffy.Pagination
def dashboard(conn, %{"context" => context}) do
render(conn, "dashboard.html",
layout: {KaffyWeb.LayoutView, "app.html"},
context: String.to_existing_atom(context)
)
end
def index(
conn,
%{
"context" => context,
"resource" => resource,
"c" => _target_context,
"r" => _target_resource,
"pick" => _field
} = params
) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
case can_proceed?(my_resource, conn) do
false ->
unauthorized_access(conn)
true ->
fields = Kaffy.ResourceAdmin.index(my_resource)
{filtered_count, entries} = Kaffy.ResourceQuery.list_resource(conn, my_resource, params)
items_per_page = Map.get(params, "limit", "100") |> String.to_integer()
page = Map.get(params, "page", "1") |> String.to_integer()
has_next = round(filtered_count / items_per_page) > page
next_class = if has_next, do: "", else: " disabled"
has_prev = page >= 2
prev_class = if has_prev, do: "", else: " disabled"
list_pages = Pagination.get_pages(page, ceil(filtered_count / items_per_page))
render(conn, "pick_resource.html",
layout: {KaffyWeb.LayoutView, "bare.html"},
context: context,
resource: resource,
fields: fields,
my_resource: my_resource,
filtered_count: filtered_count,
page: page,
has_next_page: has_next,
next_class: next_class,
has_prev_page: has_prev,
prev_class: prev_class,
list_pages: list_pages,
entries: entries,
params: params
)
end
end
def index(conn, %{"context" => context, "resource" => resource} = params) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
case can_proceed?(my_resource, conn) do
false ->
unauthorized_access(conn)
true ->
fields = Kaffy.ResourceAdmin.index(my_resource)
{filtered_count, entries} = Kaffy.ResourceQuery.list_resource(conn, my_resource, params)
items_per_page = Map.get(params, "limit", "100") |> String.to_integer()
page = Map.get(params, "page", "1") |> String.to_integer()
has_next = round(filtered_count / items_per_page) > page
next_class = if has_next, do: "", else: " disabled"
has_prev = page >= 2
prev_class = if has_prev, do: "", else: " disabled"
list_pages = Pagination.get_pages(page, ceil(filtered_count / items_per_page))
render(conn, "index.html",
layout: {KaffyWeb.LayoutView, "app.html"},
context: context,
resource: resource,
fields: fields,
my_resource: my_resource,
filtered_count: filtered_count,
page: page,
has_next_page: has_next,
next_class: next_class,
has_prev_page: has_prev,
prev_class: prev_class,
list_pages: list_pages,
entries: entries,
params: params
)
end
end
def show(conn, %{"context" => context, "resource" => resource, "id" => id}) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
schema = my_resource[:schema]
resource_name = Kaffy.ResourceAdmin.singular_name(my_resource)
can_edit = :edit in Kaffy.ResourceAdmin.default_actions(my_resource)
can_delete = :delete in Kaffy.ResourceAdmin.default_actions(my_resource)
form_method = if can_edit or can_delete, do: :put, else: :get
case can_proceed?(my_resource, conn) do
false ->
unauthorized_access(conn)
true ->
if entry = Kaffy.ResourceQuery.fetch_resource(conn, my_resource, id) do
changeset = Ecto.Changeset.change(entry)
render(conn, "show.html",
layout: {KaffyWeb.LayoutView, "app.html"},
changeset: changeset,
context: context,
resource: resource,
my_resource: my_resource,
resource_name: resource_name,
schema: schema,
entry: entry,
can_edit: can_edit,
can_delete: can_delete,
form_method: form_method
)
else
put_flash(conn, :error, "The resource you are trying to visit does not exist!")
|> redirect(
to: Kaffy.Utils.router().kaffy_resource_path(conn, :index, context, resource)
)
end
end
end
def update(conn, %{"context" => context, "resource" => resource, "id" => id} = params) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
schema = my_resource[:schema]
params = Kaffy.ResourceParams.decode_map_fields(resource, schema, params)
resource_name = Kaffy.ResourceAdmin.singular_name(my_resource) |> String.capitalize()
can_edit = :edit in Kaffy.ResourceAdmin.default_actions(my_resource)
can_delete = :delete in Kaffy.ResourceAdmin.default_actions(my_resource)
form_method = if can_edit or can_delete, do: :put, else: :get
case can_proceed?(my_resource, conn) do
false ->
unauthorized_access(conn)
true ->
entry = Kaffy.ResourceQuery.fetch_resource(conn, my_resource, id)
changes = Map.get(params, resource, %{})
case Kaffy.ResourceCallbacks.update_callbacks(conn, my_resource, entry, changes) do
{:ok, entry} ->
conn = put_flash(conn, :success, "#{resource_name} saved successfully")
save_button = Map.get(params, "submit", "Save")
case save_button do
"Save" ->
conn
|> put_flash(:success, "#{resource_name} saved successfully")
|> redirect(
to: Kaffy.Utils.router().kaffy_resource_path(conn, :index, context, resource)
)
"Save and add another" ->
conn
|> put_flash(:success, "#{resource_name} saved successfully")
|> redirect(
to: Kaffy.Utils.router().kaffy_resource_path(conn, :new, context, resource)
)
"Save and continue editing" ->
conn
|> put_flash(:success, "#{resource_name} saved successfully")
|> redirect_to_resource(context, resource, entry)
end
{:error, %Ecto.Changeset{} = changeset} ->
conn =
put_flash(
conn,
:error,
"A problem occurred while trying to save this #{resource}"
)
render(conn, "show.html",
layout: {KaffyWeb.LayoutView, "app.html"},
changeset: changeset,
context: context,
resource: resource,
my_resource: my_resource,
resource_name: resource_name,
schema: schema,
entry: entry,
can_edit: can_edit,
can_delete: can_delete,
form_method: form_method
)
{:error, {entry, error}} when is_binary(error) ->
conn = put_flash(conn, :error, error)
changeset = Ecto.Changeset.change(entry)
render(conn, "show.html",
layout: {KaffyWeb.LayoutView, "app.html"},
changeset: changeset,
context: context,
resource: resource,
my_resource: my_resource,
resource_name: resource_name,
schema: schema,
entry: entry,
can_edit: can_edit,
can_delete: can_delete,
form_method: form_method
)
end
end
end
def new(conn, %{"context" => context, "resource" => resource}) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
resource_name = Kaffy.ResourceAdmin.singular_name(my_resource)
with {:permitted, true} <- {:permitted, can_proceed?(my_resource, conn)},
{:enabled, true} <- {:enabled, is_enabled?(my_resource, :new)} do
changeset = Kaffy.ResourceAdmin.create_changeset(my_resource, %{}) |> Map.put(:errors, [])
render(conn, "new.html",
layout: {KaffyWeb.LayoutView, "app.html"},
changeset: changeset,
context: context,
resource: resource,
resource_name: resource_name,
my_resource: my_resource
)
else
{:permitted, false} -> unauthorized_access(conn)
{:enabled, false} -> not_enabled(conn)
end
end
def create(conn, %{"context" => context, "resource" => resource} = params) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
params = Kaffy.ResourceParams.decode_map_fields(resource, my_resource[:schema], params)
changes = Map.get(params, resource, %{})
resource_name = Kaffy.ResourceAdmin.singular_name(my_resource)
with {:permitted, true} <- {:permitted, can_proceed?(my_resource, conn)},
{:enabled, true} <- {:enabled, is_enabled?(my_resource, :new)} do
case Kaffy.ResourceCallbacks.create_callbacks(conn, my_resource, changes) do
{:ok, entry} ->
case Map.get(params, "submit", "Save") do
"Save" ->
put_flash(conn, :success, "Created a new #{resource_name} successfully")
|> redirect(
to: Kaffy.Utils.router().kaffy_resource_path(conn, :index, context, resource)
)
"Save and add another" ->
conn
|> put_flash(:success, "#{resource_name} saved successfully")
|> redirect(
to: Kaffy.Utils.router().kaffy_resource_path(conn, :new, context, resource)
)
"Save and continue editing" ->
put_flash(conn, :success, "Created a new #{resource_name} successfully")
|> redirect_to_resource(context, resource, entry)
end
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html",
layout: {KaffyWeb.LayoutView, "app.html"},
changeset: changeset,
context: context,
resource: resource,
resource_name: resource_name,
my_resource: my_resource
)
{:error, {entry, error}} when is_binary(error) ->
changeset = Ecto.Changeset.change(entry)
conn
|> put_flash(:error, error)
|> render("new.html",
layout: {KaffyWeb.LayoutView, "app.html"},
changeset: changeset,
context: context,
resource: resource,
resource_name: resource_name,
my_resource: my_resource
)
end
else
{:permitted, false} -> unauthorized_access(conn)
{:enabled, false} -> not_enabled(conn)
end
end
def delete(conn, %{"context" => context, "resource" => resource, "id" => id}) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
case can_proceed?(my_resource, conn) do
false ->
unauthorized_access(conn)
true ->
entry = Kaffy.ResourceQuery.fetch_resource(conn, my_resource, id)
case Kaffy.ResourceCallbacks.delete_callbacks(conn, my_resource, entry) do
:ok ->
put_flash(conn, :success, "The record was deleted successfully")
|> redirect(
to: Kaffy.Utils.router().kaffy_resource_path(conn, :index, context, resource)
)
{:error, %Ecto.Changeset{} = _changeset} ->
put_flash(
conn,
:error,
"A database-related issue prevented this record from being deleted."
)
|> redirect_to_resource(context, resource, entry)
{:error, {_entry, error}} when is_binary(error) ->
put_flash(conn, :error, error)
|> redirect_to_resource(context, resource, entry)
end
end
end
def single_action(conn, %{
"context" => context,
"resource" => resource,
"id" => id,
"action_key" => action_key
}) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
entry = Kaffy.ResourceQuery.fetch_resource(conn, my_resource, id)
actions = Kaffy.ResourceAdmin.resource_actions(my_resource, conn)
action_record = get_action_record(actions, action_key)
case action_record.action.(conn, entry) do
{:ok, entry} ->
conn = put_flash(conn, :success, "Action performed successfully")
redirect_to_resource(conn, context, resource, entry)
{:error, _} ->
conn = put_flash(conn, :error, "A validation error occurred")
redirect_to_resource(conn, context, resource, entry)
{:error, _, error_msg} ->
conn = put_flash(conn, :error, error_msg)
redirect_to_resource(conn, context, resource, entry)
end
end
def list_action(
conn,
%{"context" => context, "resource" => resource, "action_key" => action_key} = params
) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
ids = Map.get(params, "ids", "") |> String.split(",")
entries = Kaffy.ResourceQuery.fetch_list(my_resource, ids)
actions = Kaffy.ResourceAdmin.list_actions(my_resource, conn)
action_record = get_action_record(actions, action_key)
kaffy_inputs = Map.get(params, "kaffy-input", %{})
result =
case entries do
{:error, error_msg} ->
{:error, error_msg}
entries ->
case Map.get(action_record, :inputs, []) do
[] -> action_record.action.(conn, entries)
_ -> action_record.action.(conn, entries, kaffy_inputs)
end
end
case result do
:ok ->
put_flash(conn, :success, "Action performed successfully")
|> redirect(to: Kaffy.Utils.router().kaffy_resource_path(conn, :index, context, resource))
{:error, error_msg} ->
put_flash(conn, :error, error_msg)
|> redirect(to: Kaffy.Utils.router().kaffy_resource_path(conn, :index, context, resource))
end
end
# def export(conn, %{"context" => context, "resource" => resource}) do
# my_resource = Kaffy.Utils.get_resource(conn, context, resource)
# end
defp can_proceed?(resource, conn) do
Kaffy.ResourceAdmin.authorized?(resource, conn)
end
defp is_enabled?(resource, action) do
action in Kaffy.ResourceAdmin.default_actions(resource)
end
defp unauthorized_access(conn) do
conn
|> put_flash(:error, "You are not authorized to access that page")
|> redirect(to: Kaffy.Utils.router().kaffy_home_path(conn, :index))
end
defp not_enabled(conn) do
conn
|> put_flash(:error, "This action has been disabled.")
|> redirect(to: Kaffy.Utils.router().kaffy_home_path(conn, :index))
end
defp redirect_to_resource(conn, context, resource, entry) do
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
id = Kaffy.ResourceAdmin.serialize_id(my_resource, entry)
redirect(conn,
to:
Kaffy.Utils.router().kaffy_resource_path(
conn,
:show,
context,
resource,
id
)
)
end
# we received actions as map so we actually use strings as keys
defp get_action_record(actions, action_key) when is_map(actions) and is_binary(action_key) do
Map.fetch!(actions, action_key)
end
# we received actions as Keyword list so action_key needs to be an atom
defp get_action_record(actions, action_key) when is_list(actions) and is_binary(action_key) do
action_key = String.to_existing_atom(action_key)
[action_record] = Keyword.get_values(actions, action_key)
action_record
end
end