4info 1.1.1 → 1.2.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/4info.gemspec +2 -2
- data/README.markdown +45 -17
- data/VERSION +1 -1
- data/lib/contactable.rb +43 -24
- data/lib/controller.rb +1 -1
- data/test/four_info_contactable_test.rb +18 -8
- metadata +2 -2
data/4info.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{4info}
|
|
8
|
-
s.version = "1.
|
|
8
|
+
s.version = "1.2.0"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Jack Danger Canty"]
|
|
12
|
-
s.date = %q{2010-02-
|
|
12
|
+
s.date = %q{2010-02-11}
|
|
13
13
|
s.description = %q{A complete Ruby API for handling SMS messages via 4info.com}
|
|
14
14
|
s.email = %q{gitcommit@6brand.com}
|
|
15
15
|
s.extra_rdoc_files = [
|
data/README.markdown
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
Connect to the 4info SMS gateway
|
|
5
5
|
|
|
6
|
-
If you're using 4info.com as your SMS gateway this gem will give you a painless API.
|
|
6
|
+
If you're using 4info.com as your SMS gateway this gem will give you a painless API for both sending and receiving messages.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Setting Up Your Model
|
|
9
9
|
=====
|
|
10
10
|
|
|
11
|
-
Include FourInfo::Contactable into your User class or whatever you're using to represent an entity with a phone number.
|
|
11
|
+
Include FourInfo::Contactable into your User class or whatever you're using to represent an entity with a phone number.
|
|
12
12
|
|
|
13
13
|
class User < ActiveRecord::Base
|
|
14
14
|
include FourInfo::Contactable
|
|
@@ -25,25 +25,39 @@ You can also specify which attributes you'd like to use instead of the defaults
|
|
|
25
25
|
sms_confirmation_attempted_column :when_was_the_sms_confirmation_attempted
|
|
26
26
|
sms_confirmed_phone_number_column :the_mobile_number_thats_been_confirmed
|
|
27
27
|
|
|
28
|
-
# Defaults to the name on the left (minus the
|
|
28
|
+
# Defaults to the name on the left (minus the '_column' at the end)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
|
|
32
|
+
Confirming Phone Number And Sending Messages
|
|
33
|
+
====
|
|
34
|
+
|
|
31
35
|
You can manage the user's SMS state like so:
|
|
32
36
|
|
|
33
37
|
@user = User.create(:sms_phone_number => '5552223333')
|
|
34
|
-
@user.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@user.
|
|
39
|
-
|
|
38
|
+
@user.send_sms_confirmation!
|
|
39
|
+
|
|
40
|
+
then ask the user for the confirmation code off their phone and pass it in to sms_confirm_with:
|
|
41
|
+
|
|
42
|
+
@user.sms_confirm_with(user_provided_code)
|
|
43
|
+
|
|
44
|
+
If the code is right then the user's current phone number will be automatically marked as confirmed. You can check this at any time with:
|
|
45
|
+
|
|
46
|
+
@user.sms_confirmed? # => true
|
|
40
47
|
@user.send_sms!("Hi! This is a text message.")
|
|
41
|
-
|
|
48
|
+
|
|
49
|
+
Then maybe the user will reply with 'BLOCK' by accident and @user.sms_blocked? will be true.
|
|
50
|
+
You can fix this by calling:
|
|
51
|
+
|
|
42
52
|
@user.unblock_sms!
|
|
43
53
|
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
Receiving Messages From 4info.com
|
|
56
|
+
====
|
|
57
|
+
|
|
58
|
+
You can also receive data posted to you from 4info.com. This is how you'll receive messages and notices that users have been blocked.
|
|
59
|
+
All you need is to create a bare controller and include FourInfo::Controller into it. Then specify which Ruby class you're using as a contactable user model (likely User)
|
|
60
|
+
|
|
47
61
|
|
|
48
62
|
class SMSController < ApplicationController
|
|
49
63
|
include FourInfo::Controller
|
|
@@ -51,10 +65,24 @@ that receives data from 4info.com
|
|
|
51
65
|
sms_contactable User # or whichever class you included FourInfo::Contactable into
|
|
52
66
|
end
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
68
|
+
And hook this up in your routes.rb file like so:
|
|
69
|
+
|
|
70
|
+
ActionController::Routing::Routes.draw do |map|
|
|
71
|
+
map.route '4info', :controller => 'four_info', :action => :index
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
Now just tell 4info.com to POST messages and block notices to you at:
|
|
75
|
+
|
|
76
|
+
http://myrubyapp.com/4info
|
|
77
|
+
|
|
78
|
+
Now if your users reply to an SMS with 'STOP' your database will be updated to reflect this.
|
|
79
|
+
|
|
80
|
+
Incoming messages from a user will automatically be sent to that user's record:
|
|
81
|
+
|
|
82
|
+
# If "I love you!" is sent to you from a user with the phone
|
|
83
|
+
# number "555-111-9999" then the following will be executed:
|
|
84
|
+
User.find_by_sms_phone_number('5551119999').receive_sms("I love you!")
|
|
57
85
|
|
|
58
86
|
That's it. Patches welcome, forks celebrated.
|
|
59
87
|
|
|
60
|
-
Copyright (c) 2010 Jack Danger Canty
|
|
88
|
+
Copyright (c) 2010 [Jack Danger Canty](http://jåck.com/), released under the MIT license
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.2.0
|
data/lib/contactable.rb
CHANGED
|
@@ -13,7 +13,7 @@ module FourInfo
|
|
|
13
13
|
require 'net/http'
|
|
14
14
|
|
|
15
15
|
Attributes.each do |attribute|
|
|
16
|
-
# add a method for setting or retrieving
|
|
16
|
+
# add a method in the class for setting or retrieving
|
|
17
17
|
# which column should be used for which attribute
|
|
18
18
|
#
|
|
19
19
|
# :sms_phone_number_column defaults to :sms_phone_number, etc.
|
|
@@ -24,34 +24,34 @@ module FourInfo
|
|
|
24
24
|
@#{attribute}_column
|
|
25
25
|
end
|
|
26
26
|
"
|
|
27
|
-
# provide
|
|
28
|
-
# no matter which column it's stored in
|
|
27
|
+
# provide helper methods to access the right value
|
|
28
|
+
# no matter which column it's stored in.
|
|
29
29
|
#
|
|
30
30
|
# e.g.: @user.four_info_sms_confirmation_code
|
|
31
31
|
# == @user.send(User.sms_confirmation_code_column)
|
|
32
32
|
model.class_eval "
|
|
33
|
-
def four_info_#{attribute}
|
|
34
|
-
|
|
35
|
-
send(self.class.#{attribute}_column.to_s+'=', value) :
|
|
36
|
-
send(self.class.#{attribute}_column)
|
|
33
|
+
def four_info_#{attribute}
|
|
34
|
+
send self.class.#{attribute}_column
|
|
37
35
|
end
|
|
38
36
|
alias_method :four_info_#{attribute}?, :four_info_#{attribute}
|
|
39
|
-
|
|
37
|
+
def four_info_#{attribute}=(value)
|
|
38
|
+
send self.class.#{attribute}_column.to_s+'=', value
|
|
39
|
+
end
|
|
40
40
|
"
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
# Sends one or more TXT messages to the contactable record's
|
|
45
|
+
# mobile number (if the number has been confirmed).
|
|
46
|
+
# Any messages longer than 160 characters will need to be accompanied
|
|
47
|
+
# by a second argument <tt>true</tt> to clarify that sending
|
|
48
|
+
# multiple messages is intentional.
|
|
49
49
|
def send_sms!(msg, allow_multiple = false)
|
|
50
50
|
if msg.to_s.size > 160 && !allow_multiple
|
|
51
51
|
raise ArgumentError, "SMS Message is too long. Either specify that you want multiple messages or shorten the string."
|
|
52
52
|
end
|
|
53
53
|
return false if msg.to_s.strip.blank? || four_info_sms_blocked?
|
|
54
|
-
return false unless
|
|
54
|
+
return false unless sms_confirmed?
|
|
55
55
|
|
|
56
56
|
# split into pieces that fit as individual messages.
|
|
57
57
|
msg.to_s.scan(/.{1,160}/m).map do |text|
|
|
@@ -59,15 +59,18 @@ module FourInfo
|
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
# Sends an SMS validation request via xml to the 4info gateway.
|
|
63
|
+
# If request succeeds the 4info-generated confirmation code is saved
|
|
64
|
+
# in the contactable record.
|
|
65
|
+
def send_sms_confirmation!
|
|
63
66
|
return false if four_info_sms_blocked?
|
|
64
|
-
return true if
|
|
67
|
+
return true if sms_confirmed?
|
|
65
68
|
return false if four_info_sms_phone_number.blank?
|
|
66
69
|
|
|
67
70
|
response = FourInfo::Request.new.confirm(four_info_sms_phone_number)
|
|
68
71
|
if response.success?
|
|
69
|
-
self.four_info_sms_confirmation_code response.confirmation_code
|
|
70
|
-
self.four_info_sms_confirmation_attempted Time.now
|
|
72
|
+
self.four_info_sms_confirmation_code = response.confirmation_code
|
|
73
|
+
self.four_info_sms_confirmation_attempted = Time.now
|
|
71
74
|
save
|
|
72
75
|
else
|
|
73
76
|
# "Confirmation Failed: #{response['message'].inspect}"
|
|
@@ -75,21 +78,37 @@ module FourInfo
|
|
|
75
78
|
end
|
|
76
79
|
end
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
end
|
|
82
|
-
|
|
81
|
+
# Sends an unblock request via xml to the 4info gateway.
|
|
82
|
+
# If request succeeds, changes the contactable record's
|
|
83
|
+
# sms_blocked_column to false.
|
|
83
84
|
def unblock_sms!
|
|
84
85
|
return false unless four_info_sms_blocked?
|
|
85
86
|
|
|
86
87
|
response = FourInfo::Request.new.unblock(four_info_sms_phone_number)
|
|
87
88
|
if response.success?
|
|
88
|
-
four_info_sms_blocked 'false'
|
|
89
|
+
self.four_info_sms_blocked = 'false'
|
|
89
90
|
save!
|
|
90
91
|
else
|
|
91
92
|
false
|
|
92
93
|
end
|
|
93
94
|
end
|
|
95
|
+
|
|
96
|
+
# Compares user-provided code with the stored confirmation
|
|
97
|
+
# code. If they match then the current phone number is set
|
|
98
|
+
# as confirmed by the user.
|
|
99
|
+
def sms_confirm_with(code)
|
|
100
|
+
if four_info_sms_confirmation_code == code
|
|
101
|
+
# save the phone number into the 'confirmed phone number' attribute
|
|
102
|
+
self.four_info_sms_confirmed_phone_number = four_info_sms_phone_number
|
|
103
|
+
save
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Returns true if the current phone number has been confirmed by
|
|
108
|
+
# the user for recieving TXT messages.
|
|
109
|
+
def sms_confirmed?
|
|
110
|
+
return false if four_info_sms_confirmed_phone_number.blank?
|
|
111
|
+
four_info_sms_confirmed_phone_number == four_info_sms_phone_number
|
|
112
|
+
end
|
|
94
113
|
end
|
|
95
114
|
end
|
data/lib/controller.rb
CHANGED
|
@@ -47,7 +47,7 @@ module FourInfo
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def find_contactable(id)
|
|
50
|
-
[id, id.sub(/^\+/,''), id.sub(/^\+1/,'')].each do |possible_phone_number|
|
|
50
|
+
[id, id.sub(/^\+/,''), id.sub(/^\+1/,'')].uniq.compact.each do |possible_phone_number|
|
|
51
51
|
found = @@contactable_class.find(
|
|
52
52
|
:first,
|
|
53
53
|
:conditions =>
|
|
@@ -60,7 +60,7 @@ class FourInfoContactableTest < ActiveSupport::TestCase
|
|
|
60
60
|
context "when phone number is blank" do
|
|
61
61
|
setup { @user.sms_phone_number = nil}
|
|
62
62
|
context "confirming phone number" do
|
|
63
|
-
setup { @user.
|
|
63
|
+
setup { @user.send_sms_confirmation! }
|
|
64
64
|
should_not_change "any attributes" do
|
|
65
65
|
@user.attributes.inspect
|
|
66
66
|
end
|
|
@@ -82,7 +82,7 @@ class FourInfoContactableTest < ActiveSupport::TestCase
|
|
|
82
82
|
context "confirming phone number" do
|
|
83
83
|
setup {
|
|
84
84
|
FourInfo::Request.any_instance.stubs(:perform).returns(ValidationSuccess)
|
|
85
|
-
@worked = @user.
|
|
85
|
+
@worked = @user.send_sms_confirmation!
|
|
86
86
|
}
|
|
87
87
|
should "work" do assert @worked end
|
|
88
88
|
should "save confirmation number in proper attribute" do
|
|
@@ -95,15 +95,25 @@ class FourInfoContactableTest < ActiveSupport::TestCase
|
|
|
95
95
|
@user.four_info_sms_confirmation_code
|
|
96
96
|
end
|
|
97
97
|
should "not have number confirmed yet" do
|
|
98
|
-
assert !@user.
|
|
98
|
+
assert !@user.sms_confirmed?
|
|
99
99
|
end
|
|
100
|
-
context "calling
|
|
101
|
-
setup { @user.
|
|
100
|
+
context "calling sms_confirm_with(right_code)" do
|
|
101
|
+
setup { @user.sms_confirm_with(@user.four_info_sms_confirmation_code) }
|
|
102
102
|
should "save the phone number into the confirmed attribute" do
|
|
103
103
|
assert_equal @user.four_info_sms_confirmed_phone_number,
|
|
104
104
|
@user.four_info_sms_phone_number
|
|
105
105
|
end
|
|
106
|
-
should_change "confirmed phone number
|
|
106
|
+
should_change "confirmed phone number attribute" do
|
|
107
|
+
@user.four_info_sms_confirmed_phone_number
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
context "calling sms_confirm_with(wrong_code)" do
|
|
111
|
+
setup { @user.sms_confirm_with('wrong_code') }
|
|
112
|
+
should "not save the phone number into the confirmed attribute" do
|
|
113
|
+
assert_not_equal @user.four_info_sms_confirmed_phone_number,
|
|
114
|
+
@user.four_info_sms_phone_number
|
|
115
|
+
end
|
|
116
|
+
should_not_change "confirmed phone number attribute" do
|
|
107
117
|
@user.four_info_sms_confirmed_phone_number
|
|
108
118
|
end
|
|
109
119
|
end
|
|
@@ -111,7 +121,7 @@ class FourInfoContactableTest < ActiveSupport::TestCase
|
|
|
111
121
|
context "confirming phone number when the confirmation fails for some reason" do
|
|
112
122
|
setup {
|
|
113
123
|
FourInfo::Request.any_instance.stubs(:perform).returns(ValidationError)
|
|
114
|
-
@worked = @user.
|
|
124
|
+
@worked = @user.send_sms_confirmation!
|
|
115
125
|
}
|
|
116
126
|
should "not work" do assert !@worked end
|
|
117
127
|
should "not save confirmation number" do
|
|
@@ -149,7 +159,7 @@ class FourInfoContactableTest < ActiveSupport::TestCase
|
|
|
149
159
|
context "when the number is confirmed" do
|
|
150
160
|
setup {
|
|
151
161
|
FourInfo::Request.any_instance.stubs(:perform).returns(SendMsgSuccess)
|
|
152
|
-
@user.stubs(:
|
|
162
|
+
@user.stubs(:sms_confirmed?).returns(true)
|
|
153
163
|
}
|
|
154
164
|
context "sending a message" do
|
|
155
165
|
setup { @result = @user.send_sms!('message') }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: 4info
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jack Danger Canty
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2010-02-
|
|
12
|
+
date: 2010-02-11 00:00:00 -08:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|