twilio-rails 1.0.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 (90) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +0 -0
  3. data/LICENSE +21 -0
  4. data/README.md +413 -0
  5. data/Rakefile +8 -0
  6. data/app/assets/config/twilio_rails_manifest.js +1 -0
  7. data/app/assets/stylesheets/twilio/rails/application.css +15 -0
  8. data/app/controllers/twilio/rails/application_controller.rb +6 -0
  9. data/app/controllers/twilio/rails/phone_controller.rb +112 -0
  10. data/app/controllers/twilio/rails/sms_controller.rb +64 -0
  11. data/app/helpers/twilio/rails/application_helper.rb +6 -0
  12. data/app/jobs/twilio/rails/application_job.rb +6 -0
  13. data/app/jobs/twilio/rails/phone/attach_recording_job.rb +15 -0
  14. data/app/jobs/twilio/rails/phone/finished_call_job.rb +15 -0
  15. data/app/jobs/twilio/rails/phone/unanswered_call_job.rb +15 -0
  16. data/app/mailers/twilio/rails/application_mailer.rb +8 -0
  17. data/app/models/twilio/rails/application_record.rb +7 -0
  18. data/app/operations/twilio/rails/application_operation.rb +21 -0
  19. data/app/operations/twilio/rails/find_or_create_phone_caller_operation.rb +29 -0
  20. data/app/operations/twilio/rails/phone/attach_recording_operation.rb +31 -0
  21. data/app/operations/twilio/rails/phone/base_operation.rb +21 -0
  22. data/app/operations/twilio/rails/phone/create_operation.rb +49 -0
  23. data/app/operations/twilio/rails/phone/find_operation.rb +14 -0
  24. data/app/operations/twilio/rails/phone/finished_call_operation.rb +17 -0
  25. data/app/operations/twilio/rails/phone/receive_recording_operation.rb +35 -0
  26. data/app/operations/twilio/rails/phone/start_call_operation.rb +53 -0
  27. data/app/operations/twilio/rails/phone/twiml/after_operation.rb +37 -0
  28. data/app/operations/twilio/rails/phone/twiml/base_operation.rb +50 -0
  29. data/app/operations/twilio/rails/phone/twiml/error_operation.rb +22 -0
  30. data/app/operations/twilio/rails/phone/twiml/greeting_operation.rb +22 -0
  31. data/app/operations/twilio/rails/phone/twiml/prompt_operation.rb +109 -0
  32. data/app/operations/twilio/rails/phone/twiml/prompt_response_operation.rb +29 -0
  33. data/app/operations/twilio/rails/phone/twiml/request_validation_failure_operation.rb +16 -0
  34. data/app/operations/twilio/rails/phone/twiml/timeout_operation.rb +48 -0
  35. data/app/operations/twilio/rails/phone/unanswered_call_operation.rb +22 -0
  36. data/app/operations/twilio/rails/phone/update_operation.rb +26 -0
  37. data/app/operations/twilio/rails/phone/update_response_operation.rb +38 -0
  38. data/app/operations/twilio/rails/sms/base_operation.rb +17 -0
  39. data/app/operations/twilio/rails/sms/create_operation.rb +23 -0
  40. data/app/operations/twilio/rails/sms/find_message_operation.rb +15 -0
  41. data/app/operations/twilio/rails/sms/find_operation.rb +15 -0
  42. data/app/operations/twilio/rails/sms/send_operation.rb +102 -0
  43. data/app/operations/twilio/rails/sms/twiml/base_operation.rb +11 -0
  44. data/app/operations/twilio/rails/sms/twiml/error_operation.rb +15 -0
  45. data/app/operations/twilio/rails/sms/twiml/message_operation.rb +49 -0
  46. data/app/operations/twilio/rails/sms/update_message_operation.rb +27 -0
  47. data/app/views/layouts/twilio/rails/application.html.erb +15 -0
  48. data/config/routes.rb +16 -0
  49. data/lib/generators/twilio/rails/install/USAGE +15 -0
  50. data/lib/generators/twilio/rails/install/install_generator.rb +34 -0
  51. data/lib/generators/twilio/rails/install/templates/initializer.rb +83 -0
  52. data/lib/generators/twilio/rails/install/templates/message.rb +4 -0
  53. data/lib/generators/twilio/rails/install/templates/migration.rb +89 -0
  54. data/lib/generators/twilio/rails/install/templates/phone_call.rb +4 -0
  55. data/lib/generators/twilio/rails/install/templates/phone_caller.rb +4 -0
  56. data/lib/generators/twilio/rails/install/templates/recording.rb +4 -0
  57. data/lib/generators/twilio/rails/install/templates/response.rb +4 -0
  58. data/lib/generators/twilio/rails/install/templates/sms_conversation.rb +4 -0
  59. data/lib/generators/twilio/rails/phone_tree/USAGE +8 -0
  60. data/lib/generators/twilio/rails/phone_tree/phone_tree_generator.rb +12 -0
  61. data/lib/generators/twilio/rails/phone_tree/templates/tree.rb.erb +13 -0
  62. data/lib/generators/twilio/rails/sms_responder/USAGE +8 -0
  63. data/lib/generators/twilio/rails/sms_responder/sms_responder_generator.rb +12 -0
  64. data/lib/generators/twilio/rails/sms_responder/templates/responder.rb.erb +10 -0
  65. data/lib/tasks/rails_tasks.rake +45 -0
  66. data/lib/twilio/rails/client.rb +75 -0
  67. data/lib/twilio/rails/concerns/has_direction.rb +25 -0
  68. data/lib/twilio/rails/concerns/has_phone_number.rb +27 -0
  69. data/lib/twilio/rails/concerns/has_time_scopes.rb +19 -0
  70. data/lib/twilio/rails/configuration.rb +380 -0
  71. data/lib/twilio/rails/engine.rb +11 -0
  72. data/lib/twilio/rails/formatter.rb +93 -0
  73. data/lib/twilio/rails/models/message.rb +21 -0
  74. data/lib/twilio/rails/models/phone_call.rb +132 -0
  75. data/lib/twilio/rails/models/phone_caller.rb +100 -0
  76. data/lib/twilio/rails/models/recording.rb +27 -0
  77. data/lib/twilio/rails/models/response.rb +153 -0
  78. data/lib/twilio/rails/models/sms_conversation.rb +29 -0
  79. data/lib/twilio/rails/phone/base_tree.rb +229 -0
  80. data/lib/twilio/rails/phone/tree.rb +229 -0
  81. data/lib/twilio/rails/phone/tree_macros.rb +147 -0
  82. data/lib/twilio/rails/phone.rb +12 -0
  83. data/lib/twilio/rails/phone_number.rb +29 -0
  84. data/lib/twilio/rails/railtie.rb +17 -0
  85. data/lib/twilio/rails/sms/delegated_responder.rb +97 -0
  86. data/lib/twilio/rails/sms/responder.rb +33 -0
  87. data/lib/twilio/rails/sms.rb +12 -0
  88. data/lib/twilio/rails/version.rb +5 -0
  89. data/lib/twilio/rails.rb +89 -0
  90. metadata +289 -0
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module Phone
5
+ module Twiml
6
+ class TimeoutOperation < Twilio::Rails::Phone::Twiml::BaseOperation
7
+ input :tree, accepts: Twilio::Rails::Phone::Tree, type: :keyword, required: true
8
+ input :response_id, accepts: Integer, type: :keyword, required: true
9
+
10
+ def execute
11
+ return Twilio::Rails::Phone::Twiml::ErrorOperation.call(phone_call_id: phone_call.id, tree: tree) if phone_call.answering_machine?
12
+
13
+ response = phone_call.responses.find(response_id)
14
+ response.timeout = true
15
+ response.save!
16
+
17
+ if final_timeout?(response, count: tree.config[:final_timeout_attempts])
18
+ twiml_response = Twilio::TwiML::VoiceResponse.new do |twiml|
19
+ add_messages(twiml, message_set: tree.config[:final_timeout_message], response: response)
20
+ twiml.hangup
21
+ end
22
+
23
+ Twilio::Rails.config.logger.info("final timeout on phone_call##{ phone_call.id }")
24
+ Twilio::Rails.config.logger.info("timeout_twiml: #{twiml_response.to_s}")
25
+ twiml_response.to_s
26
+ else
27
+ prompt = tree.prompts[response.prompt_handle]
28
+ raise Twilio::Rails::Phone::InvalidTreeError, "cannot find #{ response.prompt_handle } in #{ tree.name }" unless prompt
29
+
30
+ after = prompt.after
31
+ after = Twilio::Rails::Phone::Tree::After.new(after.proc.call(response)) if after.proc
32
+
33
+ Twilio::Rails::Phone::Twiml::AfterOperation.call(phone_call_id: phone_call.id, tree: tree, after: after)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def final_timeout?(last_response, count: )
40
+ responses = phone_call.responses.final_timeout_check(count: count, prompt_handle: last_response.prompt_handle)
41
+
42
+ responses.count == count && responses.all? { |r| r.timeout? }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module Phone
5
+ class UnansweredCallOperation < ::Twilio::Rails::Phone::BaseOperation
6
+ def execute
7
+ if !phone_call.outbound?
8
+ Twilio::Rails.config.logger.tagged(self.class) { |l| l.error("Should never be called on inbound call") }
9
+ halt
10
+ end
11
+
12
+ if phone_call.unanswered?
13
+ Twilio::Rails.config.logger.tagged(self.class) { |l| l.warn("Skipping duplicate unanswered call job") }
14
+ else
15
+ phone_call.update!(unanswered: true)
16
+ phone_call.tree.unanswered_call.call(phone_call) if phone_call.tree.unanswered_call
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module Phone
5
+ class UpdateOperation < ::Twilio::Rails::Phone::BaseOperation
6
+ input :params, accepts: Hash, type: :keyword, required: true
7
+
8
+ def execute
9
+ if phone_call.outbound?
10
+ if params["AnsweredBy"].present? && phone_call.answered_by != params["AnsweredBy"]
11
+ phone_call.answered_by = params["AnsweredBy"]
12
+ end
13
+ end
14
+
15
+ if params["CallStatus"].present? && phone_call.call_status != params["CallStatus"]
16
+ phone_call.call_status = params["CallStatus"]
17
+ end
18
+
19
+ phone_call.save! if phone_call.changed?
20
+
21
+ phone_call
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module Phone
5
+ class UpdateResponseOperation < ::Twilio::Rails::Phone::BaseOperation
6
+ input :params, accepts: Hash, type: :keyword, required: true
7
+ input :response_id, accepts: Integer, type: :keyword, required: true
8
+
9
+ def execute
10
+ response = phone_call.responses.find(response_id)
11
+
12
+ if params["Digits"].present?
13
+ response.digits = params["Digits"]
14
+ end
15
+
16
+ if params["TranscriptionText"].present? && params["TranscriptionStatus"] == "completed"
17
+ response.transcription = params["TranscriptionText"]
18
+ response.transcribed = true
19
+ end
20
+
21
+ if params["SpeechResult"].present?
22
+ response.transcription = params["SpeechResult"]
23
+ response.transcribed = true
24
+ end
25
+
26
+ response.save! if response.changed?
27
+
28
+ if params["RecordingSid"]
29
+ Twilio::Rails::Phone::ReceiveRecordingOperation.call(phone_call_id: phone_call.id, response_id: response.id, params: params)
30
+ response.reload # This attaches to the other end of the association so this instance doesn't know about it without a reload
31
+ end
32
+
33
+ response
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ # Base class for all SMS operations. Requires the `sms_conversation_id` to be passed in.
6
+ class BaseOperation < ::Twilio::Rails::ApplicationOperation
7
+ input :sms_conversation_id, accepts: Integer, type: :keyword, required: true
8
+
9
+ protected
10
+
11
+ def conversation
12
+ @conversation ||= ::Twilio::Rails.config.sms_conversation_class.find(sms_conversation_id)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ # Called by {Twilio::Rails::SMSController} with the Twilio params to create a new SMS conversation.
6
+ class CreateOperation < ApplicationOperation
7
+ input :params, accepts: Hash, type: :keyword, required: true
8
+
9
+ def execute
10
+ conversation = ::Twilio::Rails.config.sms_conversation_class.new(
11
+ number: params["Called"].presence || params["To"].presence,
12
+ from_number: params["From"].presence,
13
+ from_city: params["FromCity"].presence,
14
+ from_province: params["FromState"].presence,
15
+ from_country: params["FromCountry"].presence,
16
+ )
17
+ conversation.save!
18
+ conversation
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ # Called by {Twilio::Rails::SMSController} with the Twilio params to find an existing SMS message.
6
+ class FindMessageOperation < ApplicationOperation
7
+ input :params, accepts: Hash, type: :keyword, required: true
8
+
9
+ def execute
10
+ ::Twilio::Rails.config.message_class.find_by!(sid: params["SmsSid"])
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ # Called by {Twilio::Rails::SMSController} with the Twilio params to find an existing SMS conversation.
6
+ class FindOperation < ApplicationOperation
7
+ input :sms_conversation_id, accepts: Integer, type: :keyword, required: true
8
+
9
+ def execute
10
+ ::Twilio::Rails.config.sms_conversation_class.find(sms_conversation_id)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ # Public entrypoint used to send an SMS message. This operation will create a new conversation to the phone caller
6
+ # and send a series of messages to them. The interaction will be stored in the database and sent via Twilio's API.
7
+ # The operation will raise if the {#from_number} is not a valid phone number.
8
+ #
9
+ # @example
10
+ # Twilio::Rails::SMS::SendOperation.call(
11
+ # phone_caller_id: a_phone_caller.id,
12
+ # messages: ["Hello world!"],
13
+ # from_number: "+1234567890"
14
+ # )
15
+ #
16
+ # *Note:* Operations should be called with `call(params)` and not by calling `new(params).execute` directly.
17
+ class SendOperation < ApplicationOperation
18
+ input :phone_caller_id, accepts: Integer, type: :keyword, required: true
19
+ input :messages, accepts: Array, type: :keyword, required: true
20
+ input :from_number, accepts: [String, Twilio::Rails::PhoneNumber], type: :keyword, required: false
21
+
22
+ TWILIO_UNSUBSCRIBED_ERROR_CODES = [ 21610 ].freeze
23
+
24
+ # @param phone_caller_id [Integer] the id of the phone caller to send the message to.
25
+ # @param messages [Array<String>] the messages to send to the phone caller. It may be empty.
26
+ # @param from_number [String, Twilio::Rails::PhoneNumber] the phone number to send the message from. If the
27
+ # number is `nil` then it will attempt to extract the phone number from the last phone call. If that is not found
28
+ # then it will raise {Twilio::Rails::SMS::Error}.
29
+ # @return [Twilio::Rails::Models::SMSConversation] the SMS conversation that was created and sent.
30
+ def execute
31
+ return nil if messages.blank?
32
+ raise Twilio::Rails::SMS::Error, "from_number=#{ from_number } is not a valid phone number" if from_number.present? && !Twilio::Rails::Formatter.coerce_to_valid_phone_number(from_number)
33
+
34
+ conversation = ::Twilio::Rails.config.sms_conversation_class.new(
35
+ number: calculated_from_number,
36
+ from_number: calculated_to_number,
37
+ from_city: phone_call&.from_city,
38
+ from_province: phone_call&.from_province,
39
+ from_country: phone_call&.from_country,
40
+ )
41
+ conversation.save!
42
+
43
+ messages.each do |body|
44
+ sid = nil
45
+ begin
46
+ sid = Twilio::Rails::Client.send_message(
47
+ message: body,
48
+ to: calculated_to_number,
49
+ from: calculated_from_number,
50
+ )
51
+ rescue Twilio::REST::RestError => e
52
+ if TWILIO_UNSUBSCRIBED_ERROR_CODES.include?(e.code)
53
+ Twilio::Rails.config.logger.tagged(self.class) { |l| l.warn("tried to send to unsubscribed and got Twilio::REST::RestError code=21610 phone_caller_id=#{ phone_caller.id } phone_number=#{ calculated_to_number } message=#{ body }") }
54
+ else
55
+ Twilio::Rails.notify_exception(e,
56
+ message: "Failed to send Twilio message. Got REST error response.",
57
+ context: {
58
+ to: calculated_to_number,
59
+ from: calculated_from_number,
60
+ phone_call_id: phone_call&.id,
61
+ },
62
+ exception_binding: binding
63
+ )
64
+ raise
65
+ end
66
+ end
67
+
68
+ message = conversation.messages.build(body: body, sid: sid, direction: "outbound")
69
+
70
+ message.save!
71
+ end
72
+
73
+ conversation
74
+ end
75
+
76
+ private
77
+
78
+ def phone_caller
79
+ @phone_caller ||= ::Twilio::Rails.config.phone_caller_class.find(phone_caller_id)
80
+ end
81
+
82
+ def phone_call
83
+ @phone_call ||= phone_caller.phone_calls.inbound.last
84
+ end
85
+
86
+ def calculated_from_number
87
+ if from_number.present?
88
+ Twilio::Rails::Formatter.coerce_to_valid_phone_number(from_number)
89
+ elsif phone_call
90
+ phone_call.number
91
+ else
92
+ raise Twilio::Rails::SMS::Error, "Cannot find a valid from_number to send from"
93
+ end
94
+ end
95
+
96
+ def calculated_to_number
97
+ phone_caller.phone_number
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ module Twiml
6
+ class BaseOperation < Twilio::Rails::SMS::BaseOperation
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ module Twiml
6
+ class ErrorOperation < ::Twilio::Rails::ApplicationOperation
7
+ def execute
8
+ twiml = Twilio::TwiML::MessagingResponse.new
9
+ twiml.to_s
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ module Twiml
6
+ class MessageOperation < Twilio::Rails::SMS::Twiml::BaseOperation
7
+ input :params, accepts: Hash, type: :keyword, required: true
8
+
9
+ def execute
10
+ inbound_message = conversation.messages.build(
11
+ direction: "inbound",
12
+ body: params["Body"],
13
+ sid: params["SmsSid"].presence || params["MessageSid"].presence
14
+ )
15
+
16
+ inbound_message.save!
17
+
18
+ body = Twilio::Rails::SMS::Responder.new(inbound_message).respond
19
+
20
+ if body.present?
21
+ message = conversation.messages.build(
22
+ direction: "outbound",
23
+ body: body,
24
+ )
25
+
26
+ message.save!
27
+
28
+ twiml_response = Twilio::TwiML::MessagingResponse.new do |twiml|
29
+ twiml.message(
30
+ body: body,
31
+ action: ::Twilio::Rails::Engine.routes.url_helpers.sms_status_message_path(message_id: message.id)
32
+ )
33
+ end
34
+
35
+ Twilio::Rails.config.logger.info("message_twiml: #{twiml_response.to_s}")
36
+ twiml_response.to_s
37
+ else
38
+ Twilio::Rails.config.logger.info("resply is blank, not sending message in response")
39
+ Twilio::Rails.config.logger.info("message_twiml: #{twiml_response.to_s}")
40
+
41
+ twiml = Twilio::TwiML::MessagingResponse.new
42
+ twiml.to_s
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ module Twilio
3
+ module Rails
4
+ module SMS
5
+ # Called by {Twilio::Rails::SMSController} with the Twilio params to update an existing SMS message with any
6
+ # status changes or updates that Twilio sends. The save will only happen if there has been a change.
7
+ class UpdateMessageOperation < ApplicationOperation
8
+ input :params, accepts: Hash, type: :keyword, required: true
9
+ input :message_id, accepts: Integer, type: :keyword, required: true
10
+
11
+ def execute
12
+ message = ::Twilio::Rails.config.message_class.find(message_id)
13
+
14
+ if params["MessageStatus"].present?
15
+ message.status = params["MessageStatus"]
16
+ end
17
+
18
+ if message.changed?
19
+ message.save!
20
+ end
21
+
22
+ message
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Twilio rails</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "twilio/rails/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,16 @@
1
+ # Implements all the routes that Twillio will call to manage the lifecycle of phone calls and SMS messages. See the
2
+ # {README.md} for detailed instructions on how to configure the Twilio dashboard to call these routes.
3
+ Twilio::Rails::Engine.routes.draw do
4
+ match "phone/receive_recording/:response_id", to: "phone#receive_response_recording", as: :phone_receive_recording, via: ::Twilio::Rails.config.controller_http_methods
5
+ match "phone/transcribe/:response_id", to: "phone#transcribe", as: :phone_transcribe, via: ::Twilio::Rails.config.controller_http_methods
6
+ match "phone/status", to: "phone#status", as: :phone_status, via: ::Twilio::Rails.config.controller_http_methods
7
+ match "phone/:tree_name/inbound", to: "phone#inbound", as: :phone_inbound, via: ::Twilio::Rails.config.controller_http_methods
8
+ match "phone/:tree_name/outbound", to: "phone#outbound", as: :phone_outbound, via: ::Twilio::Rails.config.controller_http_methods
9
+ match "phone/:tree_name/prompt/:response_id", to: "phone#prompt", as: :phone_prompt, via: ::Twilio::Rails.config.controller_http_methods
10
+ match "phone/:tree_name/prompt_response/:response_id", to: "phone#prompt_response", as: :phone_prompt_response, via: ::Twilio::Rails.config.controller_http_methods
11
+ match "phone/:tree_name/timeout/:response_id", to: "phone#timeout", as: :phone_timeout, via: ::Twilio::Rails.config.controller_http_methods
12
+
13
+ match "sms/message", to: "sms#message", as: :sms_message, via: ::Twilio::Rails.config.controller_http_methods
14
+ match "sms/status", to: "sms#status", as: :sms_status, via: ::Twilio::Rails.config.controller_http_methods
15
+ match "sms/status/:message_id", to: "sms#status", as: :sms_status_message, via: ::Twilio::Rails.config.controller_http_methods
16
+ end
@@ -0,0 +1,15 @@
1
+ Description:
2
+ Installs the initializer, routes, models, and migrations for `twilio-rails`.
3
+
4
+ Example:
5
+ bin/rails generate twilio:rails:install
6
+
7
+ This will create:
8
+ config/initializers/twilio_rails.rb
9
+ db/migrate/install_twilio_rails.rb
10
+ app/models/message.rb
11
+ app/models/phone_caller.rb
12
+ app/models/phone_call.rb
13
+ app/models/recording.rb
14
+ app/models/response.rb
15
+ app/models/sms_conversation.rb
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ class Twilio::Rails::InstallGenerator < Rails::Generators::Base
3
+ source_root File.expand_path("templates", __dir__)
4
+
5
+ include Rails::Generators::Migration
6
+
7
+ class << self
8
+ def next_migration_number(dirname)
9
+ next_migration_number = current_migration_number(dirname) + 1
10
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
11
+ end
12
+ end
13
+
14
+ def setup_initializer
15
+ copy_file "initializer.rb", "config/initializers/twilio_rails.rb"
16
+ end
17
+
18
+ def setup_routes
19
+ route "mount Twilio::Rails::Engine => '/twilio'"
20
+ end
21
+
22
+ def setup_migrations
23
+ migration_template "migration.rb", "db/migrate/install_twilio_rails.rb"
24
+ end
25
+
26
+ def setup_models
27
+ copy_file "message.rb", "app/models/message.rb"
28
+ copy_file "phone_caller.rb", "app/models/phone_caller.rb"
29
+ copy_file "phone_call.rb", "app/models/phone_call.rb"
30
+ copy_file "recording.rb", "app/models/recording.rb"
31
+ copy_file "response.rb", "app/models/response.rb"
32
+ copy_file "sms_conversation.rb", "app/models/sms_conversation.rb"
33
+ end
34
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+ Twilio::Rails.setup do |config|
3
+ # These are the Twilio account credentials used to access the Twilio API. These should likely be configured in the
4
+ # encrypted Rails credentials or loaded from an ENV variable.
5
+ config.account_sid = "TODO: account_sid"
6
+ config.auth_token = "TODO: auth_token"
7
+
8
+ # This is the phone number that will be used to send SMS messages or start Phone Calls. It must be first configured
9
+ # and purchased in the Twilio dashboard, then entered here. The format must be "+15556667777". In most applications it
10
+ # is probably the only number, but in more complex applications it is the "main" or default number. It is used when
11
+ # the phone number is not specified and the number otherwise cannot be intelligently guessed or inferred. This number
12
+ # should likely be configured in the encrypted Rails credentials or loaded from an ENV variable.
13
+ config.default_outgoing_phone_number = "TODO: +15556667777"
14
+
15
+ # All the following configuration options are optional and have reasonable defaults. Though if no phone trees or SMS
16
+ # responders are registered then the app will not be able to do much.
17
+
18
+ # Registry objects used to store and lookup phone trees and SMS responders. They must be registered here at setup time
19
+ # in order for the application to be able to use them. They can either be defined as strings that will be
20
+ # constantized, or as a block that will be evaluated after initialization. It is recommended to use the included
21
+ # generators to create new phone trees and SMS responders, which will add the lines here to register them.
22
+ #
23
+ # See the README documentation for more information on how to define and register phone trees and SMS responders.
24
+ # config.phone_trees.register { MyPhoneTree }
25
+ # config.sms_responders.register { MySMSResponder }
26
+
27
+ # This is the host that will be used to generate URLs that the Twilio API will use to make requests to the
28
+ # application. It defaults to what is defined in Rails `default_url_options` but can be overridden here. The format
29
+ # must be a protocol and domain, without the trailing slash, and no path.
30
+ # config.host = "https://example.com"
31
+
32
+ # The logger used by the framework. Defaults to `Rails.logger`. It cannot be `nil`, so to disable framework
33
+ # logging explicitly set it to `Logger.new(nil)`.
34
+ # config.logger = Rails.logger
35
+
36
+ # The HTTP methods that Twilio will use to call into the app. Defaults to `[:get, :post]` but can be restricted
37
+ # to just `[:get]` or `[:post]`. This must match the configuration in the Twilio dashboard.
38
+ # config.controller_http_methods = [:get, :post]
39
+
40
+ # Allows SMS messages to be filtered at source if they appear to be spam. This is an optional callable that is run
41
+ # with raw params from Twilio on each request. If the callable returns `true` it will prevent the message from being
42
+ # processed. This is useful for filtering out messages that are obviously spam. Setting this to `nil` will disable
43
+ # the filter and is the default.
44
+ # config.spam_filter = ->(params) {
45
+ # [ "Bad text" ].any? { |regex| regex.match?(params["Body"]) }
46
+ # }
47
+
48
+ # A proc that will be called when an exception is raised in certain key points in the framework. This will never
49
+ # capture the exception, it will raise regardless, but it is a good spot to send an email or notify in chat
50
+ # if desired. The proc needs to accept `(exception, message, context, exception_binding)` as arguments. The
51
+ # default is `nil`, which means no action will be taken.
52
+ # config.exception_notifier = ->(exception, message, context, exception_binding) {
53
+ # MyChatClient.send_message("Error: #{ message } #{ exception.message } #{ context }")
54
+ # }
55
+
56
+ # Controls if recordings will be downloaded and attached to the `Recording` model in an ActiveStorage attachment.
57
+ # This is `true` by default, but can be set to `false` to disable all downloads. It can also be set to a `Proc` or
58
+ # callable that will receive the `Recording` instance and return a boolean for this specific instance. if reordings will be downloaded.
59
+ # config.attach_recordings = true
60
+
61
+ # A list of strings to be interpreted as yes or acceptance to a question, when the response is transcribed. Used in
62
+ # the phone macros. Defaults to a list of common responses.
63
+ # config.yes_responses = ["yes"]
64
+
65
+ # A list of strings to be interpreted as no or rejection to a question, when the response is transcribed. Used in
66
+ # the phone macros. Defaults to a list of common responses.
67
+ # config.no_responses = ["no"]
68
+
69
+ # The name of the model classes, as strings, that this application uses to represent the concepts stored in the DB.
70
+ # The generators will generate the models with the default names below, but they can be changed as the application
71
+ # may need.
72
+ # config.phone_caller_class_name = "PhoneCaller"
73
+ # config.phone_call_class_name = "PhoneCall"
74
+ # config.response_class_name = "Response"
75
+ # config.sms_conversation_class_name = "SMSConversation"
76
+ # config.message_class_name = "Message"
77
+ # config.recording_class_name = "Recording"
78
+
79
+ # Allows adding a module to be included into the `macros` in the phone tree DSL. This is useful for
80
+ # adding convenience methods specific to the application. It can be called multiple times to add multiple modules.
81
+ # Built in macros are defined in `Twilio::Rails::Phone::TreeMacros`.
82
+ # config.include_phone_macros MyMacrosModule
83
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ class Message < ApplicationRecord
3
+ include Twilio::Rails::Models::Message
4
+ end