mock-twilio 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/mock-twilio.svg)](https://badge.fury.io/rb/mock-twilio)
|
3
|
+
![mock-twilio](https://github.com/schoolstatus/mock-twilio/actions/workflows/ruby.yml/badge.svg)
|
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.
|