Packages

Elixir client SDK for the Surge API

Current section

Files

Jump to
surge_api lib surge events event.ex
Raw

lib/surge/events/event.ex

defmodule Surge.Events.Event do
@moduledoc """
A wrapper for webhook events that contains the event data and metadata.
The Event struct includes the account ID, event type, and the parsed event data
which varies based on the type of event.
"""
alias Surge.Events.{
CallEnded,
CampaignApproved,
ContactOptedIn,
ContactOptedOut,
ConversationCreated,
LinkFollowed,
MessageDelivered,
MessageFailed,
MessageReceived,
MessageSent
}
@type event_type ::
:call_ended
| :campaign_approved
| :contact_opted_in
| :contact_opted_out
| :conversation_created
| :link_followed
| :message_delivered
| :message_failed
| :message_received
| :message_sent
@type event_data ::
CallEnded.t()
| CampaignApproved.t()
| ContactOptedIn.t()
| ContactOptedOut.t()
| ConversationCreated.t()
| LinkFollowed.t()
| MessageDelivered.t()
| MessageFailed.t()
| MessageReceived.t()
| MessageSent.t()
@type t :: %__MODULE__{
account_id: String.t() | nil,
type: event_type() | nil,
data: event_data() | nil
}
defstruct [
:account_id,
:type,
:data
]
@doc """
Converts JSON webhook payload to Event struct.
## Examples
iex> data = %{
...> "account_id" => "acct_01japd271aeatb7txrzr2xj8sg",
...> "type" => "message.received",
...> "data" => %{
...> "id" => "msg_01jav96823f9x9054d6gyzpp16",
...> "body" => "I don't have friends, I got family.",
...> "attachments" => [
...> %{
...> "id" => "att_01jav8z6x1j4m1b3w8v2jz7j3r",
...> "type" => "image",
...> "url" => "https://toretto.family/image.jpg"
...> }
...> ],
...> "received_at" => "2024-10-22T23:32:49Z",
...> "conversation" => %{
...> "id" => "cnv_01jav8xy7fe4nsay3c9deqxge9",
...> "phone_number" => %{
...> "id" => "pn_01jsjwe4d9fx3tpymgtg958d9w",
...> "number" => "+18015556789",
...> "type" => "local"
...> },
...> "contact" => %{
...> "id" => "ctc_01ja88cboqffhswjx8zbak3ykk",
...> "first_name" => "Dominic",
...> "last_name" => "Toretto",
...> "phone_number" => "+18015551234"
...> }
...> }
...> }
...> }
iex> Surge.Events.Event.from_json(data)
%Surge.Events.Event{
account_id: "acct_01japd271aeatb7txrzr2xj8sg",
type: :message_received,
data: %Surge.Events.MessageReceived{
id: "msg_01jav96823f9x9054d6gyzpp16",
body: "I don't have friends, I got family.",
attachments: [
%Surge.Messages.Attachment{
id: "att_01jav8z6x1j4m1b3w8v2jz7j3r",
type: "image",
url: "https://toretto.family/image.jpg"
}
],
received_at: ~U[2024-10-22 23:32:49Z],
conversation: %Surge.Messages.Conversation{
id: "cnv_01jav8xy7fe4nsay3c9deqxge9",
phone_number: %Surge.PhoneNumbers.PhoneNumber{
id: "pn_01jsjwe4d9fx3tpymgtg958d9w",
number: "+18015556789",
type: :local
},
contact: %Surge.Contacts.Contact{
id: "ctc_01ja88cboqffhswjx8zbak3ykk",
first_name: "Dominic",
last_name: "Toretto",
phone_number: "+18015551234"
}
}
}
}
"""
@spec from_json(map()) :: t()
def from_json(data) when is_map(data) do
type = parse_type(data["type"])
%__MODULE__{
account_id: data["account_id"],
type: type,
data: parse_data(type, data["data"])
}
end
# Private
@spec parse_type(String.t() | nil) :: event_type() | nil
defp parse_type(nil), do: nil
defp parse_type("call.ended"), do: :call_ended
defp parse_type("campaign.approved"), do: :campaign_approved
defp parse_type("contact.opted_in"), do: :contact_opted_in
defp parse_type("contact.opted_out"), do: :contact_opted_out
defp parse_type("conversation.created"), do: :conversation_created
defp parse_type("link.followed"), do: :link_followed
defp parse_type("message.delivered"), do: :message_delivered
defp parse_type("message.failed"), do: :message_failed
defp parse_type("message.received"), do: :message_received
defp parse_type("message.sent"), do: :message_sent
defp parse_type(_), do: nil
@spec parse_data(event_type() | nil, map() | nil) :: event_data() | nil
defp parse_data(nil, _), do: nil
defp parse_data(_, nil), do: nil
defp parse_data(:call_ended, data) when is_map(data) do
CallEnded.from_json(data)
end
defp parse_data(:campaign_approved, data) when is_map(data) do
CampaignApproved.from_json(data)
end
defp parse_data(:contact_opted_in, data) when is_map(data) do
ContactOptedIn.from_json(data)
end
defp parse_data(:contact_opted_out, data) when is_map(data) do
ContactOptedOut.from_json(data)
end
defp parse_data(:conversation_created, data) when is_map(data) do
ConversationCreated.from_json(data)
end
defp parse_data(:link_followed, data) when is_map(data) do
LinkFollowed.from_json(data)
end
defp parse_data(:message_delivered, data) when is_map(data) do
MessageDelivered.from_json(data)
end
defp parse_data(:message_failed, data) when is_map(data) do
MessageFailed.from_json(data)
end
defp parse_data(:message_received, data) when is_map(data) do
MessageReceived.from_json(data)
end
defp parse_data(:message_sent, data) when is_map(data) do
MessageSent.from_json(data)
end
defp parse_data(_, _), do: nil
end