Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Refactor Message. Finally.

  • Loading branch information...
commit 4ac73d23d6b1bfd5c4a8291720b5a413bbd80dd2 1 parent eb5fff6
Mike Burns authored November 13, 2010
4  app/controllers/messages_controller.rb
@@ -3,12 +3,12 @@ def index
3 3
     # This is when we send messages to user
4 4
     if relay?
5 5
       ### TODO: untested
6  
-      json = Message.json_for_relay(params[:session][:parameters])
  6
+      json = Message.new(params[:session][:parameters]).json_for_relay
7 7
       render :json => json
8 8
 
9 9
     # This is when we receive messages from a user
10 10
     else
11  
-      Message.handle_incoming(phone_number, message_text)
  11
+      Message.new(:to => phone_number, :message => message_text).handle_incoming
12 12
       render :status => 200, :text => Message::HANGUP_RESPONSE
13 13
     end
14 14
   end
232  app/models/message.rb
... ...
@@ -1,22 +1,25 @@
1  
-module Message
2  
-  DATING_START_STRING = '5PM EDT'
3  
-  DATING_END_STRING   = '10:59PM EDT'
4  
-  DATING_START        = Time.zone.parse(DATING_START_STRING)
5  
-  DATING_END          = Time.zone.parse(DATING_END_STRING)
  1
+class Message
6 2
   HANGUP_RESPONSE     = '{"tropo": [{"hangup": null}]}'
7 3
 
8  
-  def self.deliver(to, message, deliver_in_development = false)
  4
+  attr_accessor :to, :text
  5
+
  6
+  def initialize(params)
  7
+    self.to = params[:to]
  8
+    self.text = params[:message]
  9
+  end
  10
+
  11
+  def deliver(deliver_in_development = false)
9 12
     if Rails.env.development? && !deliver_in_development
10 13
       raise "Tried to deliver an SMS in development without passing deliver_in_development = true."
11 14
     end
12 15
 
13  
-    Rails.logger.info "Enqueued SMS: TO: #{to}: #{message}"
  16
+    Rails.logger.info "Enqueued SMS: TO: #{to}: #{text}"
14 17
 
15 18
     params = Addressable::URI.new
16 19
     params.query_values = {
17 20
       "relay" => "relay",
18  
-      "to" => to,
19  
-      "message" => message,
  21
+      "to" => self.to,
  22
+      "message" => self.text,
20 23
       "token" => MESSAGE_TOKEN,
21 24
       "action" =>"create"
22 25
     }
@@ -26,222 +29,33 @@ def self.deliver(to, message, deliver_in_development = false)
26 29
   end
27 30
 
28 31
   ### TODO: untested
29  
-  def self.json_for_relay(message_params)
30  
-    to = message_params[:to]
31  
-    message = message_params[:message]
32  
-
  32
+  def json_for_relay
33 33
     tropo = Tropo::Generator.new do
34 34
       message({
35  
-        :to => 'tel:+' + to,
  35
+        :to => "tel:+#{self.to}",
36 36
         :channel => 'TEXT',
37 37
         :network => 'SMS'
38 38
       }) do
39  
-        say :value => message
  39
+        say :value => self.text
40 40
       end
41 41
     end
42 42
 
43 43
     tropo.response
44 44
   end
45 45
 
46  
-  def self.handle_incoming(phone_number, message_text)
47  
-    Rails.logger.info("SMS INCOMING: FROM #{phone_number}: #{message_text}")
  46
+  def handle_incoming
  47
+    Rails.logger.info("SMS INCOMING: FROM #{self.to}: #{self.text}")
48 48
 
49  
-    user = User.find_by_phone_number(phone_number)
  49
+    user = User.find_by_phone_number(self.to)
50 50
 
51 51
     if user.nil?
52  
-      Message.deliver(phone_number,
53  
-                      "Sorry, you must register first at instalover.com")
54  
-      return
55  
-    end
56  
-
57  
-    if user.unconfirmed?
  52
+      Message.new(:to => self.to, :message => "Sorry, you must register first at instalover.com").deliver
  53
+    elsif user.unconfirmed?
58 54
       user.deliver_secret_code
59  
-      return
60  
-    end
61  
-
62  
-    if user.dflns.unwritten.any?
63  
-      handle_dfln(user, message_text)
64  
-      return
65  
-    end
66  
-
67  
-    if message_text =~ /^\s*#{COMMANDS[:new_date].gsub(' ','.*')}/i
68  
-      handle_new_date(user)
69  
-    elsif message_text =~ /^\s*#{COMMANDS[:ok].gsub(' ','.*')}/i
70  
-      handle_ok(user)
71  
-    elsif message_text =~ /^\s*#{COMMANDS[:skeeze].gsub(' ','.*')}/i
72  
-      handle_ok(user, :skeeze => true)
73  
-    elsif message_text =~ /^\s*#{COMMANDS[:accept].gsub(' ','.*')}/i
74  
-      handle_accept(user)
75  
-    elsif message_text =~ /^\s*#{COMMANDS[:sext].gsub(' ','.*')}\s*(.*)/i
76  
-      handle_texting_proxy(user, $1)
77  
-    elsif message_text =~ /^\s*#{COMMANDS[:quit].gsub(' ','.*')}/i
78  
-      handle_safeword(user)
79  
-    elsif message_text =~ /^\s*#{COMMANDS[:retry].gsub(' ','.*')}/i
80  
-      handle_retry(user)
81  
-    elsif message_text =~ /^\s*#{COMMANDS[:women_only].gsub(' ','.*')}/i
82  
-      handle_new_date(user, :desires_male => false, :desires_female => true, :desires_other => false)
83  
-    elsif message_text =~ /^\s*#{COMMANDS[:men_only].gsub(' ','.*')}/i
84  
-      handle_new_date(user, :desires_male => true, :desires_female => false, :desires_other => false)
85  
-    elsif message_text =~ /^\s*#{COMMANDS[:other_only].gsub(' ','.*')}/i
86  
-      handle_new_date(user, :desires_male => false, :desires_female => false, :desires_other => true)
87  
-    elsif message_text =~ /^\s*#{COMMANDS[:anything].gsub(' ','.*')}/i
88  
-      handle_new_date(user, :desires_male => true, :desires_female => true, :desires_other => true)
89  
-    else
90  
-      handle_unknown(user)
91  
-    end
92  
-  end
93  
-
94  
-  def self.handle_texting_proxy(user, message)
95  
-    if dating_user = user.date
96  
-      user.date.tell("#{user.name} says: #{message}")
97  
-    else
98  
-      user.tell("You have no date for us to share that with. Reply with '#{COMMANDS[:new_date]}'.")
99  
-    end
100  
-  end
101  
-
102  
-  def self.handle_new_date(user, meetup_restrictions = {})
103  
-    if within_dating_hours?
104  
-      user.founded_meetups.proposed.destroy_all
105  
-
106  
-      if user.founded_meetups.unscheduled.any?
107  
-        user.tell("Whoa there, pardner - we're looking for someone right now.  If nobody shows after 5 minutes, then you can ask again.")
108  
-      else
109  
-        user.offers.cancel_all
110  
-
111  
-        meetup = Meetup.create(
112  
-          meetup_restrictions.merge(
113  
-            :first_user => user,
114  
-            :description => DateSuggestion.next_place_and_time)
115  
-        )
116  
-
117  
-
118  
-        user.tell("Should we find you a date at #{meetup.description}? Reply 'ok' or 'new date' to try again.")
119  
-        QUEUE.enqueue_at(5.minutes.from_now, OkTimeoutMessageDelayer, :user_id => user.id)
120  
-      end
  55
+    elsif user.dflns.unwritten.any?
  56
+      user.handle_dfln(text)
121 57
     else
122  
-      outside_dating_hours(user)
123  
-    end
124  
-  end
125  
-
126  
-  def self.handle_retry(user)
127  
-    if within_dating_hours?
128  
-      if meetup = user.founded_meetups.retryable.last
129  
-        meetup.unschedule!
130  
-        user.matching_for_meetup(meetup).first(5).each do |matching_user|
131  
-          Offer.create(:offered_user => matching_user, :meetup => meetup)
132  
-        end
133  
-        QUEUE.enqueue_at(5.minutes.from_now, RejectMessageDelayer, :user_id => user.id)
134  
-        user.tell("Trying to get you a date. Back in five.")
135  
-      else
136  
-        handle_new_date(user)
137  
-      end
138  
-    else
139  
-      ### TODO: untested
140  
-      outside_dating_hours(user)
141  
-    end
142  
-  end
143  
-
144  
-  def self.within_dating_hours?
145  
-    now = Time.zone.now
146  
-    now.hour >= DATING_START.hour &&
147  
-      now.hour <= DATING_END.hour
148  
-  end
149  
-
150  
-  def self.outside_dating_hours(user)
151  
-    user.tell("Outside of the dating hours: #{DATING_START_STRING} to #{DATING_END_STRING}. Please try again then!")
152  
-  end
153  
-
154  
-  def self.handle_ok(user, meetup_restrictions = {})
155  
-    meetup = user.founded_meetups.proposed.first
156  
-    if meetup
157  
-      meetup.unschedule!
158  
-      if meetup_restrictions[:skeeze]
159  
-        matches = user.skeeze_matching_for_meetup(meetup).first(5)
160  
-      else
161  
-        matches = user.matching_for_meetup(meetup).first(5)
162  
-      end
163  
-      matches.each do |matching_user|
164  
-        Offer.create(:offered_user => matching_user, :meetup => meetup)
165  
-      end
166  
-      QUEUE.enqueue_at(5.minutes.from_now, RejectMessageDelayer, :user_id => user.id)
167  
-    else
168  
-      handle_unknown(user)
169  
-    end
170  
-  end
171  
-
172  
-  def self.handle_skeeze(user)
173  
-    meetup = user.founded_meetups.proposed.first
174  
-    if meetup
175  
-      meetup.unschedule!
176  
-      user.skeeze_matching_for_meetup(meetup).first(5).each do |matching_user|
177  
-        Offer.create(:offered_user => matching_user, :meetup => meetup)
178  
-      end
179  
-      QUEUE.enqueue_at(5.minutes.from_now, RejectMessageDelayer, :user_id => user.id)
180  
-    else
181  
-      handle_unknown(user)
182  
-    end
183  
-  end
184  
-
185  
-  def self.handle_unknown(user)
186  
-      user.tell("Sorry, I don't know what to do with that. You can text '#{COMMANDS[:new_date]}' to get a date. To stop receiving texts, please text '#{COMMANDS[:quit]}'")
187  
-
188  
-  end
189  
-
190  
-  def self.handle_accept(user)
191  
-    if accepted_offer = user.latest_offer
192  
-      accept_offer(accepted_offer)
193  
-
194  
-      meetup = accepted_offer.meetup
195  
-      meetup.pending_offers.each do |offer|
196  
-        offer.offered_user.tell("Too slow! Would you like to get a date? Reply '#{COMMANDS[:new_date]}'.")
197  
-        offer.decline!
198  
-      end
199  
-    else
200  
-      user.tell("You don't have any date offers to accept")
201  
-    end
202  
-  end
203  
-
204  
-  def self.accept_offer(offer)
205  
-    offer.schedule_meetup!
206  
-    deliver_date(offer.offered_user, offer.meetup.first_user)
207  
-    deliver_date(offer.meetup.first_user, offer.meetup.second_user)
208  
-    offer.accept!
209  
-  end
210  
-
211  
-  def self.deliver_date(first_user, second_user)
212  
-    first_user.tell(%{Nice! You've got a date with #{second_user.name}. Describe yourself using '#{COMMANDS[:sext]}' followed by a message.})
213  
-  end
214  
-
215  
-  def self.handle_safeword(user)
216  
-    user.tell("I got it - 'no' means no!  We could just be friends, but we're not fooling anyone.  You're unsubscribed - have a nice life!")
217  
-    user.destroy
218  
-  end
219  
-
220  
-  def self.handle_dfln(user, message)
221  
-    dfln = user.dflns.unwritten.last
222  
-    dfln.update_attributes({
223  
-      :text => message
224  
-    })
225  
-  end
226  
-
227  
-  def self.handle_no_responses(user)
228  
-    meetup = user.founded_meetups.unscheduled.first
229  
-    if !meetup.nil?
230  
-      user.tell("We called every number in our little black book, but only got answering machines. Try again with '#{COMMANDS[:retry]}'.")
231  
-      meetup.offers.pending.each do |offer|
232  
-        offer.offered_user.tell("Too slow! Would you like to get a date? Reply '#{COMMANDS[:new_date]}'.")
233  
-        offer.cancel!
234  
-      end
235  
-      meetup.retryable!
236  
-    end
237  
-  end
238  
-
239  
-  def self.handle_ok_timeout(user)
240  
-    meetup = user.founded_meetups.proposed.first
241  
-    if !meetup.nil?
242  
-      user.tell("I guess you don't want to go on a date... Text '#{COMMANDS[:new_date]}' again when you change your mind")
243  
-      meetup.state = "cancelled"
244  
-      meetup.save
  58
+      user.handle_incoming(self.text)
245 59
     end
246 60
   end
247 61
 end
3  app/models/offer.rb
@@ -18,6 +18,9 @@ def self.cancel_all
18 18
   end
19 19
 
20 20
   def accept!
  21
+    self.schedule_meetup!
  22
+    self.offered_user.deliver_date(self.meetup.first_user)
  23
+    self.meetup.first_user.deliver_date(self.meetup.second_user)
21 24
     self.state = 'accepted'
22 25
     self.save!
23 26
   end
2  app/models/ok_timeout_message_delayer.rb
@@ -4,6 +4,6 @@ class OkTimeoutMessageDelayer
4 4
   def self.perform(args_hash)
5 5
     user_id = args_hash["user_id"]
6 6
     user = User.find(user_id)
7  
-    Message.handle_ok_timeout(user)
  7
+    user.handle_ok_timeout
8 8
   end
9 9
 end
2  app/models/reject_message_delayer.rb
@@ -4,6 +4,6 @@ class RejectMessageDelayer
4 4
   def self.perform(args_hash)
5 5
     user_id = args_hash["user_id"]
6 6
     user = User.find(user_id)
7  
-    Message.handle_no_responses(user)
  7
+    user.handle_no_responses
8 8
   end
9 9
 end
172  app/models/user.rb
... ...
@@ -1,4 +1,9 @@
1 1
 class User < ActiveRecord::Base
  2
+  DATING_START_STRING = '5PM EDT'
  3
+  DATING_END_STRING   = '10:59PM EDT'
  4
+  DATING_START        = Time.zone.parse(DATING_START_STRING)
  5
+  DATING_END          = Time.zone.parse(DATING_END_STRING)
  6
+
2 7
   attr_protected :secret_code, :phone_number
3 8
   validates_presence_of :phone_number
4 9
   validate :secret_code_matches_or_nil
@@ -140,7 +145,7 @@ def latest_offer
140 145
   end
141 146
 
142 147
   def tell(msg)
143  
-    Message.deliver(self.phone_number, msg)
  148
+    Message.new(:to => self.phone_number, :message => msg).deliver
144 149
   end
145 150
 
146 151
   def incomplete?
@@ -151,6 +156,164 @@ def start_annoyer
151 156
     QUEUE.enqueue_at(7.days.from_now, ProfileAnnoyer, :user_id => self.id)
152 157
   end
153 158
 
  159
+  def handle_incoming(text)
  160
+    case text
  161
+    when /^\s*#{COMMANDS[:new_date].gsub(' ','.*')}/i
  162
+      handle_new_date
  163
+    when /^\s*#{COMMANDS[:ok].gsub(' ','.*')}/i
  164
+      handle_ok
  165
+    when /^\s*#{COMMANDS[:skeeze].gsub(' ','.*')}/i
  166
+      handle_ok :skeeze => true
  167
+    when /^\s*#{COMMANDS[:accept].gsub(' ','.*')}/i
  168
+      handle_accept
  169
+    when /^\s*#{COMMANDS[:sext].gsub(' ','.*')}\s*(.*)/i
  170
+      handle_texting_proxy($1)
  171
+    when /^\s*#{COMMANDS[:quit].gsub(' ','.*')}/i
  172
+      handle_safeword
  173
+    when /^\s*#{COMMANDS[:retry].gsub(' ','.*')}/i
  174
+      handle_retry
  175
+    when /^\s*#{COMMANDS[:women_only].gsub(' ','.*')}/i
  176
+      handle_new_date(:desires_male => false, :desires_female => true, :desires_other => false)
  177
+    when /^\s*#{COMMANDS[:men_only].gsub(' ','.*')}/i
  178
+      handle_new_date(:desires_male => true, :desires_female => false, :desires_other => false)
  179
+    when /^\s*#{COMMANDS[:other_only].gsub(' ','.*')}/i
  180
+      handle_new_date(:desires_male => false, :desires_female => false, :desires_other => true)
  181
+    when /^\s*#{COMMANDS[:anything].gsub(' ','.*')}/i
  182
+      handle_new_date(:desires_male => true, :desires_female => true, :desires_other => true)
  183
+    else
  184
+      handle_unknown
  185
+    end
  186
+  end
  187
+
  188
+  def handle_texting_proxy(message)
  189
+    if self.date
  190
+      self.date.tell("#{self.name} says: #{message}")
  191
+    else
  192
+      self.tell("You have no date for us to share that with. Reply with '#{COMMANDS[:new_date]}'.")
  193
+    end
  194
+  end
  195
+
  196
+  def handle_new_date(meetup_restrictions = {})
  197
+    if within_dating_hours?
  198
+      self.founded_meetups.proposed.destroy_all
  199
+
  200
+      if self.founded_meetups.unscheduled.any?
  201
+        self.tell("Whoa there, pardner - we're looking for someone right now.  If nobody shows after 5 minutes, then you can ask again.")
  202
+      else
  203
+        self.offers.cancel_all
  204
+        ### TODO: cancel all retryable meetups for this user
  205
+
  206
+        meetup = Meetup.create(
  207
+          meetup_restrictions.merge(
  208
+            :first_user => self,
  209
+            :description => DateSuggestion.next_place_and_time)
  210
+        )
  211
+
  212
+        self.tell("Should we find you a date at #{meetup.description}? Reply 'ok' or 'new date' to try again.")
  213
+        QUEUE.enqueue_at(5.minutes.from_now, OkTimeoutMessageDelayer, :user_id => self.id)
  214
+      end
  215
+    else
  216
+      self.outside_dating_hours
  217
+    end
  218
+  end
  219
+
  220
+  def handle_retry
  221
+    if within_dating_hours?
  222
+      if meetup = self.founded_meetups.retryable.last
  223
+        meetup.unschedule!
  224
+        self.matching_for_meetup(meetup).first(5).each do |matching_user|
  225
+          Offer.create(:offered_user => matching_user, :meetup => meetup)
  226
+        end
  227
+        QUEUE.enqueue_at(5.minutes.from_now, RejectMessageDelayer, :user_id => self.id)
  228
+        self.tell("Trying to get you a date. Back in five.")
  229
+      else
  230
+        self.handle_new_date
  231
+      end
  232
+    else
  233
+      ### TODO: untested
  234
+      self.outside_dating_hours
  235
+    end
  236
+  end
  237
+
  238
+  def outside_dating_hours
  239
+    self.tell("Outside of the dating hours: #{DATING_START_STRING} to #{DATING_END_STRING}. Please try again then!")
  240
+  end
  241
+
  242
+  def handle_ok(meetup_restrictions = {})
  243
+    meetup = self.founded_meetups.proposed.first
  244
+    if meetup
  245
+      meetup.unschedule!
  246
+      ### TODO: move this `if' out
  247
+      if meetup_restrictions[:skeeze]
  248
+        matches = self.skeeze_matching_for_meetup(meetup).first(5)
  249
+      else
  250
+        matches = self.matching_for_meetup(meetup).first(5)
  251
+      end
  252
+      matches.each do |matching_user|
  253
+        Offer.create(:offered_user => matching_user, :meetup => meetup)
  254
+      end
  255
+      QUEUE.enqueue_at(5.minutes.from_now, RejectMessageDelayer, :user_id => self.id)
  256
+    else
  257
+      self.handle_unknown
  258
+    end
  259
+  end
  260
+
  261
+  def handle_unknown
  262
+    self.tell("Sorry, I don't know what to do with that. You can text '#{COMMANDS[:new_date]}' to get a date. To stop receiving texts, please text '#{COMMANDS[:quit]}'")
  263
+  end
  264
+
  265
+  def handle_accept
  266
+    if accepted_offer = self.latest_offer
  267
+      accepted_offer.accept!
  268
+
  269
+      meetup = accepted_offer.meetup
  270
+      meetup.pending_offers.each do |offer|
  271
+        ### TODO: move into #decline! ?
  272
+        offer.offered_user.tell("Too slow! Would you like to get a date? Reply '#{COMMANDS[:new_date]}'.")
  273
+        offer.decline!
  274
+      end
  275
+    else
  276
+      self.tell("You don't have any date offers to accept")
  277
+    end
  278
+  end
  279
+
  280
+  def deliver_date(second_user)
  281
+    self.tell(%{Nice! You've got a date with #{second_user.name}. Describe yourself using '#{COMMANDS[:sext]}' followed by a message.})
  282
+  end
  283
+
  284
+  def handle_safeword
  285
+    self.tell("I got it - 'no' means no!  We could just be friends, but we're not fooling anyone.  You're unsubscribed - have a nice life!")
  286
+    self.destroy
  287
+  end
  288
+
  289
+  def handle_dfln(message)
  290
+    dfln = self.dflns.unwritten.last
  291
+    dfln.update_attributes(:text => message)
  292
+  end
  293
+
  294
+  def handle_no_responses
  295
+    meetup = self.founded_meetups.unscheduled.first
  296
+    if !meetup.nil?
  297
+      self.tell("We called every number in our little black book, but only got answering machines. Try again with '#{COMMANDS[:retry]}'.")
  298
+      meetup.offers.pending.each do |offer|
  299
+        ### TODO: move into #cancel! ?
  300
+        offer.offered_user.tell("Too slow! Would you like to get a date? Reply '#{COMMANDS[:new_date]}'.")
  301
+        offer.cancel!
  302
+      end
  303
+      meetup.retryable!
  304
+    end
  305
+  end
  306
+
  307
+  def handle_ok_timeout
  308
+    meetup = self.founded_meetups.proposed.first
  309
+    if !meetup.nil?
  310
+      # TODO: move into Meetup#cancel! ?
  311
+      self.tell("I guess you don't want to go on a date... Text '#{COMMANDS[:new_date]}' again when you change your mind")
  312
+      meetup.state = "cancelled"
  313
+      meetup.save!
  314
+    end
  315
+  end
  316
+
154 317
   protected
155 318
 
156 319
   def normalize_phone_number
@@ -234,4 +397,11 @@ def deliver_confirmation_congratulations
234 397
       self.tell("Congrats, #{self.name}, you are now an instalover.  Text '#{COMMANDS[:new_date]}' to get a new date.")
235 398
     end
236 399
   end
  400
+
  401
+  ### TODO: doesn't belong here
  402
+  def within_dating_hours?
  403
+    now = Time.zone.now
  404
+    now.hour >= DATING_START.hour &&
  405
+      now.hour <= DATING_END.hour
  406
+  end
237 407
 end
4  lib/tasks/instalover.rake
... ...
@@ -1,9 +1,7 @@
1 1
 namespace :instalover do
2 2
   desc "Ping women for dates to poke the pot"
3 3
   task :ping_female_dates => :environment do
4  
-    User.women.each do |w|
5  
-      Message.handle_new_date(w)
6  
-    end
  4
+    User.women.each(&:handle_new_date)
7 5
   end
8 6
 
9 7
   namespace :annoy do

0 notes on commit 4ac73d2

Please sign in to comment.
Something went wrong with that request. Please try again.