예제 #1
0
 def post(self):
     """
     Receive a Twilio request, return a TwiML response
     """
     from_phone_number = self.strip_incoming_number(
         self.get_argument('From')
     )
     
     to_phone_number = self.strip_incoming_number(
         self.get_argument('To')
     )
     
     buyer_phone_number_hash = md5.new(from_phone_number).hexdigest()
     call_status = self.get_argument('CallStatus')
     logging.info('Receiving call from %s to %s, hash %s, status %s' % (
         repr(from_phone_number), repr(to_phone_number), repr(buyer_phone_number_hash), repr(call_status)
     ))
     
     if call_status == 'ringing':
         resale_db.phone_map.ensure_index([('buyer_phone_number_hash', 1)])
         # TODO: also add some logging info to phone_map, see if we can do it in
         # one round trip to DB
         twilio_phone_number = resale_db.twilio_phone_number.find_one({
             'phone_number': to_phone_number,
         })
         
         phone_map = resale_db.phone_map.find_one({
             'buyer_phone_number_hash': buyer_phone_number_hash,
             'twilio_phone_number.$id': twilio_phone_number['_id'],
             'expires': { '$gt': resale_time.utcnow() },
         }, {
             'post': True,
         })
         
         post = resale_db.dereference(phone_map['post'])
         
         # TODO: if no phone_map, speak error message to user, or latest phone_map
         # is expired
         
         response = twilio.Response()
         # Current-time phone number for testing call redirection
         #response.append(twilio.Dial("2027621401", timeLimit=45))
         response.append(twilio.Dial(post['phone_number']))
         logging.info('Responding:\n%s\n', response)
         self.write(str(response))
예제 #2
0
 def post(self, json):
     """
     Setup a Twilio phone number to receive calls from the buyer (who
     initiates this request) to the seller of this post.
     
     Returns: {'result': 'OK', 'seller_phone_number': '1234567890'}
     or: {'result': 'OK', 'wait_seconds': 30} if no number is available now
     """
     resale_db.twilio_phone_number.ensure_index([('create_date', 1)])
     resale_db.phone_map.ensure_index([('buyer_phone_number_hash', 1), ('expires', 1)])
     
     # Get the buyer's active phone_maps, which associate the buyer's phone
     # number with a Twilio phone number and a seller's phone number
     # TODO: deny this whole flow if seller didn't enter phone number -
     # prevent user from even clicking 'Call' in Javascript
     utcnow = resale_time.utcnow()
     buyer_phone_maps = list(resale_db.phone_map.find({
         'buyer_phone_number_hash': json['buyer_phone_number_hash'],
         'expires': { '$gt': utcnow },
     }, {
         'twilio_phone_number.$id': True,
         'expires': True,
     }).sort('expires', 1))
     
     logging.info('buyer_phone_maps: %s' % repr(list(buyer_phone_maps)))
     
     # Get oldest twilio phone number not in an active phone_map for this buyer
     active_twilio_phone_numbers = [phone_map['twilio_phone_number']['$id'] for phone_map in buyer_phone_maps]
     logging.info('active_twilio_phone_numbers: %s' % repr(active_twilio_phone_numbers))
     twilio_phone_numbers = list(resale_db.twilio_phone_number.find({
         '_id': { '$nin': [phone_map['twilio_phone_number']['$id'] for phone_map in buyer_phone_maps] },
     }).sort('create_date', 1).limit(1))
     
     logging.info('twilio_phone_numbers: %s' % repr(list(twilio_phone_numbers)))
     
     if len(twilio_phone_numbers):
         twilio_phone_number = twilio_phone_numbers[0]
         post = post_with_short_code_or_404(json['short_code'])
         resale_db.phone_map.insert({
             'post': DBRef('post', post['_id']),
             'buyer_phone_number_hash': json['buyer_phone_number_hash'],
             'twilio_phone_number': DBRef('twilio_phone_number', twilio_phone_number['_id']),
             'expires': utcnow + datetime.timedelta(seconds=resale_settings.phone_map_lifetime),
         })
         return {'result': 'OK', 'seller_phone_number': twilio_phone_number['phone_number']}
     else:
         # How long will user have to wait before a Twilio phone number becomes available?
         logging.info('first phone map expires: %s, now is: %s' % (
             buyer_phone_maps[0]['expires'].ctime(),
             utcnow.ctime()
         ))
         
         # Round up to nearest 10 seconds, plus 2 seconds fudge, for simplicity
         rounding_seconds = 10
         wait_seconds = int(math.ceil(
             ((resale_time.utc_cast(buyer_phone_maps[0]['expires']) - utcnow).total_seconds() + 2) / rounding_seconds
         ) * rounding_seconds)
         
         assert wait_seconds > 0, (
             "Buyer with phone number hash %s has negative wait_seconds %d" % (
                 repr(json['buyer_phone_number_hash']), wait_seconds
             )
         )
         
         return { 'result': 'OK', 'wait_seconds': wait_seconds }