Current section
Files
Jump to
Current section
Files
lib/listmonk/models/campaign.ex
defmodule Listmonk.Models.Campaign do
@moduledoc """
Struct representing a Listmonk campaign.
"""
@type campaign_type :: :regular | :optin
@type content_type :: :richtext | :html | :markdown | :plain
@type status :: :draft | :scheduled | :running | :paused | :finished | :cancelled
@type t :: %__MODULE__{
id: integer() | nil,
uuid: String.t() | nil,
name: String.t() | nil,
subject: String.t() | nil,
from_email: String.t() | nil,
body: String.t() | nil,
altbody: String.t() | nil,
type: campaign_type() | nil,
content_type: content_type() | nil,
status: status() | nil,
lists: list(map()) | nil,
tags: list(String.t()) | nil,
template_id: integer() | nil,
messenger: String.t() | nil,
headers: map() | nil,
send_at: DateTime.t() | nil,
started_at: DateTime.t() | nil,
to_send: integer() | nil,
sent: integer() | nil,
views: integer() | nil,
clicks: integer() | nil,
created_at: DateTime.t() | nil,
updated_at: DateTime.t() | nil
}
defstruct [
:id,
:uuid,
:name,
:subject,
:from_email,
:body,
:altbody,
:type,
:content_type,
:status,
:lists,
:tags,
:template_id,
:messenger,
:headers,
:send_at,
:started_at,
:to_send,
:sent,
:views,
:clicks,
:created_at,
:updated_at
]
@doc """
Creates a new campaign struct from API response data.
"""
@spec from_api(map()) :: t()
def from_api(data) when is_map(data) do
%__MODULE__{
id: data["id"],
uuid: data["uuid"],
name: data["name"],
subject: data["subject"],
from_email: data["from_email"],
body: data["body"],
altbody: data["altbody"],
type: parse_campaign_type(data["type"]),
content_type: parse_content_type(data["content_type"]),
status: parse_status(data["status"]),
lists: data["lists"] || [],
tags: data["tags"] || [],
template_id: data["template_id"],
messenger: data["messenger"],
headers: data["headers"] || %{},
send_at: parse_datetime(data["send_at"]),
started_at: parse_datetime(data["started_at"]),
to_send: data["to_send"],
sent: data["sent"],
views: data["views"],
clicks: data["clicks"],
created_at: parse_datetime(data["created_at"]),
updated_at: parse_datetime(data["updated_at"])
}
end
@doc """
Converts a campaign struct to API request format.
"""
@spec to_api(t(), keyword()) :: map()
def to_api(%__MODULE__{} = campaign, opts \\ []) do
list_ids = Keyword.get(opts, :list_ids, extract_list_ids(campaign.lists))
%{
"name" => campaign.name,
"subject" => campaign.subject,
"from_email" => campaign.from_email,
"body" => campaign.body,
"altbody" => campaign.altbody,
"type" => campaign_type_to_string(campaign.type),
"content_type" => content_type_to_string(campaign.content_type),
"lists" => list_ids,
"tags" => campaign.tags || [],
"template_id" => campaign.template_id,
"messenger" => campaign.messenger,
"headers" => campaign.headers || %{},
"send_at" => format_datetime(campaign.send_at)
}
|> Enum.reject(fn {_k, v} -> is_nil(v) end)
|> Map.new()
end
defp parse_campaign_type("regular"), do: :regular
defp parse_campaign_type("optin"), do: :optin
defp parse_campaign_type(_), do: :regular
defp campaign_type_to_string(:regular), do: "regular"
defp campaign_type_to_string(:optin), do: "optin"
defp campaign_type_to_string(nil), do: "regular"
defp parse_content_type("richtext"), do: :richtext
defp parse_content_type("html"), do: :html
defp parse_content_type("markdown"), do: :markdown
defp parse_content_type("plain"), do: :plain
defp parse_content_type(_), do: :richtext
defp content_type_to_string(:richtext), do: "richtext"
defp content_type_to_string(:html), do: "html"
defp content_type_to_string(:markdown), do: "markdown"
defp content_type_to_string(:plain), do: "plain"
defp content_type_to_string(nil), do: "richtext"
defp parse_status("draft"), do: :draft
defp parse_status("scheduled"), do: :scheduled
defp parse_status("running"), do: :running
defp parse_status("paused"), do: :paused
defp parse_status("finished"), do: :finished
defp parse_status("cancelled"), do: :cancelled
defp parse_status(_), do: :draft
defp parse_datetime(nil), do: nil
defp parse_datetime(datetime_string) when is_binary(datetime_string) do
case DateTime.from_iso8601(datetime_string) do
{:ok, datetime, _offset} -> datetime
{:error, _} -> nil
end
end
defp parse_datetime(_), do: nil
defp format_datetime(nil), do: nil
defp format_datetime(%DateTime{} = datetime) do
DateTime.to_iso8601(datetime)
end
defp extract_list_ids(nil), do: []
defp extract_list_ids([]), do: []
defp extract_list_ids(lists) when is_list(lists) do
Enum.map(lists, fn
%{"id" => id} -> id
id when is_integer(id) -> id
_ -> nil
end)
|> Enum.reject(&is_nil/1)
end
end