def POST_user_numbers(request, format): """ Respond to a "POST user_numbers" request. """ params = apiHelper.get_params(request, "user_number") error = apiHelper.check_params(params, required_params=["token", "number"], optional_params=["country"]) if error != None: return error token = params['token'] number = params['number'] if "country" in params: country = params['country'] else: country = "US" if not session.validate(token): return HttpResponseBadRequest("Invalid token") user = session.get_user(token) # Ask the "phonenumbers" library to format the phone number into E.164 # format. phone_number = phonenumbers.parse(number, country) phone_format = phonenumbers.PhoneNumberFormat.E164 formatted_number = phonenumbers.format_number(phone_number, phone_format) # If we already have a UserNumber record for this phone number, delete the # old one. try: user_num = UserNumber.objects.get(number=formatted_number) except UserNumber.DoesNotExist: user_num = None if user_num != None: user_num.delete() # ??? What if the number is owned by someone else? # Create the UserNumber record for this phone number. user_num = UserNumber() user_num.user = user user_num.number = formatted_number user_num.code = utils.calc_random_digits(num_digits=4) user_num.verified = False user_num.created_at = datetime.datetime.now() user_num.updated_at = datetime.datetime.now() user_num.save() # Ask our SMS gateway to send a verification message to the phone. _send_verification_code(user_num) # Finally, return the newly-created user number back to the caller. return apiHelper.response({'user_number' : user_num.to_dict()}, format=format, status=HTTP_RESPONSE_POST_OK)
def test_create_conversation_no_account(self): """ Test the "POST /conversations" call when one party has no account. """ # Create the first user. token,profile = self.createUserAndProfile("Profile 1") # Set up a phone number to use for testing. Note that we use the # "phonenumbers" library to convert the number to E.164 format, so we # can find the formatted number again. raw_phone_number = "64212772641" phone_number = phonenumbers.parse(raw_phone_number, "US") phone_format = phonenumbers.PhoneNumberFormat.E164 formatted_number = phonenumbers.format_number(phone_number, phone_format) # Now create the conversation, supplying only the raw phone number for # the second user. response = self.sendRequest("POST", "/conversations", {'token' : token, 'number' : raw_phone_number, 'sender_id': profile['id']}) self.assertEqual(response.status_code, HTTP_RESPONSE_POST_OK) self.assertEqual(response['Content-Type'], "application/json") conversation = json.loads(response.content)['conversation'] # Check that a user and profile have been created for the second user. other_profile_id = conversation['profile_id'] try: other_profile = Profile.objects.get(id=other_profile_id) except Profile.DoesNotExist: self.fail("Didn't create profile for other party.") other_user = other_profile.user found = False for number in UserNumber.objects.filter(user=other_user): if number.number == formatted_number: found = True self.assertTrue(found)
def POST_sessions(request, format): """ Respond to a "POST sessions" request. """ params = apiHelper.get_params(request, "session") if "username" in params: error = apiHelper.check_params(params, required_params=["username", "password"]) login_via_username = True elif "number" in params: error = apiHelper.check_params(params, required_params=["number"], optional_params=["country"]) login_via_username = False else: return HttpResponseBadRequest("username/password or " + "phone number required") if error != None: return error if login_via_username: # Log the caller in using the supplied username and password. username = params['username'] password = params['password'] try: user = User.objects.get(username=username) except User.DoesNotExist: user = None if user == None or not user.check_password(password): return HttpResponseForbidden("Incorrect username or password") # Open up a session for this user. token = session.create(user) # Finally, return the user and the login token back to the caller. return apiHelper.response({'user' : user.to_dict(), 'token' : token}, format=format, status=HTTP_RESPONSE_POST_OK) else: # Log the caller in using the supplied phone number. number = params['number'] if "country" in params: country = params['country'] else: country = "US" # Ask the "phonenumbers" library to format the phone number into E.164 # format. phone_number = phonenumbers.parse(number, country) phone_format = phonenumbers.PhoneNumberFormat.E164 formatted_number = phonenumbers.format_number(phone_number, phone_format) # Open up a session for this phone number. token,verification_code = session.create_for_phone(formatted_number) # Send an SMS message to the supplied phone number. sms_gateway.send_message(text="code: " + verification_code + " -- " + settings.SYSTEM_NAME, from_user=None, from_profile=None, to_user=None, to_profile=None, to_phone_number=formatted_number, message_id=None) # Finally, return the formatted phone number and login token back to # the caller. return apiHelper.response({'number' : formatted_number, 'token' : token}, format=format, status=HTTP_RESPONSE_POST_OK)
def POST_conversations(request, format): """ Respond to the "POST conversations" request. """ # Get the request parameters. params = apiHelper.get_params(request, resource_name="conversation") error = apiHelper.check_params(params, required_params=["token", "sender_id"], optional_params=["number", "country", "recipient_id", "aka", "tag"]) if error != None: return error token = params['token'] sender_id = params['sender_id'] number = params.get("number") country = params.get("country") recipient_id = params.get("recipient_id") aka = params.get("aka") if "tag" in params: tags = params.getlist("tag") else: tags = [] if not session.validate(token): return HttpResponseBadRequest("Invalid token") user = session.get_user(token) # If the caller supplied a phone number and not a recipient ID, try to # match the phone number against an existing user. If the phone number is # new, we create a new user for that phone number on-the-fly. if number != None and recipient_id == None: # Normalize the phone number into E.164 format. if country == None: country = "US" phone_number = phonenumbers.parse(number, country) phone_format = phonenumbers.PhoneNumberFormat.E164 formatted_number = phonenumbers.format_number(phone_number, phone_format) # See if the phone number already exists in the system. try: recipient_number = UserNumber.objects.get(number=formatted_number) except UserNumber.DoesNotExist: recipient_number = None if recipient_number == None: # This is the first time we've encountered this phone number -> # create a new User record for this user, and attach it to the # phone number. recipient_user = User() recipient_user.created_at = datetime.datetime.now() recipient_user.updated_at = datetime.datetime.now() recipient_user.save() recipient_number = UserNumber() recipient_number.user = recipient_user recipient_number.number = formatted_number recipient_number.verified = True # Number is already validated. recipient_number.created_at = datetime.datetime.now() recipient_number.updated_at = datetime.datetime.now() recipient_number.save() else: recipient_user = recipient_number.user # We now have a User and UserNumber record for this phone number. # Check that we have a profile for that user; if not, we have to create # one on the fly. profiles = [] for profile in recipient_user.profile_set.order_by("id"): profiles.append(profile) if len(profiles) == 0: recipient_profile = Profile() recipient_profile.user = recipient_user recipient_profile.created_at = datetime.datetime.now() recipient_profile.updated_at = datetime.datetime.now() recipient_profile.save() else: recipient_profile = profiles[recipient_user.default_profile] # Finally, use the recipient profile for this conversation. recipient_id = recipient_profile.id else: # Check that the caller specified a recipient ID. if recipient_id == None: return HttpResponseBadRequest("Missing recipient_id parameter") # Get the sender and recipient profiles. try: sender_profile = Profile.objects.get(id=sender_id) except Profile.DoesNotExist: return HttpResponseBadRequest("Nonexistent sending profile") if sender_profile.user != user: return HttpResponseBadRequest("sender_id not your profile") try: recipient_profile = Profile.objects.get(id=recipient_id) except Profile.DoesNotExist: return HttpResponseBadRequest("Nonexistent recipient profile") # See if we already have a conversation for this sender and recipient. try: conversation = Conversation.objects.get(profile1=sender_profile, profile2=recipient_profile) except Conversation.DoesNotExist: try: conversation = Conversation.objects.get(profile1=recipient_profile, profile2=sender_profile) except Conversation.DoesNotExist: conversation = None if conversation != None: # Unhide the existing conversation for both parties. conversation.hidden1 = False conversation.hidden2 = False conversation.updated_at = datetime.datetime.now() conversation.save() else: # There's no existing conversation for these two profiles -> create # one. conversation = Conversation() conversation.profile1 = sender_profile conversation.profile2 = recipient_profile conversation.hidden1 = False conversation.hidden2 = False conversation.created_at = datetime.datetime.now() conversation.updated_at = datetime.datetime.now() conversation.save() # If either party has made revelations to the "PUBLIC" profile, copy # those revelations and make them directly to the other party. In this # way, changing the public revelations won't affect the revelations # made in this conversation. _copy_public_revelations(sender_profile, recipient_profile) _copy_public_revelations(recipient_profile, sender_profile) # Store the "aka" value for this conversation, if one was supplied. if aka != None: if sender_profile == conversation.profile1: conversation.aka1 = aka else: conversation.aka2 = aka conversation.updated_at = datetime.datetime.now() conversation.save() # If the caller supplied any "tag" values, use these to replace the # existing tags (if any). if len(tags) > 0: ConversationTag.objects.filter(conversation=conversation, profile=sender_profile).delete() for tag in tags: conversation_tag = ConversationTag() conversation_tag.conversation = conversation conversation_tag.profile = sender_profile conversation_tag.tag = tag conversation_tag.created_at = datetime.datetime.now() conversation_tag.updated_at = datetime.datetime.now() conversation_tag.save() # Finally, return the conversation back to the caller. cdict = conversation.to_dict_for_profile(sender_profile, include_revelations=True) return apiHelper.response({'conversation' : cdict}, format=format, status=HTTP_RESPONSE_POST_OK)