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/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2010 [name of plugin creator]
|
|
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.markdown
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
4info
|
|
2
|
+
=====
|
|
3
|
+
|
|
4
|
+
Connect to the 4info SMS gateway
|
|
5
|
+
|
|
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
|
+
|
|
8
|
+
Setting Up Your Model
|
|
9
|
+
=====
|
|
10
|
+
|
|
11
|
+
Include Txter::Contactable into your User class or whatever you're using to represent an entity with a phone number.
|
|
12
|
+
|
|
13
|
+
class User < ActiveRecord::Base
|
|
14
|
+
include Txter::Contactable
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
You can also specify which attributes you'd like to use instead of the defaults
|
|
18
|
+
|
|
19
|
+
class User < ActiveRecord::Base
|
|
20
|
+
include Txter::Contactable
|
|
21
|
+
|
|
22
|
+
sms_phone_number_column :mobile_number
|
|
23
|
+
sms_blocked_column :is_sms_blocked
|
|
24
|
+
sms_confirmation_code_column :the_sms_confirmation_code
|
|
25
|
+
sms_confirmation_attempted_column :when_was_the_sms_confirmation_attempted
|
|
26
|
+
sms_confirmed_phone_number_column :the_mobile_number_thats_been_confirmed
|
|
27
|
+
|
|
28
|
+
# Defaults to the name on the left (minus the '_column' at the end)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Turning the thing on
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
Because it can be expensive to send TXTs accidentally, it's required that you manually configure Txter in your app. Put this line in config/environments/production.rb or anything that loads _only_ in your production environment:
|
|
35
|
+
|
|
36
|
+
Txter.mode = :live
|
|
37
|
+
|
|
38
|
+
Skipping this step (or adding any other value) will prevent TXTs from actually being sent.
|
|
39
|
+
|
|
40
|
+
You'll also want to configure your setup with your client_id and client_key. Put this in the same file as above or in a separate initializer if you wish:
|
|
41
|
+
|
|
42
|
+
Txter.configure do |config|
|
|
43
|
+
# these two are required:
|
|
44
|
+
# (replace them with your actual account info)
|
|
45
|
+
config.client_id = 12345
|
|
46
|
+
config.client_key = 'ABC123'
|
|
47
|
+
|
|
48
|
+
# the rest are optional:
|
|
49
|
+
config.short_code = 00001 # if you have a custom short code
|
|
50
|
+
config.proxy_address = 'my.proxy.com'
|
|
51
|
+
config.proxy_port = '80'
|
|
52
|
+
config.proxy_username = 'user'
|
|
53
|
+
config.proxy_password = 'password'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
Phone number formatting
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
Whatever is stored in the sms_phone_number_column will be subject to normalized formatting:
|
|
60
|
+
|
|
61
|
+
user = User.create :sms_phone_number => '(206) 555-1234'
|
|
62
|
+
user.sms_phone_number # => 2065551234
|
|
63
|
+
|
|
64
|
+
If you want to preserve the format of the number exactly as the user entered it you'll want
|
|
65
|
+
to save that in a different attribute.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
Confirming Phone Number And Sending Messages
|
|
69
|
+
====
|
|
70
|
+
|
|
71
|
+
You can manage the user's SMS state like so:
|
|
72
|
+
|
|
73
|
+
@user = User.create(:sms_phone_number => '5552223333')
|
|
74
|
+
@user.send_sms_confirmation!
|
|
75
|
+
@user.sms_confirmed? # => false
|
|
76
|
+
|
|
77
|
+
then ask the user for the confirmation code off their phone and pass it in to sms_confirm_with:
|
|
78
|
+
|
|
79
|
+
@user.sms_confirm_with(user_provided_code)
|
|
80
|
+
|
|
81
|
+
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:
|
|
82
|
+
|
|
83
|
+
@user.sms_confirmed? # => true
|
|
84
|
+
@user.send_sms!("Hi! This is a text message.")
|
|
85
|
+
|
|
86
|
+
Then maybe the user will reply with 'BLOCK' by accident and @user.sms_blocked? will be true.
|
|
87
|
+
You can fix this by calling:
|
|
88
|
+
|
|
89
|
+
@user.unblock_sms!
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
Receiving Messages From 4info.com
|
|
93
|
+
====
|
|
94
|
+
|
|
95
|
+
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.
|
|
96
|
+
All you need is to create a bare controller and include Txter::Controller into it. Then specify which Ruby class you're using as a contactable user model (likely User)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class SMSController < ApplicationController
|
|
100
|
+
include Txter::Controller
|
|
101
|
+
|
|
102
|
+
sms_contactable User # or whichever class you included Txter::Contactable into
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
And hook this up in your routes.rb file like so:
|
|
106
|
+
|
|
107
|
+
ActionController::Routing::Routes.draw do |map|
|
|
108
|
+
map.route '4info', :controller => 'txter', :action => :index
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
Now just tell 4info.com to POST messages and block notices to you at:
|
|
112
|
+
|
|
113
|
+
http://myrubyapp.com/4info
|
|
114
|
+
|
|
115
|
+
Now if your users reply to an SMS with 'STOP' your database will be updated to reflect this.
|
|
116
|
+
|
|
117
|
+
Incoming messages from a user will automatically be sent to that user's record:
|
|
118
|
+
|
|
119
|
+
# If "I love you!" is sent to you from a user with the phone
|
|
120
|
+
# number "555-111-9999" then the following will be executed:
|
|
121
|
+
User.find_by_sms_phone_number('5551119999').receive_sms("I love you!")
|
|
122
|
+
|
|
123
|
+
That's it. Patches welcome, forks celebrated.
|
|
124
|
+
|
|
125
|
+
Copyright (c) 2010 [Jack Danger Canty](http://jåck.com/), released under the MIT license
|
data/Rakefile
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'jeweler'
|
|
6
|
+
Jeweler::Tasks.new do |gem|
|
|
7
|
+
gem.name = "txter"
|
|
8
|
+
gem.summary = %Q{Send and receive SMS messages simply via the Twilio gateway or the 4info.com gateway}
|
|
9
|
+
gem.description = %Q{Drop-in functionality to let Ruby apps send and receive TXT messages}
|
|
10
|
+
gem.email = "gitcommit@6brand.com"
|
|
11
|
+
gem.homepage = "http://github.com/JackDanger/txter"
|
|
12
|
+
gem.authors = ["Jack Danger Canty"]
|
|
13
|
+
# gem.add_dependency "hpricot", ">= 0"
|
|
14
|
+
# gem.add_dependency "haml", ">= 0"
|
|
15
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
|
16
|
+
gem.add_development_dependency "mocha", ">= 0"
|
|
17
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
18
|
+
end
|
|
19
|
+
Jeweler::GemcutterTasks.new
|
|
20
|
+
rescue LoadError
|
|
21
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require 'rake/testtask'
|
|
25
|
+
desc "Test Txter"
|
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
|
27
|
+
test.libs << 'lib' << 'test'
|
|
28
|
+
test.pattern = 'test/**/*_test.rb'
|
|
29
|
+
test.verbose = true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
begin
|
|
33
|
+
require 'rcov/rcovtask'
|
|
34
|
+
Rcov::RcovTask.new do |test|
|
|
35
|
+
test.libs << 'test'
|
|
36
|
+
test.pattern = 'test/**/test_*.rb'
|
|
37
|
+
test.verbose = true
|
|
38
|
+
end
|
|
39
|
+
rescue LoadError
|
|
40
|
+
task :rcov do
|
|
41
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
task :test => :check_dependencies
|
|
46
|
+
|
|
47
|
+
task :default => :test
|
|
48
|
+
|
|
49
|
+
require 'rake/rdoctask'
|
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
|
51
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
|
52
|
+
|
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
54
|
+
rdoc.title = "inline_styles #{version}"
|
|
55
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
56
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.0.2
|
data/init.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
!!! XML
|
|
2
|
+
%request{ :clientId => config.client_id, :clientKey => config.client_key, :type => "MESSAGE" }
|
|
3
|
+
%message
|
|
4
|
+
- if config.short_code
|
|
5
|
+
%sender
|
|
6
|
+
%type= 6
|
|
7
|
+
%id= config.short_code
|
|
8
|
+
%recipient
|
|
9
|
+
%type= 5
|
|
10
|
+
%id= number
|
|
11
|
+
%text= message.gsub("&", "&").gsub("<", "<").gsub(">", ">").gsub("'", "'").gsub('"', """)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Txter
|
|
2
|
+
class << self
|
|
3
|
+
def mode
|
|
4
|
+
@@mode ||= :test
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def mode=(new_mode)
|
|
8
|
+
@@mode = new_mode
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def configured?
|
|
12
|
+
return false unless configuration
|
|
13
|
+
configuration.client_id && configuration.client_key
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def configuration
|
|
17
|
+
@@configuration
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def configure(&block)
|
|
21
|
+
@@configuration = Configuration.new(&block)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Configuration
|
|
26
|
+
|
|
27
|
+
attr_accessor :client_id
|
|
28
|
+
attr_accessor :client_key
|
|
29
|
+
attr_accessor :gateway
|
|
30
|
+
attr_accessor :short_code
|
|
31
|
+
attr_accessor :default_from_phone_number
|
|
32
|
+
attr_accessor :proxy_address
|
|
33
|
+
attr_accessor :proxy_port
|
|
34
|
+
attr_accessor :proxy_username
|
|
35
|
+
attr_accessor :proxy_password
|
|
36
|
+
|
|
37
|
+
def initialize
|
|
38
|
+
yield self
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/contactable.rb
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
module Txter
|
|
2
|
+
module Contactable
|
|
3
|
+
|
|
4
|
+
Attributes = [ :sms_phone_number,
|
|
5
|
+
:sms_blocked,
|
|
6
|
+
:sms_confirmation_code,
|
|
7
|
+
:sms_confirmation_attempted,
|
|
8
|
+
:sms_confirmed_phone_number ]
|
|
9
|
+
|
|
10
|
+
def self.included(model)
|
|
11
|
+
gem 'haml'
|
|
12
|
+
require 'haml'
|
|
13
|
+
require 'net/http'
|
|
14
|
+
|
|
15
|
+
Attributes.each do |attribute|
|
|
16
|
+
# add a method in the class for setting or retrieving
|
|
17
|
+
# which column should be used for which attribute
|
|
18
|
+
#
|
|
19
|
+
# :sms_phone_number_column defaults to :sms_phone_number, etc.
|
|
20
|
+
model.instance_eval "
|
|
21
|
+
def #{attribute}_column(value = nil)
|
|
22
|
+
@#{attribute}_column ||= :#{attribute}
|
|
23
|
+
@#{attribute}_column = value if value
|
|
24
|
+
@#{attribute}_column
|
|
25
|
+
end
|
|
26
|
+
"
|
|
27
|
+
# provide helper methods to access the right value
|
|
28
|
+
# no matter which column it's stored in.
|
|
29
|
+
#
|
|
30
|
+
# e.g.: @user.txter_sms_confirmation_code
|
|
31
|
+
# == @user.send(User.sms_confirmation_code_column)
|
|
32
|
+
model.class_eval "
|
|
33
|
+
def txter_#{attribute}
|
|
34
|
+
send self.class.#{attribute}_column
|
|
35
|
+
end
|
|
36
|
+
alias_method :txter_#{attribute}?, :txter_#{attribute}
|
|
37
|
+
def txter_#{attribute}=(value)
|
|
38
|
+
send self.class.#{attribute}_column.to_s+'=', value
|
|
39
|
+
end
|
|
40
|
+
"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# normalize the phone number before it's saved in the database
|
|
44
|
+
# (only for model classes using callbacks a la ActiveRecord,
|
|
45
|
+
# other folks will have to do this by hand)
|
|
46
|
+
if model.respond_to?(:before_save)
|
|
47
|
+
model.before_save :normalize_sms_phone_number
|
|
48
|
+
model.class_eval do
|
|
49
|
+
def normalize_sms_phone_number
|
|
50
|
+
self.txter_sms_phone_number = Txter.numerize(txter_sms_phone_number)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Sends one or more TXT messages to the contactable record's
|
|
57
|
+
# mobile number (if the number has been confirmed).
|
|
58
|
+
# Any messages longer than 160 characters will need to be accompanied
|
|
59
|
+
# by a second argument <tt>true</tt> to clarify that sending
|
|
60
|
+
# multiple messages is intentional.
|
|
61
|
+
def send_sms!(msg, allow_multiple = false)
|
|
62
|
+
if msg.to_s.size > 160 && !allow_multiple
|
|
63
|
+
raise ArgumentError, "SMS Message is too long. Either specify that you want multiple messages or shorten the string."
|
|
64
|
+
end
|
|
65
|
+
return false if msg.to_s.strip.blank? || txter_sms_blocked?
|
|
66
|
+
return false unless sms_confirmed?
|
|
67
|
+
|
|
68
|
+
# split into pieces that fit as individual messages.
|
|
69
|
+
msg.to_s.scan(/.{1,160}/m).map do |text|
|
|
70
|
+
if Txter.deliver(text, txter_sms_phone_number).success?
|
|
71
|
+
text.size
|
|
72
|
+
else
|
|
73
|
+
false
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Sends an SMS validation request through the gateway
|
|
79
|
+
def send_sms_confirmation!
|
|
80
|
+
return false if txter_sms_blocked?
|
|
81
|
+
return true if sms_confirmed?
|
|
82
|
+
return false if txter_sms_phone_number.blank?
|
|
83
|
+
|
|
84
|
+
confirmation_code = Txter.generate_confirmation_code
|
|
85
|
+
|
|
86
|
+
# Use this class' confirmation_message method if it
|
|
87
|
+
# exists, otherwise use the generic message
|
|
88
|
+
message = (self.class.respond_to?(:confirmation_message) ?
|
|
89
|
+
self.class :
|
|
90
|
+
Txter).confirmation_message(confirmation_code)
|
|
91
|
+
|
|
92
|
+
if message.to_s.size > 160
|
|
93
|
+
raise ArgumentError, "SMS Confirmation Message is too long. Limit it to 160 characters of unescaped text."
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
response = Txter.deliver(message, txter_sms_phone_number)
|
|
97
|
+
|
|
98
|
+
if response.success?
|
|
99
|
+
update_txter_sms_confirmation confirmation_code
|
|
100
|
+
else
|
|
101
|
+
false
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# Sends an unblock request via xml to the 4info gateway.
|
|
107
|
+
# If request succeeds, changes the contactable record's
|
|
108
|
+
# sms_blocked_column to false.
|
|
109
|
+
def unblock_sms!
|
|
110
|
+
return false unless txter_sms_blocked?
|
|
111
|
+
|
|
112
|
+
response = Txter.unblock(txter_sms_phone_number)
|
|
113
|
+
if response.success?
|
|
114
|
+
self.txter_sms_blocked = 'false'
|
|
115
|
+
save
|
|
116
|
+
else
|
|
117
|
+
false
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Compares user-provided code with the stored confirmation
|
|
122
|
+
# code. If they match then the current phone number is set
|
|
123
|
+
# as confirmed by the user.
|
|
124
|
+
def sms_confirm_with(code)
|
|
125
|
+
if txter_sms_confirmation_code.to_s.downcase == code.downcase
|
|
126
|
+
# save the phone number into the 'confirmed phone number' attribute
|
|
127
|
+
self.txter_sms_confirmed_phone_number = txter_sms_phone_number
|
|
128
|
+
save
|
|
129
|
+
else
|
|
130
|
+
false
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Returns true if the current phone number has been confirmed by
|
|
135
|
+
# the user for recieving TXT messages.
|
|
136
|
+
def sms_confirmed?
|
|
137
|
+
return false if txter_sms_confirmed_phone_number.blank?
|
|
138
|
+
txter_sms_confirmed_phone_number == txter_sms_phone_number
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
protected
|
|
142
|
+
|
|
143
|
+
def update_txter_sms_confirmation(new_code)
|
|
144
|
+
self.txter_sms_confirmation_code = new_code
|
|
145
|
+
self.txter_sms_confirmation_attempted = Time.now.utc
|
|
146
|
+
self.txter_sms_confirmed_phone_number = nil
|
|
147
|
+
save
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
data/lib/controller.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Txter
|
|
2
|
+
module Controller
|
|
3
|
+
|
|
4
|
+
def self.included(controller)
|
|
5
|
+
controller.instance_eval do
|
|
6
|
+
# the user should specify which class gets contacted
|
|
7
|
+
def sms_contactable(klass)
|
|
8
|
+
@@contactable_class = klass
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# the likely default
|
|
14
|
+
def index
|
|
15
|
+
recieve_xml
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# in case this is hooked up as a RESTful route
|
|
19
|
+
def create
|
|
20
|
+
recieve_xml
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
protected
|
|
24
|
+
|
|
25
|
+
def recieve_xml
|
|
26
|
+
|
|
27
|
+
unless defined?(@@contactable_class)
|
|
28
|
+
raise RuntimeError, "Please define your user class in the Txter controller via the 'sms_contactable' method"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
request = params[:request]
|
|
32
|
+
render :text => 'unknown format', :status => 500 and return unless request
|
|
33
|
+
case request['type']
|
|
34
|
+
when 'BLOCK'
|
|
35
|
+
@contactable = find_contactable(request[:block][:recipient][:id])
|
|
36
|
+
@contactable.txter_sms_blocked = true
|
|
37
|
+
@contactable.save!
|
|
38
|
+
when 'MESSAGE'
|
|
39
|
+
@contactable = find_contactable(request[:message][:sender][:id])
|
|
40
|
+
if @contactable.respond_to?(:receive_sms)
|
|
41
|
+
@contactable.receive_sms(request[:message][:text])
|
|
42
|
+
else
|
|
43
|
+
warn "An SMS message was received but #{@@contactable_class.name.inspect} doesn't have a receive_sms method!"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
render :text => 'OK', :status => 200
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def find_contactable(id)
|
|
50
|
+
[id, id.sub(/^\+/,''), id.sub(/^\+1/,'')].uniq.compact.each do |possible_phone_number|
|
|
51
|
+
found = @@contactable_class.find(
|
|
52
|
+
:first,
|
|
53
|
+
:conditions =>
|
|
54
|
+
{ @@contactable_class.sms_phone_number_column => possible_phone_number }
|
|
55
|
+
)
|
|
56
|
+
return found if found
|
|
57
|
+
end
|
|
58
|
+
# rescue => error
|
|
59
|
+
# render :text => error.inspect
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|