lib/chimeway/rendering/channels/email.ex

defmodule Chimeway.Rendering.Channels.Email do
  @moduledoc """
  Validates the durable email render contract.
  """

  use Chimeway.Rendering.Channel

  import Ecto.Changeset

  @types %{
    subject: :string,
    html_body: :string,
    text_body: :string
  }

  @required_fields [:subject, :html_body, :text_body]

  @impl Chimeway.Rendering.Channel
  @spec validate(map()) :: {:ok, map()} | {:error, Ecto.Changeset.t()}
  def validate(attrs) when is_map(attrs) do
    {%{}, @types}
    |> cast(attrs, Map.keys(@types))
    |> validate_required(@required_fields)
    |> apply_action(:insert)
    |> case do
      {:ok, validated} -> {:ok, stringify_keys(validated)}
      {:error, changeset} -> {:error, changeset}
    end
  end

  def validate(other) do
    types = %{payload: :map}

    {%{}, types}
    |> cast(%{payload: other}, [:payload])
    |> add_error(:payload, "must be a map")
    |> apply_action(:insert)
  end

  defp stringify_keys(map) do
    Enum.into(map, %{}, fn {key, value} ->
      {Atom.to_string(key), value}
    end)
  end
end