def send_notifications(self): """ Send out notifications for this message. If the user has at least one device, we send out device notification(s) using the APN or Android gateways. Otherwise, we fall back to sending out SMS notifications to each of the user's verified phone numbers. """ from api.gateways import apn_gateway from api.gateways import android_gateway from api.gateways import sms_gateway from api.gateways import push_gateway has_device = False # initially. for device in Device.objects.filter(user=self.recipient.user): type = device.notification_type token = device.notification_token if type == Device.TYPE_APPLE: apn_gateway.send_notification(text=self.body, user=self.sender.user, profile=self.sender, device_token=token, message_id=self.id) elif type == Device.TYPE_ANDROID: android_gateway.send_notification(text=self.body, user=self.sender.user, profile=self.sender, device_token=token, message_id=self.id) has_device = True if not has_device: # Fall back to sending SMS notifications for this message. for user_num in UserNumber.objects.filter( user=self.recipient.user): if user_num.verified: sms_gateway.send_message(text=self.body, from_user=self.sender.user, from_profile=self.sender, to_user=self.recipient.user, to_profile=self.recipient, to_phone_number=user_num.number, message_id=self.id) # Finally, send notification for this message out using the push # gateway. push_gateway.send_message(self)
def _send_verification_code(user_num): """ Send the verification code to the given phone number. 'user_num' should be the UserNumber object to send the verification code to. """ # Find the first profile for this user. profiles = Profile.objects.filter(user=user_num.user) if len(profiles) == 0: first_profile = None else: first_profile = profiles[0] sms_gateway.send_message(text="code: " + user_num.code + " -- " + settings.SYSTEM_NAME, from_user=None, from_profile=None, to_user=user_num.user, to_profile=first_profile, to_phone_number=user_num.number, message_id=None)
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 test_sends_via_sms(self): """ Test the logic of sending a message via SMS. """ with self.settings(ENABLE_GATEWAYS=False): # Create two dummy users, profiles and phone numbers for testing. token_1,profile_dict_1 = self.createUserAndProfile("Profile 1") token_2,profile_dict_2 = self.createUserAndProfile("Profile 2") profile_1 = Profile.objects.get(id=profile_dict_1['id']) user_1 = profile_1.user profile_2 = Profile.objects.get(id=profile_dict_2['id']) user_2 = profile_2.user number_1 = UserNumber() number_1.user = user_1 number_1.number = self.randomDigits() number_1.verified = True number_1.created_at = datetime.datetime.now() number_1.updated_at = datetime.datetime.now() number_1.save() number_2 = UserNumber() number_2.user = user_2 number_2.number = self.randomDigits() number_2.verified = True number_2.created_at = datetime.datetime.now() number_2.updated_at = datetime.datetime.now() number_2.save() # Set up a signal handler to check that the sms_message_sent signal # is being sent. self.signal_received = False # initially. self.payload = None # ditto. def signal_handler(sender, **kwargs): self.signal_received = True self.payload = kwargs.get("payload") signals.sms_message_sent.connect(signal_handler) # Send a dummy message via the SMS gateway. sms_gateway.send_message(text="Test Message", from_user=user_1, from_profile=profile_1, to_user=user_2, to_profile=profile_2, to_phone_number=number_2.number) # Clean up, and check that the SMS gateway worked correctly. signals.sms_message_sent.disconnect(signal_handler) self.assertTrue(self.signal_received, "Message wasn't sent via SMS gateway!") self.assertItemsEqual(self.payload.keys(), ["from_phone", "to_phone", "sms_text"], "Bad SMS payload!") self.assertEqual(self.payload['to_phone'], number_2.number, "SMS text sent to the wrong number!") from_phone = self.payload['from_phone'] try: phone_number = TwilioPhoneNumber.objects.get(number=from_phone) except TwilioPhoneNumber.DoesNotExist: phone_number = None self.assertIsNotNone(phone_number, "SMS sent from non-existent phone number!") try: channel = TwilioSMSChannel.objects.get( sender=profile_1, recipient=profile_2, phone_number=phone_number) except TwilioSMSChannel.DoesNotExist: channel = None self.assertIsNotNone(channel, "No SMS channel set up!")
def test_creates_second_sms_channel(self): """ Check that two users sending to a profile use different channels. """ with self.settings(ENABLE_GATEWAYS=False): # Create three dummy users, profiles and phone numbers for testing. token_1,profile_dict_1 = self.createUserAndProfile("Profile 1") token_2,profile_dict_2 = self.createUserAndProfile("Profile 2") token_3,profile_dict_3 = self.createUserAndProfile("Profile 3") profile_1 = Profile.objects.get(id=profile_dict_1['id']) user_1 = profile_1.user profile_2 = Profile.objects.get(id=profile_dict_2['id']) user_2 = profile_2.user profile_3 = Profile.objects.get(id=profile_dict_3['id']) user_3 = profile_3.user number_1 = UserNumber() number_1.user = user_1 number_1.number = self.randomDigits() number_1.verified = True number_1.created_at = datetime.datetime.now() number_1.updated_at = datetime.datetime.now() number_1.save() number_2 = UserNumber() number_2.user = user_2 number_2.number = self.randomDigits() number_2.verified = True number_2.created_at = datetime.datetime.now() number_2.updated_at = datetime.datetime.now() number_2.save() number_3 = UserNumber() number_3.user = user_3 number_3.number = self.randomDigits() number_3.verified = True number_3.created_at = datetime.datetime.now() number_3.updated_at = datetime.datetime.now() number_3.save() # Set up a handler to grab the payload from the sms_gateway signal. self.signal_received = False # initially. self.payload = None # ditto. def signal_handler(sender, **kwargs): self.signal_received = True self.payload = kwargs.get("payload") signals.sms_message_sent.connect(signal_handler) # Send a dummy message via the SMS gateway from profile 1 to # profile 3. sms_gateway.send_message(text="Test Message", from_user=user_1, from_profile=profile_1, to_user=user_3, to_profile=profile_3, to_phone_number=number_3.number) # Grab the SMS channel used to send this message. from_phone = self.payload['from_phone'] phone_number = TwilioPhoneNumber.objects.get(number=from_phone) channel_1 = TwilioSMSChannel.objects.get( sender=profile_1, recipient=profile_3, phone_number=phone_number) # Now send a second message via the SMS gateway, from profile 2 to # profile 3. self.signal_received = False self.payload = None sms_gateway.send_message(text="Test Message", from_user=user_2, from_profile=profile_2, to_user=user_3, to_profile=profile_3, to_phone_number=number_3.number) # Check that a different SMS channel was used for the two messages. from_phone = self.payload['from_phone'] try: phone_number = TwilioPhoneNumber.objects.get(number=from_phone) except TwilioPhoneNumber.DoesNotExist: phone_number = None try: channel_2 = TwilioSMSChannel.objects.get( sender=profile_2, recipient=profile_3, phone_number=phone_number) except TwilioSMSChannel.DoesNotExist: channel_2 = None self.assertNotEqual(channel_1, channel_2, "The same channel was used for both messages!") # Clean up. signals.sms_message_sent.disconnect(signal_handler)