twilio-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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