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.
- 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 [](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
|