Current section
Files
Jump to
Current section
Files
lib/plato_web/controllers/field_controller.ex
defmodule PlatoWeb.FieldController do
use Phoenix.Controller, formats: [:html]
import Ecto.Query
def create(conn, %{"schema_id" => schema_id, "field" => field_params}) do
attrs =
field_params
|> Map.put("schema_id", schema_id)
|> normalize_field_params()
|> extract_field_options()
case Plato.Field.create(attrs, repo(conn), otp_app: otp_app(conn)) do
{:ok, field} ->
conn
|> put_flash(:info, "Field '#{field.name}' added successfully!")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
{:error, changeset} ->
error_message =
case changeset.errors[:field_type] do
{msg, _} -> msg
nil -> "Failed to add field"
end
conn
|> put_flash(:error, error_message)
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
end
end
def reorder(conn, %{"schema_id" => _schema_id, "field_ids" => field_ids}) do
# Update position for each field based on the order in the array
Enum.with_index(field_ids, 1)
|> Enum.each(fn {field_id, position} ->
case repo(conn).get(Plato.Field, field_id) do
nil -> :ok
field ->
field
|> Plato.Field.changeset(%{position: position}, otp_app: otp_app(conn))
|> repo(conn).update()
end
end)
json(conn, %{success: true})
end
def edit(conn, %{"schema_id" => schema_id, "id" => field_id}) do
schema = repo(conn).get(Plato.Schema, schema_id)
field = repo(conn).get(Plato.Field, field_id) |> repo(conn).preload(:referenced_schema)
all_schemas = repo(conn).all(Plato.Schema)
cond do
!schema || !field || field.schema_id != String.to_integer(schema_id) ->
conn
|> put_flash(:error, "Field or schema not found")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
schema.managed_by == "code" ->
conn
|> put_flash(:error, "Cannot edit fields in code-managed schemas")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
true ->
render(conn, :edit,
schema: schema,
field: field,
all_schemas: all_schemas,
base_path: base_path(conn)
)
end
end
def update(conn, %{"schema_id" => schema_id, "id" => field_id, "field" => field_params}) do
field = repo(conn).get(Plato.Field, field_id) |> repo(conn).preload(:schema)
cond do
!field || field.schema_id != String.to_integer(schema_id) ->
conn
|> put_flash(:error, "Field not found")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
field.schema.managed_by == "code" ->
conn
|> put_flash(:error, "Cannot update fields in code-managed schemas")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
true ->
attrs =
field_params
|> normalize_field_params()
|> extract_field_options_for_update(field)
case field
|> Plato.Field.changeset(attrs, otp_app: otp_app(conn))
|> repo(conn).update() do
{:ok, _field} ->
conn
|> put_flash(:info, "Field updated successfully!")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
{:error, changeset} ->
error_message =
case changeset.errors[:field_type] do
{msg, _} -> msg
nil -> "Failed to update field"
end
conn
|> put_flash(:error, error_message)
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}/fields/#{field_id}/edit")
end
end
end
defp normalize_field_params(%{"field_type" => "reference", "referenced_schema_id" => ""} = params) do
Map.put(params, "referenced_schema_id", nil)
end
defp normalize_field_params(%{"field_type" => "text"} = params) do
Map.put(params, "referenced_schema_id", nil)
end
defp normalize_field_params(params), do: params
defp extract_field_options(%{"field_type" => "text"} = params) do
# Extract multiline and as_title options
options = %{}
options =
case Map.get(params, "multiline") do
"true" -> Map.put(options, "multiline", true)
"on" -> Map.put(options, "multiline", true)
_ -> options
end
options =
case Map.get(params, "as_title") do
"true" -> Map.put(options, "as_title", true)
"on" -> Map.put(options, "as_title", true)
_ -> options
end
# Remove temporary form fields and add options
params
|> Map.delete("multiline")
|> Map.delete("as_title")
|> Map.put("options", options)
end
defp extract_field_options(params) do
# Extract as_title option for non-text fields
options = %{}
options =
case Map.get(params, "as_title") do
"true" -> Map.put(options, "as_title", true)
"on" -> Map.put(options, "as_title", true)
_ -> options
end
params
|> Map.delete("as_title")
|> Map.put("options", options)
end
defp extract_field_options_for_update(params, field) do
# Similar to extract_field_options but for updates
options = %{}
# Handle as_title for all field types
options =
case Map.get(params, "as_title") do
"true" -> Map.put(options, "as_title", true)
"on" -> Map.put(options, "as_title", true)
_ -> options
end
# Handle multiline for text fields
options =
if field.field_type == "text" do
case Map.get(params, "multiline") do
"true" -> Map.put(options, "multiline", true)
"on" -> Map.put(options, "multiline", true)
_ -> options
end
else
options
end
params
|> Map.delete("multiline")
|> Map.delete("as_title")
|> Map.put("options", options)
end
def delete_confirm(conn, %{"schema_id" => schema_id, "id" => field_id}) do
schema = repo(conn).get(Plato.Schema, schema_id)
field = repo(conn).get(Plato.Field, field_id) |> repo(conn).preload(:referenced_schema)
if schema && field && field.schema_id == String.to_integer(schema_id) do
# Get all content for this schema
contents =
repo(conn).all(
from c in Plato.Content,
where: c.schema_id == ^schema_id
)
|> repo(conn).preload(:schema)
# Find contents that have this field filled
affected_contents =
contents
|> Enum.filter(fn content ->
field_value = Map.get(content.field_values, to_string(field.id))
field_value && field_value != ""
end)
render(conn, :delete_confirm,
schema: schema,
field: field,
affected_contents: affected_contents,
base_path: base_path(conn)
)
else
conn
|> put_flash(:error, "Field or schema not found")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
end
end
def delete(conn, %{"schema_id" => schema_id, "id" => field_id}) do
field = repo(conn).get(Plato.Field, field_id)
if field && field.schema_id == String.to_integer(schema_id) do
# Remove field data from all content instances
contents =
repo(conn).all(
from c in Plato.Content,
where: c.schema_id == ^schema_id
)
Enum.each(contents, fn content ->
updated_field_values = Map.delete(content.field_values, to_string(field.id))
content
|> Plato.Content.changeset(%{field_values: updated_field_values})
|> repo(conn).update()
end)
# Delete the field
repo(conn).delete(field)
conn
|> put_flash(:info, "Field '#{field.name}' deleted successfully!")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
else
conn
|> put_flash(:error, "Field not found")
|> redirect(to: "#{base_path(conn)}/schemas/#{schema_id}")
end
end
# Private helper to get otp_app from conn assigns
defp otp_app(conn), do: conn.assigns[:plato_otp_app] || :plato
# Private helper to get repo from conn assigns
defp repo(conn) do
otp_app(conn)
|> Application.get_env(:plato, [])
|> Keyword.get(:repo, Plato.Repo)
end
# Private helper to get base_path from conn assigns
defp base_path(conn), do: conn.assigns[:plato_base_path] || "/"
end