telnyx 2.2.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/scripts/before_install.sh +9 -0
  3. data/.github/workflows/ruby.yml +39 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +6 -36
  6. data/.rubocop_todo.yml +300 -0
  7. data/.travis.yml.bak +48 -0
  8. data/Gemfile +10 -6
  9. data/README.md +1 -1
  10. data/VERSION +1 -1
  11. data/bin/telnyx-console +5 -0
  12. data/examples/2 factor authentication/Gemfile +7 -0
  13. data/examples/2 factor authentication/main.rb +67 -0
  14. data/examples/2 factor authentication/readme.md +5 -0
  15. data/examples/fax/Gemfile +7 -0
  16. data/examples/fax/config.yaml +4 -0
  17. data/examples/fax/fax.rb +42 -0
  18. data/examples/fax/options.rb +41 -0
  19. data/examples/fax/readme.md +18 -0
  20. data/lib/telnyx.rb +5 -1
  21. data/lib/telnyx/api_operations/create.rb +6 -1
  22. data/lib/telnyx/api_operations/save.rb +1 -1
  23. data/lib/telnyx/api_resource.rb +24 -3
  24. data/lib/telnyx/call.rb +3 -1
  25. data/lib/telnyx/conference.rb +17 -1
  26. data/lib/telnyx/fax.rb +13 -0
  27. data/lib/telnyx/fax_application.rb +12 -0
  28. data/lib/telnyx/messaging_phone_number.rb +4 -0
  29. data/lib/telnyx/phone_number.rb +7 -3
  30. data/lib/telnyx/phone_number_regulatory_requirement.rb +1 -0
  31. data/lib/telnyx/sim_card.rb +12 -1
  32. data/lib/telnyx/telnyx_client.rb +16 -25
  33. data/lib/telnyx/util.rb +12 -34
  34. data/lib/telnyx/verification.rb +36 -0
  35. data/lib/telnyx/verify_profile.rb +11 -0
  36. data/lib/telnyx/version.rb +1 -1
  37. data/telnyx.gemspec +2 -2
  38. data/test/telnyx/alphanumeric_sender_id_test.rb +1 -1
  39. data/test/telnyx/api_operations_test.rb +1 -1
  40. data/test/telnyx/api_resource_test.rb +1 -1
  41. data/test/telnyx/available_phone_number_test.rb +1 -1
  42. data/test/telnyx/call_control_test.rb +50 -47
  43. data/test/telnyx/conference_test.rb +57 -20
  44. data/test/telnyx/credential_connection_test.rb +5 -1
  45. data/test/telnyx/errors_test.rb +1 -1
  46. data/test/telnyx/fax_application_test.rb +32 -0
  47. data/test/telnyx/fax_test.rb +33 -0
  48. data/test/telnyx/fqdn_connection_test.rb +1 -1
  49. data/test/telnyx/fqdn_test.rb +1 -1
  50. data/test/telnyx/list_object_test.rb +1 -1
  51. data/test/telnyx/message_test.rb +1 -1
  52. data/test/telnyx/messaging_phone_number_test.rb +9 -5
  53. data/test/telnyx/messaging_profile_test.rb +2 -2
  54. data/test/telnyx/number_reservation_test.rb +2 -0
  55. data/test/telnyx/phone_number_regulatory_requirement_test.rb +1 -1
  56. data/test/telnyx/phone_number_test.rb +9 -21
  57. data/test/telnyx/public_key_test.rb +1 -1
  58. data/test/telnyx/sim_card_test.rb +6 -6
  59. data/test/telnyx/telnyx_client_test.rb +43 -49
  60. data/test/telnyx/telnyx_object_test.rb +17 -19
  61. data/test/telnyx/telnyx_response_test.rb +1 -1
  62. data/test/telnyx/util_test.rb +1 -1
  63. data/test/telnyx/verification_test.rb +24 -0
  64. data/test/telnyx/verify_profile_test.rb +33 -0
  65. data/test/telnyx/webhook_test.rb +1 -1
  66. data/test/telnyx/wireless_detail_records_report_test.rb +1 -0
  67. data/test/telnyx_test.rb +20 -24
  68. data/test/test_helper.rb +1 -1
  69. metadata +52 -11
  70. data/.travis.yml +0 -51
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ gemspec
6
6
 
7
7
  group :development do
8
8
  gem "coveralls", require: false
9
- gem "faraday", "0.15.4"
9
+ gem "faraday", "~> 1.0"
10
10
  gem "mocha", "~> 0.13.2"
11
11
  gem "rake"
12
12
  gem "shoulda-context"
@@ -22,20 +22,24 @@ group :development do
22
22
  gem "guard"
23
23
  gem "guard-rake"
24
24
  gem "guard-rubocop"
25
- gem "rubocop", "0.50.0"
25
+ gem "rubocop", "~> 1.6"
26
+
27
+ # debugging
28
+ # gem 'httplog' # when included logs all http requests
29
+ # gem 'awesome_print'
26
30
 
27
31
  # Rack 2.0+ requires Ruby >= 2.2.2 which is problematic for the test suite on
28
32
  # older Ruby versions. Check Ruby the version here and put a maximum
29
33
  # constraint on Rack if necessary.
30
34
  if RUBY_VERSION >= "2.2.2"
31
- gem "rack", ">= 2.0.6"
35
+ gem "rack", ">= 2.1.4"
32
36
  else
33
37
  gem "rack", ">= 1.6.11", "< 2.0" # rubocop:disable Bundler/DuplicatedGem
34
38
  end
35
39
 
36
40
  platforms :mri do
37
- gem "byebug"
38
- gem "pry"
39
- gem "pry-byebug"
41
+ # gem "byebug"
42
+ # gem "pry"
43
+ # gem "pry-byebug"
40
44
  end
41
45
  end
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Telnyx Ruby Library
2
2
 
3
- [![Build Status](https://travis-ci.org/team-telnyx/telnyx-ruby.svg?branch=master)](https://travis-ci.org/team-telnyx/telnyx-ruby)
3
+ ![Build Status](https://github.com/team-telnyx/telnyx-ruby/workflows/Ruby/badge.svg)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/team-telnyx/telnyx-ruby/badge.svg?branch=master)](https://coveralls.io/github/team-telnyx/telnyx-ruby?branch=master)
5
5
  [![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://joinslack.telnyx.com/)
6
6
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 2.7.0
data/bin/telnyx-console CHANGED
@@ -13,5 +13,10 @@ IRB.conf[:PROMPT_MODE] = :SIMPLE
13
13
  IRB.conf[:AUTO_INDENT] = true
14
14
 
15
15
  puts "Loaded gem 'telnyx'"
16
+ def load_mock_settings!
17
+ Telnyx.api_base = "http://localhost:12111"
18
+ Telnyx.api_key = "KEYSUPERSECRET"
19
+ nil
20
+ end
16
21
 
17
22
  IRB.start
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "amazing_print"
6
+ gem "telnyx", path: "../../."
7
+ gem "tty-prompt"
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "telnyx"
4
+ require "amazing_print" # for displaying the api requests nicely.
5
+ require "tty-prompt" # for prettier interactive prompts.
6
+
7
+ Telnyx.api_key = ENV["TELNYX_KEY"] # Set your key here
8
+ raise "Please set your API key in this script, or set the TELNYX_KEY env variable!" unless Telnyx.api_key
9
+
10
+ class Demo
11
+ def initialize
12
+ @prompt = TTY::Prompt.new
13
+ end
14
+
15
+ def start
16
+ create_profile
17
+ puts "Profile object returned from API:"
18
+ ap @profile
19
+
20
+ verify
21
+ puts "Verification object returned from API:"
22
+ ap @verification
23
+
24
+ puts "A SMS should be sent to the phone number soon."
25
+ check_prompt
26
+ end
27
+
28
+ def create_profile
29
+ # Ask what to call the new verification profile.
30
+ profile_name = @prompt.ask("Profile name:", default: "demo profile")
31
+ # Check if we already created a demo profile.
32
+ existing_profile = Telnyx::VerifyProfile.list.first { |p| p.name == profile_name }
33
+ # Check if we should use the existing one.
34
+ return @profile = existing_profile if existing_profile && @prompt.yes?(%(Found a profile already called "#{profile_name}", would you like to use that instead of creating a new profile?))
35
+
36
+ # Create a new profile.
37
+ @profile = Telnyx::VerifyProfile.create name: profile_name
38
+ end
39
+
40
+ def verify
41
+ # Create a new verification, this will send a code via SMS to the number provided.
42
+ @verification = Telnyx::Verification.create(
43
+ type: "sms",
44
+ verify_profile_id: @profile.id,
45
+ phone_number: @prompt.ask("Enter a phone number to send a verification code to (must be e164 format, e.g., +15554443333):", value: "+1") { |p| p.validate(/^\+?[1-9]\d{1,14}$/) }
46
+ )
47
+ end
48
+
49
+ def check_prompt
50
+ loop do
51
+ # Ask the user for the verification code.
52
+ code = @prompt.ask "Enter verification code:"
53
+ # Ask the api if this is the correct code.
54
+ response = Telnyx::Verification.submit_code code: code, phone_number: @verification.phone_number
55
+ puts "Api responded with:"
56
+ ap response
57
+
58
+ # If it's not the right code try again.
59
+ break if response.response_code == "accepted"
60
+
61
+ puts "\e[31mIncorrect code, try again!\e[0m"
62
+ create_profile if @prompt.yes?("Resend code?")
63
+ end
64
+ end
65
+ end
66
+
67
+ Demo.new.start
@@ -0,0 +1,5 @@
1
+ # Usage
2
+ ```
3
+ bundle
4
+ bundle exec ruby main.rb
5
+ ```
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "amazing_print"
6
+ gem "sinatra"
7
+ gem "telnyx", path: "../../."
@@ -0,0 +1,4 @@
1
+ fax_app_id:
2
+ outbound_connection_id:
3
+ to:
4
+ from:
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "telnyx"
4
+ require_relative "options"
5
+ require "sinatra/base"
6
+ require "json"
7
+ require "amazing_print"
8
+ require "uri"
9
+
10
+ class WebhookServer < Sinatra::Base
11
+ set :port, 9090
12
+
13
+ def initialize
14
+ super
15
+ Thread.new { telnyx_setup }
16
+ end
17
+
18
+ def telnyx_setup
19
+ @fax_application = Telnyx::FaxApplication.retrieve CONFIG.fax_app_id
20
+ @fax_application.webhook_event_url = CONFIG.webhook_url
21
+ @fax_application.save
22
+
23
+ puts "## Fax Send Request ##"
24
+ ap @sent_fax = Telnyx::Fax.create(
25
+ connection_id: CONFIG["outbound_connection_id"],
26
+ media_url: CONFIG.document_url,
27
+ to: CONFIG.to,
28
+ from: CONFIG.from,
29
+ outbound_voice_profile_id: CONFIG.outbound_voice_profile_id
30
+ )
31
+ end
32
+
33
+ # Receive webhooks
34
+ post "/*" do
35
+ hook = JSON.parse(request.body.read, symbolize_names: true)
36
+ puts "## Received Webhook ##"
37
+ ap hook
38
+ 200
39
+ end
40
+ end
41
+
42
+ WebhookServer.run!
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Helper script to parse the command line options.
4
+
5
+ require "optparse"
6
+ require "ostruct"
7
+ require "yaml"
8
+
9
+ CONFIG = OpenStruct.new(
10
+ document_url: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
11
+ **YAML.safe_load(open("config.yaml")).to_h
12
+ )
13
+ OptionParser.new do |opts|
14
+ opts.banner = "Telnyx fax demo\nUsage: bundle exec fax.rb -- [options]"
15
+
16
+ opts.on("-h", "--help", "Prints this help") do
17
+ puts opts
18
+ exit
19
+ end
20
+
21
+ opts.on(
22
+ "-h=URL", "--webhook-url=URL",
23
+ "[REQUIRED] URL to send webhook events to. This should be an address exposed to the internet. For testing purposes try Ngrok or Hookbin."
24
+ ) { |url| CONFIG.webhook_url = url }
25
+
26
+ opts.on(
27
+ "-k=KEY", "--api-key=KEY", "[REQUIRED] Telnyx API key."
28
+ ) { |key| CONFIG.api_key = Telnyx.api_key = key }
29
+
30
+ opts.on(
31
+ "--to=NUMBER", "Phone number to send a fax to"
32
+ ) { |number| CONFIG.to = number }
33
+
34
+ opts.on(
35
+ "--document-url=URL", "URL for document to fax. Default is https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
36
+ ) { |url| CONFIG.document_url = url }
37
+ end.parse!
38
+
39
+ missing_args = %i[webhook_url api_key] - CONFIG.to_h.keys
40
+ missing_args.any? and raise OptionParser::MissingArgument, "missing the following options: [#{missing_args.join ', '}]. Use --help for more information."
41
+ CONFIG.to_h.values.any?(&:nil?) and raise "Missing config values, check config.yaml"
@@ -0,0 +1,18 @@
1
+ # Usage
2
+
3
+ For convince use a utility like Ngrok or Hookbin to expose the demo server to the internet. For example with Ngrok run the following: `ngrok http 9090` and copy the exposed url, you will need this to properly complete the setup below.
4
+
5
+ Before you can use the demo application you will need to login to your telnyx portal and configure the following:
6
+
7
+ 1. You will need to setup an inbound and an outbound Fax Application for this demo.
8
+ 2. Create two phone numbers:
9
+ - One for inbound faxes, this will need to be associated with a fax application.
10
+ - One for outbound faxes.
11
+ 3. You will also need to create a SIP Connection for your outbound faxes, be sure to configure it to use your webhook url.
12
+
13
+ Finally you will need to fill out `config.yaml` with the IDs listed, as well as with the outbound and inbound phone numbers.
14
+
15
+ ```
16
+ bundle
17
+ bundle exec ruby main.rb --api-key=<YOUR API KEY>
18
+ ```
data/lib/telnyx.rb CHANGED
@@ -40,12 +40,14 @@ require "telnyx/address"
40
40
  require "telnyx/alphanumeric_sender_id"
41
41
  require "telnyx/available_phone_number"
42
42
  require "telnyx/billing_group"
43
+ require "telnyx/call_control_application"
43
44
  require "telnyx/call"
44
45
  require "telnyx/conference"
45
46
  require "telnyx/connection"
46
- require "telnyx/call_control_application"
47
47
  require "telnyx/credential_connection"
48
48
  require "telnyx/event"
49
+ require "telnyx/fax"
50
+ require "telnyx/fax_application"
49
51
  require "telnyx/fqdn_connection"
50
52
  require "telnyx/fqdn"
51
53
  require "telnyx/ip_connection"
@@ -64,6 +66,8 @@ require "telnyx/portout"
64
66
  require "telnyx/public_key"
65
67
  require "telnyx/regulatory_requirement"
66
68
  require "telnyx/sim_card"
69
+ require "telnyx/verification"
70
+ require "telnyx/verify_profile"
67
71
  require "telnyx/wireless_detail_records_report"
68
72
 
69
73
  module Telnyx
@@ -4,7 +4,12 @@ module Telnyx
4
4
  module APIOperations
5
5
  module Create
6
6
  def create(params = {}, opts = {})
7
- resp, opts = request(:post, resource_url, params, opts)
7
+ if opts.respond_to? :fetch
8
+ url = opts.fetch(:resource_url, nil)
9
+ opts.delete :resource_url
10
+ end
11
+ url ||= resource_url
12
+ resp, opts = request(:post, url, params, opts)
8
13
  Util.convert_to_telnyx_object(resp.data, opts)
9
14
  end
10
15
  end
@@ -22,7 +22,7 @@ module Telnyx
22
22
  end
23
23
  end
24
24
 
25
- resp, opts = request(:patch, "#{resource_url}/#{id}", params, opts)
25
+ resp, opts = request(:patch, identified_resource_url(id), params, opts)
26
26
  Util.convert_to_telnyx_object(resp.data, opts)
27
27
  end
28
28
  end
@@ -10,17 +10,36 @@ module Telnyx
10
10
  # own endpoints, but there are certain cases where this is allowed.
11
11
  attr_accessor :save_with_parent
12
12
 
13
+ class << self
14
+ def inherited(subclass)
15
+ super
16
+ @descendants ||= []
17
+ @descendants << subclass
18
+ end
19
+
20
+ attr_reader :descendants
21
+ end
22
+
13
23
  def self.class_name
14
24
  name.split("::")[-1]
15
25
  end
16
26
 
17
- def self.resource_url
27
+ def self.resource_url(inner_id = nil)
18
28
  if self == APIResource
19
29
  raise NotImplementedError, "APIResource is an abstract class. You should perform actions on its subclasses"
20
30
  end
21
31
  # Namespaces are separated in object names with periods (.) and in URLs
22
32
  # with forward slashes (/), so replace the former with the latter.
23
- const_defined?("RESOURCE_PATH") ? "/v2/#{self::RESOURCE_PATH}" : "/v2/#{self::OBJECT_NAME.downcase.tr('.', '/')}s"
33
+ return "/v2/#{resource_path(inner_id)}" if respond_to?("resource_path")
34
+ return "/v2/#{self::RESOURCE_PATH}" if const_defined?("RESOURCE_PATH")
35
+
36
+ "/v2/#{self::OBJECT_NAME.downcase.tr('.', '/')}s"
37
+ end
38
+
39
+ def self.identified_resource_url(id)
40
+ return "/v2/#{resource_path(id)}" if respond_to?("resource_path")
41
+
42
+ "#{resource_url}/#{CGI.escape(id)}"
24
43
  end
25
44
 
26
45
  # A metaprogramming call that specifies that a field of a resource can be
@@ -51,6 +70,8 @@ module Telnyx
51
70
  unless (id = self["id"])
52
71
  raise InvalidRequestError, "Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}"
53
72
  end
73
+ return self.class.resource_url(id).to_s if self.class.respond_to?("resource_path") # Use resource_path defined paths
74
+
54
75
  "#{self.class.resource_url}/#{CGI.escape(id)}"
55
76
  end
56
77
 
@@ -61,7 +82,7 @@ module Telnyx
61
82
 
62
83
  def self.retrieve(id, opts = {})
63
84
  opts = Util.normalize_opts(opts)
64
- instance = new(id, opts)
85
+ instance = new(id, **opts)
65
86
  instance.refresh
66
87
  instance
67
88
  end
data/lib/telnyx/call.rb CHANGED
@@ -33,7 +33,9 @@ module Telnyx
33
33
 
34
34
  ACTIONS = %w[reject answer hangup bridge speak fork_start fork_stop
35
35
  gather_using_audio gather_using_speak playback_start
36
- playback_stop record_start record_stop send_dtmf transfer].freeze
36
+ playback_stop record_start record_stop send_dtmf transfer
37
+ transcription_start transcription_stop record_pause
38
+ record_resume gather_stop refer enqueue leave_queue].freeze
37
39
 
38
40
  ACTIONS.each do |action|
39
41
  nested_resource_class_methods action,
@@ -6,7 +6,7 @@ module Telnyx
6
6
  extend APIOperations::Create
7
7
  extend APIOperations::NestedResource
8
8
 
9
- ACTIONS = %w[join mute unmute hold unhold].freeze
9
+ ACTIONS = %w[join mute unmute hold unhold speak play dial_participant update].freeze
10
10
 
11
11
  ACTIONS.each do |action|
12
12
  nested_resource_class_methods action,
@@ -14,6 +14,22 @@ module Telnyx
14
14
  operations: [:create],
15
15
  instance_methods: { create: action }
16
16
  end
17
+
18
+ nested_resource_class_methods "record_start",
19
+ path: ["actions", "record_start"],
20
+ operations: [:create],
21
+ instance_methods: { create: "start_recording" }
22
+
23
+ nested_resource_class_methods "record_stop",
24
+ path: ["actions", "record_stop"],
25
+ operations: [:create],
26
+ instance_methods: { create: "stop_recording" }
27
+
28
+ nested_resource_class_methods "participants",
29
+ path: "participants",
30
+ operations: [:list],
31
+ instance_methods: { list: "participants" }
32
+
17
33
  OBJECT_NAME = "conference".freeze
18
34
  end
19
35
  Conferences = Conference # Name change without breaking existing code
data/lib/telnyx/fax.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telnyx
4
+ class Fax < APIResource
5
+ extend Telnyx::APIOperations::List
6
+ extend Telnyx::APIOperations::Create
7
+ include Telnyx::APIOperations::Delete
8
+ include Telnyx::APIOperations::Save
9
+
10
+ OBJECT_NAME = "fax".freeze
11
+ RESOURCE_PATH = "faxes".freeze
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telnyx
4
+ class FaxApplication < APIResource
5
+ extend Telnyx::APIOperations::List
6
+ extend Telnyx::APIOperations::Create
7
+ include Telnyx::APIOperations::Delete
8
+ include Telnyx::APIOperations::Save
9
+
10
+ OBJECT_NAME = "fax_application".freeze
11
+ end
12
+ end