defmodule GlificWeb.ExotelController do
@moduledoc """
The controller to process events received from exotel
"""
use GlificWeb, :controller
require Logger
alias Glific.{Contacts, Flows, Partners, Repo}
@doc """
First implementation of processing optin contact callback from exotel
for digital green. Will need to make it more generic for broader use case
across other NGOs
We use the callto and directon parameters to ensure a valid call from exotel
"""
@spec optin(Plug.Conn.t(), map) :: Plug.Conn.t()
def optin(
%Plug.Conn{assigns: %{organization_id: organization_id}} = conn,
%{
"CallFrom" => exotel_from,
"CallTo" => _exotel_call_to,
"To" => exotel_to
} = params
) do
Logger.info("exotel #{inspect(params)}")
organization = Partners.organization(organization_id)
Repo.put_process_state(organization.id)
credentials = organization.services["exotel"]
if is_nil(credentials) do
log_error("exotel credentials missing")
else
keys = credentials.keys
{phone, ngo_exotel_phone} =
if keys["direction"] == "incoming",
do: {exotel_from, exotel_to},
else: {exotel_to, exotel_from}
if ngo_exotel_phone == credentials.secrets["phone"] do
# first create and optin the contact
attrs = %{
phone: clean_phone(phone),
method: "Exotel",
organization_id: organization_id
}
result = Contacts.optin_contact(attrs)
# then start the intro flow
case result do
{:ok, contact} ->
{:ok, flow_id} = Glific.parse_maybe_integer(keys["flow_id"])
Flows.start_contact_flow(flow_id, contact)
{:error, error} ->
log_error(error)
end
else
log_error("exotel credentials mismatch")
end
end
# always return 200 and an empty response
json(conn, "")
end
def optin(conn, params) do
Logger.info("exotel unhandled #{inspect(params)}")
json(conn, "")
end
@country_code "91"
@spec clean_phone(String.t()) :: String.t()
defp clean_phone(phone) when is_binary(phone),
do: @country_code <> String.slice(phone, -10, 10)
defp clean_phone(phone), do: phone
@spec log_error(String.t()) :: any
defp log_error(message) do
# log this error and send to appsignal also
Logger.error(message)
{_, stacktrace} = Process.info(self(), :current_stacktrace)
Appsignal.send_error(:error, message, stacktrace)
end
end