action_smser 1.0.0
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.
- data/MIT-LICENSE +20 -0
- data/README.md +191 -0
- data/Rakefile +39 -0
- data/app/assets/javascripts/action_smser/delivery_reports.js +2 -0
- data/app/assets/stylesheets/action_smser/application.css +7 -0
- data/app/assets/stylesheets/action_smser/delivery_reports.css +4 -0
- data/app/assets/stylesheets/scaffold.css +56 -0
- data/app/controllers/action_smser/application_controller.rb +4 -0
- data/app/controllers/action_smser/delivery_reports_controller.rb +63 -0
- data/app/models/action_smser/delivery_report.rb +30 -0
- data/app/views/action_smser/delivery_reports/index.html.erb +143 -0
- data/app/views/layouts/action_smser/delivery_reports.html.erb +56 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20120102215215_create_action_smser_delivery_reports.rb +19 -0
- data/lib/action_smser.rb +24 -0
- data/lib/action_smser/base.rb +133 -0
- data/lib/action_smser/delivery_methods/simple_http.rb +70 -0
- data/lib/action_smser/delivery_methods/test_array.rb +30 -0
- data/lib/action_smser/engine.rb +5 -0
- data/lib/action_smser/version.rb +3 -0
- data/lib/tasks/action_smser_tasks.rake +4 -0
- data/test/action_smser_test.rb +7 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +7 -0
- data/test/dummy/app/assets/stylesheets/application.css +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/hello_smser.rb +9 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +51 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +26 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +30 -0
- data/test/dummy/config/environments/production.rb +60 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/git_ignored_passwords.rb +10 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +28 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +540 -0
- data/test/dummy/log/test.log +18246 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/functional/action_smser/delivery_reports_controller_test.rb +118 -0
- data/test/integration/navigation_test.rb +11 -0
- data/test/test_helper.rb +25 -0
- data/test/unit/action_smser/base_test.rb +83 -0
- data/test/unit/action_smser/delivery_methods/simple_http_test.rb +52 -0
- data/test/unit/action_smser/delivery_methods/test_array_test.rb +42 -0
- data/test/unit/action_smser/delivery_report_test.rb +54 -0
- metadata +212 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>ActionSmser</title>
|
5
|
+
<%#= stylesheet_link_tag "action_smser/application" %>
|
6
|
+
<%#= javascript_include_tag "action_smser/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
|
9
|
+
<STYLE type="text/css">
|
10
|
+
table {
|
11
|
+
border: 1px solid gray;
|
12
|
+
border-collapse:collapse;
|
13
|
+
|
14
|
+
}
|
15
|
+
th, td {
|
16
|
+
border: 1px solid gray;
|
17
|
+
padding: 1px 10px 1px 3px;
|
18
|
+
}
|
19
|
+
|
20
|
+
h1 { margin-top: 40px; }
|
21
|
+
h2 { margin-top: 40px; }
|
22
|
+
|
23
|
+
body, div {
|
24
|
+
color: #444;
|
25
|
+
font-size: 12px;
|
26
|
+
line-height: 150%;
|
27
|
+
line-height: 130%;
|
28
|
+
font-family: Helvetica, Arial, sans-serif;
|
29
|
+
|
30
|
+
}
|
31
|
+
hr { margin-top: 20px; margin-bottom: 10px; }
|
32
|
+
|
33
|
+
</STYLE>
|
34
|
+
|
35
|
+
</head>
|
36
|
+
<body class="delivery_reports_layout">
|
37
|
+
|
38
|
+
<h1>ActionSmser infos</h1>
|
39
|
+
|
40
|
+
Back to <%= link_to 'Main application', '/' %>
|
41
|
+
|
42
|
+
<hr>
|
43
|
+
|
44
|
+
<%= yield %>
|
45
|
+
|
46
|
+
|
47
|
+
<hr>
|
48
|
+
<p>
|
49
|
+
Stats by ActionSmser gem, see homepage: <%= link_to 'https://github.com/holli/action_smser', 'https://github.com/holli/action_smser' %>
|
50
|
+
</p>
|
51
|
+
|
52
|
+
<p style="margin-top: 400px"></p>
|
53
|
+
|
54
|
+
|
55
|
+
</body>
|
56
|
+
</html>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateActionSmserDeliveryReports < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :action_smser_delivery_reports do |t|
|
4
|
+
t.string :msg_id
|
5
|
+
t.string :status
|
6
|
+
t.datetime :status_updated_at
|
7
|
+
t.string :sms_type
|
8
|
+
t.text :log
|
9
|
+
|
10
|
+
t.string :to
|
11
|
+
t.string :from
|
12
|
+
t.string :body
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index "action_smser_delivery_reports", :msg_id
|
18
|
+
end
|
19
|
+
end
|
data/lib/action_smser.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "action_smser/engine"
|
2
|
+
require "action_smser/base"
|
3
|
+
|
4
|
+
Dir[File.dirname(__FILE__) + '/action_smser/delivery_methods/*.rb'].each do |file|
|
5
|
+
require file
|
6
|
+
end
|
7
|
+
|
8
|
+
module ActionSmser
|
9
|
+
|
10
|
+
mattr_accessor :delivery_options
|
11
|
+
self.delivery_options= {:delivery_method => :test_array, :save_delivery_reports => false}
|
12
|
+
|
13
|
+
class Logger
|
14
|
+
def self.info(str)
|
15
|
+
Rails.logger.info("ActionSmser: #{str}")
|
16
|
+
end
|
17
|
+
def self.warn(str)
|
18
|
+
Rails.logger.warn("ActionSmser: #{str}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'cgi'
|
3
|
+
require 'iconv'
|
4
|
+
|
5
|
+
class ActionSmser::Base
|
6
|
+
|
7
|
+
# This is the main class that your sms mailers will inherit.
|
8
|
+
class << self
|
9
|
+
def method_missing(method, *args) #:nodoc:
|
10
|
+
return super unless respond_to?(method)
|
11
|
+
new(method, *args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def respond_to?(method, include_private = false) #:nodoc:
|
15
|
+
#super || public_instance_methods(true).include?(method.to_s)
|
16
|
+
super || method_defined?(method.to_sym)
|
17
|
+
end
|
18
|
+
|
19
|
+
# http://en.wikipedia.org/wiki/GSM_03.38 , some chars takes 2 spaces
|
20
|
+
SMS_DOUBLE_CHARS = '€[\]^{|}~' # http://sites.google.com/site/freesmsuk/gsm7-encoding
|
21
|
+
def message_real_length(message)
|
22
|
+
i = 0
|
23
|
+
message.to_s.chars.each do |char| i += SMS_DOUBLE_CHARS.include?(char) ? 2 : 1 end
|
24
|
+
i
|
25
|
+
end
|
26
|
+
# Make sure that double chars are taken account
|
27
|
+
def message_real_cropped(message, max_length = 159)
|
28
|
+
result = ""
|
29
|
+
length = 0
|
30
|
+
message.to_s.chars.each do |char|
|
31
|
+
length += SMS_DOUBLE_CHARS.include?(char) ? 2 : 1
|
32
|
+
result << char if length <= max_length
|
33
|
+
end
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
##################################################################
|
41
|
+
## INSTANCE METHODS
|
42
|
+
|
43
|
+
attr_accessor :body, :to, :from
|
44
|
+
|
45
|
+
# Initialized to duplicate of ActionSmser.delivery_options
|
46
|
+
attr_accessor :delivery_options
|
47
|
+
|
48
|
+
# Delivery methods can use this to save data for debugging, e.g. http responses etc
|
49
|
+
attr_accessor :delivery_info
|
50
|
+
|
51
|
+
# sms_type is string "ClassName.ActionName", initialized in beginning
|
52
|
+
def sms_type
|
53
|
+
"#{self.class}.#{@sms_action}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Called from class.method_missing with own_sms_message when you call OwnMailer.own_sms_message
|
57
|
+
def initialize(method_name, *args)
|
58
|
+
@delivery_options = ActionSmser.delivery_options.dup
|
59
|
+
@valid = true
|
60
|
+
@sms_action = method_name
|
61
|
+
send method_name, *args
|
62
|
+
end
|
63
|
+
|
64
|
+
# Main method for creating sms infos
|
65
|
+
def sms(options)
|
66
|
+
@body = options[:body]
|
67
|
+
@to = options[:to]
|
68
|
+
@from = options[:from]
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
"Sms #{sms_type} - From: #{from.inspect}, To: #{to.inspect}, Body: #{body.inspect}, Valid: #{@valid}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def valid?
|
77
|
+
!body.blank? && !from.blank? && !to_numbers_array.collect{|number| number.to_s.blank? ? nil : true}.compact.blank?
|
78
|
+
end
|
79
|
+
|
80
|
+
def delivery_method
|
81
|
+
ActionSmser::DeliveryMethods.const_get(delivery_options[:delivery_method].to_s.downcase.camelize)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def deliver
|
86
|
+
return false unless valid?
|
87
|
+
|
88
|
+
logger.info "Sending sms (#{self.to_s})"
|
89
|
+
|
90
|
+
response = delivery_method.deliver(self) if valid?
|
91
|
+
|
92
|
+
self.send(:after_delivery, response) if self.respond_to?(:after_delivery)
|
93
|
+
|
94
|
+
response
|
95
|
+
#SmsSentInfo.create_from_http_response(@response, self.sender, recipients_receive_sms, sms_type, self.message)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Most of the gateways want escaped and ISO encoded messages
|
99
|
+
# Also make sure that its max 500 chars long
|
100
|
+
def body_encoded_escaped
|
101
|
+
msg = body.first(500)
|
102
|
+
CGI.escape(Iconv.iconv('ISO-8859-15//TRANSLIT//IGNORE', 'utf-8', msg).first.to_s)
|
103
|
+
end
|
104
|
+
|
105
|
+
# make sure that to is an array and remove leading '+' or '0' chars
|
106
|
+
def to_numbers_array
|
107
|
+
array = if @to.is_a?(Array)
|
108
|
+
@to.collect{|number| number.to_s}
|
109
|
+
else
|
110
|
+
[@to.to_s]
|
111
|
+
end
|
112
|
+
array.collect{|number| number.gsub(/^(\+|0)/, "")}
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_as_array
|
116
|
+
@to.is_a?(Array) ? @to : [@to]
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_encoded
|
120
|
+
to_numbers_array.join(",")
|
121
|
+
end
|
122
|
+
|
123
|
+
def from_encoded
|
124
|
+
from.to_s.gsub(/^(\+|0)/, "")
|
125
|
+
end
|
126
|
+
|
127
|
+
def logger
|
128
|
+
ActionSmser::Logger
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
end
|
133
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
module ActionSmser::DeliveryMethods
|
5
|
+
|
6
|
+
# Very simple implementation of http request to gateway. Options used are
|
7
|
+
# server, use_ssl, username, password
|
8
|
+
# overwrite deliver_path(sms, options) with your own if you have different type of path
|
9
|
+
class SimpleHttp
|
10
|
+
|
11
|
+
def self.deliver(sms)
|
12
|
+
logger.info "Delivering sms by https"
|
13
|
+
|
14
|
+
options = sms.delivery_options[:simple_http]
|
15
|
+
deliver_path = self.deliver_path(sms, options)
|
16
|
+
response = self.deliver_http_request(sms, options, deliver_path)
|
17
|
+
|
18
|
+
logger.info "SimpleHttp delivery ||| #{deliver_path} ||| #{response.inspect}"
|
19
|
+
logger.info response.body if !response.blank?
|
20
|
+
sms.delivery_info = response
|
21
|
+
|
22
|
+
# Results include sms_id or error code in each line
|
23
|
+
|
24
|
+
results = response.body.split("\n")
|
25
|
+
if sms.delivery_options[:save_delivery_reports]
|
26
|
+
delivery_reports = []
|
27
|
+
sms.to_numbers_array.each_with_index do |to, i|
|
28
|
+
delivery_reports << ActionSmser::DeliveryReport.create_from_sms(sms, to, results[i].to_s.strip)
|
29
|
+
end
|
30
|
+
return delivery_reports
|
31
|
+
else
|
32
|
+
return results
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.deliver_http_request(sms, options, path)
|
38
|
+
# http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
|
39
|
+
# http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/
|
40
|
+
|
41
|
+
response = nil
|
42
|
+
|
43
|
+
server_port = options[:use_ssl] ? 443 : 80
|
44
|
+
http = Net::HTTP.new(options[:server], server_port)
|
45
|
+
if options[:use_ssl]
|
46
|
+
http.use_ssl = true
|
47
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
48
|
+
end
|
49
|
+
|
50
|
+
unless Rails.env.test?
|
51
|
+
http.start do |http|
|
52
|
+
response = http.request(Net::HTTP::Get.new(path)) unless Rails.env.test? #Never request by accident in test environment.
|
53
|
+
end
|
54
|
+
else
|
55
|
+
logger.warn "SimpleHttp does never make real http requests in test environment!"
|
56
|
+
end
|
57
|
+
|
58
|
+
response
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.deliver_path(sms, options)
|
62
|
+
"/api/sendsms/plain?user=#{options[:username]}&password=#{options[:password]}&sender=#{sms.from_encoded}&SMSText=#{sms.body_encoded_escaped}&GSM=#{sms.to_encoded}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.logger
|
66
|
+
ActionSmser::Logger
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActionSmser::DeliveryMethods
|
2
|
+
|
3
|
+
# Default delivery method for test environments.
|
4
|
+
# Saves delivered sms to ActionSmser::DeliveryMethods::TestArray.deliveries to help test your own software
|
5
|
+
# Normal array, see sms by 'ActionSmser::DeliveryMethods::TestArray.deliveries' and
|
6
|
+
# clear it between tests by 'ActionSmser::DeliveryMethods::TestArray.deliveries.clear'
|
7
|
+
class TestArray
|
8
|
+
@@deliveries = []
|
9
|
+
def self.deliveries
|
10
|
+
@@deliveries
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.deliver(sms)
|
14
|
+
ActionSmser::Logger.info "ActionSmser::DeliveryMethods::TestArray.deliveries added message, no real delivery."
|
15
|
+
self.deliveries << sms
|
16
|
+
|
17
|
+
if sms.delivery_options[:save_delivery_reports]
|
18
|
+
delivery_reports = []
|
19
|
+
sms.to_numbers_array.each do |to|
|
20
|
+
delivery_reports << ActionSmser::DeliveryReport.create_from_sms(sms, to, "test_array_id_#{rand(99999999)}")
|
21
|
+
end
|
22
|
+
delivery_reports
|
23
|
+
else
|
24
|
+
return sms.to_numbers_array
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/test/dummy/Rakefile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
Dummy::Application.load_tasks
|
@@ -0,0 +1,7 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into including all the files listed below.
|
2
|
+
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
3
|
+
// be included in the compiled file accessible from http://example.com/assets/application.js
|
4
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
5
|
+
// the compiled file.
|
6
|
+
//
|
7
|
+
//= require_tree .
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
|
+
*= require_self
|
6
|
+
*= require_tree .
|
7
|
+
*/
|