diff --git a/.env.sample b/.env.sample index 7c6420c..8cf35af 100644 --- a/.env.sample +++ b/.env.sample @@ -1,6 +1,7 @@ export TWILIO_ACCOUNT_SID="" export TWILIO_AUTH_TOKEN="" export TWILIO_WORKSPACE_SID="" +export TWILIO_PROXY_SERVICE_SID="" export TWILIO_TEST_ACCOUNT_SID="" export TWILIO_TEST_AUTH_TOKEN="" diff --git a/README.md b/README.md index 0018d58..edd912e 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,10 @@ You will need to set the following configuration variables in your ```elixir use Mix.Config -config :ex_twilio, account_sid: {:system, "TWILIO_ACCOUNT_SID"}, - auth_token: {:system, "TWILIO_AUTH_TOKEN"}, - workspace_sid: {:system, "TWILIO_WORKSPACE_SID"} # optional +config :ex_twilio, account_sid: {:system, "TWILIO_ACCOUNT_SID"}, + auth_token: {:system, "TWILIO_AUTH_TOKEN"}, + workspace_sid: {:system, "TWILIO_WORKSPACE_SID"}, # optional + proxy_service_sid: {:system, "TWILIO_PROXY_SERVICE_SID"} # optional if using proxy API ``` For security, I recommend that you use environment variables rather than hard @@ -53,6 +54,7 @@ following content: export TWILIO_ACCOUNT_SID= export TWILIO_AUTH_TOKEN= export TWILIO_WORKSPACE_SID= #optional +export TWILIO_PROXY_SERVICE_SID= #optional ``` Then, just be sure to run `source .env` in your shell before compiling your @@ -150,6 +152,17 @@ Twilio's TaskRouter API: - [Workspaces](https://www.twilio.com/docs/api/taskrouter/workspaces) - [Statistics](https://www.twilio.com/docs/api/taskrouter/workspace-statistics) +Twilio's Proxy API: + +- [Overview](https://www.twilio.com/docs/proxy/api) +- [Service](https://www.twilio.com/docs/proxy/api/service) +- [Phone Number](https://www.twilio.com/docs/proxy/api/phone-number) +- [Short Code](https://www.twilio.com/docs/proxy/api/short-code) +- [Session Resource](https://www.twilio.com/docs/proxy/api/session) +- [Participant](https://www.twilio.com/docs/proxy/api/participant) +- [Interaction](https://www.twilio.com/docs/proxy/api/interaction) +- [Sending Messages](https://www.twilio.com/docs/proxy/api/sending-messages) + Twilio's ProgrammableChat API: - [Overview](https://www.twilio.com/docs/api/chat/rest) diff --git a/config/dev.exs b/config/dev.exs index 6e1f8e7..1b832a5 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -3,4 +3,5 @@ use Mix.Config config :ex_twilio, account_sid: {:system, "TWILIO_ACCOUNT_SID"}, auth_token: {:system, "TWILIO_AUTH_TOKEN"}, - workspace_sid: {:system, "TWILIO_WORKSPACE_SID"} + workspace_sid: {:system, "TWILIO_WORKSPACE_SID"}, + proxy_service_sid: {:system, "TWILIO_PROXY_SERVICE_SID"} diff --git a/config/test.exs b/config/test.exs index 3eda472..f808cf0 100644 --- a/config/test.exs +++ b/config/test.exs @@ -3,6 +3,7 @@ use Mix.Config config :ex_twilio, account_sid: {:system, "TWILIO_TEST_ACCOUNT_SID"}, auth_token: {:system, "TWILIO_TEST_AUTH_TOKEN"}, - workspace_sid: {:system, "TWILIO_TEST_WORKSPACE_SID"} + workspace_sid: {:system, "TWILIO_WORKSPACE_SID"}, + proxy_service_sid: {:system, "TWILIO_PROXY_SERVICE_SID"} config :logger, level: :info diff --git a/lib/ex_twilio/config.ex b/lib/ex_twilio/config.ex index 3e6b638..8740a05 100644 --- a/lib/ex_twilio/config.ex +++ b/lib/ex_twilio/config.ex @@ -49,6 +49,8 @@ defmodule ExTwilio.Config do def workspace_sid, do: Application.get_env(:ex_twilio, :workspace_sid) || "12345" + def proxy_service_sid, do: Application.get_env(:ex_twilio, :proxy_service_sid) || "12345" + @doc """ Return the combined base URL of the Twilio API, using the configuration settings given. @@ -69,6 +71,8 @@ defmodule ExTwilio.Config do def video_url, do: "https://video.twilio.com/v1" + def proxy_url, do: "https://proxy.twilio.com/v1" + @doc """ A light wrapper around `Application.get_env/2`, providing automatic support for `{:system, "VAR"}` tuples. diff --git a/lib/ex_twilio/resources/proxy/interaction.ex b/lib/ex_twilio/resources/proxy/interaction.ex new file mode 100644 index 0000000..5a2910f --- /dev/null +++ b/lib/ex_twilio/resources/proxy/interaction.ex @@ -0,0 +1,35 @@ +defmodule ExTwilio.Proxy.Interaction do + @moduledoc """ + Represents an Interaction of a Session. + + - [Twilio docs](https://www.twilio.com/docs/proxy/api/interaction) + """ + + defstruct sid: nil, + account_sid: nil, + session_sid: nil, + service_sid: nil, + data: nil, + type: nil, + inbound_participant_sid: nil, + inbound_resource_sid: nil, + inbound_resource_status: nil, + inbound_resource_type: nil, + inbound_resource_url: nil, + outbound_participant_sid: nil, + outbound_resource_sid: nil, + outbound_resource_status: nil, + outbound_resource_type: nil, + outbound_resource_url: nil, + date_created: nil, + date_updated: nil, + url: nil + + use ExTwilio.Resource, import: [:stream, :all, :find, :delete] + + def parents, + do: [ + %ExTwilio.Parent{module: ExTwilio.Proxy.Service, key: :service}, + %ExTwilio.Parent{module: ExTwilio.Proxy.SessionResource, key: :session} + ] +end diff --git a/lib/ex_twilio/resources/proxy/message.ex b/lib/ex_twilio/resources/proxy/message.ex new file mode 100644 index 0000000..9322aee --- /dev/null +++ b/lib/ex_twilio/resources/proxy/message.ex @@ -0,0 +1,39 @@ +defmodule ExTwilio.Proxy.Message do + @moduledoc """ + Represents a Message Interaction of a Session. + + - [Twilio docs](https://www.twilio.com/docs/proxy/api/sending-messages) + """ + + defstruct sid: nil, + account_sid: nil, + session_sid: nil, + service_sid: nil, + participant_sid: nil, + data: nil, + type: nil, + inbound_participant_sid: nil, + inbound_resource_sid: nil, + inbound_resource_status: nil, + inbound_resource_type: nil, + inbound_resource_url: nil, + outbound_participant_sid: nil, + outbound_resource_sid: nil, + outbound_resource_status: nil, + outbound_resource_type: nil, + outbound_resource_url: nil, + date_created: nil, + date_updated: nil, + url: nil + + use ExTwilio.Resource, import: [:create] + + def parents, + do: [ + %ExTwilio.Parent{module: ExTwilio.Proxy.Service, key: :service}, + %ExTwilio.Parent{module: ExTwilio.Proxy.SessionResource, key: :session}, + %ExTwilio.Parent{module: ExTwilio.Proxy.Participant, key: :participant} + ] + + def resource_name, do: "MessageInteractions" +end diff --git a/lib/ex_twilio/resources/proxy/participant.ex b/lib/ex_twilio/resources/proxy/participant.ex new file mode 100644 index 0000000..1caca54 --- /dev/null +++ b/lib/ex_twilio/resources/proxy/participant.ex @@ -0,0 +1,29 @@ +defmodule ExTwilio.Proxy.Participant do + @moduledoc """ + Represents a Participant attached to a Session. + + - [Twilio docs](https://www.twilio.com/docs/proxy/api/participant) + """ + + defstruct sid: nil, + account_sid: nil, + session_sid: nil, + service_sid: nil, + friendly_name: nil, + identifier: nil, + proxy_identifier: nil, + proxy_identifier_sid: nil, + date_deleted: nil, + date_created: nil, + date_updated: nil, + url: nil, + links: nil + + use ExTwilio.Resource, import: [:stream, :all, :find, :create, :delete] + + def parents, + do: [ + %ExTwilio.Parent{module: ExTwilio.Proxy.Service, key: :service}, + %ExTwilio.Parent{module: ExTwilio.Proxy.SessionResource, key: :session} + ] +end diff --git a/lib/ex_twilio/resources/proxy/phone_number.ex b/lib/ex_twilio/resources/proxy/phone_number.ex new file mode 100644 index 0000000..fbc2905 --- /dev/null +++ b/lib/ex_twilio/resources/proxy/phone_number.ex @@ -0,0 +1,34 @@ +defmodule ExTwilio.Proxy.PhoneNumber do + @moduledoc """ + Represents a Phone Number attached to a Service. + + - [Twilio docs](https://www.twilio.com/docs/proxy/api/phone-number) + """ + + defstruct sid: nil, + account_sid: nil, + service_sid: nil, + date_created: nil, + date_updated: nil, + phone_number: nil, + friendly_name: nil, + iso_country: nil, + capabilities: nil, + url: nil, + is_reserved: nil, + in_use: nil + + use ExTwilio.Resource, import: [:stream, :all, :find, :create, :update, :delete] + + alias ExTwilio.Parser + alias ExTwilio.Api + + @spec create_reserved(Api.data(), list) :: Parser.success() | Parser.error() + def create_reserved(data, options) when is_map(data), + do: data |> Map.to_list() |> create_reserved(options) + + def create_reserved(data, options), + do: data |> Keyword.merge(is_reserved: true) |> create(options) + + def parents, do: [%ExTwilio.Parent{module: ExTwilio.Proxy.Service, key: :service}] +end diff --git a/lib/ex_twilio/resources/proxy/service.ex b/lib/ex_twilio/resources/proxy/service.ex new file mode 100644 index 0000000..e5da221 --- /dev/null +++ b/lib/ex_twilio/resources/proxy/service.ex @@ -0,0 +1,25 @@ +defmodule ExTwilio.Proxy.Service do + @moduledoc """ + A Service is a container for Proxy Sessions, Phone Numbers and Short Codes. + Each of these items exists within a single Service and will not be shared across Services. + + - [Twilio docs](https://www.twilio.com/docs/proxy/api/service) + """ + + defstruct sid: nil, + account_sid: nil, + unique_name: nil, + chat_instance_sid: nil, + callback_url: nil, + default_ttl: nil, + number_selection_behavior: nil, + geo_match_level: nil, + intercept_callback_url: nil, + out_of_session_callback_url: nil, + date_created: nil, + date_updated: nil, + url: nil, + links: nil + + use ExTwilio.Resource, import: [:stream, :all, :find, :create, :update, :delete] +end diff --git a/lib/ex_twilio/resources/proxy/session_resource.ex b/lib/ex_twilio/resources/proxy/session_resource.ex new file mode 100644 index 0000000..5c49386 --- /dev/null +++ b/lib/ex_twilio/resources/proxy/session_resource.ex @@ -0,0 +1,32 @@ +defmodule ExTwilio.Proxy.SessionResource do + @moduledoc """ + Represents an allocated Session containing Participants, an allocated Phone Number, and Interations. + + - [Twilio docs](https://www.twilio.com/docs/proxy/api/session) + """ + + defstruct sid: nil, + account_sid: nil, + service_sid: nil, + date_started: nil, + date_ended: nil, + date_last_interation: nil, + date_expirty: nil, + unique_name: nil, + status: nil, + closed_reason: nil, + ttl: nil, + mode: nil, + date_created: nil, + date_updated: nil, + url: nil, + links: nil + + use ExTwilio.Resource, import: [:stream, :all, :find, :create, :update, :delete] + + def parents, do: [%ExTwilio.Parent{module: ExTwilio.Proxy.Service, key: :service}] + + def resource_name, do: "Sessions" + + def resource_collection_name, do: "sessions" +end diff --git a/lib/ex_twilio/resources/proxy/short_code.ex b/lib/ex_twilio/resources/proxy/short_code.ex new file mode 100644 index 0000000..5dc171a --- /dev/null +++ b/lib/ex_twilio/resources/proxy/short_code.ex @@ -0,0 +1,22 @@ +defmodule ExTwilio.Proxy.ShortCode do + @moduledoc """ + Represents a Short Code attached to a Service. + + - [Twilio docs](https://www.twilio.com/docs/proxy/api/short-code) + """ + + defstruct sid: nil, + account_sid: nil, + service_sid: nil, + date_created: nil, + date_updated: nil, + short_code: nil, + iso_country: nil, + capabilities: nil, + url: nil, + is_reserved: nil + + use ExTwilio.Resource, import: [:stream, :all, :find, :create, :update, :delete] + + def parents, do: [%ExTwilio.Parent{module: ExTwilio.Proxy.Service, key: :service}] +end diff --git a/lib/ex_twilio/url_generator.ex b/lib/ex_twilio/url_generator.ex index 7fdb2a6..32b2d40 100644 --- a/lib/ex_twilio/url_generator.ex +++ b/lib/ex_twilio/url_generator.ex @@ -68,6 +68,11 @@ defmodule ExTwilio.UrlGenerator do url = add_segments(Config.video_url(), module, id, options) {url, options} + ["ExTwilio", "Proxy" | _] -> + options = add_proxy_service_to_options(module, options) + url = add_segments(Config.proxy_url(), module, id, options) + {url, options} + _ -> # Add Account SID segment if not already present options = add_account_to_options(module, options) @@ -165,6 +170,11 @@ defmodule ExTwilio.UrlGenerator do Keyword.put_new(options, :workspace, Config.workspace_sid()) end + @spec add_proxy_service_to_options(atom, list) :: list + defp add_proxy_service_to_options(_module, options) do + Keyword.put_new(options, :service, Config.proxy_service_sid()) + end + @spec normalize_parents(list) :: list defp normalize_parents(parents) do parents diff --git a/mix.lock b/mix.lock index 94abd4d..34f660e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,12 +1,12 @@ %{ "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, - "certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"}, + "certifi": {:hex, :certifi, "2.5.3", "70bdd7e7188c804f3a30ee0e7c99655bc35d8ac41c23e12325f36ab449b70651", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "ed516acb3929b101208a9d700062d520f3953da3b6b918d866106ffa980e1c10"}, "dialyze": {:hex, :dialyze, "0.2.1", "9fb71767f96649020d769db7cbd7290059daff23707d6e851e206b1fdfa92f9d", [:mix], [], "hexpm", "f485181fa53229356621261a384963cb47511cccf1454e82ca4fde53274fcd48"}, "earmark_parser": {:hex, :earmark_parser, "1.4.10", "6603d7a603b9c18d3d20db69921527f82ef09990885ed7525003c7fe7dc86c56", [:mix], [], "hexpm", "8e2d5370b732385db2c9b22215c3f59c84ac7dda7ed7e544d7c459496ae519c0"}, "ex_doc": {:hex, :ex_doc, "0.23.0", "a069bc9b0bf8efe323ecde8c0d62afc13d308b1fa3d228b65bca5cf8703a529d", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "f5e2c4702468b2fd11b10d39416ddadd2fcdd173ba2a0285ebd92c39827a5a16"}, - "hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"}, - "httpoison": {:hex, :httpoison, "1.7.0", "abba7d086233c2d8574726227b6c2c4f6e53c4deae7fe5f6de531162ce9929a0", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "975cc87c845a103d3d1ea1ccfd68a2700c211a434d8428b10c323dc95dc5b980"}, - "idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"}, + "hackney": {:hex, :hackney, "1.17.0", "717ea195fd2f898d9fe9f1ce0afcc2621a41ecfe137fae57e7fe6e9484b9aa99", [:rebar3], [{:certifi, "~>2.5", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "64c22225f1ea8855f584720c0e5b3cd14095703af1c9fbc845ba042811dc671c"}, + "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "inch_ex": {:hex, :inch_ex, "2.0.0", "24268a9284a1751f2ceda569cd978e1fa394c977c45c331bb52a405de544f4de", [:mix], [{:bunt, "~> 0.2", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "96d0ec5ecac8cf63142d02f16b7ab7152cf0f0f1a185a80161b758383c9399a8"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, @@ -19,7 +19,7 @@ "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mock": {:hex, :mock, "0.3.6", "e810a91fabc7adf63ab5fdbec5d9d3b492413b8cda5131a2a8aa34b4185eb9b4", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "bcf1d0a6826fb5aee01bae3d74474669a3fa8b2df274d094af54a25266a1ebd2"}, "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, + "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, }