mock-twilio 0.1.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile +3 -0
- data/README.md +19 -7
- data/Rakefile +1 -0
- data/lib/mock/twilio/client.rb +1 -1
- data/lib/mock/twilio/decorator.rb +11 -2
- data/lib/mock/twilio/decorators/api_2010/calls.rb +55 -0
- data/lib/mock/twilio/decorators/api_2010/conferences_participants_create.rb +38 -0
- data/lib/mock/twilio/decorators/api_2010/conferences_participants_update.rb +38 -0
- data/lib/mock/twilio/decorators/api_2010/messages.rb +44 -0
- data/lib/mock/twilio/schemas/api_2010.rb +23 -15
- data/lib/mock/twilio/schemas/messaging_v1.rb +1 -1
- data/lib/mock/twilio/util/configuration.rb +27 -0
- data/lib/mock/twilio/version.rb +1 -1
- data/lib/mock/twilio/webhook_client.rb +45 -0
- data/lib/mock/twilio/webhooks/base.rb +37 -0
- data/lib/mock/twilio/webhooks/call_status_updates.rb +78 -0
- data/lib/mock/twilio/webhooks/calls.rb +74 -0
- data/lib/mock/twilio/webhooks/conferences.rb +53 -0
- data/lib/mock/twilio/webhooks/messages.rb +38 -0
- data/lib/mock/twilio.rb +23 -3
- metadata +62 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2832d75e6a41828ad36e39908bc9316a8d851ced711843a9ec3142e46ac65a04
|
4
|
+
data.tar.gz: d20f52b78ef3d357e1210100b874ab08e35429993ee3c7499077267e40f25733
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73a12decb37e2c63b6ab66d2d74fa49d9a281bd8a4391ed321a44f4dfb83ae81946a80e1d26f18903185e5393267714184bab959d8b073dd52d2dd8196aed0d1
|
7
|
+
data.tar.gz: cbdabf698e265893034d10ff001d7ae01ca035e8da18af469b1fbb9c399425e509bc3d49be40c6cb72b418ea86dc53f2336cc8cc75dce4cc6ecc2e262912a84c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.3.0] - 2024-06-24
|
2
|
+
- Support Calls service
|
3
|
+
- Support Conferences service
|
4
|
+
- Support Webhooks CallStatusUpdates, Conferences and Calls
|
5
|
+
|
6
|
+
## [0.2.0] - 2024-06-09
|
7
|
+
- Support MessageSid SMS and MMS
|
8
|
+
- Support Webhooks::Messages SMS and MMS
|
9
|
+
|
1
10
|
## [0.1.0] - 2024-05-29
|
2
11
|
|
3
12
|
- Initial release
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,19 +1,15 @@
|
|
1
1
|
## Mock::Twilio::Client
|
2
|
+
[](https://badge.fury.io/rb/mock-twilio)
|
3
|
+

|
2
4
|
|
3
5
|
This is a SchoolStatus implementation to mock twilio client to perform requests to [twilio-oai](https://github.com/twilio/twilio-oai)
|
4
6
|
|
5
7
|
|
6
8
|
# Installation
|
7
9
|
|
8
|
-
To install using
|
10
|
+
To install using bundler grab the latest stable version:
|
9
11
|
|
10
12
|
```ruby
|
11
|
-
gem 'mock-twilio', '~> 0.1.0'
|
12
|
-
```
|
13
|
-
|
14
|
-
To manually install `twilio-ruby` via [Rubygems][rubygems] simply gem install:
|
15
|
-
|
16
|
-
```bash
|
17
13
|
gem install mock-twilio
|
18
14
|
```
|
19
15
|
|
@@ -31,7 +27,18 @@ OR
|
|
31
27
|
- `proxy_protocol = http`
|
32
28
|
|
33
29
|
## How to use
|
30
|
+
Initializer sample
|
31
|
+
```ruby
|
32
|
+
Mock::Twilio.configure do |config|
|
33
|
+
config.host = "http://shunkan-ido-service"
|
34
|
+
config.forwarded_host = "shunkan-ido-service"
|
35
|
+
config.port = "3000"
|
36
|
+
config.proto = "http"
|
37
|
+
end
|
34
38
|
|
39
|
+
```
|
40
|
+
|
41
|
+
Example
|
35
42
|
```ruby
|
36
43
|
export TWILIO_ACCOUNT_SID=ACFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
37
44
|
export TWILIO_API_KEY=SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
@@ -42,6 +49,11 @@ client = Twilio::REST::Client.new(nil, nil, nil, nil, mock_client)
|
|
42
49
|
client.messages.create(to: "+593978613041", body: "RB This is the ship that made the Kesssssel Run in fourteen parsecs?", from: "+13212855389")
|
43
50
|
```
|
44
51
|
|
52
|
+
## Run tests
|
53
|
+
```unix
|
54
|
+
rake test
|
55
|
+
```
|
56
|
+
|
45
57
|
## Swagger - OpenApi Issues
|
46
58
|
|
47
59
|
- Array and Boolean validations due open api formats, ie params as `status_callback_event`, `early_media`. Validations removed for them on json files.
|
data/Rakefile
CHANGED
data/lib/mock/twilio/client.rb
CHANGED
@@ -7,7 +7,7 @@ module Mock
|
|
7
7
|
# client.messages.create(to: "+593978613041", body: "RB This is the ship that made the Kesssssel Run in fourteen parsecs?", from: "+13212855389")
|
8
8
|
class Client
|
9
9
|
attr_accessor :adapter
|
10
|
-
attr_reader :timeout, :last_response, :last_request
|
10
|
+
attr_reader :timeout, :last_response, :last_request, :proxy_addr, :proxy_port, :proxy_prot
|
11
11
|
|
12
12
|
def initialize(proxy_prot = nil, proxy_addr = nil, proxy_port = nil, timeout: nil)
|
13
13
|
@proxy_prot = proxy_prot || 'http'
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "schemas/api_2010"
|
4
|
+
require_relative "schemas/messaging_v1"
|
5
|
+
|
3
6
|
module Mock
|
4
7
|
module Twilio
|
5
8
|
class Decorator
|
@@ -11,9 +14,15 @@ module Mock
|
|
11
14
|
class << self
|
12
15
|
def call(body, request)
|
13
16
|
body = JSON.parse(body)
|
17
|
+
|
18
|
+
case body["status"]
|
19
|
+
when 400..600
|
20
|
+
return body
|
21
|
+
end
|
22
|
+
|
14
23
|
schema = url_from(body, request)
|
15
|
-
# return body
|
16
|
-
return ENDPOINTS[schema].
|
24
|
+
# return body decorate if needed
|
25
|
+
return ENDPOINTS[schema].for(body, request) if schema
|
17
26
|
|
18
27
|
body
|
19
28
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Decorators
|
6
|
+
module Api2010
|
7
|
+
class Calls
|
8
|
+
class << self
|
9
|
+
def decorate(body, request)
|
10
|
+
body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
|
11
|
+
body["date_sent"] = Time.current.rfc2822 if body["date_sent"]
|
12
|
+
body["date_created"] = Time.current.rfc2822 if body["date_created"]
|
13
|
+
body["start_time"] = Time.current.rfc2822 if body["start_time"]
|
14
|
+
body["end_time"] = Time.current.rfc2822 if body["end_time"]
|
15
|
+
|
16
|
+
call_sid(body, request) if body["sid"]
|
17
|
+
phone_number_sid(body, request) if body["phone_number_sid"]
|
18
|
+
body["direction"] = "outbound-api" if body["direction"]
|
19
|
+
body["api_version"] = "2010-04-01" if body["api_version"]
|
20
|
+
body["to"] = request.data['To'] if body["to"]
|
21
|
+
body["from"] = request.data['From'] if body["from"]
|
22
|
+
|
23
|
+
body
|
24
|
+
end
|
25
|
+
|
26
|
+
def call_sid(body, request)
|
27
|
+
prefix = "CA"
|
28
|
+
sid = prefix + SecureRandom.hex(16)
|
29
|
+
scheduler = Rufus::Scheduler.new
|
30
|
+
scheduler.in '2s' do
|
31
|
+
conference_uuid = request.data["Url"].split("conference_uuid=").last
|
32
|
+
response = Mock::Twilio::Webhooks::CallStatusUpdates.trigger(sid, conference_uuid)
|
33
|
+
|
34
|
+
conference_response = if response.status == 200
|
35
|
+
twiMl_xml = Nokogiri::XML response.body
|
36
|
+
friendly_name = twiMl_xml.at_xpath('//Dial').at_xpath('//Conference').children.text
|
37
|
+
Mock::Twilio::Webhooks::Conferences.trigger(friendly_name)
|
38
|
+
end
|
39
|
+
|
40
|
+
Mock::Twilio::Webhooks::Calls.trigger(sid) if conference_response.status == 200
|
41
|
+
end
|
42
|
+
body["sid"] = sid
|
43
|
+
end
|
44
|
+
|
45
|
+
def phone_number_sid(body, request)
|
46
|
+
prefix = "PN"
|
47
|
+
sid = prefix + SecureRandom.hex(16)
|
48
|
+
body["phone_number_sid"] = sid
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Decorators
|
6
|
+
module Api2010
|
7
|
+
class ConferencesParticipantsCreate
|
8
|
+
class << self
|
9
|
+
def decorate(body, request)
|
10
|
+
body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
|
11
|
+
body["date_created"] = Time.current.rfc2822 if body["date_created"]
|
12
|
+
body["account_sid"] = ::Twilio.account_sid if body["account_sid"]
|
13
|
+
body["label"] = "Mock Customer" if body["label"]
|
14
|
+
body["status"] = "initiated" if body["status"]
|
15
|
+
|
16
|
+
parse_call_sid(body, request) if body["call_sid"]
|
17
|
+
parse_conference_sid(body, request) if body["conference_sid"]
|
18
|
+
|
19
|
+
body
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_call_sid(body, request)
|
23
|
+
prefix = "CA"
|
24
|
+
call_sid = prefix + SecureRandom.hex(16)
|
25
|
+
body["call_sid"] = call_sid
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_conference_sid(body, request)
|
29
|
+
uri = URI(request.url)
|
30
|
+
conference_sid = uri.path.split('/')[5]
|
31
|
+
body["conference_sid"] = conference_sid
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Decorators
|
6
|
+
module Api2010
|
7
|
+
class ConferencesParticipantsUpdate
|
8
|
+
class << self
|
9
|
+
def decorate(body, request)
|
10
|
+
body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
|
11
|
+
body["date_created"] = Time.current.rfc2822 if body["date_created"]
|
12
|
+
body["account_sid"] = ::Twilio.account_sid if body["account_sid"]
|
13
|
+
body["label"] = "Mock Customer" if body["label"]
|
14
|
+
body["status"] = "complete" if body["status"]
|
15
|
+
|
16
|
+
parse_call_sid(body, request) if body["call_sid"]
|
17
|
+
parse_conference_sid(body, request) if body["conference_sid"]
|
18
|
+
|
19
|
+
body
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_call_sid(body, request)
|
23
|
+
uri = URI(request.url)
|
24
|
+
call_sid = uri.path.split('/')[7].split('.').first
|
25
|
+
body["call_sid"] = call_sid
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_conference_sid(body, request)
|
29
|
+
uri = URI(request.url)
|
30
|
+
conference_sid = uri.path.split('/')[5]
|
31
|
+
body["conference_sid"] = conference_sid
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Decorators
|
6
|
+
module Api2010
|
7
|
+
class Messages
|
8
|
+
class << self
|
9
|
+
def decorate(body, request)
|
10
|
+
body["date_updated"] = Time.current.rfc2822 if body["date_updated"]
|
11
|
+
body["date_sent"] = Time.current.rfc2822 if body["date_sent"]
|
12
|
+
body["date_created"] = Time.current.rfc2822 if body["date_created"]
|
13
|
+
body["start_time"] = Time.current.rfc2822 if body["start_time"]
|
14
|
+
body["end_time"] = Time.current.rfc2822 if body["end_time"]
|
15
|
+
|
16
|
+
message_sid(body, request) if body["sid"]
|
17
|
+
pagination(body) if body["available_phone_numbers"]
|
18
|
+
|
19
|
+
body
|
20
|
+
end
|
21
|
+
|
22
|
+
def pagination(body)
|
23
|
+
# Params returned in mock_server but not on real twilio request for the moment.
|
24
|
+
# Not needed for us now.
|
25
|
+
PAGES_KEYS.each do |key|
|
26
|
+
body.delete(key) if body[key]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def message_sid(body, request)
|
31
|
+
prefix = request.data["MediaUrl"] ? "MM" : "SM"
|
32
|
+
sid = prefix + SecureRandom.hex(16)
|
33
|
+
scheduler = Rufus::Scheduler.new
|
34
|
+
scheduler.in '2s' do
|
35
|
+
Mock::Twilio::Webhooks::Messages.trigger(sid)
|
36
|
+
end
|
37
|
+
body["sid"] = sid
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,10 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../decorators/api_2010/messages"
|
4
|
+
require_relative "../decorators/api_2010/calls"
|
5
|
+
require_relative "../decorators/api_2010/conferences_participants_update"
|
6
|
+
require_relative "../decorators/api_2010/conferences_participants_create"
|
7
|
+
|
3
8
|
module Mock
|
4
9
|
module Twilio
|
5
10
|
module Schemas
|
6
11
|
class Api2010
|
7
12
|
class << self
|
13
|
+
RESOURCES = {
|
14
|
+
messages: Mock::Twilio::Decorators::Api2010::Messages,
|
15
|
+
calls: Mock::Twilio::Decorators::Api2010::Calls,
|
16
|
+
conferences_participants_update: Mock::Twilio::Decorators::Api2010::ConferencesParticipantsUpdate,
|
17
|
+
conferences_participants_create: Mock::Twilio::Decorators::Api2010::ConferencesParticipantsCreate,
|
18
|
+
}
|
19
|
+
|
8
20
|
PAGES_KEYS = [
|
9
21
|
"end",
|
10
22
|
"first_page_uri",
|
@@ -19,22 +31,18 @@ module Mock
|
|
19
31
|
"uri"
|
20
32
|
].freeze
|
21
33
|
|
22
|
-
def
|
23
|
-
|
24
|
-
body["date_sent"] = Time.current.rfc2822 if body["date_sent"]
|
25
|
-
body["date_created"] = Time.current.rfc2822 if body["date_created"]
|
26
|
-
body["start_time"] = Time.current.rfc2822 if body["start_time"]
|
27
|
-
body["end_time"] = Time.current.rfc2822 if body["end_time"]
|
28
|
-
|
29
|
-
pagination(body) if body["available_phone_numbers"]
|
30
|
-
body
|
31
|
-
end
|
34
|
+
def for(body, request)
|
35
|
+
url = request.url.split(request.host).last
|
32
36
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
case url
|
38
|
+
when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Messages.json}
|
39
|
+
RESOURCES[:messages].decorate(body, request)
|
40
|
+
when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Calls.json}
|
41
|
+
RESOURCES[:calls].decorate(body, request)
|
42
|
+
when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Conferences/[A-Za-z0-9]+/Participants/[A-Za-z0-9]+.json}
|
43
|
+
RESOURCES[:conferences_participants_update].decorate(body, request)
|
44
|
+
when %r{\/2010-04-01/Accounts/[A-Za-z0-9]+/Conferences/[A-Za-z0-9]+/Participants.json}
|
45
|
+
RESOURCES[:conferences_participants_create].decorate(body, request)
|
38
46
|
end
|
39
47
|
end
|
40
48
|
end
|
@@ -5,7 +5,7 @@ module Mock
|
|
5
5
|
module Schemas
|
6
6
|
class MessagingV1
|
7
7
|
class << self
|
8
|
-
def decorate(body)
|
8
|
+
def decorate(body, request)
|
9
9
|
# Params for twilio pagination, needed for twilio-ruby serializers and absolute paths
|
10
10
|
body["meta"]["key"] = "phone_numbers" if body["meta"]
|
11
11
|
body["meta"]["page_size"] = 20 if body["meta"]
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Util
|
6
|
+
class Configuration
|
7
|
+
attr_accessor :host, :forwarded_host, :port, :proto
|
8
|
+
|
9
|
+
def host=(value)
|
10
|
+
@host = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def forwarded_host=(value)
|
14
|
+
@forwarded_host = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def port=(value)
|
18
|
+
@port = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def proto=(value)
|
22
|
+
@proto = value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/mock/twilio/version.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
class WebhooksClient
|
6
|
+
attr_accessor :adapter
|
7
|
+
attr_reader :timeout, :last_request
|
8
|
+
|
9
|
+
def initialize(timeout: nil)
|
10
|
+
@timeout = timeout
|
11
|
+
@adapter = Faraday.default_adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
def _request(request)
|
15
|
+
@connection = Faraday.new(url: request.host + ":" + request.port.to_s, ssl: { verify: true }) do |f|
|
16
|
+
f.options.params_encoder = Faraday::FlatParamsEncoder
|
17
|
+
f.request :url_encoded
|
18
|
+
f.adapter @adapter
|
19
|
+
f.headers = request.headers
|
20
|
+
f.request(:authorization, :basic, request.auth[0], request.auth[1])
|
21
|
+
|
22
|
+
f.options.open_timeout = request.timeout || @timeout
|
23
|
+
f.options.timeout = request.timeout || @timeout
|
24
|
+
end
|
25
|
+
|
26
|
+
response = @connection.send(request.method.downcase.to_sym,
|
27
|
+
request.url,
|
28
|
+
request.method == "GET" ? request.params : request.data)
|
29
|
+
|
30
|
+
if response.body && !response.body.empty?
|
31
|
+
object = response.body
|
32
|
+
elsif response.status == 400
|
33
|
+
object = { message: "Bad request", code: 400 }.to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
response
|
37
|
+
end
|
38
|
+
|
39
|
+
def request(host, port, method, url, params = {}, data = {}, headers = {}, auth = nil, timeout = nil)
|
40
|
+
request = ::Twilio::Request.new(host, port, method, url, params, data, headers, auth, timeout)
|
41
|
+
_request(request)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Webhooks
|
6
|
+
class RestError < StandardError
|
7
|
+
end
|
8
|
+
class Base
|
9
|
+
DELAY = [0.5, 0.8]
|
10
|
+
|
11
|
+
def self.build_signature_for_request(request_url, params)
|
12
|
+
validator = ::Twilio::Security::RequestValidator.new(::Twilio.auth_token)
|
13
|
+
validator.build_signature_for(request_url, params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.twilio_client
|
17
|
+
::Twilio::REST::Client.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.webhook_client
|
21
|
+
Mock::Twilio::WebhooksClient.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.auth_twilio
|
25
|
+
[twilio_client.account_sid, twilio_client.auth_token]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.headers
|
29
|
+
{
|
30
|
+
'X-Forwarded-Proto': Mock::Twilio.proto,
|
31
|
+
'Host': Mock::Twilio.forwarded_host
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Webhooks
|
6
|
+
class CallStatusUpdates < Base
|
7
|
+
URL = "/api/v1/twilio_calls/voice_responses"
|
8
|
+
|
9
|
+
def self.trigger(sid, conference_uuid)
|
10
|
+
# Wait simulation from twilio
|
11
|
+
sleep DELAY.sample
|
12
|
+
|
13
|
+
request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
|
14
|
+
|
15
|
+
data = call_status_updates_data(sid, conference_uuid)
|
16
|
+
|
17
|
+
signature = build_signature_for_request(request_url, data)
|
18
|
+
|
19
|
+
response = webhook_client.request(Mock::Twilio.host,
|
20
|
+
Mock::Twilio.port,
|
21
|
+
'POST',
|
22
|
+
URL,
|
23
|
+
nil,
|
24
|
+
data,
|
25
|
+
headers.merge!({ 'X-Twilio-Signature': signature }),
|
26
|
+
auth_twilio,
|
27
|
+
nil)
|
28
|
+
case response.status
|
29
|
+
when 200..204
|
30
|
+
response
|
31
|
+
when 400..600
|
32
|
+
raise Webhooks::RestError, response.body
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.call_status_updates_data(sid, conference_uuid)
|
37
|
+
{
|
38
|
+
:AccountSid=> twilio_client.account_sid,
|
39
|
+
:ApiVersion=> "2010-04-01",
|
40
|
+
:CallbackSource=> "call-progress-events",
|
41
|
+
:CallDuration=> "0",
|
42
|
+
:Called=> "+18222222222",
|
43
|
+
:CalledCity=> "TAMPA",
|
44
|
+
:CalledCountry=> "US",
|
45
|
+
:CalledState=> "FL",
|
46
|
+
:CalledZip=> "33605",
|
47
|
+
:Caller=> "+18111111111",
|
48
|
+
:CallerCity=> "no value",
|
49
|
+
:CallerCountry=> "US",
|
50
|
+
:CallerState=> "CA",
|
51
|
+
:CallerZip=> "no value",
|
52
|
+
:CallSid=> sid,
|
53
|
+
:CallStatus=> "in-progress",
|
54
|
+
:Direction=> "outbound-api",
|
55
|
+
:Duration=> "0",
|
56
|
+
:From=> "+18111111111",
|
57
|
+
:FromCity=> "no value",
|
58
|
+
:FromCountry=> "US",
|
59
|
+
:FromState=> "CA",
|
60
|
+
:FromZip=> "no value",
|
61
|
+
:SequenceNumber=> "2",
|
62
|
+
:SipResponseCode=> "487",
|
63
|
+
:Timestamp=> "2024-06-17 16:49:31 UTC",
|
64
|
+
:To=> "+18222222222",
|
65
|
+
:ToCity=> "TAMPA",
|
66
|
+
:ToCountry=> "US",
|
67
|
+
:ToState=> "FL",
|
68
|
+
:ToZip=> "33605",
|
69
|
+
:StirStatus=> "B",
|
70
|
+
:StirVerstat=> "TN-Validation-Passed-B",
|
71
|
+
:AnsweredBy=> "unknown",
|
72
|
+
:conference_uuid=> conference_uuid
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Webhooks
|
6
|
+
class Calls < Base
|
7
|
+
URL = "/api/v1/twilio_calls/participant_status_changes"
|
8
|
+
|
9
|
+
def self.trigger(sid)
|
10
|
+
# Wait simulation from twilio
|
11
|
+
sleep DELAY.sample
|
12
|
+
|
13
|
+
request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
|
14
|
+
|
15
|
+
data = call_data(sid)
|
16
|
+
|
17
|
+
signature = build_signature_for_request(request_url, data)
|
18
|
+
|
19
|
+
response = webhook_client.request(Mock::Twilio.host,
|
20
|
+
Mock::Twilio.port,
|
21
|
+
'POST',
|
22
|
+
URL,
|
23
|
+
nil,
|
24
|
+
data,
|
25
|
+
headers.merge!({ 'X-Twilio-Signature': signature }),
|
26
|
+
auth_twilio,
|
27
|
+
nil)
|
28
|
+
case response.status
|
29
|
+
when 200..204
|
30
|
+
response
|
31
|
+
when 400..600
|
32
|
+
raise Webhooks::RestError, response.body
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.call_data(sid)
|
37
|
+
{
|
38
|
+
:AccountSid=> twilio_client.account_sid,
|
39
|
+
:ApiVersion=> "2010-04-01",
|
40
|
+
:CallbackSource=> "call-progress-events",
|
41
|
+
:CallDuration=> "0",
|
42
|
+
:Called=> "+18222222222",
|
43
|
+
:CalledCity=> "TAMPA",
|
44
|
+
:CalledCountry=> "US",
|
45
|
+
:CalledState=> "FL",
|
46
|
+
:CalledZip=> "33605",
|
47
|
+
:Caller=> "+18111111111",
|
48
|
+
:CallerCity=> "no value",
|
49
|
+
:CallerCountry=> "US",
|
50
|
+
:CallerState=> "CA",
|
51
|
+
:CallerZip=> "no value",
|
52
|
+
:CallSid=> sid,
|
53
|
+
:CallStatus=> "in-progress",
|
54
|
+
:Direction=> "outbound-api",
|
55
|
+
:Duration=> "0",
|
56
|
+
:From=> "+18111111111",
|
57
|
+
:FromCity=> "no value",
|
58
|
+
:FromCountry=> "US",
|
59
|
+
:FromState=> "CA",
|
60
|
+
:FromZip=> "no value",
|
61
|
+
:SequenceNumber=> "2",
|
62
|
+
:SipResponseCode=> "487",
|
63
|
+
:Timestamp=> "2024-06-17 16:49:31 UTC",
|
64
|
+
:To=> "+18222222222",
|
65
|
+
:ToCity=> "TAMPA",
|
66
|
+
:ToCountry=> "US",
|
67
|
+
:ToState=> "FL",
|
68
|
+
:ToZip=> "33605"
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Webhooks
|
6
|
+
class Conferences < Base
|
7
|
+
URL = "/api/v1/twilio_calls/conference_status_changes"
|
8
|
+
|
9
|
+
def self.trigger(friendly_name)
|
10
|
+
# Wait simulation from twilio
|
11
|
+
sleep DELAY.sample
|
12
|
+
|
13
|
+
request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
|
14
|
+
|
15
|
+
data = conference_data(friendly_name)
|
16
|
+
|
17
|
+
signature = build_signature_for_request(request_url, data)
|
18
|
+
|
19
|
+
response = webhook_client.request(Mock::Twilio.host,
|
20
|
+
Mock::Twilio.port,
|
21
|
+
'POST',
|
22
|
+
URL,
|
23
|
+
nil,
|
24
|
+
data,
|
25
|
+
headers.merge!({ 'X-Twilio-Signature': signature }),
|
26
|
+
auth_twilio,
|
27
|
+
nil)
|
28
|
+
|
29
|
+
case response.status
|
30
|
+
when 200..204
|
31
|
+
response
|
32
|
+
when 400..600
|
33
|
+
raise Webhooks::RestError, response.body
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.conference_data(friendly_name)
|
38
|
+
prefix = "CF"
|
39
|
+
sid = prefix + SecureRandom.hex(16)
|
40
|
+
{
|
41
|
+
:FriendlyName=> friendly_name,
|
42
|
+
:SequenceNumber=> "6",
|
43
|
+
:ConferenceSid=> sid,
|
44
|
+
:StatusCallbackEvent=> "conference-start",
|
45
|
+
:Timestamp=> "2024-06-17 16:49:31 UTC",
|
46
|
+
:AccountSid=> twilio_client.account_sid,
|
47
|
+
:Reason=> "Participant from mock twilio"
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mock
|
4
|
+
module Twilio
|
5
|
+
module Webhooks
|
6
|
+
class Messages < Base
|
7
|
+
URL = "/api/v1/twilio_requests/webhook_message_updates"
|
8
|
+
|
9
|
+
def self.trigger(sid)
|
10
|
+
# Wait simulation from twilio
|
11
|
+
sleep DELAY.sample
|
12
|
+
|
13
|
+
request_url = Mock::Twilio.proto + "://" + Mock::Twilio.forwarded_host + URL
|
14
|
+
|
15
|
+
data = { :MessageSid=>sid, :MessageStatus=>"delivered" }
|
16
|
+
|
17
|
+
signature = build_signature_for_request(request_url, data)
|
18
|
+
|
19
|
+
response = webhook_client.request(Mock::Twilio.host,
|
20
|
+
Mock::Twilio.port,
|
21
|
+
'POST',
|
22
|
+
URL,
|
23
|
+
nil,
|
24
|
+
data,
|
25
|
+
headers.merge!({ 'X-Twilio-Signature': signature }),
|
26
|
+
auth_twilio,
|
27
|
+
nil)
|
28
|
+
case response.status
|
29
|
+
when 200..204
|
30
|
+
response
|
31
|
+
when 400..600
|
32
|
+
raise Webhooks::RestError, response.body
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/mock/twilio.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rufus-scheduler"
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/core_ext/time"
|
3
6
|
require_relative "twilio/middleware/proxy"
|
4
|
-
require_relative "twilio/
|
5
|
-
require_relative "twilio/
|
7
|
+
require_relative "twilio/webhook_client"
|
8
|
+
require_relative "twilio/webhooks/base"
|
9
|
+
require_relative "twilio/webhooks/messages"
|
10
|
+
require_relative "twilio/webhooks/calls"
|
11
|
+
require_relative "twilio/webhooks/call_status_updates"
|
12
|
+
require_relative "twilio/webhooks/conferences"
|
13
|
+
require_relative "twilio/util/configuration"
|
6
14
|
require_relative "twilio/client"
|
7
15
|
require_relative "twilio/decorator"
|
8
16
|
require_relative "twilio/response"
|
@@ -10,6 +18,18 @@ require_relative "twilio/version"
|
|
10
18
|
|
11
19
|
module Mock
|
12
20
|
module Twilio
|
13
|
-
|
21
|
+
extend SingleForwardable
|
22
|
+
|
23
|
+
def_delegators :configuration, :host, :forwarded_host, :port, :proto
|
24
|
+
|
25
|
+
def self.configure(&block)
|
26
|
+
yield configuration
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.configuration
|
30
|
+
@configuration ||= Util::Configuration.new
|
31
|
+
end
|
32
|
+
|
33
|
+
private_class_method :configuration
|
14
34
|
end
|
15
35
|
end
|
metadata
CHANGED
@@ -1,29 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mock-twilio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SchoolStatus Platform Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-06-
|
11
|
+
date: 2024-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.9.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.9.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rufus-scheduler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.9.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.9.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: twilio-ruby
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 6.7.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 6.7.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 7.1.3.4
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 7.1.3.4
|
27
69
|
description: This repository contains Mock::Twilio::Client for Twilio's API.
|
28
70
|
email:
|
29
71
|
executables: []
|
@@ -38,19 +80,30 @@ files:
|
|
38
80
|
- lib/mock/twilio.rb
|
39
81
|
- lib/mock/twilio/client.rb
|
40
82
|
- lib/mock/twilio/decorator.rb
|
83
|
+
- lib/mock/twilio/decorators/api_2010/calls.rb
|
84
|
+
- lib/mock/twilio/decorators/api_2010/conferences_participants_create.rb
|
85
|
+
- lib/mock/twilio/decorators/api_2010/conferences_participants_update.rb
|
86
|
+
- lib/mock/twilio/decorators/api_2010/messages.rb
|
41
87
|
- lib/mock/twilio/middleware/proxy.rb
|
42
88
|
- lib/mock/twilio/response.rb
|
43
89
|
- lib/mock/twilio/schemas/api_2010.rb
|
44
90
|
- lib/mock/twilio/schemas/messaging_v1.rb
|
91
|
+
- lib/mock/twilio/util/configuration.rb
|
45
92
|
- lib/mock/twilio/version.rb
|
93
|
+
- lib/mock/twilio/webhook_client.rb
|
94
|
+
- lib/mock/twilio/webhooks/base.rb
|
95
|
+
- lib/mock/twilio/webhooks/call_status_updates.rb
|
96
|
+
- lib/mock/twilio/webhooks/calls.rb
|
97
|
+
- lib/mock/twilio/webhooks/conferences.rb
|
98
|
+
- lib/mock/twilio/webhooks/messages.rb
|
46
99
|
- sig/mock/twilio.rbs
|
47
100
|
homepage: https://github.com/schoolstatus/mock-twilio
|
48
101
|
licenses:
|
49
102
|
- MIT
|
50
103
|
metadata:
|
51
104
|
homepage_uri: https://github.com/schoolstatus/mock-twilio
|
52
|
-
source_code_uri: https://github.com/schoolstatus/mock-twilio
|
53
|
-
changelog_uri: https://github.com/schoolstatus/mock-twilio/CHANGELOG.md
|
105
|
+
source_code_uri: https://github.com/schoolstatus/mock-twilio
|
106
|
+
changelog_uri: https://github.com/schoolstatus/mock-twilio/blob/main/CHANGELOG.md
|
54
107
|
post_install_message:
|
55
108
|
rdoc_options: []
|
56
109
|
require_paths:
|
@@ -66,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
119
|
- !ruby/object:Gem::Version
|
67
120
|
version: '0'
|
68
121
|
requirements: []
|
69
|
-
rubygems_version: 3.
|
122
|
+
rubygems_version: 3.5.12
|
70
123
|
signing_key:
|
71
124
|
specification_version: 4
|
72
125
|
summary: This repository contains Mock::Twilio::Client for Twilio's API.
|