smster 0.0.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +32 -0
- data/Rakefile +34 -0
- data/app/controllers/smster/clickatell_controller.rb +22 -0
- data/app/controllers/smster/nexmo_controller.rb +17 -0
- data/lib/generators/smster/install/templates/create_smsters.rb +20 -0
- data/lib/generators/smster/install/templates/smster.rb +8 -0
- data/lib/generators/smster/install_generator.rb +38 -0
- data/lib/smster.rb +21 -0
- data/lib/smster/configuration.rb +11 -0
- data/lib/smster/sms.rb +32 -0
- data/lib/smster/sms/clickatell.rb +34 -0
- data/lib/smster/sms/nexmo.rb +45 -0
- data/lib/smster/version.rb +3 -0
- data/lib/tasks/smster_tasks.rake +4 -0
- data/test/controller/smster/clickatell_controller_test.rb +27 -0
- data/test/controller/smster/nexmo_controller_test.rb +19 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/smster.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20150330154603_create_smsters.rb +20 -0
- data/test/dummy/db/schema.rb +29 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +141 -0
- data/test/dummy/log/test.log +1918 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/smster/sms/clickatell_test.rb +21 -0
- data/test/smster/sms/nexmo_test.rb +22 -0
- data/test/smster_test.rb +16 -0
- data/test/test_helper.rb +19 -0
- metadata +181 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 715e7236f095993ddfa89768a85a791ae4c0efd8
|
4
|
+
data.tar.gz: dd512320a0ffc07130b56771512cab7f9d86d410
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 733d1fc0f88b29bb49fc5ae099142bb03c9cf07a03a23eaaabcbd8be8b8f807d98cb96906dfd3dea633849fb54be15e34783fc78043439d28871faf2c2a686fd
|
7
|
+
data.tar.gz: f46599540651ddb19bfdf1fe08ea7fd875b4791cbb743271f0dfe5d11020ae0a27cd8d38d5796c0b17d70d103773555e4115e131479c62b531bf23c4b65c3d49
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2015 doniv
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
= Smster
|
2
|
+
SMS sending service through different providers with maximum convenience.
|
3
|
+
|
4
|
+
===== Supported
|
5
|
+
* {Nexmo}[https://www.nexmo.com/]
|
6
|
+
* {Clickatell}[https://www.clickatell.com/]
|
7
|
+
|
8
|
+
== Setup
|
9
|
+
Add gem:
|
10
|
+
gem 'smster', git: 'git@github.com:IlyaDonskikh/smster.git'
|
11
|
+
|
12
|
+
Install:
|
13
|
+
rails g smster:install
|
14
|
+
|
15
|
+
== Sending message
|
16
|
+
Add config of your provider into config/initializers/smster.rb.
|
17
|
+
|
18
|
+
And let's start!
|
19
|
+
Sms::Nexmo.create(text: 'sms text', to: phone_number)
|
20
|
+
Sms::Clickatell.create(text: 'sms text', to: phone_number)
|
21
|
+
|
22
|
+
== Callbacks
|
23
|
+
Add to routes, setup proveder callbacks and get sms statuses:
|
24
|
+
post 'smster/$provider_name/callback'
|
25
|
+
|
26
|
+
== Feedback
|
27
|
+
Please use the {issue tracker}[https://github.com/IlyaDonskikh/smster/issues].
|
28
|
+
|
29
|
+
== Thanks
|
30
|
+
1. Mickhail Zelenin for the idea for this gem.
|
31
|
+
2. Egor Kiselev for help in creation of this manual.
|
32
|
+
3. Alexey Bandar for the recommendation of the first provider.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Smster'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
task default: :test
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Smster::ClickatellController < ApplicationController
|
2
|
+
skip_before_filter :verify_authenticity_token
|
3
|
+
|
4
|
+
def callback
|
5
|
+
code = clickatell_params[:apiMessageId]
|
6
|
+
description = clickatell_params[:description]
|
7
|
+
sms = Sms::Clickatell.find_by!(code: code)
|
8
|
+
|
9
|
+
sms.status_message = description
|
10
|
+
sms.save
|
11
|
+
|
12
|
+
sms.accept! if description == 'Received by recipient'
|
13
|
+
result = { sms.id => sms.status }
|
14
|
+
|
15
|
+
render json: result.as_json, status: 200
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def clickatell_params
|
20
|
+
params.require(:data)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Smster::NexmoController < ApplicationController
|
2
|
+
skip_before_filter :verify_authenticity_token
|
3
|
+
|
4
|
+
def callback
|
5
|
+
code = params['messageId']
|
6
|
+
status = params['status']
|
7
|
+
sms = Sms::Nexmo.find_by!(code: code)
|
8
|
+
|
9
|
+
sms.status_message = status
|
10
|
+
sms.save
|
11
|
+
|
12
|
+
sms.accept! if status == 'delivered'
|
13
|
+
result = { sms.id => sms.status }
|
14
|
+
|
15
|
+
render json: result.as_json, status: 200
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateSmsters< ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
create_table :smsters do |t|
|
4
|
+
t.string :text
|
5
|
+
t.string :name
|
6
|
+
t.string :from
|
7
|
+
t.string :to
|
8
|
+
t.string :code
|
9
|
+
t.string :type
|
10
|
+
t.integer :status
|
11
|
+
t.string :status_message
|
12
|
+
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def down
|
18
|
+
drop_table :smsters
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
module Smster
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc "Add migration"
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
source_root File.expand_path('../install/templates', __FILE__)
|
7
|
+
|
8
|
+
def copy_migrations
|
9
|
+
copy_migration "create_smsters"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.next_migration_number(path)
|
13
|
+
unless @prev_migration_nr
|
14
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
15
|
+
else
|
16
|
+
@prev_migration_nr += 1
|
17
|
+
end
|
18
|
+
@prev_migration_nr.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Add initializer'
|
22
|
+
source_root File.expand_path('../install/templates', __FILE__)
|
23
|
+
|
24
|
+
def copy_initializer
|
25
|
+
filename = 'smster'
|
26
|
+
copy_file "#{filename}.rb", "config/initializers/#{filename}.rb"
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
def copy_migration(filename)
|
31
|
+
if self.class.migration_exists?("db/migrate", "#{filename}")
|
32
|
+
say_status("skipped", "Migration #{filename}.rb already exists")
|
33
|
+
else
|
34
|
+
migration_template "#{filename}.rb", "db/migrate/#{filename}.rb"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/smster.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require "smster/configuration"
|
3
|
+
require 'smster/sms'
|
4
|
+
require 'smster/sms/clickatell'
|
5
|
+
require 'smster/sms/nexmo'
|
6
|
+
|
7
|
+
module Smster
|
8
|
+
class Engine < Rails::Engine; end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.configuration
|
15
|
+
@configuration ||= Configuration.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.configure
|
19
|
+
yield(configuration)
|
20
|
+
end
|
21
|
+
end
|
data/lib/smster/sms.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
class Sms < ActiveRecord::Base
|
2
|
+
self.table_name = "smsters"
|
3
|
+
attr_accessor :mode
|
4
|
+
|
5
|
+
## Codes
|
6
|
+
STATUS_CODES = { created: 0, sent: 1, delivered: 2, failed: 3 }
|
7
|
+
|
8
|
+
## Callbacks
|
9
|
+
after_create :send_sms
|
10
|
+
|
11
|
+
## Validations
|
12
|
+
validates :type, :to, :text, presence: true
|
13
|
+
|
14
|
+
## Etc.
|
15
|
+
def initialize(attributes = {})
|
16
|
+
attr_with_defaults = {
|
17
|
+
status: STATUS_CODES[:created]
|
18
|
+
}.merge(attributes)
|
19
|
+
super(attr_with_defaults)
|
20
|
+
end
|
21
|
+
|
22
|
+
def mode
|
23
|
+
@mode ||= case Rails.env
|
24
|
+
when 'test' then 'test'
|
25
|
+
else 'production'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def accept!
|
30
|
+
self.update(status: STATUS_CODES[:delivered])
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Sms::Clickatell < Sms
|
2
|
+
def send_sms
|
3
|
+
config = Smster.configuration
|
4
|
+
authorization_code = config.clickatell_authorization_code
|
5
|
+
|
6
|
+
text = self.text.tr(" ", "+")
|
7
|
+
phone = to.gsub(/\D/, '')
|
8
|
+
|
9
|
+
api_message_id = if self.mode == 'test'
|
10
|
+
logger.debug("Mode: #{mode}. To: #{phone}, text: #{text}")
|
11
|
+
self.id
|
12
|
+
else
|
13
|
+
response = RestClient.post('https://api.clickatell.com/rest/message',
|
14
|
+
{ "text" => text, "to" => [phone.to_s] }.to_json,
|
15
|
+
:content_type => :json,
|
16
|
+
:accept => :json,
|
17
|
+
'X-Version' => 1,
|
18
|
+
'Authorization' => "bearer #{authorization_code}")
|
19
|
+
response = JSON.parse(response)
|
20
|
+
response['data']['message'][0]['apiMessageId']
|
21
|
+
end
|
22
|
+
|
23
|
+
if api_message_id.present?
|
24
|
+
self.code = api_message_id
|
25
|
+
self.status = STATUS_CODES[:sent]
|
26
|
+
self.save
|
27
|
+
end
|
28
|
+
rescue => e
|
29
|
+
logger.debug("Error #{e}")
|
30
|
+
self.status = STATUS_CODES[:failed]
|
31
|
+
self.status_message = e.to_s
|
32
|
+
self.save
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Sms::Nexmo < Sms
|
2
|
+
def send_sms
|
3
|
+
config = Smster.configuration
|
4
|
+
api_key = config.nexmo_key
|
5
|
+
api_secret = config.nexmo_sekret
|
6
|
+
|
7
|
+
text = self.text.tr(" ", "+")
|
8
|
+
phone = to.gsub(/\D/, '')
|
9
|
+
current_status = STATUS_CODES[:sent]
|
10
|
+
|
11
|
+
api_message_id = if self.mode == 'test'
|
12
|
+
logger.debug("Mode: #{mode}. To: #{phone}, text: #{text}")
|
13
|
+
self.id
|
14
|
+
else
|
15
|
+
response = RestClient.post('https://rest.nexmo.com/sms/json',
|
16
|
+
"text" => text,
|
17
|
+
"to" => phone.to_s,
|
18
|
+
:content_type => :json,
|
19
|
+
:from => 'OnlinePay',
|
20
|
+
:api_key => api_key,
|
21
|
+
:api_secret => api_secret)
|
22
|
+
|
23
|
+
json_response = JSON.parse(response)
|
24
|
+
error_text = json_response['messages'][0]['error-text']
|
25
|
+
json_response['messages'][0]['message-id']
|
26
|
+
end
|
27
|
+
|
28
|
+
if api_message_id.present?
|
29
|
+
self.code = api_message_id
|
30
|
+
self.status = STATUS_CODES[:sent]
|
31
|
+
end
|
32
|
+
|
33
|
+
if error_text.present?
|
34
|
+
self.status = STATUS_CODES[:failed]
|
35
|
+
self.status_message = error_text
|
36
|
+
end
|
37
|
+
|
38
|
+
self.save
|
39
|
+
rescue => e
|
40
|
+
logger.debug("Error #{e}")
|
41
|
+
self.status = STATUS_CODES[:failed]
|
42
|
+
self.status_message = e.to_s
|
43
|
+
self.save
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Smster::ClickatellControllerTest < ActionController::TestCase
|
4
|
+
def setup
|
5
|
+
@text = "simple text"
|
6
|
+
@number = (0...7).map { (1..9).to_a.sample }.join
|
7
|
+
@provider = Sms::Clickatell
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'callback' do
|
11
|
+
delivered_code = Sms::STATUS_CODES[:delivered]
|
12
|
+
sms = @provider.create(text: @text, to: @number)
|
13
|
+
|
14
|
+
post :callback, {
|
15
|
+
"data" => {
|
16
|
+
"charge" => 1.5,
|
17
|
+
"messageStatus" => 003,
|
18
|
+
"description" => "Received by recipient",
|
19
|
+
"apiMessageId" => sms.code
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
response = JSON.parse(@response.body)
|
24
|
+
result = { sms.id => delivered_code }
|
25
|
+
assert_equal result.as_json, response
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Smster::NexmoControllerTest < ActionController::TestCase
|
4
|
+
def setup
|
5
|
+
@text = "simple text"
|
6
|
+
@number = (0...7).map { (1..9).to_a.sample }.join
|
7
|
+
@provider = Sms::Nexmo
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'callback' do
|
11
|
+
delivered_code = Sms::STATUS_CODES[:delivered]
|
12
|
+
sms = @provider.create(text: @text, to: @number)
|
13
|
+
|
14
|
+
post :callback, { "messageId" => sms.code, "status" => 'delivered' }
|
15
|
+
response = JSON.parse(@response.body)
|
16
|
+
result = { sms.id => delivered_code }
|
17
|
+
assert_equal result.as_json, response
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|