sms_kit 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +118 -0
- data/Rakefile +9 -0
- data/lib/sms_kit.rb +15 -0
- data/lib/sms_kit/config.rb +43 -0
- data/lib/sms_kit/delivery.rb +13 -0
- data/lib/sms_kit/http.rb +28 -0
- data/lib/sms_kit/logging.rb +27 -0
- data/lib/sms_kit/provider.rb +25 -0
- data/lib/sms_kit/providers.rb +3 -0
- data/lib/sms_kit/providers/central_ict.rb +46 -0
- data/lib/sms_kit/providers/mobi_web.rb +54 -0
- data/lib/sms_kit/providers/mobimex.rb +56 -0
- data/lib/sms_kit/providers/sms_trade.rb +77 -0
- data/lib/sms_kit/railtie.rb +7 -0
- data/lib/sms_kit/utils.rb +13 -0
- data/lib/sms_kit/version.rb +3 -0
- data/test/central_ict_test.rb +40 -0
- data/test/config_test.rb +34 -0
- data/test/delivery_test.rb +21 -0
- data/test/fixtures/vcr_cassettes/central_ict/failure.yml +33 -0
- data/test/fixtures/vcr_cassettes/central_ict/success.yml +33 -0
- data/test/fixtures/vcr_cassettes/mobi_web/failure.yml +32 -0
- data/test/fixtures/vcr_cassettes/mobi_web/quick_deliver.yml +32 -0
- data/test/fixtures/vcr_cassettes/mobi_web/success.yml +32 -0
- data/test/fixtures/vcr_cassettes/mobimex/failure.yml +24 -0
- data/test/fixtures/vcr_cassettes/mobimex/success.yml +25 -0
- data/test/fixtures/vcr_cassettes/sms_trade/failure.yml +32 -0
- data/test/fixtures/vcr_cassettes/sms_trade/success.yml +34 -0
- data/test/fixtures/vcr_cassettes/stub_provider/success.yml +22 -0
- data/test/helper.rb +30 -0
- data/test/http_test.rb +22 -0
- data/test/logging_test.rb +21 -0
- data/test/mobi_web_test.rb +46 -0
- data/test/mobimex_test.rb +40 -0
- data/test/provider_test.rb +49 -0
- data/test/sms_trade_test.rb +44 -0
- data/test/utils_test.rb +12 -0
- 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
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
|
data/lib/sms_kit/http.rb
ADDED
@@ -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,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
|