berrypod/lib/berrypod_web/controllers/navigation_controller.ex

82 lines
2.2 KiB
Elixir
Raw Normal View History

defmodule BerrypodWeb.NavigationController do
@moduledoc """
No-JS fallback for navigation form submission.
With JS enabled, the LiveView handles everything. Without JS,
the form POSTs here and we redirect back to the LiveView page.
"""
use BerrypodWeb, :controller
alias Berrypod.Settings
def save(conn, %{"header_nav" => header_json, "footer_nav" => footer_json}) do
with {:ok, header_items} <- Jason.decode(header_json),
{:ok, footer_items} <- Jason.decode(footer_json) do
all_items = header_items ++ footer_items
errors = validate_nav_items(all_items)
if errors == [] do
Settings.put_setting("header_nav", header_items, "json")
Settings.put_setting("footer_nav", footer_items, "json")
conn
|> put_flash(:info, "Navigation saved")
|> redirect(to: ~p"/admin/navigation")
else
conn
|> put_flash(:error, Enum.join(errors, ". "))
|> redirect(to: ~p"/admin/navigation")
end
else
{:error, _} ->
conn
|> put_flash(:error, "Invalid navigation data")
|> redirect(to: ~p"/admin/navigation")
end
end
defp validate_nav_items(items) do
items
|> Enum.flat_map(fn item ->
cond do
item["label"] == "" || item["label"] == nil ->
["All links need a label"]
item["href"] == "" || item["href"] == nil ->
["\"#{item["label"]}\" needs a destination"]
item["external"] == true || is_external_url?(item["href"]) ->
if valid_url?(item["href"]) do
[]
else
["\"#{item["label"]}\" has an invalid URL"]
end
true ->
[]
end
end)
|> Enum.uniq()
end
defp valid_url?(url) when is_binary(url) do
case URI.parse(url) do
%URI{scheme: scheme, host: host}
when scheme in ["http", "https"] and is_binary(host) and host != "" ->
true
_ ->
false
end
end
defp valid_url?(_), do: false
defp is_external_url?(nil), do: false
defp is_external_url?(""), do: false
defp is_external_url?(href) do
String.starts_with?(href, "http://") || String.starts_with?(href, "https://")
end
end