defmodule Nostrum.Struct.Embed do @moduledoc ~S""" Functions that work on Discord embeds. ## Building Embeds `Nostrum.Struct.Embed`s can be built using this module's builder functions or standard `Map` syntax: ```Elixir iex> import Nostrum.Struct.Embed ...> embed = ...> %Nostrum.Struct.Embed{} ...> |> put_title("craig") ...> |> put_description("nostrum") ...> |> put_url("https://google.com/") ...> |> put_timestamp("2016-05-05T21:04:13.203Z") ...> |> put_color(431_948) ...> |> put_field("Field 1", "Test") ...> |> put_field("Field 2", "More test", true) ...> embed %Nostrum.Struct.Embed{ title: "craig", description: "nostrum", url: "https://google.com/", timestamp: "2016-05-05T21:04:13.203Z", color: 431_948, fields: [ %Nostrum.Struct.Embed.Field{name: "Field 1", value: "Test"}, %Nostrum.Struct.Embed.Field{name: "Field 2", value: "More test", inline: true} ] } ``` """ alias Nostrum.Struct.Embed.{Author, Field, Footer, Image, Provider, Thumbnail, Video} alias Nostrum.Util alias Poison.Encoder defstruct [ :title, :type, :description, :url, :timestamp, :color, :footer, :image, :thumbnail, :video, :provider, :author, :fields ] defimpl Encoder do def encode(embed, options) do embed |> Map.from_struct() |> Enum.filter(fn {_, v} -> v != nil end) |> Map.new() |> Encoder.encode(options) end end @typedoc "Title of the embed" @type title :: String.t() | nil @typedoc "Type of the embed" @type type :: String.t() | nil @typedoc "Description of the embed" @type description :: String.t() | nil @typedoc "Url of the embed" @type url :: String.t() | nil @typedoc "Timestamp of embed content" @type timestamp :: String.t() | nil @typedoc "Color code of the embed" @type color :: Integer.t() | nil @typedoc "Footer information" @type footer :: Footer.t() | nil @typedoc "Image information" @type image :: Image.t() | nil @typedoc "Thumbnail information" @type thumbnail :: Thumbnail.t() | nil @typedoc "Video information" @type video :: Video.t() | nil @typedoc "Provider information" @type provider :: Provider.t() | nil @typedoc "Author information" @type author :: Author.t() | nil @typedoc "Fields information" @type fields :: [Field.t()] | nil @type t :: %__MODULE__{ title: title, type: type, description: description, url: url, timestamp: timestamp, color: color, footer: footer, image: image, thumbnail: thumbnail, video: video, provider: provider, author: author, fields: fields } @doc ~S""" Puts the given `value` under `:title` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_title(embed, "nostrum") %Nostrum.Struct.Embed{title: "nostrum"} ``` """ @spec put_title(t, title) :: t def put_title(%__MODULE__{} = embed, value) do %__MODULE__{embed | title: value} end @doc false @spec put_type(t, type) :: t def put_type(%__MODULE__{} = embed, value) do %__MODULE__{embed | type: value} end @doc ~S""" Puts the given `value` under `:description` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_description(embed, "An elixir library for the discord API.") %Nostrum.Struct.Embed{description: "An elixir library for the discord API."} ``` """ @spec put_description(t, description) :: t def put_description(%__MODULE__{} = embed, value) do %__MODULE__{embed | description: value} end @doc ~S""" Puts the given `value` under `:url` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_url(embed, "https://github.com/Kraigie/nostrum") %Nostrum.Struct.Embed{url: "https://github.com/Kraigie/nostrum"} ``` """ @spec put_url(t, url) :: t def put_url(%__MODULE__{} = embed, value) do %__MODULE__{embed | url: value} end @doc ~S""" Puts the given `value` under `:timestamp` in `embed`. ## Examples ```elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_timestamp(embed, "2018-04-21T17:33:51.893000Z") %Nostrum.Struct.Embed{timestamp: "2018-04-21T17:33:51.893000Z"} ``` """ @spec put_timestamp(t, timestamp) :: t def put_timestamp(%__MODULE__{} = embed, value) do %__MODULE__{embed | timestamp: value} end @doc ~S""" Puts the given `value` under `:color` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_color(embed, 431948) %Nostrum.Struct.Embed{color: 431948} ``` """ @spec put_color(t, color) :: t def put_color(%__MODULE__{} = embed, value) do %__MODULE__{embed | color: value} end @doc ~S""" Puts a `Nostrum.Struct.Embed.Footer` under `:footer` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_footer(embed, "Discord API", nil) %Nostrum.Struct.Embed{ footer: %Nostrum.Struct.Embed.Footer{ text: "Discord API", icon_url: nil } } iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_footer(embed, "nostrum footer", "https://discordapp.com/assets/53ef346458017da2062aca5c7955946b.svg") %Nostrum.Struct.Embed{ footer: %Nostrum.Struct.Embed.Footer{ text: "nostrum footer", icon_url: "https://discordapp.com/assets/53ef346458017da2062aca5c7955946b.svg" } } ``` """ @spec put_footer(t, Footer.text(), Footer.icon_url()) :: t def put_footer(%__MODULE__{} = embed, text, icon_url \\ nil) do footer = %Footer{ text: text, icon_url: icon_url } %__MODULE__{embed | footer: footer} end @doc ~S""" Puts a `Nostrum.Struct.Embed.Image` under `:image` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_image(embed, "https://discordapp.com/assets/af92e60c16b7019f34a467383b31490a.svg") %Nostrum.Struct.Embed{ image: %Nostrum.Struct.Embed.Image{ url: "https://discordapp.com/assets/af92e60c16b7019f34a467383b31490a.svg" } } ``` """ @spec put_image(t, Image.url()) :: t def put_image(%__MODULE__{} = embed, url) do image = %Image{ url: url } %__MODULE__{embed | image: image} end @doc ~S""" Puts a `Nostrum.Struct.Embed.Thumbnail` under `:thumbnail` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_thumbnail(embed, "https://discordapp.com/assets/af92e60c16b7019f34a467383b31490a.svg") %Nostrum.Struct.Embed{ thumbnail: %Nostrum.Struct.Embed.Thumbnail{ url: "https://discordapp.com/assets/af92e60c16b7019f34a467383b31490a.svg" } } ``` """ @spec put_thumbnail(t, Thumbnail.url()) :: t def put_thumbnail(%__MODULE__{} = embed, url) do thumbnail = %Thumbnail{ url: url } %__MODULE__{embed | thumbnail: thumbnail} end @doc false @spec put_video(t, Video.url()) :: t def put_video(%__MODULE__{} = embed, url) do video = %Video{ url: url } %__MODULE__{embed | video: video} end @doc false @spec put_provider(t, Provider.name(), Provider.url()) :: t def put_provider(%__MODULE__{} = embed, name, url) do provider = %Provider{ name: name, url: url } %__MODULE__{embed | provider: provider} end @doc ~S""" Puts a `Nostrum.Struct.Embed.Author` under `:author` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_author(embed, "skippi", "https://github.com/skippi", nil) %Nostrum.Struct.Embed{ author: %Nostrum.Struct.Embed.Author{ name: "skippi", url: "https://github.com/skippi", icon_url: nil } } ``` """ @spec put_author(t, Author.name(), Author.url(), Author.icon_url()) :: t def put_author(%__MODULE__{} = embed, name, url, icon_url) do author = %Author{ name: name, url: url, icon_url: icon_url } %__MODULE__{embed | author: author} end @doc ~S""" Adds a `Nostrum.Struct.Embed.Field` under `:fields` in `embed`. ## Examples ```Elixir iex> embed = %Nostrum.Struct.Embed{} ...> Nostrum.Struct.Embed.put_field(embed, "First User", "b1nzy") %Nostrum.Struct.Embed{ fields: [ %Nostrum.Struct.Embed.Field{name: "First User", value: "b1nzy"} ] } iex> embed = %Nostrum.Struct.Embed{ ...> fields: [ ...> %Nostrum.Struct.Embed.Field{name: "First User", value: "b1nzy"} ...> ] ...> } ...> Nostrum.Struct.Embed.put_field(embed, "Second User", "Danny") %Nostrum.Struct.Embed{ fields: [ %Nostrum.Struct.Embed.Field{name: "First User", value: "b1nzy"}, %Nostrum.Struct.Embed.Field{name: "Second User", value: "Danny"} ] } ``` """ @spec put_field(t, Field.name(), Field.value(), Field.inline()) :: t def put_field(embed, name, value, inline \\ nil) def put_field(%__MODULE__{fields: fields} = embed, name, value, inline) when is_list(fields) do field = %Field{ name: name, value: value, inline: inline } %__MODULE__{embed | fields: fields ++ [field]} end def put_field(embed, name, value, inline) do put_field(%__MODULE__{embed | fields: []}, name, value, inline) end # TODO: Jump down the rabbit hole @doc false def p_encode do %__MODULE__{} end @doc false def to_struct(map) do new = map |> Map.new(fn {k, v} -> {Util.maybe_to_atom(k), v} end) |> Map.update(:footer, nil, &Util.cast(&1, {:struct, Footer})) |> Map.update(:image, nil, &Util.cast(&1, {:struct, Image})) |> Map.update(:thumbnail, nil, &Util.cast(&1, {:struct, Thumbnail})) |> Map.update(:video, nil, &Util.cast(&1, {:struct, Video})) |> Map.update(:provider, nil, &Util.cast(&1, {:struct, Provider})) |> Map.update(:author, nil, &Util.cast(&1, {:struct, Author})) |> Map.update(:fields, nil, &Util.cast(&1, {:list, {:struct, Field}})) struct(__MODULE__, new) end end