lib/glific/providers/gupshup/api_client.ex

defmodule Glific.Providers.Gupshup.ApiClient do
  @moduledoc """
  Https API client to interact with Gupshup
  """
  alias Glific.Partners
  alias Plug.Conn.Query
  import GlificWeb.Gettext

  @gupshup_url "https://api.gupshup.io/sm/api/v1"

  use Tesla
  # you can add , log_level: :debug to the below if you want debugging info
  plug(Tesla.Middleware.Logger)

  plug(Tesla.Middleware.FormUrlencoded,
    encode: &Query.encode/1
  )

  @doc """
  Making Tesla get call and adding api key in header
  """
  @spec gupshup_get(String.t(), String.t()) :: Tesla.Env.result()
  def gupshup_get(url, api_key), do: get(url, headers: [{"apikey", api_key}])

  @doc """
  Making Tesla post call and adding api key in header
  """
  @spec gupshup_post(String.t(), any(), String.t()) :: Tesla.Env.result()
  def gupshup_post(url, payload, api_key), do: post(url, payload, headers: [{"apikey", api_key}])

  @spec get_credentials(non_neg_integer()) :: {:error, String.t()} | {:ok, map()}
  defp get_credentials(org_id) do
    organization = Partners.organization(org_id)

    if is_nil(organization.services["bsp"]) do
      {:error, dgettext("errors", "No active BSP available")}
    else
      bsp_credentials = organization.services["bsp"]

      with false <- is_nil(bsp_credentials.secrets["api_key"]),
           false <- is_nil(bsp_credentials.secrets["api_key"]) do
        api_key = bsp_credentials.secrets["api_key"]
        app_name = bsp_credentials.secrets["app_name"]
        {:ok, %{api_key: api_key, app_name: app_name}}
      else
        _ ->
          {:error,
           "Please check your credential settings and ensure you have added the API Key and App Name also"}
      end
    end
  end

  @doc """
  Fetching HSM templates for an organization
  """
  @spec get_templates(non_neg_integer()) :: Tesla.Env.result() | {:error, String.t()}
  def get_templates(org_id) do
    with {:ok, credentials} <- get_credentials(org_id) do
      template_url = @gupshup_url <> "/template/list/" <> credentials.app_name
      gupshup_get(template_url, credentials.api_key)
    end
  end

  @doc """
  Submitting HSM template for approval
  """
  @spec submit_template_for_approval(non_neg_integer(), map()) ::
          Tesla.Env.result() | {:error, any()}
  def submit_template_for_approval(org_id, payload) do
    with {:ok, credentials} <- get_credentials(org_id) do
      template_url = @gupshup_url <> "/template/add/" <> credentials.app_name
      opts = [headers: [{"apikey", credentials.api_key}], opts: [adapter: [recv_timeout: 10_000]]]
      # Adding a delay of 30 seconds when applying for template
      post(template_url, payload, opts)
    end
  end

  @doc """
  Sending HSM template to contact
  """
  @spec send_template(non_neg_integer(), map()) :: Tesla.Env.result() | {:error, String.t()}
  def send_template(org_id, payload) do
    with {:ok, credentials} <- get_credentials(org_id) do
      template_url = @gupshup_url <> "/template/msg"
      gupshup_post(template_url, payload, credentials.api_key)
    end
  end

  @doc """
  Sending message to contact
  """
  @spec send_message(non_neg_integer(), map()) :: Tesla.Env.result() | any()
  def send_message(org_id, payload) do
    with {:ok, credentials} <- get_credentials(org_id) do
      url = @gupshup_url <> "/msg"
      gupshup_post(url, payload, credentials.api_key)
    end
  end

  @doc """
  Update a contact phone as opted in
  """
  @spec optin_contact(non_neg_integer(), map()) :: Tesla.Env.result() | {:error, String.t()}
  def optin_contact(org_id, payload) do
    get_credentials(org_id)

    with {:ok, credentials} <- get_credentials(org_id) do
      url = @gupshup_url <> "/app/opt/in/" <> credentials.app_name
      gupshup_post(url, payload, credentials.api_key)
    end
  end

  @doc """
  Fetch opted in contacts data from providers server
  """
  @spec fetch_opted_in_contacts(non_neg_integer()) :: Tesla.Env.result() | {:error, String.t()}
  def fetch_opted_in_contacts(org_id) do
    with {:ok, credentials} <- get_credentials(org_id),
         do: users_get(credentials.api_key, credentials.app_name)
  end

  @doc """
  Build the Gupshup user list url
  """
  @spec users_get(String.t(), String.t()) :: Tesla.Env.result() | {:error, String.t()}
  def users_get(api_key, app_name) do
    url = @gupshup_url <> "/users/" <> app_name
    gupshup_get(url, api_key)
  end
end