twilio-rails 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -17
  3. data/app/controllers/twilio/rails/phone_controller.rb +6 -2
  4. data/app/controllers/twilio/rails/sms_controller.rb +6 -5
  5. data/app/jobs/twilio/rails/phone/attach_recording_job.rb +1 -0
  6. data/app/jobs/twilio/rails/phone/finished_call_job.rb +1 -0
  7. data/app/jobs/twilio/rails/phone/unanswered_call_job.rb +1 -0
  8. data/app/operations/twilio/rails/application_operation.rb +2 -1
  9. data/app/operations/twilio/rails/find_or_create_phone_caller_operation.rb +2 -1
  10. data/app/operations/twilio/rails/phone/attach_recording_operation.rb +3 -2
  11. data/app/operations/twilio/rails/phone/base_operation.rb +1 -0
  12. data/app/operations/twilio/rails/phone/create_operation.rb +11 -8
  13. data/app/operations/twilio/rails/phone/find_operation.rb +1 -0
  14. data/app/operations/twilio/rails/phone/finished_call_operation.rb +2 -1
  15. data/app/operations/twilio/rails/phone/receive_recording_operation.rb +3 -2
  16. data/app/operations/twilio/rails/phone/start_call_operation.rb +15 -13
  17. data/app/operations/twilio/rails/phone/twiml/after_operation.rb +2 -1
  18. data/app/operations/twilio/rails/phone/twiml/base_operation.rb +11 -5
  19. data/app/operations/twilio/rails/phone/twiml/error_operation.rb +2 -1
  20. data/app/operations/twilio/rails/phone/twiml/greeting_operation.rb +3 -2
  21. data/app/operations/twilio/rails/phone/twiml/invalid_phone_number_operation.rb +25 -0
  22. data/app/operations/twilio/rails/phone/twiml/prompt_operation.rb +6 -6
  23. data/app/operations/twilio/rails/phone/twiml/prompt_response_operation.rb +2 -1
  24. data/app/operations/twilio/rails/phone/twiml/request_validation_failure_operation.rb +1 -0
  25. data/app/operations/twilio/rails/phone/twiml/timeout_operation.rb +5 -4
  26. data/app/operations/twilio/rails/phone/unanswered_call_operation.rb +2 -1
  27. data/app/operations/twilio/rails/phone/update_operation.rb +1 -0
  28. data/app/operations/twilio/rails/phone/update_response_operation.rb +1 -0
  29. data/app/operations/twilio/rails/sms/base_operation.rb +1 -0
  30. data/app/operations/twilio/rails/sms/create_operation.rb +2 -1
  31. data/app/operations/twilio/rails/sms/find_message_operation.rb +1 -0
  32. data/app/operations/twilio/rails/sms/find_operation.rb +1 -0
  33. data/app/operations/twilio/rails/sms/send_operation.rb +12 -12
  34. data/app/operations/twilio/rails/sms/twiml/base_operation.rb +1 -0
  35. data/app/operations/twilio/rails/sms/twiml/error_operation.rb +1 -0
  36. data/app/operations/twilio/rails/sms/twiml/message_operation.rb +4 -3
  37. data/app/operations/twilio/rails/sms/update_message_operation.rb +1 -0
  38. data/lib/generators/twilio/rails/install/install_generator.rb +1 -0
  39. data/lib/generators/twilio/rails/install/templates/initializer.rb +5 -8
  40. data/lib/generators/twilio/rails/install/templates/message.rb +1 -0
  41. data/lib/generators/twilio/rails/install/templates/phone_call.rb +1 -0
  42. data/lib/generators/twilio/rails/install/templates/phone_caller.rb +1 -0
  43. data/lib/generators/twilio/rails/install/templates/recording.rb +1 -0
  44. data/lib/generators/twilio/rails/install/templates/response.rb +1 -0
  45. data/lib/generators/twilio/rails/install/templates/sms_conversation.rb +1 -0
  46. data/lib/generators/twilio/rails/phone_tree/phone_tree_generator.rb +1 -0
  47. data/lib/generators/twilio/rails/sms_responder/sms_responder_generator.rb +1 -0
  48. data/lib/generators/twilio/rails/sms_responder/templates/responder.rb.erb +2 -2
  49. data/lib/tasks/rails_tasks.rake +6 -5
  50. data/lib/twilio/rails/client.rb +9 -8
  51. data/lib/twilio/rails/concerns/has_direction.rb +2 -1
  52. data/lib/twilio/rails/concerns/has_phone_number.rb +13 -4
  53. data/lib/twilio/rails/concerns/has_time_scopes.rb +1 -0
  54. data/lib/twilio/rails/configuration.rb +46 -42
  55. data/lib/twilio/rails/formatter.rb +35 -29
  56. data/lib/twilio/rails/models/message.rb +1 -0
  57. data/lib/twilio/rails/models/phone_call.rb +1 -0
  58. data/lib/twilio/rails/models/phone_caller.rb +4 -3
  59. data/lib/twilio/rails/models/recording.rb +1 -0
  60. data/lib/twilio/rails/models/response.rb +7 -6
  61. data/lib/twilio/rails/models/sms_conversation.rb +1 -0
  62. data/lib/twilio/rails/phone/base_tree.rb +8 -8
  63. data/lib/twilio/rails/phone/tree.rb +8 -8
  64. data/lib/twilio/rails/phone/tree_macros.rb +27 -8
  65. data/lib/twilio/rails/phone.rb +3 -2
  66. data/lib/twilio/rails/phone_number.rb +6 -5
  67. data/lib/twilio/rails/phone_number_formatter/north_america.rb +52 -0
  68. data/lib/twilio/rails/phone_number_formatter.rb +20 -0
  69. data/lib/twilio/rails/railtie.rb +6 -1
  70. data/lib/twilio/rails/sms/delegated_responder.rb +6 -5
  71. data/lib/twilio/rails/sms/responder.rb +3 -2
  72. data/lib/twilio/rails/sms.rb +3 -2
  73. data/lib/twilio/rails/version.rb +1 -1
  74. data/lib/twilio/rails.rb +12 -26
  75. metadata +22 -6
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Twilio
3
4
  module Rails
4
5
  module Phone
5
6
  # Base error class for errors relating to Twilio phone interactions.
6
- class Error < ::Twilio::Rails::Error ; end
7
+ class Error < ::Twilio::Rails::Error; end
7
8
 
8
9
  # Error raised when attempting to build a phone tree.
9
- class InvalidTreeError < Error ; end
10
+ class InvalidTreeError < Error; end
10
11
  end
11
12
  end
12
13
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Twilio
3
4
  module Rails
4
5
  # A phone number object that includes the country and some optional metadata.
@@ -10,8 +11,8 @@ module Twilio
10
11
  # @param label [String, nil] an optional label for the phone number, such as its source or purpose.
11
12
  # @param project [String, nil] an optional project identifier for grouping phone numbers.
12
13
  def initialize(number:, country:, label: nil, project: nil)
13
- @number = Twilio::Rails::Formatter.coerce_to_valid_phone_number(number)
14
- raise Twilio::Rails::Phone::Error, "Invalid phone number '#{ number }'" unless @number
14
+ @number = Twilio::Rails::PhoneNumberFormatter.coerce(number)
15
+ raise Twilio::Rails::Phone::Error, "Invalid phone number '#{number}'" unless @number
15
16
  @country = country&.upcase
16
17
  @label = label
17
18
  @project = project.presence&.to_s
@@ -19,9 +20,9 @@ module Twilio
19
20
 
20
21
  # @return [String] a human readable string representation of the phone number and its metadata.
21
22
  def to_s
22
- s = "Phone number #{ number } (#{ country })"
23
- s = "#{ s } #{ label }" if label.present?
24
- s = "#{ s } for #{ project }" if project.present?
23
+ s = "Phone number #{number} (#{country})"
24
+ s = "#{s} #{label}" if label.present?
25
+ s = "#{s} for #{project}" if project.present?
25
26
  s
26
27
  end
27
28
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twilio
4
+ module Rails
5
+ module PhoneNumberFormatter
6
+ # Formats phone numbers as North American 10 digit numbers only, and treats any other number as invalid.
7
+ # This is the legacy behavior from 1.0 which will be the default still in 1.1 as an upgrade path.
8
+ class NorthAmerica
9
+ PHONE_NUMBER_REGEX = /\A\+1[0-9]{10}\Z/
10
+ PHONE_NUMBER_SEGMENTS_REGEX = /\A\+1([0-9]{3})([0-9]{3})([0-9]{4})\Z/
11
+
12
+ def coerce(string)
13
+ string = string.number if string.is_a?(Twilio::Rails::PhoneNumber)
14
+ string = string.to_s.presence
15
+
16
+ if string
17
+ string = string.gsub(/[^0-9]/, "")
18
+ string = "1#{string}" unless string.starts_with?("1")
19
+ string = "+#{string}"
20
+ string = nil unless valid?(string)
21
+ end
22
+
23
+ string
24
+ end
25
+
26
+ def valid?(string)
27
+ string = string.number if string.is_a?(Twilio::Rails::PhoneNumber)
28
+ !!string&.match?(PHONE_NUMBER_REGEX)
29
+ end
30
+
31
+ def to_param(string)
32
+ string = coerce(string)
33
+ return "" unless string
34
+ matches = string.match(PHONE_NUMBER_SEGMENTS_REGEX)
35
+ raise Twilio::Rails::Error, "[to_param] Phone number marked as valid but could not capture. I made a bad regex: #{string}" unless matches
36
+ matches.captures.join("-")
37
+ end
38
+
39
+ def display(string)
40
+ coerced_phone_number = coerce(string)
41
+ if coerced_phone_number
42
+ matches = coerced_phone_number.match(PHONE_NUMBER_SEGMENTS_REGEX)
43
+ raise Twilio::Rails::Error, "[display] Phone number marked as valid but could not capture. I made a bad regex: #{string}" unless matches
44
+ "(#{matches.captures[0]}) #{matches.captures[1]} #{matches.captures[2]}"
45
+ else
46
+ string
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twilio
4
+ module Rails
5
+ # The interface for the phone number validator and formatter that is defined in the `Twilio::Rails.config.phone_number_formatter`
6
+ # configuration. This delegates the methods to that instance and is used both internally to the gem and by the gem consumer.
7
+ module PhoneNumberFormatter
8
+ extend self
9
+ extend Forwardable
10
+
11
+ def_delegators :formatter, :coerce, :valid?, :to_param, :display
12
+
13
+ private
14
+
15
+ def formatter
16
+ Twilio::Rails.config.phone_number_formatter
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Twilio
3
4
  module Rails
4
5
  class Railtie < ::Rails::Railtie
5
6
  config.before_initialize do
6
7
  ActiveSupport::Inflector.inflections(:en) do |inflect|
7
- inflect.acronym 'SMS'
8
+ inflect.acronym "SMS"
8
9
  end
9
10
  end
10
11
 
@@ -12,6 +13,10 @@ module Twilio
12
13
  # TODO: This should work but it does not. I think maybe it happens too late? The same line works if you add it directly to the `application.rb` of the app. It is needed for dev mode.
13
14
  # application.config.hosts << Twilio::Rails.config.host_domain
14
15
  end
16
+
17
+ initializer "twilio_rails.deprecator" do |app|
18
+ app.deprecators[:twilio_rails] = Twilio::Rails.deprecator
19
+ end
15
20
  end
16
21
  end
17
22
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Twilio
3
4
  module Rails
4
5
  module SMS
@@ -34,7 +35,7 @@ module Twilio
34
35
  #
35
36
  # @return [String] the name of the responder.
36
37
  def responder_name
37
- self.name.demodulize.underscore.gsub(/_responder\Z/, "")
38
+ name.demodulize.underscore.gsub(/_responder\Z/, "")
38
39
  end
39
40
  end
40
41
 
@@ -43,22 +44,22 @@ module Twilio
43
44
  @sms_conversation = message.sms_conversation
44
45
  end
45
46
 
46
- # Must be implemented by the subclass otherwise will raise a `NotImplementedError`. Returns true if this
47
+ # Must be implemented by the subclass otherwise will raise a `NoMethodError`. Returns true if this
47
48
  # responder should handle the given message. If true then the {#reply} method will be called to generate the
48
49
  # body of the response. It has access to the message and the conversation.
49
50
  #
50
51
  # @return [true, false] true if this responder should handle the given message.
51
52
  def handle?
52
- raise NotImplementedError
53
+ raise NoMethodError, "#{self.class}#handle? must be implemented."
53
54
  end
54
55
 
55
- # Must be implemented by the subclass otherwise will raise a `NotImplementedError`. Returns the body of the
56
+ # Must be implemented by the subclass otherwise will raise a `NoMethodError`. Returns the body of the
56
57
  # message to be sent in response. Will only be called if {#handle?} returns true. It has access to the message
57
58
  # and the conversation.
58
59
  #
59
60
  # @return [String, nil] the body of the response to be sent as SMS, or `nil` if no message should be sent.
60
61
  def reply
61
- raise NotImplementedError
62
+ raise NoMethodError, "#{self.class}#reply must be implemented."
62
63
  end
63
64
 
64
65
  protected
@@ -1,5 +1,5 @@
1
-
2
1
  # frozen_string_literal: true
2
+
3
3
  module Twilio
4
4
  module Rails
5
5
  module SMS
@@ -25,7 +25,8 @@ module Twilio
25
25
  return responder.reply if responder.handle?
26
26
  end
27
27
 
28
- raise Twilio::Rails::SMS::InvalidResponderError, "No responder found for message_id=#{ message.id } : #{ message.body }"
28
+ raise Twilio::Rails::SMS::InvalidResponderError, "No responder found for SMS. message_id=#{message.id} " \
29
+ "phone_caller_id=#{sms_conversation.phone_caller&.id} from_number=\"#{sms_conversation.from_number}\" body=\"#{message.body}\""
29
30
  end
30
31
  end
31
32
  end
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Twilio
3
4
  module Rails
4
5
  module SMS
5
6
  # Base error class for errors relating to Twilio phone interactions.
6
- class Error < ::Twilio::Rails::Error ; end
7
+ class Error < ::Twilio::Rails::Error; end
7
8
 
8
9
  # Error raised when a responder is unable to handle an SMS message.
9
- class InvalidResponderError < Error ; end
10
+ class InvalidResponderError < Error; end
10
11
  end
11
12
  end
12
13
  end
@@ -1,5 +1,5 @@
1
1
  module Twilio
2
2
  module Rails
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
data/lib/twilio/rails.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "forwardable"
1
2
  require "active_operation"
2
3
  require "twilio-ruby"
3
4
  require "faraday"
@@ -8,13 +9,15 @@ require "twilio/rails/engine"
8
9
  module Twilio
9
10
  module Rails
10
11
  # Base error class for all errors raised by the Twilio::Rails gem. Every error is a subclass of this one.
11
- class Error < StandardError ; end
12
+ class Error < StandardError; end
12
13
  end
13
14
  end
14
15
 
15
16
  require "twilio/rails/railtie"
16
17
  require "twilio/rails/configuration"
17
18
  require "twilio/rails/formatter"
19
+ require "twilio/rails/phone_number_formatter"
20
+ require "twilio/rails/phone_number_formatter/north_america"
18
21
  require "twilio/rails/phone_number"
19
22
  require "twilio/rails/client"
20
23
 
@@ -40,7 +43,6 @@ require "twilio/rails/models/message"
40
43
  module Twilio
41
44
  module Rails
42
45
  class << self
43
-
44
46
  # Read and write accessible configuration object. In most cases this should only be read after the app has been
45
47
  # initialized. See {Twilio::Rails::Configuration} for more information.
46
48
  #
@@ -49,6 +51,14 @@ module Twilio
49
51
  @config ||= ::Twilio::Rails::Configuration.new
50
52
  end
51
53
 
54
+ # See the ActiveSupport::Deprecation documentation:
55
+ # https://api.rubyonrails.org/classes/ActiveSupport/Deprecation.html
56
+ #
57
+ # @return [ActiveSupport::Deprecation] the deprecator for the engine.
58
+ def deprecator
59
+ @deprecator ||= ActiveSupport::Deprecation.new("2.0", "Twilio::Rails")
60
+ end
61
+
52
62
  # Called in the `config/initializers/twilio_rails.rb` file to configure the engine. This yields the {.config}
53
63
  # object above and then calls {Twilio::Rails::Configuration#validate!} to ensure the configuration is valid.
54
64
  #
@@ -60,30 +70,6 @@ module Twilio
60
70
  config.validate!
61
71
  nil
62
72
  end
63
-
64
- # Abstraction for the framework to notify of an important exception that has occurred. This safely calls the
65
- # configured `config.exception_notifier` or does nothing if it is set to `nil`. This does not catch, handle, or
66
- # prevent the exception from raising.
67
- #
68
- # @param exception [Exception] the exception that has occurred.
69
- # @param message [String] a description of the exception, defaults to `exception.message` if blank.
70
- # @param context [Hash] a hash of arbitrary additional context to include in the notification.
71
- # @param exception_binding [Binding] the binding of where the exception is being notified.
72
- # @return [true, false] if an exception has been successfully notified.
73
- def notify_exception(exception, message: nil, context: {}, exception_binding: nil)
74
- if config.exception_notifier
75
- begin
76
- message = message.presence || exception.message
77
- config.exception_notifier.call(exception, message, context, exception_binding)
78
- true
79
- rescue => e
80
- config.logger.tagged(self.class) { |l| l.error("ExceptionNotifier failed to notify of exception=#{ exception.inspect } message=#{ message.inspect } context=#{ context.inspect }") }
81
- false
82
- end
83
- else
84
- false
85
- end
86
- end
87
73
  end
88
74
  end
89
75
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twilio-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin McPhillips
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-09-02 00:00:00.000000000 Z
10
+ date: 2025-02-21 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -164,6 +163,20 @@ dependencies:
164
163
  - - ">="
165
164
  - !ruby/object:Gem::Version
166
165
  version: '0'
166
+ - !ruby/object:Gem::Dependency
167
+ name: standardrb
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
167
180
  description: A Rails engine that provides the framework to build complex phone interactions
168
181
  using the Twilio API.
169
182
  email:
@@ -201,6 +214,7 @@ files:
201
214
  - app/operations/twilio/rails/phone/twiml/base_operation.rb
202
215
  - app/operations/twilio/rails/phone/twiml/error_operation.rb
203
216
  - app/operations/twilio/rails/phone/twiml/greeting_operation.rb
217
+ - app/operations/twilio/rails/phone/twiml/invalid_phone_number_operation.rb
204
218
  - app/operations/twilio/rails/phone/twiml/prompt_operation.rb
205
219
  - app/operations/twilio/rails/phone/twiml/prompt_response_operation.rb
206
220
  - app/operations/twilio/rails/phone/twiml/request_validation_failure_operation.rb
@@ -255,6 +269,8 @@ files:
255
269
  - lib/twilio/rails/phone/tree.rb
256
270
  - lib/twilio/rails/phone/tree_macros.rb
257
271
  - lib/twilio/rails/phone_number.rb
272
+ - lib/twilio/rails/phone_number_formatter.rb
273
+ - lib/twilio/rails/phone_number_formatter/north_america.rb
258
274
  - lib/twilio/rails/railtie.rb
259
275
  - lib/twilio/rails/sms.rb
260
276
  - lib/twilio/rails/sms/delegated_responder.rb
@@ -267,7 +283,8 @@ metadata:
267
283
  homepage_uri: https://github.com/kmcphillips/twilio-rails
268
284
  source_code_uri: https://github.com/kmcphillips/twilio-rails
269
285
  changelog_uri: https://github.com/kmcphillips/twilio-rails/blob/main/CHANGELOG.md
270
- post_install_message:
286
+ documentation_uri: https://rubydoc.info/gems/twilio-rails
287
+ rubygems_mfa_required: 'true'
271
288
  rdoc_options: []
272
289
  require_paths:
273
290
  - lib
@@ -282,8 +299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
282
299
  - !ruby/object:Gem::Version
283
300
  version: '0'
284
301
  requirements: []
285
- rubygems_version: 3.4.12
286
- signing_key:
302
+ rubygems_version: 3.6.2
287
303
  specification_version: 4
288
304
  summary: A framework for building rich phone interactions in Rails using Twilio.
289
305
  test_files: []