twilio_base 1.9.0 → 1.11.11

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +2 -7
  4. data/app/services/twilio_base/phone_number.rb +5 -1
  5. data/app/services/twilio_base/protocols/voice/base.rb +16 -0
  6. data/app/services/twilio_base/protocols/voice/sip.rb +26 -1
  7. data/app/services/twilio_base/routers/voice/base.rb +19 -14
  8. data/circle.yml +7 -4
  9. data/lib/twilio_base/version.rb +1 -1
  10. data/spec/services/twilio_base/phone_number_spec.rb +15 -0
  11. data/spec/services/twilio_base/protocols/voice/base_spec.rb +35 -0
  12. data/spec/services/twilio_base/protocols/voice/sip_spec.rb +116 -5
  13. data/spec/services/twilio_base/routers/voice/base_spec.rb +49 -21
  14. data/spec/spec_helper.rb +1 -0
  15. data/spec/support/twilio_base/fake/account.rb +20 -0
  16. data/spec/support/twilio_base/fake/chat/channel.rb +10 -6
  17. data/spec/support/twilio_base/fake/clients/rest.rb +4 -0
  18. data/spec/support/twilio_base/fake/sync/services/document.rb +6 -6
  19. data/spec/support/twilio_base/fake/sync/services/list.rb +5 -5
  20. data/spec/support/twilio_base/fake/sync/services/lists/item.rb +9 -3
  21. data/spec/support/twilio_base/fake/sync/services/map.rb +28 -7
  22. data/spec/support/twilio_base/fake/sync/services/maps/item.rb +42 -5
  23. data/spec/support/twilio_base/fake/task_router/worker.rb +4 -0
  24. data/spec/support/twilio_base/fake/task_router/worker_statistic.rb +49 -0
  25. data/spec/support/twilio_base/responses/twiml.rb +11 -0
  26. data/spec/twilio_base_dummy/config/database.example.yml +1 -1
  27. data/twilio_base.gemspec +2 -1
  28. metadata +28 -12
  29. data/.tool-versions +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c446ad08567bcbe8261020d83ce5723dfdd8040bd1ac4d079081a9c6610dd70b
4
- data.tar.gz: 05e5a017a5a572b8f7b946f86c6c3db72f8d72bf9cb5ad632ca9fb1ec331457a
3
+ metadata.gz: f5cca3af8d5d0d1cccb5338087a09cebd0d2eafea819ff77a2bd1b5ee830029d
4
+ data.tar.gz: a578e6a7fa3d0ddcc2b01101923f5a4803a0e3b0fc938f77f7de12812b139b41
5
5
  SHA512:
6
- metadata.gz: dbaceb9b8ae08813fe790091e7a1b57b3000a7a8b58aa71c296af8177f1c9739948a9a531457728a4a730d398ab75db0237f470116615ca02ed35b1c38d914ca
7
- data.tar.gz: 1138756197d7f69b6e689e4612c169df54540fc4aa5a9ed909d25642d7e6e21c49662682b864dbb743ba67691ec647f7e120c77bd77eed190cc139b9df476a85
6
+ metadata.gz: 329f90af23c78753e3947f7e9b41ad5879ff566f0145764d9b85e1f81df8172d6052abe168ba52ef251704c216894838bddcbb67577a9fd7fe9e80956a27bf13
7
+ data.tar.gz: 26a104211a55761bf40ae03269cdc8c2dd66c68875466c44c48a371061a1263451204910dfa0482414b34dd9c2aee49d356f66e3148ca4100a2406872e7aa5af
data/.gitignore CHANGED
@@ -14,3 +14,7 @@
14
14
 
15
15
  # rspec failure tracking
16
16
  .rspec_status
17
+
18
+ # version control
19
+ .tool-versions
20
+ .idea
@@ -11,19 +11,14 @@ Layout/ExtraSpacing:
11
11
  Exclude:
12
12
  - 'bin/*'
13
13
 
14
- Layout/IndentFirstArgument:
15
- EnforcedStyle: consistent
16
-
17
- Layout/IndentFirstArrayElement:
18
- EnforcedStyle: consistent
19
-
20
14
  Layout/MultilineMethodCallIndentation:
21
15
  EnforcedStyle: indented
22
16
 
23
17
  Metrics/AbcSize:
24
18
  Exclude:
25
- - 'spec/support/twilio_base/responses/twiml.rb'
26
19
  - 'spec/support/twilio_base/fake/helpers.rb'
20
+ - 'spec/support/twilio_base/fake/task_router/worker_statistic.rb'
21
+ - 'spec/support/twilio_base/responses/twiml.rb'
27
22
 
28
23
  Metrics/LineLength:
29
24
  Max: 80
@@ -11,10 +11,14 @@ module TwilioBase
11
11
  phone_number ? find(phone_number) : create
12
12
  end
13
13
 
14
+ def incoming_phone_number_list(**args)
15
+ incoming_phone_numbers.list(args)
16
+ end
17
+
14
18
  private
15
19
 
16
20
  def find(phone_number)
17
- incoming_phone_numbers.list(phone_number: phone_number).first
21
+ incoming_phone_number_list(phone_number: phone_number).first
18
22
  end
19
23
 
20
24
  def create
@@ -52,10 +52,26 @@ module TwilioBase
52
52
  params[:wait_url]
53
53
  end
54
54
 
55
+ def routing_method
56
+ :dial
57
+ end
58
+
59
+ def routing_attributes
60
+ dial_attribues
61
+ end
62
+
55
63
  private
56
64
 
57
65
  attr_accessor :params, :to
58
66
 
67
+ def dial_attribues
68
+ {
69
+ action: action_url,
70
+ caller_id: caller_uuid,
71
+ timeout: timeout
72
+ }
73
+ end
74
+
59
75
  def mpoa
60
76
  extract_mpoa(params[:caller_uuid])
61
77
  end
@@ -4,6 +4,8 @@ module TwilioBase
4
4
  module Protocols
5
5
  module Voice
6
6
  class Sip < Base
7
+ UTU_HEADER_NAME = 'User-to-User'
8
+
7
9
  def endpoint
8
10
  "sip:#{sip_endpoint}?#{parsed_headers}"
9
11
  end
@@ -12,11 +14,22 @@ module TwilioBase
12
14
  :sip
13
15
  end
14
16
 
17
+ def routing_method
18
+ sip_refer_enabled? ? :refer : :dial
19
+ end
20
+
21
+ def routing_attributes
22
+ sip_refer_enabled? ? refer_attribues : dial_attribues
23
+ end
24
+
15
25
  private
16
26
 
17
27
  def parsed_headers
18
28
  hash = headers.each_with_object({}) do |(k, v), obj|
19
- key = "X-#{k.to_s.camelize}"
29
+ key = k.to_s
30
+
31
+ key = "X-#{key}" unless utu_header?(key)
32
+
20
33
  value = v.presence || '-'
21
34
 
22
35
  obj[key] = value
@@ -33,6 +46,14 @@ module TwilioBase
33
46
  sip_whip
34
47
  end
35
48
 
49
+ def sip_refer_enabled?
50
+ params[:sip_refer_enabled]
51
+ end
52
+
53
+ def refer_attribues
54
+ { action: action_url }
55
+ end
56
+
36
57
  def sip_whip
37
58
  @sip_whip ||= sip_endpoints.sample.to_s.strip
38
59
  end
@@ -42,6 +63,10 @@ module TwilioBase
42
63
 
43
64
  value.flat_map { |v| v.split(',') }
44
65
  end
66
+
67
+ def utu_header?(key)
68
+ key == UTU_HEADER_NAME
69
+ end
45
70
  end
46
71
  end
47
72
  end
@@ -6,6 +6,17 @@ module TwilioBase
6
6
  class Base
7
7
  include Rails.application.routes.url_helpers
8
8
 
9
+ delegate :action_url,
10
+ :caller_uuid,
11
+ :endpoint,
12
+ :name,
13
+ :routing_attributes,
14
+ :routing_method,
15
+ :status_callback_events,
16
+ :status_callback_url,
17
+ :timeout,
18
+ to: :protocol
19
+
9
20
  def initialize(protocol:)
10
21
  self.protocol = protocol
11
22
  end
@@ -13,12 +24,14 @@ module TwilioBase
13
24
  def route
14
25
  yield_response = yield if block_given?
15
26
 
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
27
+ vr = yield_response || voice_response
28
+
29
+ vr.public_send(routing_method, routing_attributes) do |router|
30
+ router.public_send(
31
+ name,
32
+ endpoint,
33
+ status_callback_event: status_callback_events,
34
+ status_callback: status_callback_url
22
35
  )
23
36
  end.to_s
24
37
  end
@@ -30,14 +43,6 @@ module TwilioBase
30
43
  def voice_response
31
44
  @voice_response ||= Twilio::TwiML::VoiceResponse.new
32
45
  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
46
  end
42
47
  end
43
48
  end
data/circle.yml CHANGED
@@ -1,17 +1,20 @@
1
1
  version: 2
2
2
  jobs:
3
3
  build:
4
+ working_directory: ~/twilio_base
4
5
  docker:
5
6
  - image: circleci/ruby:2.5.1-node-browsers
6
7
  environment:
7
8
  PGHOST: 127.0.0.1
8
- PGUSER: twilio_base
9
+ PGUSER: postgres
9
10
  RAILS_ENV: test
10
- - image: postgres:9.5
11
+ RACK_ENV: test
12
+
13
+ - image: circleci/postgres:9.6.2-alpine
11
14
  environment:
12
- POSTGRES_USER: twilio_base
15
+ POSTGRES_USER: postgres
13
16
  POSTGRES_DB: twilio_base_test
14
- POSTGRES_PASSWORD: ""
17
+
15
18
  steps:
16
19
  - checkout
17
20
  - run: bundle install
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwilioBase
4
- VERSION = '1.9.0'
4
+ VERSION = '1.11.11'
5
5
  end
@@ -46,4 +46,19 @@ RSpec.describe TwilioBase::PhoneNumber do
46
46
  end
47
47
  end
48
48
  end
49
+
50
+ describe '.incoming_phone_number_list' do
51
+ it 'returns active numbers' do
52
+ phone_numbers = []
53
+ 3.times do
54
+ phone_numbers << TwilioBase::Fake::IncomingPhoneNumber::PhoneNumber.new(
55
+ Faker::PhoneNumber.phone_number
56
+ )
57
+ end
58
+ TwilioBase::Fake::IncomingPhoneNumber.phone_numbers = phone_numbers
59
+
60
+ expect(described_class.incoming_phone_number_list)
61
+ .to match_array(phone_numbers)
62
+ end
63
+ end
49
64
  end
@@ -131,4 +131,39 @@ RSpec.describe TwilioBase::Protocols::Voice::Base do
131
131
  expect(protocol.wait_url).to eq(wait_url)
132
132
  end
133
133
  end
134
+
135
+ describe '#routing_attributes' do
136
+ it 'returns dial attributes' do
137
+ action_url = 'https://example.com'
138
+ caller_uuid = '+1234567890'
139
+ timeout = 1
140
+ sip = described_class.new(
141
+ params: {
142
+ action_url: action_url,
143
+ caller_uuid: caller_uuid,
144
+ timeout: timeout
145
+ },
146
+ to: caller_uuid
147
+ )
148
+
149
+ expected_result = {
150
+ action: action_url,
151
+ caller_id: caller_uuid,
152
+ timeout: timeout
153
+ }
154
+
155
+ expect(sip.routing_attributes).to eq(expected_result)
156
+ end
157
+ end
158
+
159
+ describe '#routing_method' do
160
+ it 'returns dial' do
161
+ sip = described_class.new(
162
+ params: {},
163
+ to: '+1234567890'
164
+ )
165
+
166
+ expect(sip.routing_method).to eq(:dial)
167
+ end
168
+ end
134
169
  end
@@ -24,7 +24,7 @@ RSpec.describe TwilioBase::Protocols::Voice::Sip do
24
24
 
25
25
  sip_headers = build_sip_headers(
26
26
  headers: {
27
- 'X-CallSid' => 'CAsid'
27
+ 'X-call_sid' => 'CAsid'
28
28
  }
29
29
  )
30
30
 
@@ -47,7 +47,7 @@ RSpec.describe TwilioBase::Protocols::Voice::Sip do
47
47
 
48
48
  sip_headers = build_sip_headers(
49
49
  headers: {
50
- 'X-CallSid' => 'CAsid'
50
+ 'X-call_sid' => 'CAsid'
51
51
  }
52
52
  )
53
53
 
@@ -60,7 +60,7 @@ RSpec.describe TwilioBase::Protocols::Voice::Sip do
60
60
  end
61
61
 
62
62
  context 'header has blank value' do
63
- it 'returns -' do
63
+ it 'returns "-" as a value' do
64
64
  endpoint = '3000@127.0.0.1'
65
65
  params = {
66
66
  headers: {
@@ -72,14 +72,58 @@ RSpec.describe TwilioBase::Protocols::Voice::Sip do
72
72
 
73
73
  expected_result = build_sip_headers(
74
74
  headers: {
75
- 'X-BlankValue' => '-',
76
- 'X-CallSid' => 'CAsid'
75
+ 'X-blank_value' => '-',
76
+ 'X-call_sid' => 'CAsid'
77
77
  }
78
78
  )
79
79
 
80
80
  expect(sip.endpoint).to eq("sip:#{endpoint}?#{expected_result}")
81
81
  end
82
82
  end
83
+
84
+ describe 'prefix adding' do
85
+ context 'with UTU header' do
86
+ it 'does not add an X- prefix' do
87
+ endpoint = '3000@127.0.0.1'
88
+ header_name = described_class::UTU_HEADER_NAME
89
+ params = {
90
+ headers: {
91
+ header_name => 'value'
92
+ }
93
+ }
94
+ sip = described_class.new(params: params, to: endpoint)
95
+
96
+ expected_result = build_sip_headers(
97
+ headers: {
98
+ header_name => 'value'
99
+ }
100
+ )
101
+
102
+ expect(sip.endpoint).to eq("sip:#{endpoint}?#{expected_result}")
103
+ end
104
+ end
105
+
106
+ context 'without UTU header' do
107
+ it 'does not add an X- prefix' do
108
+ endpoint = '3000@127.0.0.1'
109
+ header_name = 'random-key'
110
+ params = {
111
+ headers: {
112
+ header_name => 'value'
113
+ }
114
+ }
115
+ sip = described_class.new(params: params, to: endpoint)
116
+
117
+ expected_result = build_sip_headers(
118
+ headers: {
119
+ 'X-random-key' => 'value'
120
+ }
121
+ )
122
+
123
+ expect(sip.endpoint).to eq("sip:#{endpoint}?#{expected_result}")
124
+ end
125
+ end
126
+ end
83
127
  end
84
128
 
85
129
  describe '#name' do
@@ -90,6 +134,73 @@ RSpec.describe TwilioBase::Protocols::Voice::Sip do
90
134
  end
91
135
  end
92
136
 
137
+ describe '#routing_attributes' do
138
+ context 'with sip refer enabled' do
139
+ it 'returns refer attributes' do
140
+ action_url = 'https://example.com'
141
+ sip = described_class.new(
142
+ params: {
143
+ action_url: action_url,
144
+ sip_refer_enabled: true
145
+ },
146
+ to: '+1234567890'
147
+ )
148
+
149
+ expected_result = { action: action_url }
150
+ expect(sip.routing_attributes).to eq(expected_result)
151
+ end
152
+ end
153
+
154
+ context 'with sip refer disabled' do
155
+ it 'returns dial attributes' do
156
+ action_url = 'https://example.com'
157
+ caller_uuid = '+1234567890'
158
+ timeout = 1
159
+ sip = described_class.new(
160
+ params: {
161
+ action_url: action_url,
162
+ caller_uuid: caller_uuid,
163
+ sip_refer_enabled: false,
164
+ timeout: timeout
165
+ },
166
+ to: caller_uuid
167
+ )
168
+
169
+ expected_result = {
170
+ action: action_url,
171
+ caller_id: caller_uuid,
172
+ timeout: timeout
173
+ }
174
+
175
+ expect(sip.routing_attributes).to eq(expected_result)
176
+ end
177
+ end
178
+ end
179
+
180
+ describe '#routing_method' do
181
+ context 'with sip refer enabled' do
182
+ it 'returns refer' do
183
+ sip = described_class.new(
184
+ params: { sip_refer_enabled: true },
185
+ to: '+1234567890'
186
+ )
187
+
188
+ expect(sip.routing_method).to eq(:refer)
189
+ end
190
+ end
191
+
192
+ context 'with sip refer disabled' do
193
+ it 'returns dial' do
194
+ sip = described_class.new(
195
+ params: { sip_refer_enabled: false },
196
+ to: '+1234567890'
197
+ )
198
+
199
+ expect(sip.routing_method).to eq(:dial)
200
+ end
201
+ end
202
+ end
203
+
93
204
  def build_sip_headers(headers: {})
94
205
  Addressable::URI.new(query_values: headers).query
95
206
  end
@@ -62,29 +62,57 @@ RSpec.describe TwilioBase::Routers::Voice::DirectDial do
62
62
  end
63
63
 
64
64
  context 'protocol is Sip' do
65
- it 'returns sip dial Twiml' do
66
- protocol = TwilioBase::Protocols::Voice::Sip.new(
67
- params: {
68
- action_url: 'https://someurl.com',
69
- sip_endpoint: '124@abc.net',
70
- status_callback_url: 'https://somestatusurl.com'
71
- },
72
- to: '+442039605098'
73
- )
74
- direct_dial = described_class.new(protocol: protocol)
65
+ context 'with refer disabled' do
66
+ it 'returns sip dial Twiml' do
67
+ protocol = TwilioBase::Protocols::Voice::Sip.new(
68
+ params: {
69
+ action_url: 'https://someurl.com',
70
+ sip_endpoint: '124@abc.net',
71
+ status_callback_url: 'https://somestatusurl.com'
72
+ },
73
+ to: '+442039605098'
74
+ )
75
+ direct_dial = described_class.new(protocol: protocol)
75
76
 
76
- expected_result = dial_twiml(
77
- params: {
78
- action_url: protocol.action_url,
79
- caller_id: protocol.caller_uuid,
80
- endpoint: protocol.endpoint,
81
- protocol: protocol.name,
82
- status_callback_url: protocol.status_callback_url,
83
- status_callback_events: protocol.status_callback_events
84
- }
85
- )
77
+ expected_result = dial_twiml(
78
+ params: {
79
+ action_url: protocol.action_url,
80
+ caller_id: protocol.caller_uuid,
81
+ endpoint: protocol.endpoint,
82
+ protocol: protocol.name,
83
+ status_callback_url: protocol.status_callback_url,
84
+ status_callback_events: protocol.status_callback_events
85
+ }
86
+ )
86
87
 
87
- expect(direct_dial.route).to eq(expected_result)
88
+ expect(direct_dial.route).to eq(expected_result)
89
+ end
90
+ end
91
+
92
+ context 'with refer enabled' do
93
+ it 'returns sip refer Twiml' do
94
+ protocol = TwilioBase::Protocols::Voice::Sip.new(
95
+ params: {
96
+ action_url: 'https://someurl.com',
97
+ sip_endpoint: '124@abc.net',
98
+ status_callback_url: 'https://somestatusurl.com',
99
+ sip_refer_enabled: true
100
+ },
101
+ to: '+442039605098'
102
+ )
103
+ direct_dial = described_class.new(protocol: protocol)
104
+
105
+ expected_result = refer_twiml(
106
+ params: {
107
+ action_url: protocol.action_url,
108
+ endpoint: protocol.endpoint,
109
+ status_callback_url: protocol.status_callback_url,
110
+ status_callback_events: protocol.status_callback_events
111
+ }
112
+ )
113
+
114
+ expect(direct_dial.route).to eq(expected_result)
115
+ end
88
116
  end
89
117
  end
90
118
  end
@@ -18,6 +18,7 @@ Dir[File.join(__dir__, 'support', '**', '*.rb')].each { |file| require file }
18
18
 
19
19
  require 'bundler/setup'
20
20
  require 'byebug'
21
+ require 'faker'
21
22
  require 'database_cleaner'
22
23
  require 'shoulda/matchers'
23
24
  require 'shoulda/callback/matchers'
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Fake
5
+ class Account
6
+ Account = Struct.new(:sid)
7
+
8
+ cattr_accessor :accounts, :sid
9
+ self.accounts = []
10
+
11
+ def initialize(sid = nil)
12
+ self.sid = sid
13
+ end
14
+
15
+ def fetch
16
+ accounts.detect { |account| account.sid == sid }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -4,9 +4,13 @@ module TwilioBase
4
4
  module Fake
5
5
  module Chat
6
6
  class Channel
7
- Channel = Struct.new(:attributes) do
7
+ Channel = Struct.new(:attrs) do
8
8
  def friendly_name
9
- attributes[:friendly_name]
9
+ attrs[:friendly_name]
10
+ end
11
+
12
+ def attributes
13
+ attrs.dig(:attributes)
10
14
  end
11
15
 
12
16
  def messages
@@ -25,8 +29,8 @@ module TwilioBase
25
29
  TwilioBase::Fake::Chat::Channel.channels.pop
26
30
  end
27
31
 
28
- def update(update_attributes)
29
- attributes.merge! update_attributes
32
+ def update(update_attrs)
33
+ attrs.merge! update_attrs
30
34
  end
31
35
  end
32
36
 
@@ -37,8 +41,8 @@ module TwilioBase
37
41
  self.channel_sid = channel_sid
38
42
  end
39
43
 
40
- def create(attributes)
41
- self.class.channels << Channel.new(attributes)
44
+ def create(attrs)
45
+ self.class.channels << Channel.new(attrs)
42
46
  channels.last
43
47
  end
44
48
 
@@ -19,6 +19,10 @@ module TwilioBase
19
19
  self.class.messages << Message.new(from, to, body)
20
20
  end
21
21
 
22
+ def accounts(sid = nil)
23
+ TwilioBase::Fake::Account.new(sid)
24
+ end
25
+
22
26
  def taskrouter
23
27
  TwilioBase::Fake::TaskRouter::Client.new(nil, nil)
24
28
  end
@@ -5,21 +5,21 @@ module TwilioBase
5
5
  module Sync
6
6
  module Services
7
7
  class Document
8
+ attr_accessor :data, :date_expires, :unique_name
9
+
8
10
  cattr_accessor :documents
9
11
  self.documents = []
10
12
 
11
- def initialize(data: {}, ttl: '', unique_name: '')
13
+ def initialize(data: {}, date_expires: '', unique_name: '')
12
14
  self.data = data
13
- self.ttl = ttl
15
+ self.date_expires = date_expires
14
16
  self.unique_name = unique_name
15
17
  end
16
18
 
17
- attr_accessor :data, :ttl, :unique_name
18
-
19
- def create(data: {}, ttl: '', unique_name: '')
19
+ def create(data: {}, ttl: 0, unique_name: '')
20
20
  document = Document.new(
21
21
  data: data,
22
- ttl: ttl,
22
+ date_expires: Time.current + ttl,
23
23
  unique_name: unique_name
24
24
  )
25
25
  self.class.documents << document
@@ -8,18 +8,18 @@ module TwilioBase
8
8
  cattr_accessor :lists
9
9
  self.lists = []
10
10
 
11
- attr_accessor :data, :ttl, :unique_name
11
+ attr_accessor :data, :date_expires, :unique_name
12
12
 
13
- def initialize(data: {}, ttl: '', unique_name: '')
13
+ def initialize(data: {}, date_expires: '', unique_name: '')
14
14
  self.data = data
15
- self.ttl = ttl
15
+ self.date_expires = date_expires
16
16
  self.unique_name = unique_name
17
17
  end
18
18
 
19
- def create(data: {}, ttl: '', unique_name: '')
19
+ def create(data: {}, ttl: 0, unique_name: '')
20
20
  list = List.new(
21
21
  data: data,
22
- ttl: ttl,
22
+ date_expires: Time.current + ttl,
23
23
  unique_name: unique_name
24
24
  )
25
25
  self.class.lists << list
@@ -9,8 +9,13 @@ module TwilioBase
9
9
  Item = Struct.new(:data) do
10
10
  attr_accessor :sid
11
11
 
12
- def create(data: {})
12
+ def create(data: {}, date_expires: '')
13
13
  self.data = data
14
+ self.date_expires = date_expires
15
+ end
16
+
17
+ def date_expires
18
+ data[:date_expires]
14
19
  end
15
20
  end
16
21
 
@@ -21,9 +26,10 @@ module TwilioBase
21
26
  self.sid = sid
22
27
  end
23
28
 
24
- def create(data: {})
29
+ def create(data: {}, ttl: 0)
25
30
  item = Item.new(
26
- data: data
31
+ data: data,
32
+ date_expires: Time.current + ttl
27
33
  )
28
34
  self.class.items << item
29
35
  item
@@ -8,18 +8,19 @@ module TwilioBase
8
8
  cattr_accessor :maps
9
9
  self.maps = {}
10
10
 
11
- attr_accessor :data, :ttl, :unique_name
11
+ attr_accessor :data, :date_expires, :unique_name, :context
12
12
 
13
- def initialize(data: {}, ttl: '', unique_name: '')
13
+ def initialize(data: {}, date_expires: '', unique_name: '')
14
+ self.context = MapContext.new
14
15
  self.data = data
15
- self.ttl = ttl
16
+ self.date_expires = date_expires
16
17
  self.unique_name = unique_name
17
18
  end
18
19
 
19
- def create(data: {}, ttl: '', unique_name: '')
20
+ def create(data: {}, ttl: 0, unique_name: '')
20
21
  map = Map.new(
21
22
  data: data,
22
- ttl: ttl,
23
+ date_expires: Time.current + ttl,
23
24
  unique_name: unique_name
24
25
  )
25
26
  self.class.maps << map
@@ -37,11 +38,31 @@ module TwilioBase
37
38
  end
38
39
 
39
40
  def maps(unique_name = nil)
40
- Map.new(unique_name || rand(999).to_s)
41
+ Map.new(unique_name: unique_name || rand(999).to_s)
41
42
  end
42
43
 
43
44
  def sync_map_items
44
- Fake::Sync::Services::Maps::Item.new
45
+ context.sync_map_items
46
+ end
47
+ end
48
+
49
+ class MapContext
50
+ def sync_map_items(key = :unset)
51
+ if key.nil?
52
+ raise(ArgumentError, 'key cannot be nil')
53
+ end
54
+
55
+ if key == :unset
56
+ item_klass.items
57
+ else
58
+ item_klass.find_or_create(key)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def item_klass
65
+ Fake::Sync::Services::Maps::Item
45
66
  end
46
67
  end
47
68
  end
@@ -6,35 +6,72 @@ module TwilioBase
6
6
  module Services
7
7
  module Maps
8
8
  class Item
9
- Map = Struct.new(:data, :key) do
9
+ Map = Struct.new(:data, :date_expires, :key) do
10
10
  attr_accessor :sid
11
11
 
12
- def create(data: {}, key: '')
12
+ def create(data: {}, date_expires: '', key: '')
13
13
  self.data = data
14
+ self.date_expires = date_expires
14
15
  self.key = key
15
16
  end
16
17
 
17
- def update(data: {})
18
+ def update(data: {}, ttl: 0)
19
+ if self.data.empty?
20
+ raise(Twilio::REST::RestError, 'Unable to update record')
21
+ end
22
+
18
23
  self.data = data
24
+ self.date_expires = (Time.current + ttl) if ttl
19
25
  end
20
26
  end
21
27
 
22
28
  cattr_accessor :items
23
- self.items = []
29
+ Items = Struct.new(:name) do
30
+ delegate(*[].methods, to: :items)
31
+
32
+ def create(data: {}, date_expires: '', key: '')
33
+ item = Item.find_or_create(key)
34
+ unless item.data.blank?
35
+ raise(Twilio::REST::RestError, 'Unable to create record')
36
+ end
37
+
38
+ item.update(data: data, date_expires: date_expires)
39
+ item
40
+ end
41
+
42
+ def items
43
+ @items ||= []
44
+ end
45
+ end
46
+
47
+ self.items = Items.new(name: 'SyncItemListMock')
24
48
 
25
49
  def initialize(sid = nil)
26
50
  self.sid = sid
27
51
  end
28
52
 
29
- def create(data: {}, key: '')
53
+ def create(data: {}, ttl: 0, key: '')
30
54
  item = Map.new(
31
55
  data: data,
56
+ date_expires: Time.current + ttl,
32
57
  key: key
33
58
  )
34
59
  self.class.items << item
60
+ item.key = key
35
61
  item
36
62
  end
37
63
 
64
+ class << self
65
+ def find_or_create(key)
66
+ items.select { |item| item.key == key }.first ||
67
+ new.create(key: key)
68
+ end
69
+
70
+ def items=(value)
71
+ items.items = Array(value)
72
+ end
73
+ end
74
+
38
75
  private
39
76
 
40
77
  attr_accessor :sid
@@ -55,6 +55,10 @@ module TwilioBase
55
55
  self
56
56
  end
57
57
 
58
+ def statistics
59
+ Fake::TaskRouter::WorkerStatistic.new(list)
60
+ end
61
+
58
62
  def worker_channels(name = nil)
59
63
  Channel.new(name)
60
64
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwilioBase
4
+ module Fake
5
+ module TaskRouter
6
+ class WorkerStatistic
7
+ cattr_accessor :attributes
8
+
9
+ WorkerStatistic = Struct.new(:attributes) do
10
+ def realtime
11
+ activities = attributes.map do |a|
12
+ { activity: a.activity_name, sid: a.sid }
13
+ end.uniq
14
+
15
+ statistics = []
16
+
17
+ activities.each do |a|
18
+ stats = {}
19
+ stats[:friendly_name] = a[:activity]
20
+ stats[:sid] = a[:sid]
21
+ stats[:workers] = attributes.select do |w|
22
+ w.activity_name == a[:activity]
23
+ end.length
24
+
25
+ statistics << stats
26
+ end
27
+
28
+ {
29
+ total_workers: attributes.length,
30
+ activity_statistics: statistics
31
+ }
32
+ end
33
+ end
34
+
35
+ def initialize(attributes = {})
36
+ self.attributes = attributes
37
+ end
38
+
39
+ def statistics
40
+ @statistics ||= WorkerStatistic.new(attributes)
41
+ end
42
+
43
+ def fetch
44
+ statistics
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -24,6 +24,17 @@ module TwilioBase
24
24
  "\n</Dial>\n" \
25
25
  "</Response>\n"
26
26
  end
27
+
28
+ def refer_twiml(params: {})
29
+ vr = Twilio::TwiML::VoiceResponse.new
30
+ vr.refer(action: params[:action_url]) do |refer|
31
+ refer.sip(
32
+ params[:endpoint],
33
+ status_callback: params[:status_callback_url],
34
+ status_callback_event: params[:status_callback_events]
35
+ )
36
+ end.to_s
37
+ end
27
38
  end
28
39
  end
29
40
  end
@@ -9,5 +9,5 @@ development:
9
9
  <<: *default
10
10
 
11
11
  test:
12
- database: twilio_base_development
12
+ database: twilio_base_test
13
13
  <<: *default
@@ -26,12 +26,13 @@ Gem::Specification.new do |spec|
26
26
  spec.require_paths = ['lib']
27
27
 
28
28
  spec.add_dependency 'addressable', '~> 2.5.2'
29
- spec.add_dependency 'twilio-ruby', '~> 5.26.0'
29
+ spec.add_dependency 'twilio-ruby', '~> 5.39.3'
30
30
 
31
31
  spec.add_development_dependency 'bundler'
32
32
  spec.add_development_dependency 'byebug', '9.0.6'
33
33
  spec.add_development_dependency 'database_cleaner', '1.6.1'
34
34
  spec.add_development_dependency 'factory_bot_rails'
35
+ spec.add_development_dependency 'faker'
35
36
  spec.add_development_dependency 'generator_spec'
36
37
  spec.add_development_dependency 'listen'
37
38
  spec.add_development_dependency 'pg', '0.20.0'
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twilio_base
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.11.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Brown
8
8
  - Vania Ermakovets
9
9
  - Ilya Umanets
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2019-11-06 00:00:00.000000000 Z
13
+ date: 2020-09-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable
@@ -32,14 +32,14 @@ dependencies:
32
32
  requirements:
33
33
  - - "~>"
34
34
  - !ruby/object:Gem::Version
35
- version: 5.26.0
35
+ version: 5.39.3
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
- version: 5.26.0
42
+ version: 5.39.3
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: bundler
45
45
  requirement: !ruby/object:Gem::Requirement
@@ -96,6 +96,20 @@ dependencies:
96
96
  - - ">="
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
+ - !ruby/object:Gem::Dependency
100
+ name: faker
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
99
113
  - !ruby/object:Gem::Dependency
100
114
  name: generator_spec
101
115
  requirement: !ruby/object:Gem::Requirement
@@ -236,7 +250,7 @@ dependencies:
236
250
  - - ">="
237
251
  - !ruby/object:Gem::Version
238
252
  version: '0'
239
- description:
253
+ description:
240
254
  email:
241
255
  - richard@dvelp.co.uk
242
256
  executables: []
@@ -247,7 +261,6 @@ files:
247
261
  - ".rspec"
248
262
  - ".rubocop.yml"
249
263
  - ".ruby-version"
250
- - ".tool-versions"
251
264
  - Gemfile
252
265
  - LICENSE.txt
253
266
  - README.md
@@ -327,6 +340,7 @@ files:
327
340
  - spec/support/factory_bot.rb
328
341
  - spec/support/shared_contexts/global_config.rb
329
342
  - spec/support/shared_contexts/twilio_controller.rb
343
+ - spec/support/twilio_base/fake/account.rb
330
344
  - spec/support/twilio_base/fake/api_key.rb
331
345
  - spec/support/twilio_base/fake/application.rb
332
346
  - spec/support/twilio_base/fake/available_phone_number.rb
@@ -364,6 +378,7 @@ files:
364
378
  - spec/support/twilio_base/fake/task_router/task.rb
365
379
  - spec/support/twilio_base/fake/task_router/task_queue.rb
366
380
  - spec/support/twilio_base/fake/task_router/worker.rb
381
+ - spec/support/twilio_base/fake/task_router/worker_statistic.rb
367
382
  - spec/support/twilio_base/fake/task_router/workflow.rb
368
383
  - spec/support/twilio_base/fake/task_router/workspace.rb
369
384
  - spec/support/twilio_base/fake/voice_call.rb
@@ -422,11 +437,11 @@ files:
422
437
  - spec/twilio_base_dummy/vendor/assets/stylesheets/.keep
423
438
  - spec/twilio_base_spec.rb
424
439
  - twilio_base.gemspec
425
- homepage:
440
+ homepage:
426
441
  licenses: []
427
442
  metadata:
428
443
  allowed_push_host: https://rubygems.org
429
- post_install_message:
444
+ post_install_message:
430
445
  rdoc_options: []
431
446
  require_paths:
432
447
  - lib
@@ -441,9 +456,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
441
456
  - !ruby/object:Gem::Version
442
457
  version: '0'
443
458
  requirements: []
444
- rubyforge_project:
445
- rubygems_version: 2.7.6
446
- signing_key:
459
+ rubygems_version: 3.0.8
460
+ signing_key:
447
461
  specification_version: 4
448
462
  summary: It provides twilio logic
449
463
  test_files:
@@ -487,6 +501,7 @@ test_files:
487
501
  - spec/support/factory_bot.rb
488
502
  - spec/support/shared_contexts/global_config.rb
489
503
  - spec/support/shared_contexts/twilio_controller.rb
504
+ - spec/support/twilio_base/fake/account.rb
490
505
  - spec/support/twilio_base/fake/api_key.rb
491
506
  - spec/support/twilio_base/fake/application.rb
492
507
  - spec/support/twilio_base/fake/available_phone_number.rb
@@ -524,6 +539,7 @@ test_files:
524
539
  - spec/support/twilio_base/fake/task_router/task.rb
525
540
  - spec/support/twilio_base/fake/task_router/task_queue.rb
526
541
  - spec/support/twilio_base/fake/task_router/worker.rb
542
+ - spec/support/twilio_base/fake/task_router/worker_statistic.rb
527
543
  - spec/support/twilio_base/fake/task_router/workflow.rb
528
544
  - spec/support/twilio_base/fake/task_router/workspace.rb
529
545
  - spec/support/twilio_base/fake/voice_call.rb
@@ -1 +0,0 @@
1
- ruby 2.5.1