defmodule SigmaKit.Util.Changeset do import Ecto.Changeset def ensure_upcase(changeset, field) when is_atom(field), do: update_change(changeset, field, &String.upcase/1) def ensure_upcase(changeset, fields) when is_list(fields) do Enum.reduce(fields, changeset, fn field, cs -> update_change(cs, field, &String.upcase/1) end) end def ensure_downcase(changeset, field) when is_atom(field), do: update_change(changeset, field, &String.downcase/1) def ensure_downcase(changeset, fields) when is_list(fields) do Enum.reduce(fields, changeset, fn field, cs -> update_change(cs, field, &String.downcase/1) end) end def ensure_trimmed(changeset, field) when is_atom(field), do: update_change(changeset, field, &trim/1) def ensure_trimmed(changeset, fields) when is_list(fields) do Enum.reduce(fields, changeset, fn field, cs -> update_change(cs, field, &trim/1) end) end def valdiate_phone_number(changeset, field) do update_change(changeset, field, fn value -> String.replace(value, ~r/[^\d]/, "") end) |> validate_length(field, is: 10) end @doc """ Validate URLs. Adds https if a scheme doesn't exist. eg. "google.com" -> "https://google.com" Examples: defp changeset(user) do user |> cast([:website]) |> validate_and_fix_url(:website) end """ def validate_url(changeset, field) do url_change = get_change(changeset, field) cond do is_nil(url_change) -> changeset valid_url?(url_change) -> validate_url_works(changeset, field) without_scheme?(url_change) && valid_url?("https://" <> url_change) -> changeset |> force_change(field, "https://" <> url_change) |> validate_url_works(field) true -> add_error(changeset, field, "should be a HTTP or HTTPS link") end end def validate_url_works(changeset, field) do url = get_change(changeset, field) uri = URI.parse(url) case :inet.gethostbyname(to_charlist(uri.host)) do {:error, :nxdomain} -> add_error( changeset, field, "The link to #{uri.host} doesn't work. Did you spell it right?" ) _ -> changeset end end def validate_website_link(changeset) do link_website = get_field(changeset, :link_website, "") || "" if link_website != "" do # parse website and look up the hostname link_website_parse = URI.parse("https://" <> link_website) if link_website_parse.host != nil do else changeset end else changeset end end defp valid_url?(url) when is_binary(url) do uri = URI.parse(url) uri.scheme in ~w(http https) && uri.host end defp without_scheme?(url) when is_binary(url) do is_nil(URI.parse(url).scheme) end @doc "Trim whitespace on either end of a string. Account for nil" def trim(str) when is_nil(str), do: str def trim(str) when is_binary(str), do: String.trim(str) end