sms_broker 1.0.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.
@@ -0,0 +1,82 @@
1
+ module SmsBroker
2
+
3
+ class Setup
4
+
5
+ attr_reader :options,
6
+ :errors
7
+
8
+ def self.service_validation_schemas
9
+ {
10
+ nexmo: Compel.hash.keys({
11
+ key: Compel.string.required,
12
+ secret: Compel.string.required,
13
+ sender_id: Compel.string,
14
+ phone_number: Compel.string.required
15
+ }),
16
+ twilio: Compel.hash.keys({
17
+ sender_id: Compel.string,
18
+ auth_token: Compel.string.required,
19
+ account_sid: Compel.string.required,
20
+ phone_number: Compel.string.required
21
+ })
22
+ }
23
+ end
24
+
25
+ def initialize
26
+ @errors = {}
27
+ @options = {
28
+ services: ['nexmo'],
29
+ default_service: 'nexmo',
30
+ services_setups: {}
31
+ }
32
+ end
33
+
34
+ def services(services)
35
+ @options[:services] = services
36
+ end
37
+
38
+ def default_service(service)
39
+ @options[:default_service] = service
40
+ end
41
+
42
+ def valid?
43
+ result = compel_validation_schema(@options[:services]).validate(@options)
44
+
45
+ @errors = result.errors
46
+
47
+ result.valid?
48
+ end
49
+
50
+ def compel_validation_schema(services_list = [])
51
+ not_all_services_setup = Proc.new do |services_setups|
52
+ services_list.all?{ |service|
53
+ services_setups.keys.include?(service.to_sym)
54
+ }
55
+ end
56
+
57
+ services_setups_schema = \
58
+ Compel.hash.required
59
+ .keys(Setup.service_validation_schemas)
60
+ .if(not_all_services_setup, message: 'all services must be setup')
61
+
62
+ Compel.hash.keys \
63
+ services: Compel.array.required.min_length(1),
64
+ default_service: Compel.string.required.in(services_list),
65
+ services_setups: services_setups_schema
66
+ end
67
+
68
+ def method_missing(method, args, &block)
69
+ service = "#{method}".split('_setup')[0].dup
70
+
71
+ if @options[:services].include?(service)
72
+ @options[:services_setups][service.to_sym] = args
73
+ @options[:services_setups]
74
+ else
75
+
76
+ super
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,5 @@
1
+ module SmsBroker
2
+
3
+ VERSION = '1.0.0'
4
+
5
+ end
data/lib/sms_broker.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'nexmo'
2
+ require 'compel'
3
+ require 'twilio-ruby'
4
+
5
+ require 'sms_broker/client/response/error'
6
+ require 'sms_broker/client/response/success'
7
+
8
+ require 'sms_broker/configuration'
9
+ require 'sms_broker/service'
10
+
11
+ module SmsBroker
12
+
13
+ extend Configuration
14
+
15
+ def service(name = default_service)
16
+ Service.get(name)
17
+ end
18
+
19
+ def message(body)
20
+ service.message(body)
21
+ end
22
+
23
+ extend self
24
+
25
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'sms_broker/version'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = 'sms_broker'
9
+ gem.version = SmsBroker::VERSION
10
+ gem.authors = ['Streetbees Dev Team']
11
+ gem.email = ['dev@streetbees.com']
12
+ gem.description = %q{sms_broker}
13
+ gem.summary = %q{Sms Broker}
14
+ gem.homepage = 'https://github.com/streetbees/sms_broker'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ['lib']
20
+
21
+ gem.add_runtime_dependency 'nexmo', '~> 4.2'
22
+ gem.add_runtime_dependency 'compel', '~> 0.5'
23
+ gem.add_runtime_dependency 'twilio-ruby', '~> 4.11'
24
+
25
+ gem.add_development_dependency 'webmock', '~> 2.0'
26
+ gem.add_development_dependency 'rspec', '~> 3.2'
27
+ gem.add_development_dependency 'rake', '~> 0'
28
+ gem.add_development_dependency 'pry', '~> 0'
29
+ end
@@ -0,0 +1,92 @@
1
+ describe SmsBroker do
2
+
3
+ context 'Nexmo' do
4
+
5
+ let(:text_message) { 'Hello World' }
6
+ let(:from_phone) { ENV['NEXMO_PHONE_NUMBER'] }
7
+ let(:api_secret) { ENV['NEXMO_API_SECRET'] }
8
+ let(:sender_id) { ENV['NEXMO_SENDER_ID'] }
9
+ let(:to_phone) { '44741234567' }
10
+ let(:api_key) { ENV['NEXMO_API_SECRET'] }
11
+
12
+ context '#send_message' do
13
+
14
+ before(:each) do
15
+ SmsBroker.clear_setup
16
+ end
17
+
18
+ context 'valid' do
19
+
20
+ it 'should send message with success' do
21
+ SmsBroker.setup do |config|
22
+ config.nexmo_setup \
23
+ phone_number: from_phone,
24
+ sender_id: sender_id,
25
+ secret: api_secret,
26
+ key: ENV['NEXMO_API_KEY']
27
+ end
28
+
29
+ stub_nexmo_create_message_success(sender_id, to_phone, text_message)
30
+
31
+ response = SmsBroker.message(text_message).to(to_phone).deliver
32
+
33
+ expect(response.service).to eq(:nexmo)
34
+ expect(response.success?).to eq(true)
35
+ expect(response.message_id).not_to eq(nil)
36
+ end
37
+
38
+ context 'with sender_id' do
39
+
40
+ it 'should return error for invalid sender_id' do
41
+ SmsBroker.setup do |config|
42
+ config.nexmo_setup \
43
+ phone_number: from_phone,
44
+ sender_id: sender_id,
45
+ secret: api_secret,
46
+ key: ENV['NEXMO_API_KEY']
47
+ end
48
+
49
+ stub_nexmo_create_message_success \
50
+ from_phone, to_phone, text_message
51
+
52
+ stub_nexmo_create_message_invalid_sender_id_request \
53
+ sender_id, to_phone, text_message
54
+
55
+ response = SmsBroker.message(text_message).to(to_phone).deliver
56
+
57
+ expect(response.success?).to eq(true)
58
+ # this means that it tried to send with sender_id and failed
59
+ # and then sent with from_phone
60
+ expect(response.from).to eq(from_phone)
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ context 'invalid' do
68
+
69
+ it 'should return error for invalid credentials' do
70
+ SmsBroker.setup do |config|
71
+ config.nexmo_setup \
72
+ phone_number: from_phone,
73
+ secret: 'invalid',
74
+ key: 'invalid'
75
+ end
76
+
77
+ stub_nexmo_create_message_invalid_credentials \
78
+ from_phone, to_phone, text_message
79
+
80
+ response = SmsBroker.message(text_message).to(to_phone).deliver
81
+
82
+ expect(response.success?).to eq(false)
83
+ expect(response.serialized.length).to be > 0
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,161 @@
1
+ describe SmsBroker do
2
+
3
+ context 'Setup' do
4
+
5
+ before(:each) do
6
+ SmsBroker.clear_setup
7
+ end
8
+
9
+ it 'should set configs' do
10
+ setup = \
11
+ SmsBroker.setup do |config|
12
+ config.services ['nexmo', 'twilio']
13
+
14
+ config.default_service 'nexmo'
15
+
16
+ config.nexmo_setup \
17
+ key: 'NEXMO_API_KEY',
18
+ phone_number: 'phone',
19
+ secret: 'NEXMO_API_KEY'
20
+
21
+ config.twilio_setup \
22
+ phone_number: 'phone',
23
+ account_sid: 'TWILIO_ACCOUNT_SID',
24
+ auth_token: 'TWILIO_AUTH_TOKEN'
25
+ end
26
+
27
+ expect(setup.valid?).to eq(true)
28
+
29
+ expect(setup.options[:services]).to \
30
+ eq(['nexmo', 'twilio'])
31
+
32
+ expect(setup.options[:default_service]).to \
33
+ eq('nexmo')
34
+
35
+ expect(setup.options[:services_setups][:nexmo]).to \
36
+ eq \
37
+ key: 'NEXMO_API_KEY',
38
+ secret: 'NEXMO_API_KEY',
39
+ phone_number: 'phone'
40
+
41
+ expect(setup.options[:services_setups][:twilio]).to \
42
+ eq \
43
+ phone_number: 'phone',
44
+ account_sid: 'TWILIO_ACCOUNT_SID',
45
+ auth_token: 'TWILIO_AUTH_TOKEN'
46
+ end
47
+
48
+ context 'valid configs' do
49
+
50
+ before(:each) do
51
+ SmsBroker.setup do |config|
52
+ config.services ['nexmo', 'twilio']
53
+
54
+ config.default_service 'nexmo'
55
+
56
+ config.nexmo_setup \
57
+ key: 'NEXMO_API_KEY',
58
+ phone_number: 'phone',
59
+ secret: 'NEXMO_API_KEY'
60
+
61
+ config.twilio_setup \
62
+ phone_number: 'phone',
63
+ account_sid: 'TWILIO_ACCOUNT_SID',
64
+ auth_token: 'TWILIO_AUTH_TOKEN'
65
+ end
66
+ end
67
+
68
+ it 'should get default Service' do
69
+ service = SmsBroker.service
70
+
71
+ expect(service.client).to be_a SmsBroker::Client::Nexmo
72
+ end
73
+
74
+ it 'should get custom Service' do
75
+ service = SmsBroker.service(:twilio)
76
+
77
+ expect(service.client).to be_a SmsBroker::Client::Twilio
78
+ end
79
+
80
+ end
81
+
82
+ context 'invalid configs' do
83
+
84
+ it 'should return error about available services' do
85
+ setup = SmsBroker.setup do |config|
86
+ config.services ['nexmo', 'twilio']
87
+
88
+ config.default_service 'nexmo'
89
+ end
90
+
91
+ expect(setup.valid?).to eq(false)
92
+ expect(setup.errors).to eq \
93
+ services_setups: [
94
+ 'all services must be setup'
95
+ ]
96
+ end
97
+
98
+ it 'should return error for not having services' do
99
+ setup = SmsBroker.setup do |config|
100
+ config.services []
101
+ end
102
+
103
+ expect(setup.valid?).to eq(false)
104
+
105
+ expect(setup.errors[:services]).to \
106
+ include('cannot have length less than 1')
107
+ end
108
+
109
+ it 'should return error default_service' do
110
+ setup = SmsBroker.setup do |config|
111
+ config.services ['nexmo', 'twilio']
112
+
113
+ config.default_service 'nope'
114
+ end
115
+
116
+ expect(setup.valid?).to eq(false)
117
+
118
+ expect(setup.errors[:default_service]).to \
119
+ include("must be within [\"nexmo\", \"twilio\"]")
120
+ end
121
+
122
+ context 'setup!' do
123
+
124
+ it 'should raise exception for invalid setup' do
125
+ expect {
126
+ SmsBroker.setup! do |config|
127
+ config.services ['nexmo', 'twilio']
128
+ config.default_service 'nope'
129
+ end
130
+ }.to raise_error(SmsBroker::Exceptions::InvalidSetup)
131
+ end
132
+
133
+ it 'should return error for missing required service setup' do
134
+ expect {
135
+ SmsBroker.setup! do |config|
136
+ config.default_service 'nexmo'
137
+
138
+ config.nexmo_setup \
139
+ not_exists: 'key'
140
+ end
141
+ }.to raise_error(SmsBroker::Exceptions::InvalidSetup)
142
+ end
143
+
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+
150
+ it 'should respond_to :message' do
151
+ expect(SmsBroker.respond_to?(:message)).to eq(true)
152
+ end
153
+
154
+ it 'should raise InvalidSetup for service not being setup' do
155
+ SmsBroker.clear_setup
156
+
157
+ expect{ SmsBroker::Service.get(:twilio) }.to \
158
+ raise_error SmsBroker::Exceptions::InvalidSetup
159
+ end
160
+
161
+ end
@@ -0,0 +1,145 @@
1
+ describe SmsBroker do
2
+
3
+ context 'SmsBroker' do
4
+
5
+ let(:text_message) { 'Hello World' }
6
+
7
+ context 'Invalid data when trying to deliver' do
8
+
9
+ before(:all) do
10
+ SmsBroker.clear_setup
11
+
12
+ SmsBroker.setup do |config|
13
+ config.services ['twilio']
14
+
15
+ config.default_service 'twilio'
16
+
17
+ config.twilio_setup \
18
+ phone_number: '15005550001',
19
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
20
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
21
+ end
22
+ end
23
+
24
+ it 'should return error for missing number' do
25
+ response = SmsBroker.service.message(text_message).to(nil).deliver
26
+
27
+ expect(response.success?).to eq(false)
28
+ expect(response.serialized[:errors][:to]).to include("is required")
29
+ end
30
+
31
+ it 'should return error for missing message' do
32
+ response = SmsBroker.service.message(nil).to(nil).deliver
33
+
34
+ expect(response.success?).to eq(false)
35
+ expect(response.serialized[:errors][:message]).to include("is required")
36
+ end
37
+
38
+ it 'should return error for invalid message' do
39
+ message_160 = "Lorem Ipsum is simply dummy text of the printing and " \
40
+ "typesetting industry. Lorem Ipsum has been the " \
41
+ "industry's standard dummy text ever since the 1500s, when an"
42
+
43
+ response = \
44
+ SmsBroker.service.message(message_160).to('44123457891').deliver
45
+
46
+ expect(response.success?).to eq(false)
47
+ expect(response.serialized[:errors][:message]).to \
48
+ include("cannot have length greater than 140")
49
+ end
50
+
51
+ end
52
+
53
+ context 'Invalid setup when trying to deliver' do
54
+
55
+ before(:all) do
56
+ SmsBroker.clear_setup
57
+
58
+ @setu = SmsBroker.setup do |config|
59
+ config.services ['nexmo']
60
+
61
+ config.default_service 'nexmo'
62
+
63
+ config.nexmo_setup \
64
+ key: ENV['NEXMO_API_KEY'],
65
+ sender_id: ENV['NEXMO_SENDER_ID'],
66
+ phone_number: ENV['NEXMO_PHONE_NUMBER']
67
+ # secret: ENV['NEXMO_API_SECRET']
68
+ end
69
+ end
70
+
71
+ it 'should return error for missing number' do
72
+ expect {
73
+ SmsBroker.service.message(text_message).to('44123457891').deliver
74
+ }.to raise_error SmsBroker::Exceptions::InvalidService
75
+ end
76
+
77
+ end
78
+
79
+ context 'Valid real calls' do
80
+
81
+ before(:all) do
82
+ SmsBroker.clear_setup
83
+
84
+ SmsBroker.setup do |config|
85
+ config.services ['nexmo', 'twilio']
86
+
87
+ config.default_service 'nexmo'
88
+
89
+ config.nexmo_setup \
90
+ key: ENV['NEXMO_API_KEY'],
91
+ secret: ENV['NEXMO_API_SECRET'],
92
+ sender_id: ENV['NEXMO_SENDER_ID'],
93
+ phone_number: ENV['NEXMO_PHONE_NUMBER']
94
+
95
+ config.twilio_setup \
96
+ sender_id: ENV['TWILIO_LIVE_SENDER_ID'],
97
+ auth_token: ENV['TWILIO_LIVE_AUTH_TOKEN'],
98
+ account_sid: ENV['TWILIO_LIVE_ACCOUNT_SID'],
99
+ phone_number: ENV['TWILIO_LIVE_PHONE_NUMBER']
100
+ end
101
+ end
102
+
103
+ before(:all) do
104
+ unless ENV['REAL_PHONE_NUMBER']
105
+ skip "REAL_PHONE_NUMBER env var is required to run this spec"
106
+ end
107
+
108
+ WebMock.allow_net_connect!
109
+ end
110
+
111
+ after(:all) do
112
+ WebMock.disable_net_connect!
113
+ end
114
+
115
+ context 'Nexmo' do
116
+
117
+ it "should successfuly send message" do
118
+ message = \
119
+ SmsBroker.service(:nexmo).message('test').to(ENV['REAL_PHONE_NUMBER'])
120
+
121
+ response = message.deliver
122
+
123
+ expect(response.success?).to eq true
124
+ end
125
+
126
+ end
127
+
128
+ context 'Twillio' do
129
+
130
+ it "should successfuly send message" do
131
+ message = \
132
+ SmsBroker.service(:twilio).message('test').to(ENV['REAL_PHONE_NUMBER'])
133
+
134
+ response = message.deliver
135
+
136
+ expect(response.success?).to eq true
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,122 @@
1
+ describe SmsBroker do
2
+
3
+ context 'Twilio' do
4
+
5
+ context '#send_message' do
6
+
7
+ let(:text_message) { 'Hello World' }
8
+ let(:from_phone) { ENV['TWILIO_PHONE_NUMBER'] }
9
+ let(:sender_id) { ENV['TWILIO_SENDER_ID'] }
10
+
11
+ before(:each) do
12
+ SmsBroker.clear_setup
13
+ end
14
+
15
+ def send_message(text, to)
16
+ WebMock.allow_net_connect!
17
+
18
+ response = SmsBroker.service.message(text).to(to).deliver
19
+
20
+ WebMock.disable_net_connect!
21
+
22
+ response
23
+ end
24
+
25
+ context 'valid' do
26
+
27
+ it 'should send message with success' do
28
+ SmsBroker.setup do |config|
29
+ config.services ['twilio']
30
+
31
+ config.default_service 'twilio'
32
+
33
+ config.twilio_setup \
34
+ phone_number: from_phone,
35
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
36
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
37
+ end
38
+
39
+ response = send_message(text_message, '15005550006')
40
+
41
+ expect(response.service).to eq(:twilio)
42
+ expect(response.success?).to eq(true)
43
+ expect(response.message_id).not_to eq(nil)
44
+ end
45
+
46
+ context 'with sender_id' do
47
+
48
+ before(:each) do
49
+ SmsBroker.setup do |config|
50
+ config.services ['twilio']
51
+
52
+ config.default_service 'twilio'
53
+
54
+ config.twilio_setup \
55
+ phone_number: '15005550001',
56
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
57
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
58
+ end
59
+ end
60
+
61
+ it 'should return error for invalid sender_id' do
62
+ response = send_message(text_message, '15005550006')
63
+
64
+ expect(response.service).to eq(:twilio)
65
+
66
+ expect(response.success?).to eq(false)
67
+
68
+ expect(response.serialized[:errors].keys).to include('21212')
69
+ # if the code is 21212 and message includes the phone_number,
70
+ # it means that it tried with sender_id and failed
71
+ expect(response.serialized[:errors]['21212'][0]).to \
72
+ include("The 'From' number 15005550001 is not a valid")
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+
79
+ context 'invalid' do
80
+
81
+ it 'should return error for missing required data' do
82
+ SmsBroker.setup do |config|
83
+ config.services ['twilio']
84
+
85
+ config.default_service 'twilio'
86
+
87
+ config.twilio_setup \
88
+ phone_number: '15005550001',
89
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
90
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
91
+ end
92
+
93
+ response = SmsBroker.message(text_message).deliver
94
+
95
+ expect(response.serialized[:errors][:to]).to include('is required')
96
+ end
97
+
98
+ it 'should return error for invalid from phone' do
99
+ SmsBroker.setup do |config|
100
+ config.services ['twilio']
101
+
102
+ config.default_service 'twilio'
103
+
104
+ config.twilio_setup \
105
+ phone_number: '15005550001',
106
+ account_sid: ENV['TWILIO_ACCOUNT_SID'],
107
+ auth_token: ENV['TWILIO_AUTH_TOKEN']
108
+ end
109
+
110
+ response = send_message(text_message, '15005550006')
111
+
112
+ expect(response.success?).to eq(false)
113
+ expect(response.serialized.length).to be > 0
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,29 @@
1
+ require 'pry'
2
+ require 'yaml'
3
+ require 'simplecov'
4
+ require 'codeclimate-test-reporter'
5
+
6
+ SimpleCov.start do
7
+ formatter SimpleCov::Formatter::MultiFormatter.new [
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ CodeClimate::TestReporter::Formatter
10
+ ]
11
+ end
12
+
13
+ # load service_keys.yml to ENV
14
+ yml_file = File.expand_path('../support/services_keys.yml', __FILE__)
15
+
16
+ YAML.load(File.read(yml_file)).each do |key, value|
17
+ ENV[key] = value
18
+ end
19
+
20
+ require 'sms_broker'
21
+ require 'webmock/rspec'
22
+
23
+ require 'support/nexmo_helpers'
24
+
25
+ RSpec.configure do |config|
26
+
27
+ config.include NexmoHelpers
28
+
29
+ end