コード例 #1
0
def _send_sms(conversation, user, msg):
    """ Send an SMS message to the given user within the given conversation.

        Note that we only send the SMS if the user's phone number has been
        verified.
    """
    logger.debug('in core.lib.conversationHandler._send_sms(' +
                 'conversation=%s, user=%s, msg=%s' 
                 % (repr(conversation), repr(user), repr(msg)))

    if user.verified:
        sending_number = twilio_gateway.calc_sending_phone_number(conversation,
                                                                  user)
        twilio_gateway.send_sms(sending_number, user.phone_number, msg)
コード例 #2
0
ファイル: users.py プロジェクト: 3taps/MessageMe
def merge(old_session, new_session):
    """ Merge two users.
    """
    raise UnauthorizedException() # Disable for now.

    logger.debug("in core.api.users.merge(" +
                 "old_session=%s, new_session=%s)" %
                 (repr(old_session), repr(new_session)))

    # Check that the session parameters are correct.  We require two valid
    # session IDs, the old one for an ad hoc user, and the new one for a non-ad
    # hoc user.

    if old_session == None or new_session == None:
        raise InvalidParametersException()

    sessionHandler.validate(old_session)
    sessionHandler.validate(new_session)

    old_user = sessionHandler.get_user(old_session)
    new_user = sessionHandler.get_user(new_session)

    if not old_user.ad_hoc or new_user.ad_hoc:
        raise UnauthorizedException()

    # Build a list of the old user's conversations.

    old_conversations = []
    for conversation in Conversation.objects.filter(user_1=old_user):
        old_conversations.append(conversation)
    for conversation in Conversation.objects.filter(user_2=old_user):
        if conversation.user_1 != old_user:
            old_conversations.append(conversation)

    # Build a list of the old user's active conversations.  Note that we only
    # store the ID of the other user and the topic ID for the conversation, as
    # the Conversation object itself may get deleted as part of the merge
    # process.  We'll need this to send an SMS to the new user telling them
    # that they've taken the conversation mobile.

    active_conversations = [] # List of (other_user_id, topic_id) tuples.
    for conversation in Conversation.objects.filter(user_1=old_user):
        if not conversation.stopped:
            active_conversations.append((conversation.user_2.id,
                                         conversation.topic.id))
    for conversation in Conversation.objects.filter(user_2=old_user):
        if not conversation.stopped and conversation.user_1 != old_user:
            active_conversations.append((conversation.user_1.id,
                                         conversation.topic.id))

    # Build a list of the new user's conversations.

    new_conversations = []
    for conversation in Conversation.objects.filter(user_1=new_user):
        new_conversations.append(conversation)
    for conversation in Conversation.objects.filter(user_2=new_user):
        if conversation.user_1 == new_user:
            new_conversations.append(conversation)

    # Change each of the old conversations to belong to the new user.  If the
    # updated conversation is a duplicate of an existing conversation for the
    # new user, we have to delete the old conversation and update the
    # associated messages.

    for old_conversation in old_conversations:
        if old_conversation.user_1 == old_user:
            other_old_user = old_conversation.user_2
        else:
            other_old_user = old_conversation.user_1

        is_duplicate = False
        for new_conversation in new_conversations:
            if new_conversation.user_1 == new_user:
                other_new_user = new_conversation.user_2
            else:
                other_new_user = new_conversation.user_1

            if other_old_user == other_new_user:
                is_duplicate = True
                break

        if is_duplicate:
            # Update the messages for old_conversation to be part of the
            # new_conversation instead, and delete the old conversation.
            Message.objects.filter(conversation=old_conversation).update(
                                            conversation=new_conversation)
            old_conversation.delete()
        else:
            # Change the old_conversation to belong to the new_user instead of
            # the old_user.
            if old_conversation.user_1 == old_user:
                old_conversation.user_1 = new_user
            else:
                old_conversation.user_2 = new_user
            old_conversation.save()

    # Update the old user's messages to refer to the new user.

    Message.objects.filter(sender=old_user).update(sender=new_user)

    # Update any topics owned by the old user to now be owned by the new user.
    # Note that we deliberately avoid overwriting the default and any existing
    # named topics for the new user.

    topics = []
    for topic in Topic.objects.filter(user=old_user):
        topics.append(topic)

    for topic in topics:
        if topic.default:
            continue # Don't copy across default topic.
        if Topic.objects.filter(user=new_user, name=topic.name):
            continue # Don't overwrite existing named topic.
        topic.user = new_user
        topic.save()

    # Update any SMS channels which sent messages to the old user to now send
    # messages to the new user.

    channels = []
    for channel in TwilioSMSChannel.objects.filter(sender=old_user):
        channels.append(channel)

    for channel in channels:
        if TwilioSMSChannel.objects.filter(conversation=channel.conversation,
                                           recipient=channel.recipient,
                                           phone_number=channel.phone_number,
                                           sender=new_user).exists():
            continue # Don't overwrite existing SMS channel.
        channel.sender = new_user
        channel.save()

    # Update any SMS channels which sent messages from the old user to now send
    # messages from the new user.

    channels = []
    for channel in TwilioSMSChannel.objects.filter(recipient=old_user):
        channels.append(channel)

    for channel in channels:
        if TwilioSMSChannel.objects.filter(conversation=channel.conversation,
                                           sender=channel.sender,
                                           phone_number=channel.phone_number,
                                           recipient=new_user).exists():
            continue # Don't overwrite existing SMS channel.
        channel.recipient = new_user
        channel.save()

    # Finally, if the new user has a verified phone number, send a message to
    # the new user for each active conversation, telling the user that they
    # have "taken the conversation mobile."

    if new_user.verified:
        for other_user,topic in active_conversations:
            try:
                conversation = Conversation.objects.get(user_1=new_user,
                                                        user_2__id=other_user,
                                                        topic=topic)
            except Conversation.DoesNotExist:
                conversation = Conversation.objects.get(user_1__id=other_user,
                                                        user_2=new_user,
                                                        topic=topic)

            sending_phone_number = twilio_gateway.calc_sending_phone_number(
                                                    conversation, new_user)
            msg = settings.SMS_TEXT_CONVERSATION_TAKEN_MOBILE
            twilio_gateway.send_sms(sending_phone_number,
                                    new_user.phone_number, msg)
コード例 #3
0
ファイル: test_message_api.py プロジェクト: 3taps/MessageMe
    def test_stop_via_sms(self):
        """ Test the stopping of a conversation via sms message.
        """
        # Create two users, giving them a phone number so they can receive
        # messages.

        username_1 = utils.random_username()
        password_1 = utils.random_password()

        username_2 = utils.random_username()
        password_2 = utils.random_password()

        user_1 = users.create(username=username_1,
                              password=password_2,
                              phone_number=PHONE_NUMBER)

        user_2 = users.create(username=username_2,
                              password=password_2,
                              phone_number=PHONE_NUMBER_2)

        # Verify both phone numbers.

        user = User.objects.get(id=user_1['id'])
        user.verified = True
        user.save()

        user = User.objects.get(id=user_2['id'])
        user.verified = True
        user.save()

        # Log in as user 2, and create a dummy topic for this user.

        session = users.login(username=username_2,
                              password=password_2)

        topic = topics.create(session, topic_name=None)

        # Log in as user 1, and send a test message to the topic.  This
        # creates a conversation between the two users.

        session = users.login(username=username_1,
                              password=password_1)

        with self.settings(ENABLE_TWILIO=False, ENABLE_PUBNUB=False):
            message = messages.send(session, topic_id=topic['id'],
                                    message=MESSAGE_BODY)

        # Get the created conversation.

        conversation = conversationHandler.get(user_1['id'],
                                               user_2['id'],
                                               topic['id'])

        # Set up a signal listener to check that the "conversation has stopped"
        # messages were sent out.

        self.twilio_sms_messages = []

        def twilio_signal_handler(sender, **kwargs):
            self.twilio_sms_messages.append(kwargs.get("message"))

        signals.twilio_sms_sent.connect(twilio_signal_handler)

        # Ask the twilio gateway to calculate the phone number to use for
        # sending SMS messages to user 2.  This opens up an SMS channel for the
        # conversation we're pretending to have.

        sending_phone_number = \
            twilio_gateway.calc_sending_phone_number(conversation, user_2)

        # Simulate an incoming SMS reply being received from user 2, containing
        # the word "stop".  Note that we disable Twilio and PubNub so that
        # nothing will actually get sent out.

        with self.settings(ENABLE_TWILIO=False, ENABLE_PUBNUB=False):
            response = messages.receive(To=sending_phone_number,
                                        From=user_2.phone_number,
                                        Body="stop")

        # Check that the Twilio gateway sent the "conversation has been
        # stopped" message to both parties.

        self.assertEqual(len(twilio_sms_messages), 2)

        # Finally, clean everything up.

        signals.twilio_sms_sent.disconnect(twilio_signal_handler)
コード例 #4
0
ファイル: messageHandler.py プロジェクト: 3taps/MessageMe
def send_message(sender, recipient, topic, sender_name, message_text):
    """ Create and send a new message.

        The parameters are as follows:

            'sender'

                The User object for the message's sender.

            'recipient'

                The User object for the message's recipient.

            'topic'

                The Topic object that this message is about.

            'sender_name'

                The optional name for the sender of the message.

            'message_text'

                The text of the message.

        We send the given message from the given sender to the given recipient,
        about the given topic.  Note that we'll automatically create a
        conversation (and send an "intro" message") if one doesn't already
        exist.

        Upon completion, we return the newly-created Message object, or None if
        the conversation has been stopped.  If the message recipient has
        reached their rate limit, we raise a RateLimitReachedException.
    """
    logger.debug('in core.lib.messageHandler.send_mesage(' +
                 'sender=%s, recipient=%s, topic=%s, sender_name=%s, msg=%s)'
                 % (repr(sender), repr(recipient), repr(topic),
                    repr(sender_name), repr(message_text)))

    # Find the Conversation object to use for this message, creating it if
    # necessary.

    try:
        conversation = conversationHandler.get(sender.id,
                                               recipient.id,
                                               topic.id)
    except NoSuchConversationException:
        conversation = conversationHandler.start_conversation(sender.id,
                                                              recipient.id,
                                                              topic.id,
                                                              sender_name)

    # If the conversation has been stopped, don't send out the message.

    if conversation.stopped:
        return None

    # See if we can send this message via SMS.  We do this if the receipient
    # has a verified phone number.

    send_via_sms = False # initially.
    if recipient.phone_number not in ["", None] and recipient.verified:
        send_via_sms = True

    # Create the new Message object.

    message = Message()
    message.conversation = conversation
    message.sender       = sender
    message.sender_name  = sender_name
    message.body         = message_text
    message.sent_via_sms = send_via_sms
    message.created_at   = datetime.datetime.utcnow()
    message.updated_at   = datetime.datetime.utcnow()
    message.save()

    # Send the message via PubNub.

    pubnub_gateway.send_notification(message)
    pubnub_gateway.send_message_to_firehose(message)

    # Send the message via Twilio, if we can.  Note that we append the sender's
    # name (if any) to the outgoing SMS message.

    if send_via_sms:
        sending_phone_number = \
           twilio_gateway.calc_sending_phone_number(conversation, recipient)

        if sender_name not in ["", None]:
            message_text = message_text + " [" + sender_name + "]"

        twilio_gateway.send_sms(sending_phone_number, recipient.phone_number,
                                message_text)

    # Finally, return the newly-created message back to the caller.

    return message
コード例 #5
0
ファイル: test_message_api.py プロジェクト: 3taps/MessageMe
    def test_receive(self):
        """ Test messages/receive.
        """
        # Create the two users we'll need for our test.

        user_1_username = utils.random_username()
        user_1_password = utils.random_password()

        user_1_id = users.create(username=user_1_username,
                                 password=user_1_password,
                                 phone_number=PHONE_NUMBER)['id']

        user_2_id = users.create(phone_number=PHONE_NUMBER_2)['id']

        user_1 = User.objects.get(id=user_1_id)
        user_2 = User.objects.get(id=user_2_id)

        # Verify user 1's phone number, so that replies will be forwarded to
        # that number.

        user_1.verified = True
        user_1.save()

        # Log in as user 1, and create a topic for this user.  We'll need this
        # topic for our pseudo-conversation.

        session = users.login(username=user_1_username,
                              password=user_1_password)

        topic_id = topics.create(session, topic_name=None)['id']

        topic = Topic.objects.get(id=topic_id)

        # Create our pseudo-conversation.

        conversation = Conversation()
        conversation.user_1 = user_1
        conversation.user_2 = user_2
        conversation.topic  = topic
        conversation.save()

        # Ask the twilio gateway to calculate the phone number to use for
        # sending SMS messages to user 2.  This opens up an SMS channel for the
        # conversation we're pretending to have.

        sending_phone_number = \
            twilio_gateway.calc_sending_phone_number(conversation, user_2)

        # Set up a signal listener to check that the reply was forwarded via
        # Twilio.

        self.twilio_messages = []

        def twilio_signal_handler(sender, **kwargs):
            self.twilio_messages.append(kwargs.get("message"))

        signals.twilio_sms_sent.connect(twilio_signal_handler)

        # Set up a signal listener to check that the reply was forwarded via
        # PubNub.

        self.pubnub_notification_sent = False # initially.
        self.pubnub_message           = None  # ditto.

        def pubnub_signal_handler(sender, **kwargs):
            self.pubnub_notification_sent = True
            self.pubnub_message           = kwargs.get("message")

        signals.pubnub_notification_sent.connect(pubnub_signal_handler)

        # Simulate an incoming SMS reply being received from user 2.  Note that
        # we disable Twilio and PubNub so that the SMS reply isn't actually
        # sent out to the original sender.

        with self.settings(ENABLE_TWILIO=False, ENABLE_PUBNUB=False):
            response = messages.receive(To=sending_phone_number,
                                        From=user_2.phone_number,
                                        Body=REPLY_BODY)

        # Check that the response is what we expect.

        self.assertEqual(response.status_code, 201)
        self.assertEqual(response['Content-Type'], "text/xml")

        # Check that the Twilio gateway sent the message.

        if len(self.twilio_messages) == 0:
            # Whoops!  The reply wasn't forwarded, which means that something
            # went seriously wrong.  Print out the response so we can see the
            # XML message sent back to Twilio.
            print "Error response sent to Twilio:"
            print response.content
            self.fail("Reply not forwarded -> something went wrong.")

        # Check that the PubNub gateway sent the notification.

        self.assertTrue(self.pubnub_notification_sent)
        self.assertEqual(self.pubnub_message.body, REPLY_BODY)
        self.assertEqual(self.pubnub_message.conversation.topic.id, topic_id)

        # Finally, clean everything up.

        signals.twilio_sms_sent.disconnect(twilio_signal_handler)
        signals.pubnub_notification_sent.disconnect(pubnub_signal_handler)