Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions lib/kaffy/resource_admin.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ defmodule Kaffy.ResourceAdmin do
alias Kaffy.ResourceSchema
alias Kaffy.Utils

@default_id_separator "."

@moduledoc """
ResourceAdmin modules should be created for every schema you want to customize/configure in Kaffy.

Expand Down Expand Up @@ -119,7 +121,7 @@ defmodule Kaffy.ResourceAdmin do
@doc """
`ordering/1` takes a schema and returns how the entries should be ordered.

If `ordering/1` is not defined, Kaffy will return `[desc: :id]`.
If `ordering/1` is not defined, Kaffy will return `[desc: primary_key]`, or the first field of the primary key, if it's a composite.

Example:

Expand All @@ -130,7 +132,10 @@ defmodule Kaffy.ResourceAdmin do
```
"""
def ordering(resource) do
Utils.get_assigned_value_or_default(resource, :ordering, desc: :id)
schema = resource[:schema]
[order_key | _] = ResourceSchema.primary_keys(schema)

Utils.get_assigned_value_or_default(resource, :ordering, desc: order_key)
end

@doc """
Expand Down Expand Up @@ -293,6 +298,52 @@ defmodule Kaffy.ResourceAdmin do
Utils.get_assigned_value_or_default(resource, :plural_name, default)
end

@doc """
`serialize_id/2` takes a schema and record and must return a string to be used in the URL and form values.

If `serialize_id/2` is not defined, Kaffy will concatenate multiple primary keys with `"."` as a separator.

Example:

```elixir
def serialize_id(_schema, record) do
Enum.join([record.post_id, record.tag_id], ".")
end
```
"""
def serialize_id(resource, entry) do
schema = resource[:schema]
default = schema
|> ResourceSchema.primary_keys()
|> Enum.map_join(@default_id_separator, &Map.get(entry, &1))

Utils.get_assigned_value_or_default(resource, :serialize_id, default, [entry])
end

@doc """
`deserialize_id/2` takes a schema and serialized id and must return a complete
keyword list in the form of [{:primary_key, value}, ...].

If `deserialize_id/2` is not defined, Kaffy will split multiple primary keys with `"."` as a separator.

Example:

```elixir
def serialize_id(_schema, serialized_id) do
Enum.zip([:post_id, :tag_id], String.split(serialized_id, "."))
end
```
"""
def deserialize_id(resource, id) do
schema = resource[:schema]
id_list = String.split(id, @default_id_separator)
default = schema
|> ResourceSchema.primary_keys()
|> Enum.zip(id_list)

Utils.get_assigned_value_or_default(resource, :deserialize_id, default, [id])
end

def resource_actions(resource, conn) do
Utils.get_assigned_value_or_default(resource, :resource_actions, nil, [conn], false)
end
Expand Down
12 changes: 9 additions & 3 deletions lib/kaffy/resource_form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,14 @@ defmodule Kaffy.ResourceForm do
opts
end

# Check if any primary key fields are nil
is_create_event = changeset.data.__struct__
|> Kaffy.ResourceSchema.primary_keys()
|> Enum.map(&Map.get(changeset.data, &1))
|> Enum.any?(&is_nil/1)

permission =
case is_nil(changeset.data.id) do
case is_create_event do
true -> Map.get(options, :create, :editable)
false -> Map.get(options, :update, :editable)
end
Expand Down Expand Up @@ -102,13 +108,13 @@ defmodule Kaffy.ResourceForm do
end)

:id ->
case Kaffy.ResourceSchema.primary_key(schema) == [field] do
case field in Kaffy.ResourceSchema.primary_keys(schema) do
true -> text_input(form, field, opts)
false -> text_or_assoc(conn, schema, form, field, opts)
end

:binary_id ->
case Kaffy.ResourceSchema.primary_key(schema) == [field] do
case field in Kaffy.ResourceSchema.primary_keys(schema) do
true -> text_input(form, field, opts)
false -> text_or_assoc(conn, schema, form, field, opts)
end
Expand Down
3 changes: 2 additions & 1 deletion lib/kaffy/resource_query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ defmodule Kaffy.ResourceQuery do

def fetch_resource(conn, resource, id) do
schema = resource[:schema]
query = from(s in schema, where: s.id == ^id)
id_filter = Kaffy.ResourceAdmin.deserialize_id(resource, id)
query = from(s in schema, where: ^id_filter)
custom_query = Kaffy.ResourceAdmin.custom_show_query(conn, resource, query)
Kaffy.Utils.repo().one(custom_query)
end
Expand Down
11 changes: 8 additions & 3 deletions lib/kaffy/resource_schema.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Kaffy.ResourceSchema do
@moduledoc false

def primary_key(schema) do
def primary_keys(schema) do
schema.__schema__(:primary_key)
end

Expand All @@ -24,7 +24,10 @@ defmodule Kaffy.ResourceSchema do
end

def form_fields(schema) do
to_be_removed = fields_to_be_removed(schema) ++ [:id, :inserted_at, :updated_at]
to_be_removed =
fields_to_be_removed(schema) ++
primary_keys(schema) ++
[:inserted_at, :updated_at]
Keyword.drop(fields(schema), to_be_removed)
end

Expand All @@ -33,7 +36,9 @@ defmodule Kaffy.ResourceSchema do
fields_to_be_removed(schema) ++
get_has_many_associations(schema) ++
get_has_one_assocations(schema) ++
get_many_to_many_associations(schema) ++ [:id, :inserted_at, :updated_at]
get_many_to_many_associations(schema) ++
primary_keys(schema) ++
[:inserted_at, :updated_at]

Keyword.drop(fields(schema), to_be_removed)
end
Expand Down
4 changes: 3 additions & 1 deletion lib/kaffy_web/controllers/resource_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -383,14 +383,16 @@ defmodule KaffyWeb.ResourceController do
end

defp redirect_to_resource(conn, context, resource, entry) do
id = Kaffy.ResourceAdmin.serialize_id(resource, entry)

redirect(conn,
to:
Kaffy.Utils.router().kaffy_resource_path(
conn,
:show,
context,
resource,
entry.id
id
)
)
end
Expand Down
8 changes: 4 additions & 4 deletions lib/kaffy_web/templates/resource/_table.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
</thead>

<tbody>
<%= for entry <- @entries do %>
<%= for {entry, index} <- Enum.with_index(@entries) do %>
<tr>
<td>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input select-item kaffy-resource-checkbox" id="kaffy-select-<%= entry.id %>" name="resource" value="<%= entry.id %>"/>
<label class="custom-control-label" for="kaffy-select-<%= entry.id %>"></label>
<input type="checkbox" class="custom-control-input select-item kaffy-resource-checkbox" id="kaffy-select-<%= index %>" name="resource" value="<%= Kaffy.ResourceAdmin.serialize_id(@my_resource, entry) %>"/>
<label class="custom-control-label" for="kaffy-select-<%= index %>"></label>
</div>
</td>
<%= for {field, index} <- Enum.with_index(@fields) do %>
<%= if index == 0 do %>
<td><%= link Kaffy.ResourceSchema.kaffy_field_value(@conn, entry, field), to: Kaffy.Utils.router().kaffy_resource_path(@conn, :show, @context, @resource, entry) %></td>
<td><%= link Kaffy.ResourceSchema.kaffy_field_value(@conn, entry, field), to: Kaffy.Utils.router().kaffy_resource_path(@conn, :show, @context, @resource, Kaffy.ResourceAdmin.serialize_id(@my_resource, entry)) %></td>
<% else %>
<td><%= Kaffy.ResourceSchema.kaffy_field_value(@conn, entry, field) %></td>
<% end %>
Expand Down
8 changes: 4 additions & 4 deletions lib/kaffy_web/templates/resource/show.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div class="card-header">
<div class="row justify-content-between">
<div class="col-auto mr-auto">
<h1><%= @resource_name %> #<%= @changeset.data.id %></h1>
<h1><%= @resource_name %> #<%= Kaffy.ResourceAdmin.serialize_id(@my_resource, @changeset.data) %></h1>
</div>
<div class="col-auto">
<%= if Kaffy.ResourceAdmin.resource_actions(@my_resource, @conn) do %>
Expand All @@ -20,7 +20,7 @@
</button>
<div class="dropdown-menu">
<%= for {action_key, options} <- Kaffy.ResourceAdmin.resource_actions(@my_resource, @conn) do %>
<%= form_tag(Kaffy.Utils.router().kaffy_resource_path(@conn, :single_action, @context, @resource, @changeset.data.id, to_string(action_key)), method: :post) %>
<%= form_tag(Kaffy.Utils.router().kaffy_resource_path(@conn, :single_action, @context, @resource, Kaffy.ResourceAdmin.serialize_id(@my_resource, @changeset.data), to_string(action_key)), method: :post) %>
<input type="submit" name="submit" value="<%= options.name %>" class="dropdown-item" />
</form>
<% end %>
Expand All @@ -32,7 +32,7 @@
</div>
</div>
<div class="card-body">
<%= f = form_for(@changeset, Kaffy.Utils.router().kaffy_resource_path(@conn, :update, @context, @resource, @changeset.data.id), method: :put, multipart: true) %>
<%= f = form_for(@changeset, Kaffy.Utils.router().kaffy_resource_path(@conn, :update, @context, @resource, Kaffy.ResourceAdmin.serialize_id(@my_resource, @changeset.data)), method: :put, multipart: true) %>
<%= for {field, options} <- Kaffy.ResourceAdmin.form_fields(@my_resource) do %>
<%= if options.update != :hidden do %>
<%= Kaffy.ResourceForm.kaffy_input @conn, @changeset, f, field, options %>
Expand All @@ -53,7 +53,7 @@
</div>

<!-- Modal -->
<%= form_for(@changeset, Kaffy.Utils.router().kaffy_resource_path(@conn, :delete, @context, @resource, @changeset.data.id), method: :delete) %>
<%= form_for(@changeset, Kaffy.Utils.router().kaffy_resource_path(@conn, :delete, @context, @resource, Kaffy.ResourceAdmin.serialize_id(@my_resource, @changeset.data)), method: :delete) %>
<div class="modal fade" id="delete-modal" tabindex="-1" role="dialog" aria-labelledby="delete-modal-label" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
Expand Down