txter 2.0.2
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.markdown +125 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/init.rb +3 -0
- data/lib/4info_templates/confirm.haml +6 -0
- data/lib/4info_templates/deliver.haml +11 -0
- data/lib/4info_templates/unblock.haml +6 -0
- data/lib/configuration.rb +41 -0
- data/lib/contactable.rb +150 -0
- data/lib/controller.rb +62 -0
- data/lib/gateway.rb +45 -0
- data/lib/gateway_4info.rb +114 -0
- data/lib/gateway_twilio.rb +45 -0
- data/lib/txter.rb +50 -0
- data/test/.gitignore +1 -0
- data/test/database.yml +18 -0
- data/test/gateway_4info_test.rb +75 -0
- data/test/gateway_twilio_test.rb +15 -0
- data/test/test_helper.rb +46 -0
- data/test/txter_contactable_test.rb +270 -0
- data/test/txter_controller_test.rb +76 -0
- data/test/txter_module_test.rb +56 -0
- data/txter.gemspec +74 -0
- metadata +102 -0
data/lib/gateway.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Txter
|
|
2
|
+
class Gateway
|
|
3
|
+
class Request
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
class Response
|
|
7
|
+
def initialize(*args)
|
|
8
|
+
@options = args.last
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def success?
|
|
12
|
+
:success == @options[:status]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
Success = Txter::Gateway::Response.new(:status => :success)
|
|
16
|
+
Error = Txter::Gateway::Response.new(:status => :error)
|
|
17
|
+
|
|
18
|
+
def self.deliver(*args)
|
|
19
|
+
# subclasses should actually do something here
|
|
20
|
+
Success
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.unblock(*args)
|
|
24
|
+
# subclasses should actually do something here
|
|
25
|
+
Success
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.current
|
|
29
|
+
case Txter.configuration.gateway
|
|
30
|
+
when 'twilio'
|
|
31
|
+
gem 'twiliolib'
|
|
32
|
+
require 'twiliolib'
|
|
33
|
+
GatewayTwilio
|
|
34
|
+
when '4info'
|
|
35
|
+
Gateway4info
|
|
36
|
+
when 'test'
|
|
37
|
+
Txter::Gateway
|
|
38
|
+
else
|
|
39
|
+
raise "You need to specify your Txter gateway!"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
require File.join File.dirname(__FILE__), 'gateway_4info'
|
|
45
|
+
require File.join File.dirname(__FILE__), 'gateway_twilio'
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module Txter
|
|
2
|
+
class Gateway4info < Txter::Gateway
|
|
3
|
+
|
|
4
|
+
API = 'http://gateway.4info.net/msg'
|
|
5
|
+
|
|
6
|
+
def self.deliver(message, number)
|
|
7
|
+
Gateway4info.perform Request.new.deliver_message(message, number)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.perform(body)
|
|
11
|
+
if :live == Txter.mode
|
|
12
|
+
require 'net/http'
|
|
13
|
+
uri = URI.parse API
|
|
14
|
+
body = start do |http|
|
|
15
|
+
http.post(
|
|
16
|
+
uri.path,
|
|
17
|
+
body,
|
|
18
|
+
{'Content-Type' => 'text/xml'}
|
|
19
|
+
).read_body
|
|
20
|
+
end
|
|
21
|
+
Response.new(body)
|
|
22
|
+
else
|
|
23
|
+
Txter.log "Would have sent to 4info.net: #{body}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
|
|
29
|
+
def self.start
|
|
30
|
+
c = Txter.configuration
|
|
31
|
+
net = c.proxy_address ?
|
|
32
|
+
Net::HTTP::Proxy(
|
|
33
|
+
c.proxy_address,
|
|
34
|
+
c.proxy_port,
|
|
35
|
+
c.proxy_username,
|
|
36
|
+
c.proxy_password) :
|
|
37
|
+
Net::HTTP
|
|
38
|
+
uri = URI.parse API
|
|
39
|
+
net.start(uri.host, uri.port) do |http|
|
|
40
|
+
yield http
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Response < Txter::Gateway::Response
|
|
45
|
+
def initialize(xml)
|
|
46
|
+
gem 'hpricot'
|
|
47
|
+
require 'hpricot'
|
|
48
|
+
@xml = xml
|
|
49
|
+
@body = Hpricot.parse(xml)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def inspect
|
|
53
|
+
@xml.to_s
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def [](name)
|
|
57
|
+
nodes = (@body/name)
|
|
58
|
+
1 == nodes.size ? nodes.first : nodes
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def success?
|
|
62
|
+
'Success' == self['message'].inner_text
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def confirmation_code
|
|
66
|
+
self[:confcode].inner_text
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class Request < Txter::Gateway::Request
|
|
71
|
+
|
|
72
|
+
attr_accessor :number
|
|
73
|
+
attr_accessor :message
|
|
74
|
+
attr_accessor :config
|
|
75
|
+
|
|
76
|
+
def initialize
|
|
77
|
+
unless Txter.configured?
|
|
78
|
+
raise "You need to configure Txter before using it!"
|
|
79
|
+
end
|
|
80
|
+
self.config = Txter.configuration
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def deliver_message(message, number)
|
|
84
|
+
self.number = Txter.internationalize(number)
|
|
85
|
+
self.message = message
|
|
86
|
+
|
|
87
|
+
template(:deliver).render(self)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def confirm(number)
|
|
91
|
+
self.number = Txter.internationalize(number)
|
|
92
|
+
|
|
93
|
+
template(:confirm).render(self)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def unblock(number)
|
|
97
|
+
self.number = Txter.internationalize(number)
|
|
98
|
+
|
|
99
|
+
template(:unblock).render(self)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
protected
|
|
103
|
+
|
|
104
|
+
def template(name)
|
|
105
|
+
# Haml templates for XML
|
|
106
|
+
require 'cgi'
|
|
107
|
+
templates = Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), '4info_templates', '*.haml')))
|
|
108
|
+
file = templates.detect {|t| File.basename(t).chomp('.haml').to_sym == name.to_sym }
|
|
109
|
+
raise ArgumentError, "Missing 4Info template: #{name}" unless file
|
|
110
|
+
Haml::Engine.new(File.read(file))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Txter
|
|
2
|
+
class GatewayTwilio < Txter::Gateway
|
|
3
|
+
|
|
4
|
+
API_VERSION = '2008-08-01'
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
|
|
8
|
+
def deliver(message, to, from = nil)
|
|
9
|
+
|
|
10
|
+
from ||= Txter.configuration.default_from_phone_number
|
|
11
|
+
raise "'From' number required for Twilio" unless from
|
|
12
|
+
|
|
13
|
+
response = post 'To' => to,
|
|
14
|
+
'From' => from,
|
|
15
|
+
'Body' => message
|
|
16
|
+
|
|
17
|
+
Net::HTTPCreated == response.code_type ?
|
|
18
|
+
Txter::Gateway::Success :
|
|
19
|
+
Txter::Gateway::Error
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def account
|
|
23
|
+
@account ||= begin
|
|
24
|
+
if Txter.configuration.client_id.blank? ||
|
|
25
|
+
Txter.configuration.client_key.blank?
|
|
26
|
+
raise "Add your Twilio account id (as client_id) and token (as client_key) to the Txter.configure block"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Twilio::RestAccount.new(
|
|
30
|
+
Txter.configuration.client_id,
|
|
31
|
+
Txter.configuration.client_key
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
protected
|
|
37
|
+
|
|
38
|
+
def post(data = {})
|
|
39
|
+
account.request "/#{API_VERSION}/Accounts/#{Txter.configuration.client_id}/SMS/Messages",
|
|
40
|
+
"POST",
|
|
41
|
+
data
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/txter.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Txter
|
|
2
|
+
class << self
|
|
3
|
+
def gateway
|
|
4
|
+
Txter::Gateway.current
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
delegate :deliver, :to => :gateway
|
|
8
|
+
delegate :unblock, :to => :gateway
|
|
9
|
+
|
|
10
|
+
def log(msg)
|
|
11
|
+
if defined?(Rails)
|
|
12
|
+
Rails.logger.info msg
|
|
13
|
+
else
|
|
14
|
+
STDOUT.puts msg
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def numerize(numberish)
|
|
19
|
+
numberish.to_s.scan(/\d+/).join
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def internationalize(given_number)
|
|
23
|
+
number = numerize(given_number)
|
|
24
|
+
case number.size
|
|
25
|
+
when 10
|
|
26
|
+
"+1#{number}"
|
|
27
|
+
when 11
|
|
28
|
+
"+#{number}"
|
|
29
|
+
when 12
|
|
30
|
+
number =~ /\+\d(11)/ ? number : nil
|
|
31
|
+
else
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def confirmation_message(confirmation_code)
|
|
37
|
+
"4INFO alert confirm. code: #{confirmation_code} Enter code on web to verify phone. Msg&data rates may apply. Freq set by u. T&C & support at www.4info.com. Txt HELP for help"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def generate_confirmation_code
|
|
41
|
+
chars = (0..9).to_a + ('A'..'Z').to_a
|
|
42
|
+
(0...6).collect { chars[Kernel.rand(chars.length)] }.join
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
require File.join(File.dirname(__FILE__), 'configuration')
|
|
48
|
+
require File.join(File.dirname(__FILE__), 'gateway')
|
|
49
|
+
require File.join(File.dirname(__FILE__), 'contactable')
|
|
50
|
+
require File.join(File.dirname(__FILE__), 'controller')
|
data/test/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
debug.log
|
data/test/database.yml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
sqlite:
|
|
2
|
+
:adapter: sqlite
|
|
3
|
+
:database: plugin.sqlite.db
|
|
4
|
+
sqlite3:
|
|
5
|
+
:adapter: sqlite3
|
|
6
|
+
:database: ":memory:"
|
|
7
|
+
postgresql:
|
|
8
|
+
:adapter: postgresql
|
|
9
|
+
:username: postgres
|
|
10
|
+
:password: postgres
|
|
11
|
+
:database: plugin_test
|
|
12
|
+
:min_messages: ERROR
|
|
13
|
+
mysql:
|
|
14
|
+
:adapter: mysql
|
|
15
|
+
:host: localhost
|
|
16
|
+
:username: rails
|
|
17
|
+
:password:
|
|
18
|
+
:database: plugin_test
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
|
2
|
+
|
|
3
|
+
class Gateway4infoTest < ActiveSupport::TestCase
|
|
4
|
+
|
|
5
|
+
Error = Txter::Gateway4info::Response.new('<?xml version="1.0" encoding="UTF-8"?>
|
|
6
|
+
<response>
|
|
7
|
+
<status>
|
|
8
|
+
<id>4</id>
|
|
9
|
+
<message>Error</message>
|
|
10
|
+
</status>
|
|
11
|
+
</response>')
|
|
12
|
+
Success = Txter::Gateway4info::Response.new('<?xml version="1.0" ?>
|
|
13
|
+
<response>
|
|
14
|
+
<requestId>F81D4FAE-7DEC-11D0-A765-00A0C91E6BF6</requestId>
|
|
15
|
+
<status>
|
|
16
|
+
<id>1</id>
|
|
17
|
+
<message>Success</message>
|
|
18
|
+
</status>
|
|
19
|
+
</response>')
|
|
20
|
+
|
|
21
|
+
context "with 4info gateway" do
|
|
22
|
+
setup {
|
|
23
|
+
Txter.configure do |config|
|
|
24
|
+
config.client_id = 12345
|
|
25
|
+
config.client_key = 'ABC123'
|
|
26
|
+
config.gateway = '4info'
|
|
27
|
+
end
|
|
28
|
+
}
|
|
29
|
+
context "with stubbed success" do
|
|
30
|
+
setup {
|
|
31
|
+
Txter::Gateway4info.stubs(:perform).returns(Success)
|
|
32
|
+
}
|
|
33
|
+
should "generate a success response object" do
|
|
34
|
+
assert Txter.deliver("msg", "1-555-867-5309").success?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
context "with stubbed error" do
|
|
38
|
+
setup {
|
|
39
|
+
Txter::Gateway4info.stubs(:perform).returns(Error)
|
|
40
|
+
}
|
|
41
|
+
should "generate a success response object" do
|
|
42
|
+
assert !Txter.deliver("msg", "1-555-867-5309").success?
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
should "create proper xml for delivery" do
|
|
46
|
+
expected = <<-EOXML
|
|
47
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
|
48
|
+
<request clientId='12345' clientKey='ABC123' type='MESSAGE'>
|
|
49
|
+
<message>
|
|
50
|
+
<recipient>
|
|
51
|
+
<type>5</type>
|
|
52
|
+
<id>+15558675309</id>
|
|
53
|
+
</recipient>
|
|
54
|
+
<text>msg</text>
|
|
55
|
+
</message>
|
|
56
|
+
</request>
|
|
57
|
+
EOXML
|
|
58
|
+
assert_equal expected, Txter::Gateway4info::Request.new.deliver_message("msg", "1-555-867-5309")
|
|
59
|
+
end
|
|
60
|
+
should "create proper xml for unblock" do
|
|
61
|
+
expected = <<-EOXML
|
|
62
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
|
63
|
+
<request clientId='12345' clientKey='ABC123' type='UNBLOCK'>
|
|
64
|
+
<unblock>
|
|
65
|
+
<recipient>
|
|
66
|
+
<type>5</type>
|
|
67
|
+
<id>+15558675309</id>
|
|
68
|
+
</recipient>
|
|
69
|
+
</unblock>
|
|
70
|
+
</request>
|
|
71
|
+
EOXML
|
|
72
|
+
assert_equal expected, Txter::Gateway4info::Request.new.unblock("1-555-867-5309")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
|
2
|
+
|
|
3
|
+
class Gateway4infoTest < ActiveSupport::TestCase
|
|
4
|
+
|
|
5
|
+
context "with twilio gateway" do
|
|
6
|
+
setup {
|
|
7
|
+
Txter.configure do |config|
|
|
8
|
+
config.client_id = 12345
|
|
9
|
+
config.client_key = 'ABC123'
|
|
10
|
+
config.gateway = 'twilio'
|
|
11
|
+
end
|
|
12
|
+
}
|
|
13
|
+
# TODO: figure out what's left to test
|
|
14
|
+
end
|
|
15
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
gem 'test-unit'
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'mocha'
|
|
5
|
+
require 'active_support'
|
|
6
|
+
require 'active_record'
|
|
7
|
+
require 'active_support/test_case'
|
|
8
|
+
require 'shoulda'
|
|
9
|
+
require File.join(File.dirname(__FILE__), "..", 'lib', 'txter')
|
|
10
|
+
|
|
11
|
+
# default test configuration
|
|
12
|
+
Txter.configure do |config|
|
|
13
|
+
config.client_id = '1'
|
|
14
|
+
config.client_key = 'ABCDEF'
|
|
15
|
+
config.gateway = 'test'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Txter.mode = :test
|
|
19
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
|
20
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
|
21
|
+
ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3'])
|
|
22
|
+
|
|
23
|
+
ActiveRecord::Schema.define(:version => 1) do
|
|
24
|
+
create_table :users do |t|
|
|
25
|
+
t.column :sms_phone_number, :string
|
|
26
|
+
t.column :sms_confirmed_phone_number, :string
|
|
27
|
+
t.column :sms_blocked, :boolean
|
|
28
|
+
t.column :sms_confirmation_attempted, :datetime
|
|
29
|
+
t.column :sms_confirmation_code, :string
|
|
30
|
+
|
|
31
|
+
t.column :type, :string
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class User < ActiveRecord::Base
|
|
36
|
+
include Txter::Contactable
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# kill all network access
|
|
40
|
+
module Txter
|
|
41
|
+
class Request
|
|
42
|
+
def start
|
|
43
|
+
raise "You forgot to stub out your net requests!"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
|
2
|
+
|
|
3
|
+
class TxterContactableTest < ActiveSupport::TestCase
|
|
4
|
+
|
|
5
|
+
Success = Txter::Gateway::Response.new(:status => :success)
|
|
6
|
+
Error = Txter::Gateway::Response.new(:status => :error)
|
|
7
|
+
|
|
8
|
+
context "contactable class" do
|
|
9
|
+
setup {
|
|
10
|
+
@klass = Class.new
|
|
11
|
+
@klass.send :include, Txter::Contactable
|
|
12
|
+
Txter.configure do |config|
|
|
13
|
+
config.client_id = 12345
|
|
14
|
+
config.client_key = 'ABC123'
|
|
15
|
+
config.gateway = 'test'
|
|
16
|
+
end
|
|
17
|
+
}
|
|
18
|
+
Txter::Contactable::Attributes.each do |attribute|
|
|
19
|
+
should "begin with appropriate default for #{attribute}_column" do
|
|
20
|
+
assert_equal attribute, @klass.send("#{attribute}_column")
|
|
21
|
+
end
|
|
22
|
+
should "allow setting #{attribute}_column" do
|
|
23
|
+
new_column_name = :custom_column
|
|
24
|
+
@klass.send "#{attribute}_column", new_column_name
|
|
25
|
+
assert_equal new_column_name, @klass.send("#{attribute}_column")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "contactable instance" do
|
|
31
|
+
setup {
|
|
32
|
+
User.delete_all
|
|
33
|
+
@user = User.create! User.sms_phone_number_column => '(555) 123-4567'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
should "normalize phone number" do
|
|
37
|
+
assert_equal '5551234567', @user.txter_sms_phone_number
|
|
38
|
+
end
|
|
39
|
+
context "when phone number is blank" do
|
|
40
|
+
setup { @user.txter_sms_phone_number = nil}
|
|
41
|
+
context "confirming phone number" do
|
|
42
|
+
setup { @user.send_sms_confirmation! }
|
|
43
|
+
should_not_change "any attributes" do
|
|
44
|
+
@user.attributes.inspect
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
context "sending message" do
|
|
48
|
+
setup {
|
|
49
|
+
Txter.gateway.stubs(:perform).returns(Success)
|
|
50
|
+
@worked = @user.send_sms!('message')
|
|
51
|
+
}
|
|
52
|
+
should "not work" do assert !@worked end
|
|
53
|
+
should_not_change "any attributes" do
|
|
54
|
+
@user.attributes.inspect
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context "when phone number exists" do
|
|
60
|
+
setup { @user.txter_sms_phone_number = "206-555-5555"}
|
|
61
|
+
context "confirming phone number" do
|
|
62
|
+
setup {
|
|
63
|
+
Txter::Request.any_instance.stubs(:perform).returns(Success)
|
|
64
|
+
@worked = @user.send_sms_confirmation!
|
|
65
|
+
}
|
|
66
|
+
should "work" do assert @worked end
|
|
67
|
+
should "save confirmation number in proper attribute" do
|
|
68
|
+
assert @user.txter_sms_confirmation_code
|
|
69
|
+
end
|
|
70
|
+
should "set confirmation attempted time" do
|
|
71
|
+
assert @user.txter_sms_confirmation_attempted > 3.minutes.ago
|
|
72
|
+
end
|
|
73
|
+
should_change "stored code" do
|
|
74
|
+
@user.txter_sms_confirmation_code
|
|
75
|
+
end
|
|
76
|
+
should "not have number confirmed yet" do
|
|
77
|
+
assert !@user.sms_confirmed?
|
|
78
|
+
end
|
|
79
|
+
context "calling sms_confirm_with(right_code)" do
|
|
80
|
+
setup { @user.sms_confirm_with(@user.txter_sms_confirmation_code) }
|
|
81
|
+
should "work" do
|
|
82
|
+
assert @worked
|
|
83
|
+
end
|
|
84
|
+
should "save the phone number into the confirmed attribute" do
|
|
85
|
+
assert_equal @user.txter_sms_confirmed_phone_number,
|
|
86
|
+
@user.txter_sms_phone_number
|
|
87
|
+
end
|
|
88
|
+
should_change "confirmed phone number attribute" do
|
|
89
|
+
@user.txter_sms_confirmed_phone_number
|
|
90
|
+
end
|
|
91
|
+
context "and then attempting to confirm another number" do
|
|
92
|
+
setup {
|
|
93
|
+
@user.txter_sms_phone_number = "206-555-5555"
|
|
94
|
+
Txter.stubs(:deliver).returns(Success).once
|
|
95
|
+
@user.send_sms_confirmation!
|
|
96
|
+
}
|
|
97
|
+
should "eliminate the previous confirmed phone number" do
|
|
98
|
+
assert @user.txter_sms_confirmed_phone_number.blank?
|
|
99
|
+
end
|
|
100
|
+
should "un-confirm the record" do
|
|
101
|
+
assert !@user.sms_confirmed?
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
context "calling sms_confirm_with(right code, wrong case)" do
|
|
106
|
+
setup {
|
|
107
|
+
@downcased_code = @user.txter_sms_confirmation_code.downcase
|
|
108
|
+
@worked = @user.sms_confirm_with(@downcased_code)
|
|
109
|
+
}
|
|
110
|
+
should "have good test data" do
|
|
111
|
+
assert_not_equal @downcased_code,
|
|
112
|
+
@user.txter_sms_confirmation_code
|
|
113
|
+
end
|
|
114
|
+
should "work" do
|
|
115
|
+
assert @worked
|
|
116
|
+
end
|
|
117
|
+
should "save the phone number into the confirmed attribute" do
|
|
118
|
+
assert_equal @user.txter_sms_confirmed_phone_number,
|
|
119
|
+
@user.txter_sms_phone_number
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
context "calling sms_confirm_with(wrong_code)" do
|
|
123
|
+
setup { @worked = @user.sms_confirm_with('wrong_code') }
|
|
124
|
+
should "not work" do
|
|
125
|
+
assert !@worked
|
|
126
|
+
end
|
|
127
|
+
should "not save the phone number into the confirmed attribute" do
|
|
128
|
+
assert_not_equal @user.txter_sms_confirmed_phone_number,
|
|
129
|
+
@user.txter_sms_phone_number
|
|
130
|
+
end
|
|
131
|
+
should_not_change "confirmed phone number attribute" do
|
|
132
|
+
@user.reload.txter_sms_confirmed_phone_number
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
context "confirming phone number with a custom short code" do
|
|
137
|
+
context "with expectations" do
|
|
138
|
+
setup {
|
|
139
|
+
Txter.configure do |config|
|
|
140
|
+
config.short_code = '0005'
|
|
141
|
+
config.gateway = 'test'
|
|
142
|
+
config.client_id = 1
|
|
143
|
+
config.client_key = 'ABC123'
|
|
144
|
+
end
|
|
145
|
+
message = "long message blah blah MYCODE blah"
|
|
146
|
+
Txter.expects(:generate_confirmation_code).returns('MYCODE').once
|
|
147
|
+
Txter.expects(:confirmation_message).returns(message).once
|
|
148
|
+
Txter::Request.any_instance.expects(:deliver_message).with(message, @user.txter_sms_phone_number).once
|
|
149
|
+
@user.send_sms_confirmation!
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
context "(normal)" do
|
|
153
|
+
setup {
|
|
154
|
+
Txter.configure do |config|
|
|
155
|
+
config.short_code = '0005'
|
|
156
|
+
config.gateway = 'test'
|
|
157
|
+
config.client_id = 1
|
|
158
|
+
config.client_key = 'ABC123'
|
|
159
|
+
end
|
|
160
|
+
Txter::Request.any_instance.stubs(:perform).returns(Success)
|
|
161
|
+
@worked = @user.send_sms_confirmation!
|
|
162
|
+
}
|
|
163
|
+
should "work" do
|
|
164
|
+
assert @worked
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
context "confirming phone number when the confirmation fails for some reason" do
|
|
169
|
+
setup {
|
|
170
|
+
Txter.stubs(:deliver).returns(Error)
|
|
171
|
+
@worked = @user.send_sms_confirmation!
|
|
172
|
+
}
|
|
173
|
+
should "not work" do assert !@worked end
|
|
174
|
+
should "not save confirmation number" do
|
|
175
|
+
assert @user.txter_sms_confirmation_code.blank?
|
|
176
|
+
end
|
|
177
|
+
should_not_change "stored code" do
|
|
178
|
+
@user.txter_sms_confirmation_code
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
context "when the number is not confirmed" do
|
|
184
|
+
context "sending a message" do
|
|
185
|
+
setup {
|
|
186
|
+
Txter::Request.any_instance.stubs(:perform).returns(Success)
|
|
187
|
+
@result = @user.send_sms!('message')
|
|
188
|
+
}
|
|
189
|
+
should "send send no messages" do
|
|
190
|
+
assert_equal false, @result
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
context "when the number is blocked" do
|
|
195
|
+
setup {
|
|
196
|
+
@user.txter_sms_blocked = true
|
|
197
|
+
@user.save!
|
|
198
|
+
}
|
|
199
|
+
context "sending a message" do
|
|
200
|
+
setup { @result = @user.send_sms!('message') }
|
|
201
|
+
should "send nothing" do
|
|
202
|
+
assert_equal false, @result
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
context "when the number is confirmed" do
|
|
207
|
+
setup {
|
|
208
|
+
Txter::Request.any_instance.stubs(:perform).returns(Success)
|
|
209
|
+
@user.stubs(:sms_confirmed?).returns(true)
|
|
210
|
+
}
|
|
211
|
+
context "sending a message" do
|
|
212
|
+
setup { @result = @user.send_sms!('message') }
|
|
213
|
+
should "send send exactly one message" do
|
|
214
|
+
assert_equal [7], @result
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
context "sending a blank message" do
|
|
218
|
+
setup { @result = @user.send_sms!('') }
|
|
219
|
+
should "send send zero messages" do
|
|
220
|
+
assert_equal false, @result
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
context "sending a huge message" do
|
|
224
|
+
context "without the allow_multiple flag" do
|
|
225
|
+
should "raise an error" do
|
|
226
|
+
assert_raises ArgumentError do
|
|
227
|
+
@user.send_sms!("A"*200)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
context "with the allow_multiple flag" do
|
|
232
|
+
setup { @result = @user.send_sms!("A"*200, true) }
|
|
233
|
+
should "send multiple messages" do
|
|
234
|
+
assert_equal [160, 40], @result
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
context "when the number is not blocked" do
|
|
241
|
+
setup {
|
|
242
|
+
Txter::Request.any_instance.expects(:perform).never
|
|
243
|
+
}
|
|
244
|
+
context "unblocking" do
|
|
245
|
+
setup { @worked = @user.unblock_sms! }
|
|
246
|
+
should "not do anything" do
|
|
247
|
+
assert !@worked
|
|
248
|
+
end
|
|
249
|
+
should_not_change "any attributes" do
|
|
250
|
+
@user.attributes.inspect
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
context "when the number is blocked" do
|
|
255
|
+
setup {
|
|
256
|
+
Txter::Request.any_instance.stubs(:perform).returns(Success)
|
|
257
|
+
@user.update_attributes!(:sms_blocked => true)
|
|
258
|
+
}
|
|
259
|
+
context "unblocking" do
|
|
260
|
+
setup { @worked = @user.unblock_sms! }
|
|
261
|
+
should "work" do
|
|
262
|
+
assert @worked
|
|
263
|
+
end
|
|
264
|
+
should_change "blocked attribute" do
|
|
265
|
+
@user.reload.sms_blocked
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|