twilio_base 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +82 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +142 -0
- data/Rakefile +12 -0
- data/app/controllers/twilio_base/base_controller.rb +32 -0
- data/app/models/twilio_base/global_config.rb +5 -0
- data/app/services/twilio_base/api_key.rb +15 -0
- data/app/services/twilio_base/application.rb +29 -0
- data/app/services/twilio_base/clients.rb +37 -0
- data/app/services/twilio_base/phone_number.rb +40 -0
- data/app/services/twilio_base/protocols/voice/base.rb +65 -0
- data/app/services/twilio_base/protocols/voice/pstn.rb +13 -0
- data/app/services/twilio_base/protocols/voice/sip.rb +48 -0
- data/app/services/twilio_base/protocols/voice.rb +24 -0
- data/app/services/twilio_base/request_verification_service.rb +21 -0
- data/app/services/twilio_base/routers/voice/base.rb +44 -0
- data/app/services/twilio_base/routers/voice/default.rb +24 -0
- data/app/services/twilio_base/routers/voice/direct_dial.rb +10 -0
- data/app/services/twilio_base/routers/voice/task_router.rb +34 -0
- data/app/services/twilio_base/sync/service.rb +18 -0
- data/app/services/twilio_base/task_router/activity.rb +49 -0
- data/app/services/twilio_base/task_router/base.rb +17 -0
- data/app/services/twilio_base/task_router/task.rb +33 -0
- data/app/services/twilio_base/task_router/task_queue.rb +40 -0
- data/app/services/twilio_base/task_router/worker.rb +27 -0
- data/app/services/twilio_base/task_router/workflow.rb +22 -0
- data/app/services/twilio_base/task_router/workspace.rb +51 -0
- data/bin/console +8 -0
- data/bin/rails +14 -0
- data/bin/setup +6 -0
- data/circle.yml +36 -0
- data/config/locales/en.yml +2 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20171214105252_create_twilio_base_global_configs.rb +18 -0
- data/lib/twilio_base/engine.rb +7 -0
- data/lib/twilio_base/helpers/protocols.rb +12 -0
- data/lib/twilio_base/version.rb +5 -0
- data/lib/twilio_base.rb +11 -0
- data/spec/factories/channel_sid.rb +7 -0
- data/spec/factories/chat_member_id.rb +7 -0
- data/spec/factories/global_config/activity_sid.rb +7 -0
- data/spec/factories/global_config/api_key_secret.rb +7 -0
- data/spec/factories/global_config/api_key_sid.rb +7 -0
- data/spec/factories/global_config/application_sid.rb +7 -0
- data/spec/factories/global_config/chat_service_sid.rb +7 -0
- data/spec/factories/global_config/conference_sid.rb +7 -0
- data/spec/factories/global_config/message_sid.rb +7 -0
- data/spec/factories/global_config/phone_number.rb +7 -0
- data/spec/factories/global_config/recording_sid.rb +7 -0
- data/spec/factories/global_config/sync_service_sid.rb +7 -0
- data/spec/factories/global_config/task_sid.rb +7 -0
- data/spec/factories/global_config/voice_call_sid.rb +7 -0
- data/spec/factories/global_config/worker_sid.rb +7 -0
- data/spec/factories/global_config/workflow_sid.rb +7 -0
- data/spec/factories/global_config/workspace_sid.rb +7 -0
- data/spec/factories/global_configs.rb +28 -0
- data/spec/lib/twilio_base/helpers/protocols_spec.rb +49 -0
- data/spec/services/twilio_base/api_key_spec.rb +17 -0
- data/spec/services/twilio_base/application_spec.rb +31 -0
- data/spec/services/twilio_base/phone_number_spec.rb +49 -0
- data/spec/services/twilio_base/protocols/voice/base_spec.rb +134 -0
- data/spec/services/twilio_base/protocols/voice/pstn_spec.rb +13 -0
- data/spec/services/twilio_base/protocols/voice/sip_spec.rb +104 -0
- data/spec/services/twilio_base/protocols/voice_spec.rb +48 -0
- data/spec/services/twilio_base/request_verification_service_spec.rb +105 -0
- data/spec/services/twilio_base/routers/voice/base_spec.rb +91 -0
- data/spec/services/twilio_base/routers/voice/default_spec.rb +59 -0
- data/spec/services/twilio_base/routers/voice/task_router_spec.rb +63 -0
- data/spec/services/twilio_base/sync/service.rb +25 -0
- data/spec/services/twilio_base/task_router/activity_spec.rb +68 -0
- data/spec/services/twilio_base/task_router/task_queue_spec.rb +114 -0
- data/spec/services/twilio_base/task_router/worker_spec.rb +49 -0
- data/spec/services/twilio_base/task_router/workflow_spec.rb +37 -0
- data/spec/spec_helper.rb +68 -0
- data/spec/support/factory_bot.rb +9 -0
- data/spec/support/shared_contexts/global_config.rb +6 -0
- data/spec/support/shared_contexts/twilio_controller.rb +7 -0
- data/spec/support/twilio_base/fake/api_key.rb +26 -0
- data/spec/support/twilio_base/fake/application.rb +59 -0
- data/spec/support/twilio_base/fake/available_phone_number.rb +29 -0
- data/spec/support/twilio_base/fake/chat/channel.rb +63 -0
- data/spec/support/twilio_base/fake/chat/client.rb +40 -0
- data/spec/support/twilio_base/fake/chat/member.rb +27 -0
- data/spec/support/twilio_base/fake/chat/message.rb +47 -0
- data/spec/support/twilio_base/fake/chat/service.rb +52 -0
- data/spec/support/twilio_base/fake/clients/rest.rb +84 -0
- data/spec/support/twilio_base/fake/clients/sms.rb +27 -0
- data/spec/support/twilio_base/fake/conference.rb +48 -0
- data/spec/support/twilio_base/fake/flex_flow.rb +36 -0
- data/spec/support/twilio_base/fake/helpers.rb +38 -0
- data/spec/support/twilio_base/fake/incoming_phone_number.rb +46 -0
- data/spec/support/twilio_base/fake/lookup/client.rb +29 -0
- data/spec/support/twilio_base/fake/lookup/phone_number.rb +34 -0
- data/spec/support/twilio_base/fake/notify/binding.rb +41 -0
- data/spec/support/twilio_base/fake/notify/notification.rb +40 -0
- data/spec/support/twilio_base/fake/notify/segment_membership.rb +17 -0
- data/spec/support/twilio_base/fake/notify/user.rb +30 -0
- data/spec/support/twilio_base/fake/notify/v1.rb +33 -0
- data/spec/support/twilio_base/fake/proxy.rb +30 -0
- data/spec/support/twilio_base/fake/recording.rb +44 -0
- data/spec/support/twilio_base/fake/sync/client.rb +17 -0
- data/spec/support/twilio_base/fake/sync/service.rb +78 -0
- data/spec/support/twilio_base/fake/sync/services/document.rb +50 -0
- data/spec/support/twilio_base/fake/sync/services/list.rb +50 -0
- data/spec/support/twilio_base/fake/sync/services/lists/item.rb +48 -0
- data/spec/support/twilio_base/fake/sync/services/map.rb +50 -0
- data/spec/support/twilio_base/fake/sync/services/maps/item.rb +54 -0
- data/spec/support/twilio_base/fake/task_router/activity.rb +34 -0
- data/spec/support/twilio_base/fake/task_router/channel.rb +40 -0
- data/spec/support/twilio_base/fake/task_router/client.rb +31 -0
- data/spec/support/twilio_base/fake/task_router/statistic.rb +38 -0
- data/spec/support/twilio_base/fake/task_router/task.rb +80 -0
- data/spec/support/twilio_base/fake/task_router/task_queue.rb +46 -0
- data/spec/support/twilio_base/fake/task_router/worker.rb +64 -0
- data/spec/support/twilio_base/fake/task_router/workflow.rb +54 -0
- data/spec/support/twilio_base/fake/task_router/workspace.rb +83 -0
- data/spec/support/twilio_base/fake/voice_call.rb +54 -0
- data/spec/support/twilio_base/responses/twiml.rb +29 -0
- data/spec/twilio_base_dummy/.gitignore +21 -0
- data/spec/twilio_base_dummy/Rakefile +5 -0
- data/spec/twilio_base_dummy/app/assets/config/manifest.js +0 -0
- data/spec/twilio_base_dummy/app/channels/application_cable/channel.rb +6 -0
- data/spec/twilio_base_dummy/app/channels/application_cable/connection.rb +6 -0
- data/spec/twilio_base_dummy/app/controllers/application_controller.rb +5 -0
- data/spec/twilio_base_dummy/app/controllers/concerns/.keep +0 -0
- data/spec/twilio_base_dummy/app/helpers/application_helper.rb +4 -0
- data/spec/twilio_base_dummy/bin/bundle +5 -0
- data/spec/twilio_base_dummy/bin/rails +11 -0
- data/spec/twilio_base_dummy/bin/rake +11 -0
- data/spec/twilio_base_dummy/bin/setup +36 -0
- data/spec/twilio_base_dummy/bin/spring +18 -0
- data/spec/twilio_base_dummy/bin/update +31 -0
- data/spec/twilio_base_dummy/config/application.rb +13 -0
- data/spec/twilio_base_dummy/config/boot.rb +7 -0
- data/spec/twilio_base_dummy/config/cable.yml +5 -0
- data/spec/twilio_base_dummy/config/database.example.yml +13 -0
- data/spec/twilio_base_dummy/config/environment.rb +5 -0
- data/spec/twilio_base_dummy/config/environments/development.rb +28 -0
- data/spec/twilio_base_dummy/config/environments/test.rb +17 -0
- data/spec/twilio_base_dummy/config/initializers/application_controller_renderer.rb +1 -0
- data/spec/twilio_base_dummy/config/initializers/assets.rb +3 -0
- data/spec/twilio_base_dummy/config/initializers/backtrace_silencers.rb +1 -0
- data/spec/twilio_base_dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/twilio_base_dummy/config/initializers/filter_parameter_logging.rb +3 -0
- data/spec/twilio_base_dummy/config/initializers/inflections.rb +1 -0
- data/spec/twilio_base_dummy/config/initializers/mime_types.rb +1 -0
- data/spec/twilio_base_dummy/config/initializers/new_framework_defaults.rb +9 -0
- data/spec/twilio_base_dummy/config/initializers/session_store.rb +3 -0
- data/spec/twilio_base_dummy/config/initializers/wrap_parameters.rb +5 -0
- data/spec/twilio_base_dummy/config/locales/en.yml +23 -0
- data/spec/twilio_base_dummy/config/puma.rb +7 -0
- data/spec/twilio_base_dummy/config/routes.rb +5 -0
- data/spec/twilio_base_dummy/config/secrets.yml +10 -0
- data/spec/twilio_base_dummy/config/spring.rb +8 -0
- data/spec/twilio_base_dummy/config.ru +7 -0
- data/spec/twilio_base_dummy/db/schema.rb +31 -0
- data/spec/twilio_base_dummy/db/seeds.rb +1 -0
- data/spec/twilio_base_dummy/lib/assets/.keep +0 -0
- data/spec/twilio_base_dummy/lib/tasks/.keep +0 -0
- data/spec/twilio_base_dummy/log/.keep +0 -0
- data/spec/twilio_base_dummy/public/404.html +67 -0
- data/spec/twilio_base_dummy/public/422.html +67 -0
- data/spec/twilio_base_dummy/public/500.html +66 -0
- data/spec/twilio_base_dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/twilio_base_dummy/public/apple-touch-icon.png +0 -0
- data/spec/twilio_base_dummy/public/favicon.ico +0 -0
- data/spec/twilio_base_dummy/public/robots.txt +5 -0
- data/spec/twilio_base_dummy/tmp/.keep +0 -0
- data/spec/twilio_base_dummy/vendor/assets/javascripts/.keep +0 -0
- data/spec/twilio_base_dummy/vendor/assets/stylesheets/.keep +0 -0
- data/spec/twilio_base_spec.rb +7 -0
- data/twilio_base.gemspec +45 -0
- 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
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
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,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,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
|