sms_kit 1.3.1

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.
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