twilio_base 1.9.0 → 1.11.11

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