sms_kit 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +118 -0
  3. data/Rakefile +9 -0
  4. data/lib/sms_kit.rb +15 -0
  5. data/lib/sms_kit/config.rb +43 -0
  6. data/lib/sms_kit/delivery.rb +13 -0
  7. data/lib/sms_kit/http.rb +28 -0
  8. data/lib/sms_kit/logging.rb +27 -0
  9. data/lib/sms_kit/provider.rb +25 -0
  10. data/lib/sms_kit/providers.rb +3 -0
  11. data/lib/sms_kit/providers/central_ict.rb +46 -0
  12. data/lib/sms_kit/providers/mobi_web.rb +54 -0
  13. data/lib/sms_kit/providers/mobimex.rb +56 -0
  14. data/lib/sms_kit/providers/sms_trade.rb +77 -0
  15. data/lib/sms_kit/railtie.rb +7 -0
  16. data/lib/sms_kit/utils.rb +13 -0
  17. data/lib/sms_kit/version.rb +3 -0
  18. data/test/central_ict_test.rb +40 -0
  19. data/test/config_test.rb +34 -0
  20. data/test/delivery_test.rb +21 -0
  21. data/test/fixtures/vcr_cassettes/central_ict/failure.yml +33 -0
  22. data/test/fixtures/vcr_cassettes/central_ict/success.yml +33 -0
  23. data/test/fixtures/vcr_cassettes/mobi_web/failure.yml +32 -0
  24. data/test/fixtures/vcr_cassettes/mobi_web/quick_deliver.yml +32 -0
  25. data/test/fixtures/vcr_cassettes/mobi_web/success.yml +32 -0
  26. data/test/fixtures/vcr_cassettes/mobimex/failure.yml +24 -0
  27. data/test/fixtures/vcr_cassettes/mobimex/success.yml +25 -0
  28. data/test/fixtures/vcr_cassettes/sms_trade/failure.yml +32 -0
  29. data/test/fixtures/vcr_cassettes/sms_trade/success.yml +34 -0
  30. data/test/fixtures/vcr_cassettes/stub_provider/success.yml +22 -0
  31. data/test/helper.rb +30 -0
  32. data/test/http_test.rb +22 -0
  33. data/test/logging_test.rb +21 -0
  34. data/test/mobi_web_test.rb +46 -0
  35. data/test/mobimex_test.rb +40 -0
  36. data/test/provider_test.rb +49 -0
  37. data/test/sms_trade_test.rb +44 -0
  38. data/test/utils_test.rb +12 -0
  39. metadata +187 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZGYxN2NiNzg5MmE4ZDI2NmEyMzFjYTAxZjYwZDg2NTg1Mjc4YWEzNw==
5
+ data.tar.gz: !binary |-
6
+ NWI5MWFiMTQzZjEyMGZiYzkzNTM1YjZmODUwYjE5YmIwOGJiN2NlOA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ZmI5YjkwOGU5ZTE3MGQ2YTllMDQxNmQzYzgzNDVkYzUyYjg4ZGYyOGU0ZGUz
10
+ NzBkMjkzY2JkNjE0NTVlOTVjZGVhOWY5OWFjNGI2NTMyYTczZDY0YzgyZWEw
11
+ MTJkZGU2YWZhOTBjYjRmODQ0N2MwOGFmNjI5OWJkNjZlY2ViZTM=
12
+ data.tar.gz: !binary |-
13
+ N2EwNzVmMWVlMjM0ODRjZWIwMDViZGM3ZmFlYWE3ZjlmOGRlZDZjYjIxZDBm
14
+ ZGY1YzUyMGU0Njc2NjkyYjhhNzA2NDBhYzljODU0ZTk0ZWFmZTVmNmE1NmZj
15
+ YThlMTg1NDY3YTBjZDJhOGRmMGE4ZjI1ZDlmZjI3MmQzODY3MmE=
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # SmsKit [![Build Status](https://travis-ci.org/jamii-Technologies/sms_kit.svg?branch=master)](https://travis-ci.org/jamii-Technologies/sms_kit)
2
+
3
+ Easily send text messages via an HTTP SMS gateway.
4
+ The goal is to offer one streamlined API for any provider adapter.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'sms_kit', github: 'jamii-Technologies/sms_kit'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install sms_kit
19
+
20
+ ## Usage
21
+
22
+ ### Configuration
23
+
24
+ You can store arbitrary options in a provider's configuration:
25
+
26
+ ```rb
27
+ require 'sms_kit/providers/mobi_web'
28
+ SmsKit::MobiWeb.configure do |config|
29
+ config.username = 'user'
30
+ config.password = 'pass'
31
+ config.sender = 123456
32
+ end
33
+ ```
34
+
35
+ ### Send text message
36
+
37
+ ```rb
38
+ provider = SmsKit::MobiWeb.new text: 'Hello World.', to: 491231234567
39
+ result = provider.deliver
40
+
41
+ # returns the message id from MobiWeb or nil if something went wrong
42
+ puts result // 1234
43
+ ```
44
+
45
+ There's also a short version:
46
+
47
+ ```rb
48
+ SmsKit::MobiWeb.deliver text: 'Hello World.', to: 491231234567
49
+ ```
50
+
51
+ ### Sending "Objects"
52
+
53
+ If your class responds to `to_sms`, you can send it itself:
54
+
55
+ ```rb
56
+ class TextMessage
57
+ def to_sms
58
+ {
59
+ to: 491231234567
60
+ text: 'hello world'
61
+ }
62
+ end
63
+ end
64
+
65
+ SmsKit.deliver :provider_name, TextMessage.new
66
+
67
+ # or on a provider level
68
+
69
+ class MyProvider < SmsKit::Provider
70
+ # ...
71
+ end
72
+
73
+ MyProvider.deliver TextMessage.new
74
+
75
+ ```
76
+
77
+ #### Error handling
78
+
79
+ SmsKit will throw a `SmsKit::DeliveryError` if something goes wrong.
80
+ Though it depends on the specific provider this generally happens
81
+ upon authentication errors as well as returned error codes from the web service.
82
+
83
+ ```rb
84
+ begin
85
+ provider = :provider_symbol
86
+ SmsKit.deliver provider, text: 'hello world', to: '...'
87
+ rescue SmsKit::DeliveryError => e
88
+ logger.error e
89
+ end
90
+ ```
91
+
92
+ ## Common SMS options
93
+
94
+ Which options the `#deliver` method expects generallly depends on provider implementation.
95
+ However, core providers expect the following options, at least:
96
+
97
+ - `:to` The number to send the message to
98
+ - `:from` The sender ID
99
+ - `:text` The text message
100
+
101
+ ## Packaged providers
102
+
103
+ - CentralICT -- [www.centralict.com](http://www.centralict.com/)
104
+ - MobiWeb -- [mobile-sms.biz](http://mobile-sms.biz/)
105
+ - Mobimex -- [www.mobimex.com](http://www.mobimex.com/)
106
+ - smstrade -- [www.smstrade.de](http://www.smstrade.eu/)
107
+
108
+ ## Contributing
109
+
110
+ 1. Fork it
111
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
112
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
113
+ 4. Push to the branch (`git push origin my-new-feature`)
114
+ 5. Create new Pull Request
115
+
116
+ ## License
117
+
118
+ SmsKit is released under the [MIT License](http://www.opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.pattern = "test/*_test.rb"
7
+ end
8
+
9
+ task default: :test
data/lib/sms_kit.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'sms_kit/version'
2
+ require 'sms_kit/utils'
3
+ require 'sms_kit/delivery'
4
+ require 'sms_kit/logging'
5
+ require 'sms_kit/railtie' if defined?(Rails)
6
+
7
+ module SmsKit
8
+ extend Utils
9
+ extend Delivery
10
+ extend Logging
11
+
12
+ class DeliveryError < StandardError; end
13
+
14
+ USER_AGENT = "SmsKit #{VERSION}"
15
+ end
@@ -0,0 +1,43 @@
1
+ require 'ostruct'
2
+
3
+ module SmsKit
4
+ module Config
5
+
6
+ def self.included base
7
+ base.extend ClassMethods
8
+
9
+ base.class_eval do
10
+ def config
11
+ self.class.config
12
+ end
13
+ end
14
+ end
15
+
16
+ class Store < Hash
17
+ def method_missing meth, *args
18
+ unless respond_to? meth
19
+ if key = meth.to_s[/(.*)=$/, 1]
20
+ self[key.to_sym] = args.first
21
+ else
22
+ self[meth.to_sym]
23
+ end
24
+ else
25
+ super
26
+ end
27
+ end
28
+ end
29
+
30
+ module ClassMethods
31
+
32
+ def config
33
+ @config ||= Store.new
34
+ end
35
+
36
+ def configure
37
+ yield config
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,13 @@
1
+ module SmsKit
2
+ module Delivery
3
+
4
+ def deliver provider, options, &block
5
+ unless klass = providers[provider.to_sym]
6
+ raise "SMS provider #{provider} not known"
7
+ end
8
+
9
+ klass.deliver options, &block
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ require 'faraday'
2
+
3
+ module SmsKit
4
+ module HTTP
5
+
6
+ def uri
7
+ @uri ||= URI.parse self.class.const_get 'HTTP_ENDPOINT'
8
+ end
9
+
10
+ def post data
11
+ connection.post uri.path, data
12
+ end
13
+
14
+ def get data
15
+ connection.get uri.path, data
16
+ end
17
+
18
+ def connection
19
+ @conn ||= Faraday.new "#{uri.scheme}://#{uri.host}", ssl: { verify: false } do |f|
20
+ f.headers[:user_agent] = USER_AGENT
21
+ f.response :logger, SmsKit.logger
22
+ f.adapter Faraday.default_adapter
23
+ yield f if block_given?
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ require 'logger'
2
+
3
+ module SmsKit
4
+ module Logging
5
+
6
+ attr_writer :logger
7
+
8
+ def logger
9
+ @logger ||= begin
10
+ require 'logger'
11
+ Logger.new(STDOUT).tap do |l|
12
+ if l.respond_to? :formatter=
13
+ l.formatter ||= Logger::Formatter.new
14
+ l.formatter.extend Formatter
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ module Formatter
21
+ def call severity, datetime, progname, msg
22
+ '[SmsKit] ' + super(severity, datetime, progname, msg)
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ require 'sms_kit/config'
2
+ require 'sms_kit/http'
3
+
4
+ module SmsKit
5
+ class Provider
6
+ include SmsKit::Config
7
+ include SmsKit::HTTP
8
+
9
+ attr_reader :data, :error_code, :error_message
10
+
11
+ def self.deliver options = {}, &block
12
+ options = options.to_sms if options.respond_to? :to_sms
13
+ new(options, &block).deliver
14
+ end
15
+
16
+ def initialize options = {}, &block
17
+ @data = options
18
+ yield self if block_given?
19
+ end
20
+
21
+ def deliver options = {}
22
+ raise "#{self.class.name} needs to implement #deliver"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ require 'sms_kit/providers/mobi_web'
2
+ require 'sms_kit/providers/mobimex'
3
+ require 'sms_kit/providers/central_ict'
@@ -0,0 +1,46 @@
1
+ require 'sms_kit/provider'
2
+
3
+ module SmsKit
4
+ class CentralICT < Provider
5
+
6
+ HTTP_ENDPOINT = 'http://api.de.centralict.net/controller/cgi/'
7
+
8
+ def deliver
9
+ response = get params
10
+ parsed_response = parse response.body
11
+ status = parsed_response['sent']
12
+
13
+ if 1 != status.to_i
14
+ raise DeliveryError, "Delivery failed (#{status})"
15
+ else
16
+ true
17
+ end
18
+ end
19
+
20
+ def params
21
+ {
22
+ type: 'SMS',
23
+ src: data[:from] || config.sender,
24
+ dst: data[:to],
25
+ body: data[:text],
26
+ uid: data[:uid] || '',
27
+ pin: data[:pin] || '',
28
+ subject: data[:subject] || '',
29
+ call: data[:call] || 'message_sender'
30
+ }
31
+ end
32
+
33
+ def get payload
34
+ connection.basic_auth config.username, config.password
35
+ super
36
+ end
37
+
38
+ def parse string
39
+ Hash[string.scan %r{(\w+)=(.*)}]
40
+ end
41
+
42
+ end
43
+
44
+ register central_ict: CentralICT
45
+
46
+ end
@@ -0,0 +1,54 @@
1
+ require 'sms_kit/provider'
2
+
3
+ module SmsKit
4
+ class MobiWeb < Provider
5
+
6
+ # http://api2.solutions4mobiles.com/bulksms/bulksend.go?msgtext=&originator=&password=mobiweb-pass&phone=491231234567&showDLR=1&username=mail@example.com
7
+ HTTP_ENDPOINT = "https://api2.solutions4mobiles.com/bulksms/bulksend.go"
8
+
9
+ ERROR_CODES = {
10
+ 100 => 'Temporary Internal Server Error. Try again later',
11
+ 101 => 'Authentication Error',
12
+ 102 => 'No credits available',
13
+ 103 => 'MSIDSN (phone parameter) is invalid or prefix is not supported',
14
+ 104 => 'Tariff Error',
15
+ 105 => 'You are not allowed to send to that destination/country',
16
+ 106 => 'Not Valid Route number or you are not allowed to use this route',
17
+ 107 => 'No proper Authentication (IP restriction is activated)',
18
+ 108 => 'You have no permission to send messages through HTTP API',
19
+ 109 => 'Not Valid Originator',
20
+ 110 => 'You are not allowed to send (Routing not available) or Reseller is trying to send while not allowed',
21
+ 111 => 'Invalid Expiration date or Expiration Date is less than 30 minutes than the date of SMS submission',
22
+ 999 => 'Invalid HTTP request'
23
+ }
24
+
25
+ def deliver
26
+ response = get params
27
+ status = response.body[/([a-z]+)(\d+)?/i, 1]
28
+ code = response.body[/([a-z]+)(\d+)?/i, 2]
29
+
30
+ if 'ERROR' == status
31
+ raise DeliveryError, "#{ERROR_CODES[code.to_i]} (#{code})"
32
+ end
33
+
34
+ status == "OK" ? code.to_i : nil
35
+ end
36
+
37
+ def params
38
+ _data = data.dup
39
+ {
40
+ username: config.username,
41
+ password: config.password,
42
+ originator: _data.delete(:from) || config.sender,
43
+ phone: _data.delete(:to),
44
+ msgtext: _data.delete(:text),
45
+ showDLR: _data.delete(:dlr) || 1,
46
+ charset: _data.delete(:charset) || 8
47
+ }.merge _data
48
+ end
49
+
50
+ end
51
+
52
+ register mobi_web: MobiWeb
53
+
54
+ end
@@ -0,0 +1,56 @@
1
+ require 'sms_kit/provider'
2
+ require 'json'
3
+
4
+ module SmsKit
5
+ class Mobimex < Provider
6
+
7
+ ROUTE_AFRICA = 'AFRIKA'.freeze
8
+
9
+ HTTP_ENDPOINT = 'https://gate.quadra-mm.com/feed/http.asp'
10
+ RESPONSE_FORMATS = { text: 0, xml: 1, json: 2 }
11
+
12
+ # response json looks like this:
13
+ # {"procedure":"SMS Feed","result":1,"description":"DONE: SMS is in the send queue."}
14
+ def deliver
15
+ response = post params
16
+ if response.body.length > 1
17
+ json = JSON.parse(response.body)
18
+ json['result'].to_i == 1
19
+ else
20
+ raise DeliveryError, "Delivery failed (#{response.body})"
21
+ end
22
+ end
23
+
24
+ def params
25
+ {
26
+ user: config.username,
27
+ pass: config.password,
28
+ dlr: data[:dlr_profile] || 0,
29
+ xml: response_format,
30
+ from_number: data[:from] || config.sender,
31
+ number: data[:to],
32
+ message: data[:text],
33
+ idd: data[:idd] || 0,
34
+ im: data[:im] || 0,
35
+ route: data[:route] || config.route,
36
+ type: data[:type] || 'text'
37
+ }.reject { |k, v| v.nil? }
38
+ end
39
+
40
+ def response_format
41
+ RESPONSE_FORMATS.fetch data[:format], :json
42
+ end
43
+
44
+ def post payload
45
+ connection.post do |req|
46
+ req.url uri.path
47
+ req.headers['Content-Type'] = 'application/json'
48
+ req.body = payload.to_json
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ register mobimex: Mobimex
55
+
56
+ end