twilio_base 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +82 -0
  5. data/.ruby-version +1 -0
  6. data/.tool-versions +1 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +142 -0
  10. data/Rakefile +12 -0
  11. data/app/controllers/twilio_base/base_controller.rb +32 -0
  12. data/app/models/twilio_base/global_config.rb +5 -0
  13. data/app/services/twilio_base/api_key.rb +15 -0
  14. data/app/services/twilio_base/application.rb +29 -0
  15. data/app/services/twilio_base/clients.rb +37 -0
  16. data/app/services/twilio_base/phone_number.rb +40 -0
  17. data/app/services/twilio_base/protocols/voice/base.rb +65 -0
  18. data/app/services/twilio_base/protocols/voice/pstn.rb +13 -0
  19. data/app/services/twilio_base/protocols/voice/sip.rb +48 -0
  20. data/app/services/twilio_base/protocols/voice.rb +24 -0
  21. data/app/services/twilio_base/request_verification_service.rb +21 -0
  22. data/app/services/twilio_base/routers/voice/base.rb +44 -0
  23. data/app/services/twilio_base/routers/voice/default.rb +24 -0
  24. data/app/services/twilio_base/routers/voice/direct_dial.rb +10 -0
  25. data/app/services/twilio_base/routers/voice/task_router.rb +34 -0
  26. data/app/services/twilio_base/sync/service.rb +18 -0
  27. data/app/services/twilio_base/task_router/activity.rb +49 -0
  28. data/app/services/twilio_base/task_router/base.rb +17 -0
  29. data/app/services/twilio_base/task_router/task.rb +33 -0
  30. data/app/services/twilio_base/task_router/task_queue.rb +40 -0
  31. data/app/services/twilio_base/task_router/worker.rb +27 -0
  32. data/app/services/twilio_base/task_router/workflow.rb +22 -0
  33. data/app/services/twilio_base/task_router/workspace.rb +51 -0
  34. data/bin/console +8 -0
  35. data/bin/rails +14 -0
  36. data/bin/setup +6 -0
  37. data/circle.yml +36 -0
  38. data/config/locales/en.yml +2 -0
  39. data/config/routes.rb +4 -0
  40. data/db/migrate/20171214105252_create_twilio_base_global_configs.rb +18 -0
  41. data/lib/twilio_base/engine.rb +7 -0
  42. data/lib/twilio_base/helpers/protocols.rb +12 -0
  43. data/lib/twilio_base/version.rb +5 -0
  44. data/lib/twilio_base.rb +11 -0
  45. data/spec/factories/channel_sid.rb +7 -0
  46. data/spec/factories/chat_member_id.rb +7 -0
  47. data/spec/factories/global_config/activity_sid.rb +7 -0
  48. data/spec/factories/global_config/api_key_secret.rb +7 -0
  49. data/spec/factories/global_config/api_key_sid.rb +7 -0
  50. data/spec/factories/global_config/application_sid.rb +7 -0
  51. data/spec/factories/global_config/chat_service_sid.rb +7 -0
  52. data/spec/factories/global_config/conference_sid.rb +7 -0
  53. data/spec/factories/global_config/message_sid.rb +7 -0
  54. data/spec/factories/global_config/phone_number.rb +7 -0
  55. data/spec/factories/global_config/recording_sid.rb +7 -0
  56. data/spec/factories/global_config/sync_service_sid.rb +7 -0
  57. data/spec/factories/global_config/task_sid.rb +7 -0
  58. data/spec/factories/global_config/voice_call_sid.rb +7 -0
  59. data/spec/factories/global_config/worker_sid.rb +7 -0
  60. data/spec/factories/global_config/workflow_sid.rb +7 -0
  61. data/spec/factories/global_config/workspace_sid.rb +7 -0
  62. data/spec/factories/global_configs.rb +28 -0
  63. data/spec/lib/twilio_base/helpers/protocols_spec.rb +49 -0
  64. data/spec/services/twilio_base/api_key_spec.rb +17 -0
  65. data/spec/services/twilio_base/application_spec.rb +31 -0
  66. data/spec/services/twilio_base/phone_number_spec.rb +49 -0
  67. data/spec/services/twilio_base/protocols/voice/base_spec.rb +134 -0
  68. data/spec/services/twilio_base/protocols/voice/pstn_spec.rb +13 -0
  69. data/spec/services/twilio_base/protocols/voice/sip_spec.rb +104 -0
  70. data/spec/services/twilio_base/protocols/voice_spec.rb +48 -0
  71. data/spec/services/twilio_base/request_verification_service_spec.rb +105 -0
  72. data/spec/services/twilio_base/routers/voice/base_spec.rb +91 -0
  73. data/spec/services/twilio_base/routers/voice/default_spec.rb +59 -0
  74. data/spec/services/twilio_base/routers/voice/task_router_spec.rb +63 -0
  75. data/spec/services/twilio_base/sync/service.rb +25 -0
  76. data/spec/services/twilio_base/task_router/activity_spec.rb +68 -0
  77. data/spec/services/twilio_base/task_router/task_queue_spec.rb +114 -0
  78. data/spec/services/twilio_base/task_router/worker_spec.rb +49 -0
  79. data/spec/services/twilio_base/task_router/workflow_spec.rb +37 -0
  80. data/spec/spec_helper.rb +68 -0
  81. data/spec/support/factory_bot.rb +9 -0
  82. data/spec/support/shared_contexts/global_config.rb +6 -0
  83. data/spec/support/shared_contexts/twilio_controller.rb +7 -0
  84. data/spec/support/twilio_base/fake/api_key.rb +26 -0
  85. data/spec/support/twilio_base/fake/application.rb +59 -0
  86. data/spec/support/twilio_base/fake/available_phone_number.rb +29 -0
  87. data/spec/support/twilio_base/fake/chat/channel.rb +63 -0
  88. data/spec/support/twilio_base/fake/chat/client.rb +40 -0
  89. data/spec/support/twilio_base/fake/chat/member.rb +27 -0
  90. data/spec/support/twilio_base/fake/chat/message.rb +47 -0
  91. data/spec/support/twilio_base/fake/chat/service.rb +52 -0
  92. data/spec/support/twilio_base/fake/clients/rest.rb +84 -0
  93. data/spec/support/twilio_base/fake/clients/sms.rb +27 -0
  94. data/spec/support/twilio_base/fake/conference.rb +48 -0
  95. data/spec/support/twilio_base/fake/flex_flow.rb +36 -0
  96. data/spec/support/twilio_base/fake/helpers.rb +38 -0
  97. data/spec/support/twilio_base/fake/incoming_phone_number.rb +46 -0
  98. data/spec/support/twilio_base/fake/lookup/client.rb +29 -0
  99. data/spec/support/twilio_base/fake/lookup/phone_number.rb +34 -0
  100. data/spec/support/twilio_base/fake/notify/binding.rb +41 -0
  101. data/spec/support/twilio_base/fake/notify/notification.rb +40 -0
  102. data/spec/support/twilio_base/fake/notify/segment_membership.rb +17 -0
  103. data/spec/support/twilio_base/fake/notify/user.rb +30 -0
  104. data/spec/support/twilio_base/fake/notify/v1.rb +33 -0
  105. data/spec/support/twilio_base/fake/proxy.rb +30 -0
  106. data/spec/support/twilio_base/fake/recording.rb +44 -0
  107. data/spec/support/twilio_base/fake/sync/client.rb +17 -0
  108. data/spec/support/twilio_base/fake/sync/service.rb +78 -0
  109. data/spec/support/twilio_base/fake/sync/services/document.rb +50 -0
  110. data/spec/support/twilio_base/fake/sync/services/list.rb +50 -0
  111. data/spec/support/twilio_base/fake/sync/services/lists/item.rb +48 -0
  112. data/spec/support/twilio_base/fake/sync/services/map.rb +50 -0
  113. data/spec/support/twilio_base/fake/sync/services/maps/item.rb +54 -0
  114. data/spec/support/twilio_base/fake/task_router/activity.rb +34 -0
  115. data/spec/support/twilio_base/fake/task_router/channel.rb +40 -0
  116. data/spec/support/twilio_base/fake/task_router/client.rb +31 -0
  117. data/spec/support/twilio_base/fake/task_router/statistic.rb +38 -0
  118. data/spec/support/twilio_base/fake/task_router/task.rb +80 -0
  119. data/spec/support/twilio_base/fake/task_router/task_queue.rb +46 -0
  120. data/spec/support/twilio_base/fake/task_router/worker.rb +64 -0
  121. data/spec/support/twilio_base/fake/task_router/workflow.rb +54 -0
  122. data/spec/support/twilio_base/fake/task_router/workspace.rb +83 -0
  123. data/spec/support/twilio_base/fake/voice_call.rb +54 -0
  124. data/spec/support/twilio_base/responses/twiml.rb +29 -0
  125. data/spec/twilio_base_dummy/.gitignore +21 -0
  126. data/spec/twilio_base_dummy/Rakefile +5 -0
  127. data/spec/twilio_base_dummy/app/assets/config/manifest.js +0 -0
  128. data/spec/twilio_base_dummy/app/channels/application_cable/channel.rb +6 -0
  129. data/spec/twilio_base_dummy/app/channels/application_cable/connection.rb +6 -0
  130. data/spec/twilio_base_dummy/app/controllers/application_controller.rb +5 -0
  131. data/spec/twilio_base_dummy/app/controllers/concerns/.keep +0 -0
  132. data/spec/twilio_base_dummy/app/helpers/application_helper.rb +4 -0
  133. data/spec/twilio_base_dummy/bin/bundle +5 -0
  134. data/spec/twilio_base_dummy/bin/rails +11 -0
  135. data/spec/twilio_base_dummy/bin/rake +11 -0
  136. data/spec/twilio_base_dummy/bin/setup +36 -0
  137. data/spec/twilio_base_dummy/bin/spring +18 -0
  138. data/spec/twilio_base_dummy/bin/update +31 -0
  139. data/spec/twilio_base_dummy/config/application.rb +13 -0
  140. data/spec/twilio_base_dummy/config/boot.rb +7 -0
  141. data/spec/twilio_base_dummy/config/cable.yml +5 -0
  142. data/spec/twilio_base_dummy/config/database.example.yml +13 -0
  143. data/spec/twilio_base_dummy/config/environment.rb +5 -0
  144. data/spec/twilio_base_dummy/config/environments/development.rb +28 -0
  145. data/spec/twilio_base_dummy/config/environments/test.rb +17 -0
  146. data/spec/twilio_base_dummy/config/initializers/application_controller_renderer.rb +1 -0
  147. data/spec/twilio_base_dummy/config/initializers/assets.rb +3 -0
  148. data/spec/twilio_base_dummy/config/initializers/backtrace_silencers.rb +1 -0
  149. data/spec/twilio_base_dummy/config/initializers/cookies_serializer.rb +3 -0
  150. data/spec/twilio_base_dummy/config/initializers/filter_parameter_logging.rb +3 -0
  151. data/spec/twilio_base_dummy/config/initializers/inflections.rb +1 -0
  152. data/spec/twilio_base_dummy/config/initializers/mime_types.rb +1 -0
  153. data/spec/twilio_base_dummy/config/initializers/new_framework_defaults.rb +9 -0
  154. data/spec/twilio_base_dummy/config/initializers/session_store.rb +3 -0
  155. data/spec/twilio_base_dummy/config/initializers/wrap_parameters.rb +5 -0
  156. data/spec/twilio_base_dummy/config/locales/en.yml +23 -0
  157. data/spec/twilio_base_dummy/config/puma.rb +7 -0
  158. data/spec/twilio_base_dummy/config/routes.rb +5 -0
  159. data/spec/twilio_base_dummy/config/secrets.yml +10 -0
  160. data/spec/twilio_base_dummy/config/spring.rb +8 -0
  161. data/spec/twilio_base_dummy/config.ru +7 -0
  162. data/spec/twilio_base_dummy/db/schema.rb +31 -0
  163. data/spec/twilio_base_dummy/db/seeds.rb +1 -0
  164. data/spec/twilio_base_dummy/lib/assets/.keep +0 -0
  165. data/spec/twilio_base_dummy/lib/tasks/.keep +0 -0
  166. data/spec/twilio_base_dummy/log/.keep +0 -0
  167. data/spec/twilio_base_dummy/public/404.html +67 -0
  168. data/spec/twilio_base_dummy/public/422.html +67 -0
  169. data/spec/twilio_base_dummy/public/500.html +66 -0
  170. data/spec/twilio_base_dummy/public/apple-touch-icon-precomposed.png +0 -0
  171. data/spec/twilio_base_dummy/public/apple-touch-icon.png +0 -0
  172. data/spec/twilio_base_dummy/public/favicon.ico +0 -0
  173. data/spec/twilio_base_dummy/public/robots.txt +5 -0
  174. data/spec/twilio_base_dummy/tmp/.keep +0 -0
  175. data/spec/twilio_base_dummy/vendor/assets/javascripts/.keep +0 -0
  176. data/spec/twilio_base_dummy/vendor/assets/stylesheets/.keep +0 -0
  177. data/spec/twilio_base_spec.rb +7 -0
  178. data/twilio_base.gemspec +45 -0
  179. metadata +580 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c311949da93145ded13db202755e0c1be16b7af64759759bd2882c50c5bc76be
4
+ data.tar.gz: fea72528cca59bf1615562756d6acd1fd1da0bf6b0c5ac8a646c87927f390cd0
5
+ SHA512:
6
+ metadata.gz: 8115059638c69209438993dc9e3657235e196dcfd2fa8ae5ff1aa963bfa61e3213923eb59f848a3030f48488be36650dc51cbe2d76745e46931b2bbf25890c34
7
+ data.tar.gz: 1b17190e135f6e3012e8311fe11e3d55439cb53c24a9293e79afa0c681c16e4efc11db722f79b2d85054595ad2283a6dcd34d9358ce3e1ca690f29737ed5ce21
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.byebug_history
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /spec/twilio_base_dummy/config/database.yml
11
+ /spec/twilio_base_dummy/log/
12
+ /spec/twilio_base_dummy/tmp/
13
+ /tmp/
14
+
15
+ # rspec failure tracking
16
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,82 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+ Exclude:
4
+ - 'spec/twilio_base_dummy/db/**/*'
5
+ - 'vendor/**/*'
6
+
7
+ Layout/AlignParameters:
8
+ EnforcedStyle: with_fixed_indentation
9
+
10
+ Layout/ExtraSpacing:
11
+ Exclude:
12
+ - 'bin/*'
13
+
14
+ Layout/IndentFirstArgument:
15
+ EnforcedStyle: consistent
16
+
17
+ Layout/IndentFirstArrayElement:
18
+ EnforcedStyle: consistent
19
+
20
+ Layout/MultilineMethodCallIndentation:
21
+ EnforcedStyle: indented
22
+
23
+ Metrics/AbcSize:
24
+ Exclude:
25
+ - 'spec/support/twilio_base/responses/twiml.rb'
26
+ - 'spec/support/twilio_base/fake/helpers.rb'
27
+
28
+ Metrics/LineLength:
29
+ Max: 80
30
+ Exclude:
31
+ - 'spec/twilio_base_dummy/config/**/*'
32
+
33
+ Metrics/MethodLength:
34
+ Enabled: false
35
+
36
+ Metrics/BlockLength:
37
+ Exclude:
38
+ - './spec/**/*'
39
+ - 'twilio_base.gemspec'
40
+
41
+ Style/AccessModifierDeclarations:
42
+ Enabled: false
43
+
44
+ Style/BlockComments:
45
+ Exclude:
46
+ - 'spec/spec_helper.rb'
47
+
48
+ Style/Documentation:
49
+ Enabled: false
50
+
51
+ Style/GuardClause:
52
+ Enabled: false
53
+
54
+ Style/HashSyntax:
55
+ Exclude:
56
+ - 'Rakefile'
57
+ - 'lib/tasks/*.rake'
58
+
59
+ Style/IfUnlessModifier:
60
+ Enabled: false
61
+
62
+ Style/MixinUsage:
63
+ Exclude:
64
+ - 'spec/twilio_base_dummy/bin/*'
65
+
66
+ Style/PercentLiteralDelimiters:
67
+ PreferredDelimiters:
68
+ '%': ()
69
+ '%i': '[]'
70
+ '%q': ()
71
+ '%Q': ()
72
+ '%r': '{}'
73
+ '%s': ()
74
+ '%w': '[]'
75
+ '%W': '[]'
76
+ '%x': ()
77
+
78
+ Style/StringLiterals:
79
+ Exclude:
80
+ - 'bin/*'
81
+ - 'spec/support/twilio_base/responses/twiml.rb'
82
+ - 'spec/support/twilio_base/routers/voice/task_router_spec.rb'
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.5.1
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ ruby '2.5.1'
4
+
5
+ source 'https://rubygems.org'
6
+
7
+ # Specify your gem's dependencies in twilio_base.gemspec
8
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # TwilioBase
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/twilio_base`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'twilio_base'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install twilio_base
22
+
23
+
24
+ ## Migrations
25
+ The gem has a migration to create a global config to store the various sids required from a Twilio environment (either an existing environment or one created via the engine). To install the migration in your host app use `bin/rails twilio_base:install:migrations` and then run migrations as usual.
26
+
27
+ ## Protocols & Routing
28
+ Consistency in approach is a key goal of this library. `Protocols` and `Routers`
29
+ are designed to facilitate consistency in how we handle outbound voice
30
+ communications from any application.
31
+
32
+ ### Protocols
33
+ Protocols allow you to specify `sip` or `pstn` as a protocol for initiating
34
+ outbound voice calls. You can also rely on `default` if you wish to set a
35
+ default method for the application as a whole.
36
+
37
+ #### PSTN
38
+ ```ruby
39
+ TwilioBase::Protocols::Voice::Pstn.new(params: {}, to: '+447755747275')
40
+ ```
41
+
42
+ #### SIP
43
+
44
+ In order to use SIP, you must specify some SIP Session Border Controller (SBC)
45
+ settings using the `SIP_ENDPOINTS` ENV var e.g.
46
+
47
+ ```ruby
48
+ {
49
+ sbc_one: ['123@abc.net', '345@abc.net'],
50
+ sbc_two: ['123@asdf.net', '345@asdf.net']
51
+ }
52
+ ```
53
+
54
+ ```ruby
55
+ TwilioBase::Protocols::Voice::Sip.new(
56
+ params: {
57
+ sbc_provider: :sbc_one
58
+ },
59
+ to: '+447755747275'
60
+ )
61
+ ```
62
+
63
+ #### Default
64
+ ```ruby
65
+ TwilioBase::Protocols::Voice::Default.new(params: {}, to: '+447755747275')
66
+ ```
67
+ The default will be determined by the `VOICE_PROTOCOL` ENV var.
68
+
69
+ #### Options
70
+
71
+ | Option | Details | Required |
72
+ |--------|---------|----------|
73
+ | `action_url` | A url, which will receive actions from the outbound call. | No |
74
+ | `action_url_attributes` | A hash of attributes to append to the action_url as parameters. | No |
75
+ | `status_callback_url` | A url, which will receive callbacks associated with the outbound call. | No |
76
+ | `timeout` | The length of time, in seconds, that the call will ring for before timing out. | No |
77
+ | `sbc_provider` | The SIP Session Border Controller that you would like a call to deliver to. The protocol will load balance across any endpoints associated with a given SBC. | SIP only |
78
+ | `sip_endpoint` | The SIP address that you would like a call to deliver to. | SIP only |
79
+ | `wait_url` | A url , which points to an audio file that will be played if the call is put on hold. | No |
80
+
81
+ N.B. When using `sip` you must either specify a valid `sbc_provider` or a
82
+ `sip_endpoint` in the parameters when initialising the protocol.
83
+
84
+ ### Routers
85
+ Routers allow us to specify a preferred option for routing an outbound call,
86
+ either by direct dial or task router. A router accepts a `Protocol` to generate
87
+ the correct Twiml.
88
+
89
+ #### Direct Dial
90
+ ```ruby
91
+ TwilioBase::Routers::Voice::DirectDial.new(protocol: protocol).route
92
+ ```
93
+
94
+ #### Task Router
95
+ ```ruby
96
+ TwilioBase::Routers::Voice::TaskRouter.new(protocol: protocol).route
97
+ ```
98
+
99
+ #### Default
100
+ ```ruby
101
+ TwilioBase::Routers::Voice::Default.new(protocol: protocol).route
102
+ ```
103
+
104
+ The default will be determined by the `ROUTING_METHOD` ENV var.
105
+
106
+ ## Testing
107
+
108
+ The Twilio api is completely represented by a series of fake classes that can be used in your test suite. To enable them to be used in your host app's specs add the following to your rails_helper:
109
+
110
+ ### Fakes
111
+
112
+ ```ruby
113
+ Dir[Pathname(Gem::Specification.find_by_name('twilio_base').gem_dir)
114
+ .join('spec', 'support', 'twilio_base', 'fake', '**', '*.rb')]
115
+ .each { |f| require f }
116
+
117
+ Twilio::REST::Client = TwilioBase::Override::Fake::Clients::Rest
118
+ ```
119
+
120
+ You can then refer to the fake classes in test via TwilioBase::Fake...
121
+
122
+ ## Development
123
+
124
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
125
+
126
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
127
+
128
+ ## Contributing
129
+
130
+ Bug reports and pull requests are welcome on GitHub at https://github.com/DVELP/twilio_base. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
131
+
132
+ ## Code of Conduct
133
+
134
+ Everyone interacting in the TwilioBase project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/DVELP/twilio_base/blob/master/CODE_OF_CONDUCT.md).
135
+
136
+ <br></br>
137
+ [![DVELP
138
+ logo](https://raw.githubusercontent.com/DVELP/cookbook/master/assets/dvelp-logo.png
139
+ 'DVELP logo')](http://dvelp.co.uk)
140
+
141
+ TwilioBase was created and is maintained by DVELP Ltd.
142
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ APP_RAKEFILE = File.expand_path('spec/twilio_base_dummy/Rakefile', __dir__)
7
+
8
+ load 'rails/tasks/engine.rake'
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task :default => :spec
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ class BaseController < ApplicationController
5
+ before_action :validate_request
6
+ before_action :force_request_format
7
+
8
+ include ActionController::MimeResponds
9
+
10
+ private
11
+
12
+ def validate_request
13
+ request_verification_service =
14
+ TwilioBase::RequestVerificationService.new(
15
+ Twilio::Security::RequestValidator.new(
16
+ ENV.fetch('TWILIO_AUTH_TOKEN')
17
+ )
18
+ )
19
+
20
+ unless request_verification_service.verify(
21
+ uri: request.original_url,
22
+ env: request.env
23
+ )
24
+ render head :ok, status: :unauthorized && return
25
+ end
26
+ end
27
+
28
+ def force_request_format
29
+ request.format = :xml unless params[:format]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ class GlobalConfig < ActiveRecord::Base; end
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ class ApiKey
5
+ FRIENDLY_NAME = 'front-end key'
6
+
7
+ class << self
8
+ include TwilioBase::Clients
9
+
10
+ def create
11
+ rest_client.new_keys.create(friendly_name: FRIENDLY_NAME)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ class Application
5
+ class << self
6
+ include TwilioBase::Clients
7
+
8
+ def create(attributes)
9
+ applications_client.create(
10
+ attributes
11
+ )
12
+ end
13
+
14
+ def find(sid)
15
+ applications_client(sid).fetch
16
+ end
17
+
18
+ private
19
+
20
+ def applications_client(sid = nil)
21
+ if sid
22
+ rest_client.api.v2010.account.applications(sid)
23
+ else
24
+ rest_client.api.v2010.account.applications
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Clients
5
+ ACCOUNT_SID = ENV.fetch('TWILIO_ACCOUNT_SID')
6
+ AUTH_TOKEN = ENV.fetch('TWILIO_AUTH_TOKEN')
7
+
8
+ delegate :api_key_sid, to: :config
9
+ delegate :api_key_secret, to: :config
10
+ delegate :application_sid, to: :config
11
+ delegate :chat_service_sid, to: :config
12
+ delegate :phone_number, to: :config
13
+ delegate :sync_service_sid, to: :config
14
+ delegate :workflow_sid, to: :config
15
+ delegate :workspace_sid, to: :config
16
+
17
+ def config
18
+ @config ||= TwilioBase::GlobalConfig.first
19
+ end
20
+
21
+ def chat_client
22
+ @chat_client ||= Twilio::ChatClient.new(
23
+ account_sid: ACCOUNT_SID, auth_token: AUTH_TOKEN
24
+ )
25
+ end
26
+
27
+ def sms_client
28
+ @sms_client ||= TwilioBase::Clients::Sms.new(
29
+ account_sid: ACCOUNT_SID, auth_token: AUTH_TOKEN
30
+ )
31
+ end
32
+
33
+ def rest_client
34
+ @rest_client ||= Twilio::REST::Client.new(ACCOUNT_SID, AUTH_TOKEN)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ class PhoneNumber
5
+ COUNTRY_CODE = ENV.fetch('COUNTRY_CODE')
6
+
7
+ class << self
8
+ include TwilioBase::Clients
9
+
10
+ def find_or_create(phone_number)
11
+ phone_number ? find(phone_number) : create
12
+ end
13
+
14
+ private
15
+
16
+ def find(phone_number)
17
+ incoming_phone_numbers.list(phone_number: phone_number).first
18
+ end
19
+
20
+ def create
21
+ number = available_numbers.first.phone_number
22
+ purchase_number(number)
23
+ end
24
+
25
+ def available_numbers
26
+ rest_client.api.available_phone_numbers(COUNTRY_CODE).local.list(
27
+ sms_enabled: true
28
+ )
29
+ end
30
+
31
+ def purchase_number(number)
32
+ incoming_phone_numbers.create(phone_number: number)
33
+ end
34
+
35
+ def incoming_phone_numbers
36
+ rest_client.api.incoming_phone_numbers
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Protocols
5
+ module Voice
6
+ class Base
7
+ include ::Helpers::Protocols
8
+
9
+ ANONYMOUS_NUMBER = '+266696687'
10
+ STATUS_CALLBACK_EVENTS = %w[initiated ringing answered completed].freeze
11
+
12
+ def initialize(params: {}, to:)
13
+ self.params = params
14
+ self.to = to
15
+
16
+ raise 'To cannot be blank' if to.blank?
17
+ end
18
+
19
+ def action_url
20
+ params[:action_url]
21
+ end
22
+
23
+ def action_url_attributes
24
+ { endpoint: to }
25
+ end
26
+
27
+ def caller_uuid
28
+ mpoa.presence || ANONYMOUS_NUMBER
29
+ end
30
+
31
+ def endpoint
32
+ to
33
+ end
34
+
35
+ def name
36
+ :number
37
+ end
38
+
39
+ def status_callback_events
40
+ STATUS_CALLBACK_EVENTS.join(' ')
41
+ end
42
+
43
+ def status_callback_url
44
+ params[:status_callback_url]
45
+ end
46
+
47
+ def timeout
48
+ params[:timeout]
49
+ end
50
+
51
+ def wait_url
52
+ params[:wait_url]
53
+ end
54
+
55
+ private
56
+
57
+ attr_accessor :params, :to
58
+
59
+ def mpoa
60
+ extract_mpoa(params[:caller_uuid])
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Protocols
5
+ module Voice
6
+ class Pstn < Base
7
+ def name
8
+ :number
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Protocols
5
+ module Voice
6
+ class Sip < Base
7
+ def endpoint
8
+ "sip:#{sip_endpoint}?#{parsed_headers}"
9
+ end
10
+
11
+ def name
12
+ :sip
13
+ end
14
+
15
+ private
16
+
17
+ def parsed_headers
18
+ hash = headers.each_with_object({}) do |(k, v), obj|
19
+ key = "X-#{k.to_s.camelize}"
20
+ value = v.presence || '-'
21
+
22
+ obj[key] = value
23
+ end
24
+
25
+ Addressable::URI.new(query_values: hash).query
26
+ end
27
+
28
+ def headers
29
+ params[:headers].is_a?(Hash) ? params[:headers] : {}
30
+ end
31
+
32
+ def sip_endpoint
33
+ sip_whip
34
+ end
35
+
36
+ def sip_whip
37
+ @sip_whip ||= sip_endpoints.sample.to_s.strip
38
+ end
39
+
40
+ def sip_endpoints
41
+ value = Array(to)
42
+
43
+ value.flat_map { |v| v.split(',') }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Protocols
5
+ module Voice
6
+ module Default
7
+ module_function
8
+
9
+ def init(params: {}, protocol: nil, to:)
10
+ protocol ||= ENV.fetch('VOICE_PROTOCOL')
11
+ klass = {
12
+ 'pstn' => Protocols::Voice::Pstn,
13
+ 'sip' => Protocols::Voice::Sip
14
+ }.fetch(protocol.to_s, Protocols::Voice::Pstn)
15
+
16
+ klass.new(
17
+ params: params,
18
+ to: to
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ class RequestVerificationService
5
+ attr_accessor :validator
6
+
7
+ def initialize(validator)
8
+ self.validator = validator
9
+ end
10
+
11
+ def verify(uri:, env:)
12
+ params = if env['REQUEST_METHOD'] == 'POST'
13
+ env['rack.request.form_hash']
14
+ else
15
+ env['rack.request.query_hash']
16
+ end
17
+ signature = env['HTTP_X_TWILIO_SIGNATURE']
18
+ signature.present? && validator.validate(uri, params, signature)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Routers
5
+ module Voice
6
+ class Base
7
+ include Rails.application.routes.url_helpers
8
+
9
+ def initialize(protocol:)
10
+ self.protocol = protocol
11
+ end
12
+
13
+ def route
14
+ yield_response = yield if block_given?
15
+
16
+ (yield_response || voice_response).dial(dial_attribues) do |dial|
17
+ dial.public_send(
18
+ protocol.name,
19
+ protocol.endpoint,
20
+ status_callback_event: protocol.status_callback_events,
21
+ status_callback: protocol.status_callback_url
22
+ )
23
+ end.to_s
24
+ end
25
+
26
+ private
27
+
28
+ attr_accessor :protocol
29
+
30
+ def voice_response
31
+ @voice_response ||= Twilio::TwiML::VoiceResponse.new
32
+ end
33
+
34
+ def dial_attribues
35
+ {
36
+ action: protocol.action_url,
37
+ caller_id: protocol.caller_uuid,
38
+ timeout: protocol.timeout
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end