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.
Files changed (64) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +191 -0
  3. data/Rakefile +39 -0
  4. data/app/assets/javascripts/action_smser/delivery_reports.js +2 -0
  5. data/app/assets/stylesheets/action_smser/application.css +7 -0
  6. data/app/assets/stylesheets/action_smser/delivery_reports.css +4 -0
  7. data/app/assets/stylesheets/scaffold.css +56 -0
  8. data/app/controllers/action_smser/application_controller.rb +4 -0
  9. data/app/controllers/action_smser/delivery_reports_controller.rb +63 -0
  10. data/app/models/action_smser/delivery_report.rb +30 -0
  11. data/app/views/action_smser/delivery_reports/index.html.erb +143 -0
  12. data/app/views/layouts/action_smser/delivery_reports.html.erb +56 -0
  13. data/config/routes.rb +7 -0
  14. data/db/migrate/20120102215215_create_action_smser_delivery_reports.rb +19 -0
  15. data/lib/action_smser.rb +24 -0
  16. data/lib/action_smser/base.rb +133 -0
  17. data/lib/action_smser/delivery_methods/simple_http.rb +70 -0
  18. data/lib/action_smser/delivery_methods/test_array.rb +30 -0
  19. data/lib/action_smser/engine.rb +5 -0
  20. data/lib/action_smser/version.rb +3 -0
  21. data/lib/tasks/action_smser_tasks.rake +4 -0
  22. data/test/action_smser_test.rb +7 -0
  23. data/test/dummy/Rakefile +7 -0
  24. data/test/dummy/app/assets/javascripts/application.js +7 -0
  25. data/test/dummy/app/assets/stylesheets/application.css +7 -0
  26. data/test/dummy/app/controllers/application_controller.rb +3 -0
  27. data/test/dummy/app/helpers/application_helper.rb +2 -0
  28. data/test/dummy/app/mailers/hello_smser.rb +9 -0
  29. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  30. data/test/dummy/config.ru +4 -0
  31. data/test/dummy/config/application.rb +51 -0
  32. data/test/dummy/config/boot.rb +10 -0
  33. data/test/dummy/config/database.yml +26 -0
  34. data/test/dummy/config/environment.rb +5 -0
  35. data/test/dummy/config/environments/development.rb +30 -0
  36. data/test/dummy/config/environments/production.rb +60 -0
  37. data/test/dummy/config/environments/test.rb +39 -0
  38. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  39. data/test/dummy/config/initializers/git_ignored_passwords.rb +10 -0
  40. data/test/dummy/config/initializers/inflections.rb +10 -0
  41. data/test/dummy/config/initializers/mime_types.rb +5 -0
  42. data/test/dummy/config/initializers/secret_token.rb +7 -0
  43. data/test/dummy/config/initializers/session_store.rb +8 -0
  44. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  45. data/test/dummy/config/locales/en.yml +5 -0
  46. data/test/dummy/config/routes.rb +4 -0
  47. data/test/dummy/db/development.sqlite3 +0 -0
  48. data/test/dummy/db/schema.rb +28 -0
  49. data/test/dummy/db/test.sqlite3 +0 -0
  50. data/test/dummy/log/development.log +540 -0
  51. data/test/dummy/log/test.log +18246 -0
  52. data/test/dummy/public/404.html +26 -0
  53. data/test/dummy/public/422.html +26 -0
  54. data/test/dummy/public/500.html +26 -0
  55. data/test/dummy/public/favicon.ico +0 -0
  56. data/test/dummy/script/rails +6 -0
  57. data/test/functional/action_smser/delivery_reports_controller_test.rb +118 -0
  58. data/test/integration/navigation_test.rb +11 -0
  59. data/test/test_helper.rb +25 -0
  60. data/test/unit/action_smser/base_test.rb +83 -0
  61. data/test/unit/action_smser/delivery_methods/simple_http_test.rb +52 -0
  62. data/test/unit/action_smser/delivery_methods/test_array_test.rb +42 -0
  63. data/test/unit/action_smser/delivery_report_test.rb +54 -0
  64. 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,7 @@
1
+ ActionSmser::Engine.routes.draw do
2
+
3
+ match 'delivery_reports/gateway_commit/:gateway' => 'delivery_reports#gateway_commit'
4
+
5
+ resources :delivery_reports, :only => :index
6
+
7
+ end
@@ -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
@@ -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
@@ -0,0 +1,5 @@
1
+ module ActionSmser
2
+ class Engine < Rails::Engine
3
+ isolate_namespace ActionSmser
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module ActionSmser
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :action_smser do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class ActionSmserTest < ActiveSupport::TestCase
4
+ test "truth" do
5
+ assert_kind_of Module, ActionSmser
6
+ end
7
+ end
@@ -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
+ */
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,9 @@
1
+ class HelloSmser < ActionSmser::Base
2
+ def hello(to, from, body)
3
+ sms(:to => to, :from => from, :body => body)
4
+ end
5
+
6
+ def hello_world()
7
+ sms(:to => "123", :from => '123', :body => 'hello world')
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag "application" %>
6
+ <%= javascript_include_tag "application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Dummy::Application