mote_sms 1.3.0.rc1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7750e3f3a9303ab306187ab9e35755f7a7fa5abe
4
- data.tar.gz: 1108d8459f1672a55f189cadcb1df22aea9ecb04
3
+ metadata.gz: 1284a153ac39d7eb140b1c735ca4762ab3a80cce
4
+ data.tar.gz: 4067f946a3ea39defa735deb9ed18a0c9840dddb
5
5
  SHA512:
6
- metadata.gz: 4c6133b43af1691dd57eca6043c81419b77021b4dd83e7c1b39324e21f42cb8efeb4e05f3a0ebe34719ac755b79a72b87982c98d3177d1d32bb3d82e5dbd8b67
7
- data.tar.gz: bdba91cfc834a07026afba68f9ad6bdb7bc046a7093db9300e4a3f01be93e474789892c67df9aa89cdf00cf51f01f9137ef51175b0fd332f054807cb0b826064
6
+ metadata.gz: 2a0e5cf3ede57059c8c623593b4a5a430043a3a66051506c6394d0cb674029964d3dcc6da8cef0ddf4c88207b240fb9334e501006b38f1d00ca261733432f101
7
+ data.tar.gz: 060de67ac2c10da73dc52aa78181d7d29e62b8e0a9ca0fd3063aef9ca45ea8a751186bb00519a6e144f6e0e84ba4ca544b29b33e53bd1dfb4ba6515a93c00d8c
data/README.md CHANGED
@@ -33,6 +33,14 @@ end
33
33
  sms.deliver_now # OR: deliver_later
34
34
  ```
35
35
 
36
+ ## TwilioTransport
37
+ Include the gem 'twilio-ruby in your Gemfile'
38
+
39
+ ```ruby
40
+ # Transport configuration
41
+ MoteSMS.transport = MoteSMS::TwilioTransport.new 'twilio sid', 'twilio token', 'from number'
42
+ ```
43
+
36
44
  ## Contributing
37
45
 
38
46
  1. Fork it
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
3
- require "rspec/core/rake_task"
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
4
 
5
- task :default => :spec
5
+ task default: :spec
6
6
  RSpec::Core::RakeTask.new(:spec)
@@ -2,13 +2,11 @@ require 'mote_sms/number'
2
2
  require 'mote_sms/number_list'
3
3
 
4
4
  module MoteSMS
5
-
6
5
  # Represents an SMS message, currently only provides the
7
6
  # tools to build new messages, not parse incoming messages or
8
7
  # similar stuff.
9
8
  #
10
9
  class Message
11
-
12
10
  # The transport instance to use, if not defined
13
11
  # falls back to use global MoteSMS.transport instance.
14
12
  attr_accessor :transport
@@ -76,14 +74,14 @@ module MoteSMS
76
74
  #
77
75
  # Returns nothing.
78
76
  def to=(*args)
79
- @to = MoteSMS::NumberList.new.push(*args)
77
+ @to = MoteSMS::NumberList.new.push(args)
80
78
  end
81
79
 
82
80
  # Public: Returns NumberList for this message.
83
81
  #
84
82
  # Returns NumberList instance.
85
83
  def to(*numbers)
86
- @to.push(*numbers) unless numbers.empty?
84
+ @to.push(numbers) unless numbers.empty?
87
85
  @to
88
86
  end
89
87
 
@@ -112,8 +110,8 @@ module MoteSMS
112
110
  end
113
111
 
114
112
  def deliver_later(options = {})
115
- return Kernel.warn 'options[:transport] is not supported in Message#deliveer_later' if options.delete(:transport)
116
- DeliveryJob.set(options).perform_later @from.to_s, @to.normalized_numbers, @body, options
113
+ Kernel.warn 'options[:transport] is not supported in Message#deliveer_later' if options.delete(:transport)
114
+ DeliveryJob.set(options).perform_later @from.to_s.presence, @to.normalized_numbers, @body, options
117
115
  end
118
116
  end
119
117
  end
@@ -1,17 +1,19 @@
1
1
  require 'phony'
2
2
 
3
3
  module MoteSMS
4
-
5
4
  # MoteSMS::Number handles all the number parsing and formatting
6
5
  # issues, also a number is immutable.
7
6
  class Number
8
-
9
7
  # Support both Phony 1.7 and 2.x
10
- PhonyError = Phony::NormalizationError rescue Class.new(ArgumentError)
8
+ PhonyError = begin
9
+ Phony::NormalizationError
10
+ rescue
11
+ Class.new(ArgumentError)
12
+ end
11
13
 
12
14
  # Access the E164 normalized value of the number.
13
15
  attr_reader :number
14
- alias :to_number :number
16
+ alias to_number number
15
17
 
16
18
  def initialize(value, options = {})
17
19
  @options = options || {}
@@ -40,7 +42,10 @@ module MoteSMS
40
42
  # adds the country code if missing.
41
43
  #
42
44
  def parse_raw_number
43
- unless vanity?
45
+ if vanity?
46
+ @number = @raw_number.gsub(/[^A-Z0-9]/i, '').upcase.strip
47
+ raise ArgumentError, "Invalid vanity number #{@raw_number}" if @number.length.zero? || @number.length > 11
48
+ else
44
49
  raise ArgumentError, "Unable to parse #{@raw_number} as number" unless @raw_number.to_s =~ /\A[\d\.\/\-\s\(\)\+]+\z/
45
50
  cc = @options[:cc]
46
51
  normalized = Phony.normalize(@raw_number)
@@ -48,9 +53,6 @@ module MoteSMS
48
53
  raise ArgumentError, "Wrong national destination code #{@raw_number}" unless Phony.plausible?(normalized, @options)
49
54
 
50
55
  @number = Phony.normalize normalized
51
- else
52
- @number = @raw_number.gsub(/[^A-Z0-9]/i, '').upcase.strip
53
- raise ArgumentError, "Invalid vanity number #{@raw_number}" if @number.length == 0 || @number.length > 11
54
56
  end
55
57
  rescue PhonyError => e
56
58
  raise ArgumentError, "Phony: #{e}"
@@ -1,7 +1,6 @@
1
1
  require 'mote_sms/number'
2
2
 
3
3
  module MoteSMS
4
-
5
4
  # List of Number instances, which transparantly is able to add
6
5
  # new Number instances from strings, or whatever.
7
6
  #
@@ -16,7 +15,6 @@ module MoteSMS
16
15
  # # => ['41791231212', '41441231212', '08001231212']
17
16
  #
18
17
  class NumberList
19
-
20
18
  # Load ruby enumerable support.
21
19
  include ::Enumerable
22
20
 
@@ -32,13 +30,13 @@ module MoteSMS
32
30
  def length
33
31
  numbers.length
34
32
  end
35
- alias :size :length
33
+ alias size length
36
34
 
37
35
  # Public: Conform to arrayish behavior.
38
36
  def empty?
39
37
  numbers.empty?
40
38
  end
41
- alias :blank? :empty?
39
+ alias blank? empty?
42
40
 
43
41
  # Public: Add number to internal list, use duck typing to detect if
44
42
  # it appears to be a number instance or not. So everything which does
@@ -48,7 +46,7 @@ module MoteSMS
48
46
  #
49
47
  # Returns nothing.
50
48
  def <<(number)
51
- self.push(number)
49
+ push(number)
52
50
  end
53
51
 
54
52
  # Public: Add multiple numbers, with optional options hash which can
@@ -1,7 +1,6 @@
1
1
  require 'action_mailer'
2
2
 
3
3
  module MoteSMS
4
-
5
4
  # Internal: ActionMailer class to forward SMS to recipient.
6
5
  class ActionMailerSMSMailer < ::ActionMailer::Base
7
6
  def forward_sms(recipient, sms)
@@ -23,7 +22,6 @@ module MoteSMS
23
22
  # MoteSMS.transport = MoteSMS::ActionMailerTransport.new ->(msg) { "#{msg.from}@example.com" }
24
23
  #
25
24
  class ActionMailerTransport
26
-
27
25
  # Public: Read/change the recipient used when delivering the message.
28
26
  # Also accepts a Proc.
29
27
  attr_accessor :recipient
@@ -40,9 +38,11 @@ module MoteSMS
40
38
  # currently ignored.
41
39
  #
42
40
  # Returns nothing.
43
- def deliver(message, options = {})
44
- to = self.recipient.respond_to?(:call) ? self.recipient.call(message) : self.recipient
41
+ def deliver(message, _options = {})
42
+ to = recipient.respond_to?(:call) ? recipient.call(message) : recipient
45
43
  ActionMailerSMSMailer.forward_sms(to, message).deliver_now
44
+
45
+ message.to
46
46
  end
47
47
  end
48
48
  end
@@ -12,11 +12,11 @@ module Transports
12
12
  CERTS_PATH = File.expand_path File.join(File.dirname(__FILE__), '..', 'ssl_certs')
13
13
 
14
14
  def self.ssl_options
15
- @ssl_options ||= ->(http) {
15
+ @ssl_options ||= lambda do |http|
16
16
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
17
17
  http.verify_depth = 9
18
- http.cert_store = self.default_cert_store
19
- }
18
+ http.cert_store = default_cert_store
19
+ end
20
20
  end
21
21
 
22
22
  def self.default_cert_store
@@ -48,7 +48,8 @@ module Transports
48
48
  if enable_fingerprint
49
49
  @fingerprint = ENV.fetch(
50
50
  "MOTE_SMS_#{@endpoint.host.to_s.upcase.gsub(/[\.-]/, '_')}_FINGERPRINT",
51
- self.class.fingerprint_host(@endpoint.host))
51
+ self.class.fingerprint_host(@endpoint.host)
52
+ )
52
53
  end
53
54
  end
54
55
 
@@ -79,7 +80,8 @@ module Transports
79
80
 
80
81
  logger.error(
81
82
  format('[Transports::HttpClient] failed to verify %s fingerprint (ACTUAL: %s, EXPECTED: %s)',
82
- endpoint, digest, fingerprint))
83
+ endpoint, digest, fingerprint)
84
+ )
83
85
  false
84
86
  end
85
87
 
@@ -6,7 +6,6 @@ require 'logger'
6
6
  require 'mote_sms/transports/http_client'
7
7
 
8
8
  module MoteSMS
9
-
10
9
  # MoteSMS::MobileTechnicsTransport provides the implementation to
11
10
  # send messages using nth.ch bulk SMS HTTP/S API. Each customer has
12
11
  # custom endpoint (with port) and username/password.
@@ -56,8 +55,8 @@ module MoteSMS
56
55
  # logger - The Logger instance, should at least respond to #debug, #error.
57
56
  #
58
57
  # Returns nothing.
59
- def self.logger=(logger)
60
- @logger = logger
58
+ class << self
59
+ attr_writer :logger
61
60
  end
62
61
 
63
62
  # Public: Create a new instance using specified endpoint, username
@@ -78,9 +77,9 @@ module MoteSMS
78
77
  @options = self.class.defaults.merge(options)
79
78
 
80
79
  @http_client = Transports::HttpClient.new(endpoint,
81
- proxy_address: @options[:proxy_address],
82
- proxy_port: @options[:proxy_port],
83
- ssl: @options[:ssl])
80
+ proxy_address: @options[:proxy_address],
81
+ proxy_port: @options[:proxy_port],
82
+ ssl: @options[:ssl])
84
83
  end
85
84
 
86
85
  # Public: Delivers message using mobile technics HTTP/S API.
@@ -105,6 +104,8 @@ module MoteSMS
105
104
  raise ServiceError, "unable to deliver message to all recipients (CAUSE: #{resp.body.strip})" unless resp.body.split("\n").all? { |l| l =~ /Result_code: 00/ }
106
105
 
107
106
  resp['X-Nth-SmsId'].split(',')
107
+
108
+ message.to
108
109
  end
109
110
 
110
111
  private
@@ -117,9 +118,9 @@ module MoteSMS
117
118
  #
118
119
  # Returns Array with params.
119
120
  def post_params(message, options)
120
- params = options.reject { |key, v| [:proxy_address, :proxy_port, :ssl].include?(key) }
121
- params.merge! username: self.username,
122
- password: self.password,
121
+ params = options.reject { |key, _v| [:proxy_address, :proxy_port, :ssl].include?(key) }
122
+ params.merge! username: username,
123
+ password: password,
123
124
  origin: message.from ? message.from.to_number : params[:origin],
124
125
  text: message.body,
125
126
  :'call-number' => prepare_numbers(message.to)
@@ -1,10 +1,10 @@
1
1
  require 'phony'
2
2
  require 'logger'
3
+ require 'json'
3
4
 
4
5
  require 'mote_sms/transports/http_client'
5
6
 
6
7
  module MoteSMS
7
-
8
8
  # MoteSMS::MobileTechnicsTransport provides the implementation to
9
9
  # send messages using nth.ch bulk SMS HTTP/S API. Each customer has
10
10
  # custom endpoint (with port) and username/password.
@@ -60,9 +60,9 @@ module MoteSMS
60
60
  @options = options
61
61
 
62
62
  @http_client = Transports::HttpClient.new(endpoint,
63
- proxy_address: options[:proxy_address],
64
- proxy_port: options[:proxy_port],
65
- ssl: options[:ssl])
63
+ proxy_address: options[:proxy_address],
64
+ proxy_port: options[:proxy_port],
65
+ ssl: options[:ssl])
66
66
  end
67
67
 
68
68
  # Public: Delivers message using mobile technics HTTP/S API.
@@ -71,11 +71,11 @@ module MoteSMS
71
71
  # options - The Hash with service specific options.
72
72
  #
73
73
  # Returns Array with sender ids.
74
- def deliver(message, options = {})
75
- raise ArgumentError, "too many recipients, max. is #{MAX_RECIPIENT} (current: #{message.to.length})" if message.to.length > MAX_RECIPIENT
74
+ def deliver(message, _options = {})
75
+ raise ServiceError, "too many recipients, max. is #{MAX_RECIPIENT} (current: #{message.to.length})" if message.to.length > MAX_RECIPIENT
76
76
 
77
77
  # Prepare request
78
- request = Net::HTTP::Post.new("/messaging/v1/sms").tap do |request|
78
+ request = Net::HTTP::Post.new('/messaging/v1/sms').tap do |request|
79
79
  request.body = post_params(message)
80
80
  request.content_type = 'application/json; charset=utf-8'
81
81
  request['Accept'] = 'application/json; charset=utf-8'
@@ -86,17 +86,20 @@ module MoteSMS
86
86
  self.class.logger.debug "curl -X#{request.method} '#{endpoint}' -d '#{request.body}'"
87
87
 
88
88
  # Perform request
89
- resp = http.request(request)
89
+ resp = http_client.request(request)
90
90
 
91
91
  # Handle errors
92
92
  raise ServiceError, "endpoint did respond with #{resp.code} and #{resp.body}" unless resp.code.to_i == 201
93
93
  self.class.logger.debug resp.body
94
+
95
+ # Return numbers message send to
96
+ message.to
94
97
  end
95
98
 
96
99
  private
97
100
 
98
101
  def post_params(message)
99
- { to: prepare_numbers(message.to), text: message.body }
102
+ { to: prepare_numbers(message.to), text: message.body }.to_json
100
103
  end
101
104
 
102
105
  def prepare_numbers(number_list)
@@ -1,5 +1,4 @@
1
1
  module MoteSMS
2
-
3
2
  # Public: Provide access to global array of delivered
4
3
  # messages, this can be used in testing to assert sent
5
4
  # SMS messages, test their contents, recipients etc.
@@ -26,14 +25,13 @@ module MoteSMS
26
25
  # end
27
26
  #
28
27
  module TestTransport
29
-
30
28
  # Public: Appends supplied message to global deliveries array.
31
29
  #
32
30
  # message - The MoteSMS::Message instance to deliver.
33
31
  # options - The Hash with additional, transport specific options.
34
32
  #
35
33
  # Returns nothing.
36
- def self.deliver(message, options = {})
34
+ def self.deliver(message, _options = {})
37
35
  MoteSMS.deliveries << message
38
36
  end
39
37
  end
@@ -0,0 +1,78 @@
1
+ require 'phony'
2
+ require 'logger'
3
+ require 'twilio-ruby'
4
+
5
+ module MoteSMS
6
+ # MoteSMS::TwilioTransport provides the implementation to
7
+ # send messages using the Twilio Api https://github.com/twilio/twilio-ruby
8
+ #
9
+ # Examples:
10
+ #
11
+ # MoteSMS.transport = MoteSMS::TwilioTransport.new 'sid', 'token', 'from_number'
12
+ # sms = MoteSMS::Message.new do
13
+ # to 'to_number'
14
+ # body 'my cool text'
15
+ # end
16
+ # sms.deliver_now
17
+ # # => <Twilio::REST::Message>
18
+ #
19
+ class TwilioTransport
20
+ # Maximum recipients allowed by API
21
+ MAX_RECIPIENT = 1
22
+
23
+ # Custom exception subclass.
24
+ ServiceError = Class.new(::Exception)
25
+
26
+ attr_reader :from_number, :client
27
+
28
+ # Public: Create a new instance using specified endpoint, api_key
29
+ # and password.
30
+ #
31
+ # account_sid - The twilio account sid
32
+ # auth_token - The twilio api token
33
+ # from_number - The phone number to send from (mandatory on initialize or send message)
34
+ #
35
+ # Returns a new instance.
36
+ def initialize(account_sid, auth_token, from_number = nil)
37
+ @from_number = from_number
38
+
39
+ @client = Twilio::REST::Client.new account_sid, auth_token
40
+ end
41
+
42
+ # Public: Delivers message using mobile technics HTTP/S API.
43
+ #
44
+ # message - The MoteSMS::Message instance to send.
45
+ # options - The Hash with service specific options.
46
+ #
47
+ # Returns Array with sender ids.
48
+ def deliver(message, _options = {})
49
+ raise ArgumentError, "too many recipients, max. is #{MAX_RECIPIENT}" if message.to.length > MAX_RECIPIENT
50
+
51
+ from = message.from.present? ? message.from.to_s : from_number
52
+
53
+ raise ArgumentError, 'no from number given on new message or the transport given' if from.empty?
54
+
55
+ from = Phony.format(Phony.normalize(from), format: :international_absolute, spaces: '')
56
+
57
+ messages = prepare_numbers(message.to).map do |n|
58
+ @client.messages.create(
59
+ from: from,
60
+ to: n,
61
+ body: message.body
62
+ )
63
+ end
64
+ numbers = messages.map do |result|
65
+ result.try(:to)
66
+ end
67
+ NumberList.new.push numbers.compact
68
+ end
69
+
70
+ private
71
+
72
+ def prepare_numbers(number_list)
73
+ number_list.normalized_numbers.map do |n|
74
+ Phony.format(Phony.normalize(n), format: :international_absolute, spaces: '')
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,5 +1,4 @@
1
1
  module MoteSMS
2
-
3
2
  # All transports live within mote_sms/transports, though should be
4
3
  # available in ruby as `MoteSMS::<Some>Transport`.
5
4
  autoload :SslTransport, 'mote_sms/transports/concerns/ssl_transport'
@@ -7,4 +6,5 @@ module MoteSMS
7
6
  autoload :MobileTechnicsTransport, 'mote_sms/transports/mobile_technics_transport'
8
7
  autoload :ActionMailerTransport, 'mote_sms/transports/action_mailer_transport'
9
8
  autoload :SwisscomTransport, 'mote_sms/transports/swisscom_transport'
9
+ autoload :TwilioTransport, 'mote_sms/transports/twilio_transport'
10
10
  end
@@ -1,3 +1,3 @@
1
1
  module MoteSMS
2
- VERSION = "1.3.0.rc1"
2
+ VERSION = '1.3.0'.freeze
3
3
  end
data/lib/mote_sms.rb CHANGED
@@ -6,7 +6,7 @@ module MoteSMS
6
6
  autoload :Message, 'mote_sms/message'
7
7
  autoload :DeliveryJob, 'mote_sms/delivery_job'
8
8
 
9
- autoload :VERSION, 'mote_sms/version'
9
+ autoload :VERSION, 'mote_sms/version'
10
10
 
11
11
  # No default transport.
12
12
  @@transport = nil
data/mote_sms.gemspec CHANGED
@@ -5,17 +5,17 @@ Gem::Specification.new do |gem|
5
5
  gem.name = 'mote_sms'
6
6
  gem.authors = ['Lukas Westermann', 'Loris Gavillet']
7
7
  gem.email = ['lukas.westermann@at-point.ch', 'loris@at-point.ch']
8
- gem.summary = %q{Deliver SMS using Swisscom / MobileTechnics REST API.}
9
- gem.description = %q{Unofficial ruby adapter for Swisscom and MobileTechnics Bulk SMS APIs.
8
+ gem.summary = 'Deliver SMS using Swisscom / MobileTechnics REST API.'
9
+ gem.description = 'Unofficial ruby adapter for Swisscom and MobileTechnics Bulk SMS APIs.
10
10
  Tries to mimick mail API, so users can switch e.g. ActionMailer
11
- with this SMS provider.}
11
+ with this SMS provider.'
12
12
  gem.homepage = 'https://github.com/at-point/mote_sms'
13
13
 
14
- gem.files = %w{.gitignore Gemfile Rakefile README.md mote_sms.gemspec} + Dir['**/*.{rb,pem}']
14
+ gem.files = %w(.gitignore Gemfile Rakefile README.md mote_sms.gemspec) + Dir['**/*.{rb,pem}']
15
15
  gem.bindir = 'exe'
16
16
  gem.executables = gem.files.grep(%r{^exe/}) { |f| File.basename(f) }
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = %w{lib}
18
+ gem.require_paths = %w(lib)
19
19
  gem.version = MoteSMS::VERSION
20
20
 
21
21
  gem.required_ruby_version = '>= 2.0'
@@ -28,4 +28,5 @@ Gem::Specification.new do |gem|
28
28
  gem.add_development_dependency 'webmock', ['~> 1.8.0']
29
29
  gem.add_development_dependency 'actionmailer', ['>= 4.2', '< 6']
30
30
  gem.add_development_dependency 'activejob', ['>= 4.2', '< 6']
31
+ gem.add_development_dependency 'twilio-ruby', ['>= 4.11.0']
31
32
  end
@@ -10,62 +10,62 @@ describe MoteSMS::Message do
10
10
  body 'This is the SMS content'
11
11
  end
12
12
  expect(msg.from.number).to be == 'SENDER'
13
- expect(msg.to.normalized_numbers).to be == %w{41791231212}
13
+ expect(msg.to.normalized_numbers).to be == %w(41791231212)
14
14
  expect(msg.body).to be == 'This is the SMS content'
15
15
  end
16
16
 
17
17
  context '#to' do
18
18
  it 'behaves as accessor' do
19
19
  subject.to = '41791231212'
20
- expect(subject.to.normalized_numbers).to be == %w{41791231212}
20
+ expect(subject.to.normalized_numbers).to be == %w(41791231212)
21
21
  end
22
22
 
23
23
  it 'behaves as array' do
24
24
  subject.to << '41791231212'
25
25
  subject.to << '41797775544'
26
- expect(subject.to.normalized_numbers).to be == %w{41791231212 41797775544}
26
+ expect(subject.to.normalized_numbers).to be == %w(41791231212 41797775544)
27
27
  end
28
28
 
29
29
  it 'normalizes numbers' do
30
30
  subject.to = '+41 79 123 12 12'
31
- expect(subject.to.normalized_numbers).to be == %w{41791231212}
31
+ expect(subject.to.normalized_numbers).to be == %w(41791231212)
32
32
  end
33
33
  end
34
34
 
35
- context "#deliver" do
35
+ context '#deliver' do
36
36
  subject { described_class.new }
37
37
 
38
- it "delegates to deliver_now and deprecates it" do
38
+ it 'delegates to deliver_now and deprecates it' do
39
39
  expect(subject).to receive(:deliver_now)
40
40
  expect(Kernel).to receive(:warn).with('Message#deliver is deprecated and will be removed from MoteSMS. Please use #deliver_now')
41
41
  subject.deliver
42
42
  end
43
43
  end
44
44
 
45
- context "#deliver_now" do
46
- let(:transport) { double("Some Transport") }
47
- subject {
45
+ context '#deliver_now' do
46
+ let(:transport) { double('Some Transport') }
47
+ subject do
48
48
  expect(Kernel).to receive(:warn).with('Message#new(transport) is deprecated and will be removed from MoteSMS')
49
49
  described_class.new(transport)
50
- }
50
+ end
51
51
 
52
- it "sends messages to transport" do
52
+ it 'sends messages to transport' do
53
53
  expect(transport).to receive(:deliver).with(subject, {})
54
54
  subject.deliver_now
55
55
  end
56
56
 
57
- it "can pass additional attributes to transport" do
58
- expect(transport).to receive(:deliver).with(subject, serviceid: "myapplication")
59
- subject.deliver_now serviceid: "myapplication"
57
+ it 'can pass additional attributes to transport' do
58
+ expect(transport).to receive(:deliver).with(subject, serviceid: 'myapplication')
59
+ subject.deliver_now serviceid: 'myapplication'
60
60
  end
61
61
 
62
- it "can override per message transport using :transport option and it deprecates it" do
62
+ it 'can override per message transport using :transport option and it deprecates it' do
63
63
  expect(transport).to_not receive(:deliver)
64
64
  expect(Kernel).to receive(:warn).with('options[:transport] in Message#deliver_now is deprecated and will be removed from MoteSMS')
65
65
  subject.deliver_now transport: double(deliver: true)
66
66
  end
67
67
 
68
- it "uses global MoteSMS.transport if no per message transport defined" do
68
+ it 'uses global MoteSMS.transport if no per message transport defined' do
69
69
  message = described_class.new
70
70
  expect(transport).to receive(:deliver).with(message, {})
71
71
  expect(MoteSMS).to receive(:transport) { transport }
@@ -73,7 +73,7 @@ describe MoteSMS::Message do
73
73
  end
74
74
  end
75
75
 
76
- context "#deliver_later" do
76
+ context '#deliver_later' do
77
77
  before { MoteSMS.transport = MoteSMS::TestTransport }
78
78
  after { MoteSMS.transport = nil }
79
79
 
@@ -85,13 +85,13 @@ describe MoteSMS::Message do
85
85
  end
86
86
  end
87
87
 
88
- it "can not override per message transport using :transport option and it deprecates it" do
88
+ it 'can not override per message transport using :transport option and it deprecates it' do
89
89
  expect(Kernel).to receive(:warn).with('options[:transport] is not supported in Message#deliveer_later')
90
- expect(MoteSMS::DeliveryJob).to_not receive(:perform_later)
91
90
  subject.deliver_later transport: double(deliver: true)
91
+ expect(ActiveJob::Base.queue_adapter.enqueued_jobs.size).to eq 1
92
92
  end
93
93
 
94
- it "queues the delivery in the DeliveryJob" do
94
+ it 'queues the delivery in the DeliveryJob' do
95
95
  subject.deliver_later
96
96
  job = ActiveJob::Base.queue_adapter.enqueued_jobs.first
97
97
  expect(job[:job]).to eq MoteSMS::DeliveryJob
@@ -18,16 +18,16 @@ describe MoteSMS::NumberList do
18
18
 
19
19
  it 'can add numbers by string' do
20
20
  subject << '+41 79 111 22 33'
21
- expect(subject.normalized_numbers).to be == %w{41791112233}
21
+ expect(subject.normalized_numbers).to be == %w(41791112233)
22
22
  end
23
23
 
24
24
  it 'can multiple numbers using push' do
25
25
  subject.push '+41 79 111 22 33', '+41 44 111 22 33'
26
- expect(subject.normalized_numbers).to be == %w{41791112233 41441112233}
26
+ expect(subject.normalized_numbers).to be == %w(41791112233 41441112233)
27
27
  end
28
28
 
29
29
  it 'can push multiple numbers with adding country codes' do
30
30
  subject.push '079 111 22 33', '0041 44 111 22 33', cc: '41', ndc: /(44|79)/
31
- expect(subject.normalized_numbers).to be == %w{41791112233 41441112233}
31
+ expect(subject.normalized_numbers).to be == %w(41791112233 41441112233)
32
32
  end
33
33
  end
@@ -3,13 +3,14 @@ require 'mote_sms/message'
3
3
  require 'mote_sms/transports/action_mailer_transport'
4
4
 
5
5
  describe MoteSMS::ActionMailerTransport do
6
- subject { described_class.new "sms@example.com" }
7
- let(:message) { MoteSMS::Message.new do
6
+ subject { described_class.new 'sms@example.com' }
7
+ let(:message) do
8
+ MoteSMS::Message.new do
8
9
  from 'Sender'
9
10
  to '+41 79 123 12 12'
10
11
  body 'This is the SMS content'
11
12
  end
12
- }
13
+ end
13
14
  let(:email) { ActionMailer::Base.deliveries.last }
14
15
 
15
16
  before do
@@ -19,9 +20,9 @@ describe MoteSMS::ActionMailerTransport do
19
20
 
20
21
  it 'sends SMS as e-mail' do
21
22
  subject.deliver message
22
- expect(email.to).to be == ["sms@example.com"]
23
- expect(email.from).to be == ["sms@example.com"]
24
- expect(email.subject).to be == "SMS to +41 79 123 12 12"
25
- expect(email.body).to be == "This is the SMS content"
23
+ expect(email.to).to be == ['sms@example.com']
24
+ expect(email.from).to be == ['sms@example.com']
25
+ expect(email.subject).to be == 'SMS to +41 79 123 12 12'
26
+ expect(email.body).to be == 'This is the SMS content'
26
27
  end
27
28
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'mote_sms/version'
2
3
  require 'mote_sms/transports/http_client'
3
4
 
4
5
  describe Transports::HttpClient do
@@ -73,11 +74,11 @@ describe Transports::HttpClient do
73
74
  context '#request' do
74
75
  let(:request) { Net::HTTP::Get.new('/') }
75
76
 
76
- before {
77
- stub_request(:get, "https://example.org/").
78
- with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => 'Ruby/mote_sms 1.2.0' }).
79
- to_return(status: 200, body: "", headers: {})
80
- }
77
+ before(:each) do
78
+ stub_request(:get, 'https://example.org/')
79
+ .with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => "Ruby/mote_sms #{MoteSMS::VERSION}" })
80
+ .to_return(status: 200, body: '', headers: {})
81
+ end
81
82
 
82
83
  it 'submits a request and overrides the UA' do
83
84
  response = subject.request(request)
@@ -7,34 +7,34 @@ require 'mote_sms/transports/mobile_technics_transport'
7
7
  describe MoteSMS::MobileTechnicsTransport do
8
8
  before do
9
9
  @logger = described_class.logger
10
- described_class.logger = double("logger", debug: true, info: true, error: true)
10
+ described_class.logger = double('logger', debug: true, info: true, error: true)
11
11
  end
12
12
 
13
13
  after do
14
14
  described_class.logger = @logger
15
15
  end
16
16
 
17
- subject { described_class.new(endpoint, "example", "123456") }
17
+ subject { described_class.new(endpoint, 'example', '123456') }
18
18
 
19
- let(:endpoint) { "http://test.nth.ch" }
20
- let(:message) {
19
+ let(:endpoint) { 'http://test.nth.ch' }
20
+ let(:message) do
21
21
  MoteSMS::Message.new do
22
22
  to '0041 079 123 12 12'
23
23
  from 'SENDER'
24
24
  body 'Hello World, with äöü.'
25
25
  end
26
- }
26
+ end
27
27
 
28
- let(:success) {
29
- { body: "Result_code: 00, Message OK", status: 200, headers: { 'X-Nth-SmsId' => '43797917' } }
30
- }
28
+ let(:success) do
29
+ { body: 'Result_code: 00, Message OK', status: 200, headers: { 'X-Nth-SmsId' => '43797917' } }
30
+ end
31
31
 
32
- context "#deliver" do
33
- it "sends POST to endpoint with URL encoded body" do
32
+ context '#deliver' do
33
+ it 'sends POST to endpoint with URL encoded body' do
34
34
  stub_request(:post, endpoint).with do |req|
35
35
  params = CGI.parse(req.body)
36
- expect(params['username']).to be == %w{example}
37
- expect(params['password']).to be == %w{123456}
36
+ expect(params['username']).to be == %w(example)
37
+ expect(params['password']).to be == %w(123456)
38
38
  expect(params['text']).to be == ['Hello World, with äöü.']
39
39
  expect(params['call-number']).to be == ['0041791231212']
40
40
  end.to_return(success)
@@ -51,17 +51,17 @@ describe MoteSMS::MobileTechnicsTransport do
51
51
 
52
52
  it 'raises exception if required parameter is missing' do
53
53
  stub_request(:post, endpoint).to_return(body: 'Result_code: 02, call-number')
54
- expect { subject.deliver message }.to raise_error(MoteSMS::MobileTechnicsTransport::ServiceError)
54
+ expect { subject.deliver message }.to raise_error(described_class::ServiceError)
55
55
  end
56
56
 
57
57
  it 'raises exception if status code is not 200' do
58
58
  stub_request(:post, endpoint).to_return(status: 500)
59
- expect { subject.deliver message }.to raise_error(MoteSMS::MobileTechnicsTransport::ServiceError)
59
+ expect { subject.deliver message }.to raise_error(described_class::ServiceError)
60
60
  end
61
61
 
62
- it 'returns message id' do
62
+ it 'returns message delivered numbers' do
63
63
  stub_request(:post, endpoint).to_return(success)
64
- expect(subject.deliver(message)).to be == %w{43797917}
64
+ expect(subject.deliver(message).normalized_numbers).to eq(['41791231212'])
65
65
  end
66
66
 
67
67
  it 'logs curl compatible output' do
@@ -74,7 +74,7 @@ describe MoteSMS::MobileTechnicsTransport do
74
74
  end
75
75
  end
76
76
 
77
- context "#options" do
77
+ context '#options' do
78
78
  it 'can be passed in as last item in the constructor' do
79
79
  transport = described_class.new endpoint, 'user', 'pass', allow_adaption: false, validity: 30
80
80
  expect(transport.options[:allow_adaption]).to be_falsey
@@ -83,8 +83,8 @@ describe MoteSMS::MobileTechnicsTransport do
83
83
  end
84
84
 
85
85
  it 'should be exposed as hash' do
86
- subject.options[:messageid] = "test"
87
- expect(subject.options[:messageid]).to be == "test"
86
+ subject.options[:messageid] = 'test'
87
+ expect(subject.options[:messageid]).to be == 'test'
88
88
  end
89
89
 
90
90
  it 'overrides settings from #defaults' do
@@ -103,7 +103,7 @@ describe MoteSMS::MobileTechnicsTransport do
103
103
  end
104
104
 
105
105
  it 'evaluates Procs & lambdas' do
106
- subject.options[:messageid] = Proc.new { "test" }
106
+ subject.options[:messageid] = proc { 'test' }
107
107
 
108
108
  stub_request(:post, endpoint).with(body: hash_including('messageid' => 'test')).to_return(success)
109
109
  subject.deliver message
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'cgi'
4
+ require 'mote_sms/message'
5
+ require 'mote_sms/transports/swisscom_transport'
6
+
7
+ describe MoteSMS::SwisscomTransport do
8
+ before do
9
+ @logger = described_class.logger
10
+ described_class.logger = double('logger', debug: true, info: true, error: true)
11
+ end
12
+
13
+ after do
14
+ described_class.logger = @logger
15
+ end
16
+
17
+ subject { described_class.new(endpoint, 'example', '123456') }
18
+
19
+ let(:endpoint) { 'https://api.example.com' }
20
+ let(:message) do
21
+ MoteSMS::Message.new do
22
+ to '0041 079 123 12 12'
23
+ from 'SENDER'
24
+ body 'Hello World, with äöü.'
25
+ end
26
+ end
27
+
28
+ let(:success) do
29
+ { body: 'OK', status: 201 }
30
+ end
31
+
32
+ context '#deliver' do
33
+ it 'sends POST to endpoint with JSON body and Client ID' do
34
+ stub_request(:post, "#{endpoint}/messaging/v1/sms").with do |req|
35
+ params = JSON.load(req.body)
36
+ expect(params['text']).to eq 'Hello World, with äöü.'
37
+ expect(params['to']).to eq '+41791231212'
38
+ end.to_return(success)
39
+ expect(subject.deliver(message).normalized_numbers).to eq(['41791231212'])
40
+ end
41
+
42
+ it 'raises error when trying to send to multiple recipients' do
43
+ message.to << '+41 79 333 44 55'
44
+ message.to << '+41 78 111 22 33'
45
+
46
+ expect { subject.deliver message }.to raise_error(described_class::ServiceError, /too many recipients/)
47
+ end
48
+
49
+ it 'raises exception if status code is not 201' do
50
+ stub_request(:post, "#{endpoint}/messaging/v1/sms").to_return(status: 500)
51
+ expect { subject.deliver message }.to raise_error(described_class::ServiceError)
52
+ end
53
+
54
+ it 'returns truthy on success' do
55
+ stub_request(:post, "#{endpoint}/messaging/v1/sms").to_return(success)
56
+ expect(subject.deliver(message)).to be_truthy
57
+ end
58
+
59
+ it 'logs curl compatible output' do
60
+ io = StringIO.new
61
+ described_class.logger = Logger.new(io)
62
+ stub_request(:post, "#{endpoint}/messaging/v1/sms").to_return(success)
63
+ subject.deliver message
64
+ io.rewind
65
+ expect(io.read).to include('curl -XPOST \'https://api.example.com\' -d \'{')
66
+ end
67
+ end
68
+ end
@@ -10,8 +10,8 @@ describe MoteSMS::TestTransport do
10
10
  end
11
11
 
12
12
  it 'appends deliveries' do
13
- subject.deliver "firstMessage"
14
- subject.deliver "secondMessage"
15
- expect(MoteSMS.deliveries).to be == %w{firstMessage secondMessage}
13
+ subject.deliver 'firstMessage'
14
+ subject.deliver 'secondMessage'
15
+ expect(MoteSMS.deliveries).to be == %w(firstMessage secondMessage)
16
16
  end
17
17
  end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ require 'twilio-ruby'
3
+ require 'mote_sms/transports/twilio_transport'
4
+ require 'mote_sms/message'
5
+
6
+ describe MoteSMS::TwilioTransport do
7
+ subject do
8
+ client = double(Twilio::REST::Client)
9
+ expect(client).to receive(:messages).at_least(:once) { results }
10
+ expect(Twilio::REST::Client).to receive(:new).with('account', '123456') { client }
11
+ described_class.new('account', '123456', '41791110011')
12
+ end
13
+
14
+ let(:message) do
15
+ MoteSMS::Message.new do
16
+ to '+41790001122'
17
+ body 'Hello World'
18
+ end
19
+ end
20
+
21
+ let(:result) do
22
+ Twilio::REST::Message.new('/SMS', subject.client, from: '+41791110011', to: '41790001122', body: 'Hello World')
23
+ end
24
+ let(:results) do
25
+ Twilio::REST::Messages.new('/SMS', subject.client)
26
+ end
27
+
28
+ let(:message) do
29
+ MoteSMS::Message.new do
30
+ to '+41790001122'
31
+ body 'Hello World'
32
+ end
33
+ end
34
+
35
+ context '#deliver' do
36
+ it 'send message' do
37
+ expect(subject.client.messages).to receive(:create).with(
38
+ from: '+41791110011',
39
+ to: '+41790001122',
40
+ body: 'Hello World'
41
+ ).at_least(:once) { result }
42
+
43
+ expect(subject.deliver(message).normalized_numbers).to eq(['41790001122'])
44
+ end
45
+
46
+ it 'uses the number from the message' do
47
+ message.from = '41791110033'
48
+ expect(subject.client.messages).to receive(:create).with(
49
+ from: '+41791110033',
50
+ to: '+41790001122',
51
+ body: 'Hello World'
52
+ ).at_least(:once) { result }
53
+
54
+ expect(subject.deliver(message).normalized_numbers).to eq(['41790001122'])
55
+ end
56
+ end
57
+ end
@@ -8,21 +8,21 @@ describe MoteSMS do
8
8
  expect(subject::VERSION).to match /\d/
9
9
  end
10
10
 
11
- context "transport" do
11
+ context 'transport' do
12
12
  before { @current_transport = subject.transport }
13
13
  after { subject.transport = @current_transport }
14
- let(:transport) { double("transport") }
14
+ let(:transport) { double('transport') }
15
15
 
16
- it "has no default transport" do
16
+ it 'has no default transport' do
17
17
  expect(subject.transport).to be_nil
18
18
  end
19
19
 
20
- it "can change global transport" do
20
+ it 'can change global transport' do
21
21
  subject.transport = transport
22
22
  expect(subject.transport).to be == transport
23
23
  end
24
24
 
25
- context "#deliver" do
25
+ context '#deliver' do
26
26
  it 'delivers quick and dirty using global transport' do
27
27
  expect(transport).to receive(:deliver).with(kind_of(MoteSMS::Message), {})
28
28
  subject.transport = transport
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mote_sms
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0.rc1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lukas Westermann
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-06-15 00:00:00.000000000 Z
12
+ date: 2016-09-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: phony
@@ -133,6 +133,20 @@ dependencies:
133
133
  - - "<"
134
134
  - !ruby/object:Gem::Version
135
135
  version: '6'
136
+ - !ruby/object:Gem::Dependency
137
+ name: twilio-ruby
138
+ requirement: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: 4.11.0
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: 4.11.0
136
150
  description: |-
137
151
  Unofficial ruby adapter for Swisscom and MobileTechnics Bulk SMS APIs.
138
152
  Tries to mimick mail API, so users can switch e.g. ActionMailer
@@ -164,6 +178,7 @@ files:
164
178
  - lib/mote_sms/transports/mobile_technics_transport.rb
165
179
  - lib/mote_sms/transports/swisscom_transport.rb
166
180
  - lib/mote_sms/transports/test_transport.rb
181
+ - lib/mote_sms/transports/twilio_transport.rb
167
182
  - lib/mote_sms/version.rb
168
183
  - mote_sms.gemspec
169
184
  - spec/mote_sms/delivery_job_spec.rb
@@ -173,7 +188,9 @@ files:
173
188
  - spec/mote_sms/transports/action_mailer_transport_spec.rb
174
189
  - spec/mote_sms/transports/http_client_spec.rb
175
190
  - spec/mote_sms/transports/mobile_technics_transport_spec.rb
191
+ - spec/mote_sms/transports/swisscom_transport_spec.rb
176
192
  - spec/mote_sms/transports/test_transport_spec.rb
193
+ - spec/mote_sms/transports/twilio_transport_spec.rb
177
194
  - spec/mote_sms_spec.rb
178
195
  - spec/spec_helper.rb
179
196
  homepage: https://github.com/at-point/mote_sms
@@ -190,9 +207,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
190
207
  version: '2.0'
191
208
  required_rubygems_version: !ruby/object:Gem::Requirement
192
209
  requirements:
193
- - - ">"
210
+ - - ">="
194
211
  - !ruby/object:Gem::Version
195
- version: 1.3.1
212
+ version: '0'
196
213
  requirements: []
197
214
  rubyforge_project:
198
215
  rubygems_version: 2.5.1
@@ -207,6 +224,9 @@ test_files:
207
224
  - spec/mote_sms/transports/action_mailer_transport_spec.rb
208
225
  - spec/mote_sms/transports/http_client_spec.rb
209
226
  - spec/mote_sms/transports/mobile_technics_transport_spec.rb
227
+ - spec/mote_sms/transports/swisscom_transport_spec.rb
210
228
  - spec/mote_sms/transports/test_transport_spec.rb
229
+ - spec/mote_sms/transports/twilio_transport_spec.rb
211
230
  - spec/mote_sms_spec.rb
212
231
  - spec/spec_helper.rb
232
+ has_rdoc: