Esempio n. 1
0
def test_handle_message_no_organizers(send_sms, database):
    create_event()

    with pytest.raises(smschat.NoOrganizersAvailable):
        smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello")

    send_sms.assert_not_called()
Esempio n. 2
0
def test_handle_message_no_organizers(send_sms, database):
    create_event()

    with pytest.raises(smschat.NoOrganizersAvailable):
        smschat.handle_message("1234", "5678", "Hello")

    send_sms.assert_not_called()
Esempio n. 3
0
def test_handle_message_reply(send_sms, database):
    event = create_event()
    create_organizers(event)
    create_relays()

    # Send initial message to establish the chat.
    smschat.handle_message("1234", "5678", "Hello")

    # Reset the mock for send_sms
    send_sms.reset_mock()

    # Send a reply from one of the organizers.
    smschat.handle_message("101", "1111", "Goodbye")

    # Two messages should have been sent. One to the reporter, and one to the
    # other verified member.
    # The sender should be the hotline number for the reporter and the *first*
    # relay number (1111) for the member.
    assert send_sms.call_count == 2
    send_sms.assert_has_calls(
        [
            mock.call(sender="5678", to="1234", message="Bob: Goodbye"),
            mock.call(sender="1111", to="202", message="Bob: Goodbye"),
        ]
    )
Esempio n. 4
0
def test_organizer_in_two_events(send_sms, database):
    """Tests the case where an organizer is in two different events.

    This causes issues with a naive relay assignment algorithm that will try to
    assign a relay used in event one for event two, leading to a database error.
    The second event should get a unique relay number, and having an organizer in both
    effectively reduces the available number of relays.
    """
    event_one = create_event()
    event_two = create_event(name=EVENT_NAME_2, number=EVENT_NUMBER_2)
    create_organizers(event_one)
    create_organizers(event_two)
    create_relays()

    smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello")

    senders = set([call[2]["sender"] for call in send_sms.mock_calls])
    assert senders == set([EVENT_NUMBER, RELAY_NUMBER])

    # This should still work and should assign a different relay than the one above.
    smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER_2, "Hello")

    senders = set([call[2]["sender"] for call in send_sms.mock_calls])
    assert senders == set(
        [EVENT_NUMBER, EVENT_NUMBER_2, RELAY_NUMBER, RELAY_NUMBER_2])
Esempio n. 5
0
def test_handle_message_reply(send_sms, database):
    event = create_event()
    create_organizers(event)
    create_relays()
    create_chatroom(send_sms)

    # Send a reply from one of the organizers.
    smschat.handle_message(BOB_ORGANIZER_NUMBER, RELAY_NUMBER, "Goodbye")

    # Two messages should have been sent. One to the reporter, and one to the
    # other verified member.
    # The sender should be the hotline number for the reporter and the *first*
    # relay number (1111) for the member.
    assert send_sms.call_count == 2
    send_sms.assert_has_calls([
        mock.call(
            sender=EVENT_NUMBER,
            to=REPORTER_NUMBER,
            message=f"{BOB_ORGANIZER_NAME}: Goodbye",
        ),
        mock.call(
            sender=RELAY_NUMBER,
            to=ALICE_ORGANIZER_NUMBER,
            message=f"{BOB_ORGANIZER_NAME}: Goodbye",
        ),
    ])
Esempio n. 6
0
def create_chatroom(send_sms, number=EVENT_NUMBER):
    # Send initial message to establish the chat.
    smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello")

    # Reset the mock for send_sms, because it's called
    # indirectly while creating the chatroom
    send_sms.reset_mock()
Esempio n. 7
0
def test_handle_message_new_chat(send_sms, database):
    event = create_event()
    create_organizers(event)
    create_relays()

    smschat.handle_message("1234", "5678", "Hello")

    # A total of 5 messages:
    # The first should acknolwege the reporter.
    # The next two should have been sent to the two verified organizers to
    # introduce the chat.
    # The last two should relay the reporter's message.
    assert send_sms.call_count == 5
    send_sms.assert_has_calls(
        [
            mock.call(
                sender="5678",
                to="1234",
                message="You have started a new chat with the organizers of Test event.",
            ),
            # The sender should be the *first available* relay number (1111)
            mock.call(
                sender="1111",
                to="101",
                message="This is the beginning of a new chat for Test event, the last 4 digits of the reporters number are 1234.",
            ),
            mock.call(
                sender="1111",
                to="202",
                message="This is the beginning of a new chat for Test event, the last 4 digits of the reporters number are 1234.",
            ),
            mock.call(sender="1111", to="101", message="Reporter: Hello"),
            mock.call(sender="1111", to="202", message="Reporter: Hello"),
        ]
    )

    # The database should have an entry for this chat.
    assert db.Chatroom.select().count() == 1

    # And three entries for the connections, as there are three people in the
    # chat.
    room = db.Chatroom.get()
    connections = (
        db.ChatroomConnection.select()
        .where(db.ChatroomConnection.chatroom == room)
        .order_by(db.ChatroomConnection.user_number)
    )
    assert len(connections) == 3
    assert connections[0].user_name == "Bob"
    assert connections[0].user_number == "101"
    assert connections[0].relay_number == "1111"
    assert connections[1].user_name == "Reporter"
    assert connections[1].user_number == "1234"
    assert connections[1].relay_number == "5678"
    assert connections[2].user_name == "Alice"
    assert connections[2].user_number == "202"
    assert connections[2].relay_number == "1111"
Esempio n. 8
0
def test_handle_new_chat_after_stop_reply(send_sms, database):
    event = create_event()
    create_organizers(event)
    create_relays()
    create_chatroom(send_sms)

    # Verify a room currently exists for the reporter.
    initial_chat = highlevel.find_smschat_by_user_and_relay_numbers(
        REPORTER_NUMBER, EVENT_NUMBER)
    assert initial_chat

    # Verify the room no longer exists after reporter opts-out by texting stop.
    smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "STOP")
    assert not highlevel.find_smschat_by_user_and_relay_numbers(
        REPORTER_NUMBER, EVENT_NUMBER)

    # Send a new message from the reporter to re-establish the chat.
    create_chatroom(send_sms)

    # Verify a new room is recreated for the reporter under a new relay number.
    new_chat = highlevel.find_smschat_by_user_and_relay_numbers(
        REPORTER_NUMBER, EVENT_NUMBER)
    assert new_chat
    assert new_chat.id != initial_chat.id
    assert new_chat.relay_number != initial_chat.relay_number

    # Opt-out again, verify the room no longer exists.
    smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "STOP")
    assert not highlevel.find_smschat_by_user_and_relay_numbers(
        REPORTER_NUMBER, EVENT_NUMBER)

    # Verify the new relay number was used for the messages.
    assert send_sms.call_count == 3
    send_sms.assert_has_calls([
        mock.call(
            sender=new_chat.relay_number,
            to=BOB_ORGANIZER_NUMBER,
            message=
            f"{REPORTER_NAME}: This participant has chosen to leave the chat.",
        ),
        mock.call(
            sender=new_chat.relay_number,
            to=ALICE_ORGANIZER_NUMBER,
            message=
            f"{REPORTER_NAME}: This participant has chosen to leave the chat.",
        ),
        mock.call(
            sender=EVENT_NUMBER,
            to=REPORTER_NUMBER,
            message=
            "You've been successfully unsubscribed, you'll no longer receive messages from this number.",
        ),
    ])
Esempio n. 9
0
def inbound_sms():
    message = flask.request.get_json()
    user_number = lowlevel.normalize_e164_number(message["msisdn"])
    relay_number = lowlevel.normalize_e164_number(message["to"])
    message_text = message["text"]

    # Maybe handle verification, if this is a response to a verification message.
    if verification.maybe_handle_verification(user_number, message_text):
        return "", 204

    # It's not verification, so hand it off to SMS chat
    try:
        smschat.handle_message(user_number, relay_number, message_text)
    except smschat.SmsChatError as err:
        smschat.handle_sms_chat_error(err, user_number, relay_number)

    return "", 204
Esempio n. 10
0
def test_handle_message_no_event(send_sms, database):

    with pytest.raises(smschat.EventDoesNotExist):
        smschat.handle_message("1234", "5678", "Hello")

    send_sms.assert_not_called()
Esempio n. 11
0
def test_handle_message_no_event(send_sms, database):

    with pytest.raises(smschat.EventDoesNotExist):
        smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello")

    send_sms.assert_not_called()
Esempio n. 12
0
def test_handle_stop_reply(send_sms, database):
    event = create_event()
    create_organizers(event)
    create_relays()
    create_chatroom(send_sms)

    # Verify a room currently exists for the reporter, and is deleted after the
    # reporter opts-out by texting stop.
    assert highlevel.find_smschat_by_user_and_relay_numbers(
        REPORTER_NUMBER, EVENT_NUMBER)
    smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "STOP")
    assert not highlevel.find_smschat_by_user_and_relay_numbers(
        REPORTER_NUMBER, EVENT_NUMBER)

    # Three messages should have been sent. One for each of the two organizers,
    # notifying them that the reporter has left the chat, and one to the reporter,
    # to acknowledge that they opted out.
    assert send_sms.call_count == 3
    send_sms.assert_has_calls([
        mock.call(
            sender=RELAY_NUMBER,
            to=BOB_ORGANIZER_NUMBER,
            message=
            f"{REPORTER_NAME}: This participant has chosen to leave the chat.",
        ),
        mock.call(
            sender=RELAY_NUMBER,
            to=ALICE_ORGANIZER_NUMBER,
            message=
            f"{REPORTER_NAME}: This participant has chosen to leave the chat.",
        ),
        mock.call(
            sender=EVENT_NUMBER,
            to=REPORTER_NUMBER,
            message=
            "You've been successfully unsubscribed, you'll no longer receive messages from this number.",
        ),
    ])

    # Reset the mock.
    send_sms.reset_mock()

    # Verify a room currently exists for this responder, and is deleted after the
    # responder opts-out by texting stop.
    assert highlevel.find_smschat_by_user_and_relay_numbers(
        BOB_ORGANIZER_NUMBER, RELAY_NUMBER)
    smschat.handle_message(BOB_ORGANIZER_NUMBER, RELAY_NUMBER, "Stop")
    assert not highlevel.find_smschat_by_user_and_relay_numbers(
        BOB_ORGANIZER_NUMBER, RELAY_NUMBER)

    # Two messages should have been sent. One to the remaining organizer,
    # notifying them that the Bob has left the chat, and one to Bob,
    # to acknowledge that they opted out.
    assert send_sms.call_count == 2
    send_sms.assert_has_calls([
        mock.call(
            sender=RELAY_NUMBER,
            to=ALICE_ORGANIZER_NUMBER,
            message=
            f"{BOB_ORGANIZER_NAME}: This participant has chosen to leave the chat.",
        ),
        mock.call(
            sender=RELAY_NUMBER,
            to=BOB_ORGANIZER_NUMBER,
            message=
            "You've been successfully unsubscribed, you'll no longer receive messages from this number.",
        ),
    ])
Esempio n. 13
0
def test_handle_message_new_chat(send_sms, database):
    event = create_event()
    create_organizers(event)
    create_relays()

    smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello")

    # A total of 5 messages:
    # The first should acknowledge the reporter.
    # The next two should have been sent to the two verified organizers to
    # introduce the chat.
    # The last two should relay the reporter's message.
    assert send_sms.call_count == 6
    send_sms.assert_has_calls([
        mock.call(
            sender=EVENT_NUMBER,
            to=REPORTER_NUMBER,
            message=
            f"You have started a new chat with the organizers of {EVENT_NAME}.",
        ),
        # The reporter should get a notice about how to opt out.
        mock.call(
            sender=EVENT_NUMBER,
            to=REPORTER_NUMBER,
            message=
            "Reply STOP at any time to opt-out of receiving messages from this conversation.",
        ),
        # The sender should be the *first available* relay number (1111)
        mock.call(
            sender=RELAY_NUMBER,
            to=BOB_ORGANIZER_NUMBER,
            message=
            f"This is the beginning of a new chat for {EVENT_NAME}, the last 4 digits of the reporter's number are {REPORTER_NUMBER}. "
            "Reply STOP at any time to opt-out of receiving messages from this conversation.",
        ),
        mock.call(
            sender=RELAY_NUMBER,
            to=ALICE_ORGANIZER_NUMBER,
            message=
            f"This is the beginning of a new chat for {EVENT_NAME}, the last 4 digits of the reporter's number are {REPORTER_NUMBER}. "
            "Reply STOP at any time to opt-out of receiving messages from this conversation.",
        ),
        mock.call(
            sender=RELAY_NUMBER,
            to=BOB_ORGANIZER_NUMBER,
            message=f"{REPORTER_NAME}: Hello",
        ),
        mock.call(
            sender=RELAY_NUMBER,
            to=ALICE_ORGANIZER_NUMBER,
            message=f"{REPORTER_NAME}: Hello",
        ),
    ])

    # The database should have an entry for this chat.
    assert db.SmsChat.select().count() == 1

    # And three entries for the connections, as there are three people in the
    # chat.
    room = db.SmsChat.get()
    connections = (db.SmsChatConnection.select().where(
        db.SmsChatConnection.smschat == room).order_by(
            db.SmsChatConnection.user_number))
    assert len(connections) == 3
    assert connections[0].user_name == BOB_ORGANIZER_NAME
    assert connections[0].user_number == BOB_ORGANIZER_NUMBER
    assert connections[0].relay_number == RELAY_NUMBER
    assert connections[1].user_name == REPORTER_NAME
    assert connections[1].user_number == REPORTER_NUMBER
    assert connections[1].relay_number == EVENT_NUMBER
    assert connections[2].user_name == ALICE_ORGANIZER_NAME
    assert connections[2].user_number == ALICE_ORGANIZER_NUMBER
    assert connections[2].relay_number == RELAY_NUMBER