Exemplo n.º 1
0
def send_reminder(self, reminder_id):
    """
    Retrieves the reminder from the database, passes the message content to the
    Flowroute SMS client for dispatch. If it fails, the task is re-queued.
    """
    try:
        appt = Reminder.query.filter_by(id=reminder_id).one()
    except NoResultFound:
        log.error(
            {"message": "Received unknown appointment with id {}.".format(
             reminder_id), "reminder_id": reminder_id})
        return
    msg_body = create_message_body(appt)
    message = Message(
        to=appt.contact_num,
        from_=FLOWROUTE_NUMBER,
        content=msg_body)
    try:
        sms_controller.create_message(message)
    except Exception as e:
        strerr = vars(e).get('response_body', None)
        log.critical({"message": "Raised an exception sending SMS",
                      "exc": e, "strerr": strerr, "reminder_id": reminder_id})
        raise self.retry(exc=e)
    else:
        log.info(
            {"message": "Reminder sent to {} for reminder_id {}".format(
             appt.contact_num, reminder_id),
             "reminder_id": reminder_id})
        appt.reminder_sent = True
        db_session.add(appt)
        db_session.commit()
Exemplo n.º 2
0
def test_inbound_handler_expired_appointment(mock_send_reply,
                                             appointment_details):
    contact_0 = '12223333333'
    contact_1 = '12229991111'
    appt_str_time_0 = '2000-01-01T13:00+0000'
    appt_str_time_1 = '2020-01-01T12:00+0000'
    notify_win = 24
    location = 'Flowroute HQ'
    participant_0 = 'Development Teams'
    reminder_0 = Reminder(contact_0, arrow.get(appt_str_time_0), notify_win,
                          location, participant_0)
    reminder_1 = Reminder(contact_1, arrow.get(appt_str_time_1), notify_win,
                          location, participant_0)
    db_session.add(reminder_0)
    db_session.add(reminder_1)
    db_session.commit()
    client = app.test_client()
    inbound_req = {
        'to': 'myflowroutenumber',
        'from': reminder_1.contact_num,
        'body': 'Yes'
    }
    resp = client.post('/',
                       data=json.dumps(inbound_req),
                       content_type='application/json')
    reminders = Reminder.query.all()
    assert mock_send_reply.apply_async.called is True
    assert len(reminders) == 1
    reminders[0].contact_num == contact_1
    assert resp.status_code == 200
Exemplo n.º 3
0
def test_inbound_handler_expired_appointment(mock_send_reply, appointment_details):
    contact_0 = '12223333333'
    contact_1 = '12229991111'
    appt_str_time_0 = '2000-01-01T13:00+0000'
    appt_str_time_1 = '2020-01-01T12:00+0000'
    notify_win = 24
    location = 'Flowroute HQ'
    participant_0 = 'Development Teams'
    reminder_0 = Reminder(contact_0, arrow.get(appt_str_time_0), notify_win,
                          location, participant_0)
    reminder_1 = Reminder(contact_1, arrow.get(appt_str_time_1),
                          notify_win, location, participant_0)
    db_session.add(reminder_0)
    db_session.add(reminder_1)
    db_session.commit()
    client = app.test_client()
    inbound_req = {'to': 'myflowroutenumber',
                   'from': reminder_1.contact_num,
                   'body': 'Yes'}
    resp = client.post('/', data=json.dumps(inbound_req),
                       content_type='application/json')
    reminders = Reminder.query.all()
    assert mock_send_reply.apply_async.called is True
    assert len(reminders) == 1
    reminders[0].contact_num == contact_1
    assert resp.status_code == 200
Exemplo n.º 4
0
def inbound_handler():
    """
    The inbound request handler for consuming HTTP wrapped SMS content from
    Flowroute's messaging service.

    Validates proper message content, and takes time to clear the expired
    reminders before continuing. Retrieves the reminder based on the
    sender, and marks the 'will_attend' attribute according to whether
    there is 'yes' or 'no' (case insensitive) anywhere in the message.
    Responds to the user with a confirmation message and returns 200.
    """
    req = request.json
    # Take the time to clear out any past reminders
    try:
        virtual_tn = req['to']
        assert len(virtual_tn) <= 18
        sms_from = req['from']
        assert len(sms_from) <= 18
        req['body']
    except (TypeError, KeyError, AssertionError) as e:
        msg = ("Malformed inbound message: {}".format(req))
        log.error({"message": msg, "status": "failed", "exc": str(e)})
        return Response('There was an issue parsing your request.', status=400)
    else:
        Reminder.clean_expired()
        try:
            appt = Reminder.query.filter_by(
                contact_num=sms_from).one()
        except NoResultFound:
            msg = "No existing un-responded reminder for contact {}.".format(
                sms_from)
            log.info({"message": msg})
            return Response(status=200)
        else:
            message = req['body'].upper()
            if 'YES' in message:
                appt.will_attend = True
                confirm = True
            elif 'NO' in message:
                appt.will_attend = False
                confirm = False
            else:
                confirm = None
            db_session.add(appt)
            try:
                send_reply.apply_async((appt.id,), {'confirm': confirm})
            except ConnectionError as e:
                log.critical({"message": "unable to connect to redis",
                              "exc": type(e)})
                db_session.rollback()
                return Response(status=500)
            else:
                db_session.commit()
                log.info({"message":
                          ("successfully recorded response from {}, scheduled "
                           "SMS confirmation for appointment {}").format(
                               sms_from, appt.id),
                          "reminder_id": appt.id})
                return Response(status=200)
Exemplo n.º 5
0
def setup_function(function):
    if TEST_DB in app.config['SQLALCHEMY_DATABASE_URI']:
        db_session.rollback()
        Reminder.query.delete()
        db_session.commit()
    else:
        raise AttributeError(("The production database is turned on. "
                              "Flip settings.DEBUG to True"))
Exemplo n.º 6
0
def setup_function(function):
    if TEST_DB in app.config['SQLALCHEMY_DATABASE_URI']:
        db_session.rollback()
        Reminder.query.delete()
        db_session.commit()
    else:
        raise AttributeError(("The production database is turned on. "
                              "Flip settings.DEBUG to True"))
Exemplo n.º 7
0
def test_create_message_body(new_reminder):
    new_reminder.contact_num = '122998778'
    db_session.add(new_reminder)
    db_session.commit()
    msg = create_message_body(new_reminder)
    assert msg == (u"[Your Org Name]\nYou have an appointment on"
                   u" Monday Mar 23, 1:00 pm at Central Park with NY"
                   " Running Club. Please reply 'Yes' to confirm, "
                   "or 'No' to cancel.")
Exemplo n.º 8
0
def test_create_message_body(new_reminder):
    new_reminder.contact_num = '122998778'
    db_session.add(new_reminder)
    db_session.commit()
    msg = create_message_body(new_reminder)
    assert msg == (u"[Your Org Name]\nYou have an appointment on"
                   u" Monday Mar 23, 1:00 pm at Central Park with NY"
                   " Running Club. Please reply 'Yes' to confirm, "
                   "or 'No' to cancel.")
Exemplo n.º 9
0
def test_send_reply(mock_sms_controller, num, new_reminder, confirm, content):
    new_reminder.contact_num = num
    db_session.add(new_reminder)
    db_session.commit()
    reminder_id = new_reminder.id
    send_reply(reminder_id, confirm=confirm)
    assert mock_sms_controller.create_message.called is True
    msg = mock_sms_controller.create_message.call_args[0][0].content
    assert msg == content
Exemplo n.º 10
0
def test_send_reply(mock_sms_controller, num, new_reminder, confirm, content):
    new_reminder.contact_num = num
    db_session.add(new_reminder)
    db_session.commit()
    reminder_id = new_reminder.id
    send_reply(reminder_id, confirm=confirm)
    assert mock_sms_controller.create_message.called is True
    msg = mock_sms_controller.create_message.call_args[0][0].content
    assert msg == content
Exemplo n.º 11
0
def test_get_reminder_success(new_appointment):
    reminder_id = new_appointment.id
    db_session.add(new_appointment)
    db_session.commit()
    client = app.test_client()
    resp = client.get('/reminder/{}'.format(reminder_id))
    assert resp.status_code == 200
    details = json.loads(resp.data)
    for field in REMINDER_FIELDS:
        assert field in details
Exemplo n.º 12
0
def test_get_reminder_success(new_appointment):
    reminder_id = new_appointment.id
    db_session.add(new_appointment)
    db_session.commit()
    client = app.test_client()
    resp = client.get('/reminder/{}'.format(reminder_id))
    assert resp.status_code == 200
    details = json.loads(resp.data)
    for field in REMINDER_FIELDS:
        assert field in details
Exemplo n.º 13
0
def test_delete_reminder_success(new_appointment):
    reminder_id = new_appointment.id
    db_session.add(new_appointment)
    db_session.commit()
    client = app.test_client()
    stored_reminder = Reminder.query.filter_by(id=reminder_id).one()
    assert stored_reminder is not None
    resp = client.delete('/reminder/{}'.format(reminder_id))
    assert resp.status_code == 200
    with pytest.raises(NoResultFound):
        Reminder.query.filter_by(id=reminder_id).one()
Exemplo n.º 14
0
def test_delete_reminder_success(new_appointment):
    reminder_id = new_appointment.id
    db_session.add(new_appointment)
    db_session.commit()
    client = app.test_client()
    stored_reminder = Reminder.query.filter_by(id=reminder_id).one()
    assert stored_reminder is not None
    resp = client.delete('/reminder/{}'.format(reminder_id))
    assert resp.status_code == 200
    with pytest.raises(NoResultFound):
        Reminder.query.filter_by(id=reminder_id).one()
Exemplo n.º 15
0
def test_send_reminder(mock_sms_controller, new_reminder):
    db_session.add(new_reminder)
    db_session.commit()
    reminder_id = new_reminder.id
    send_reminder(reminder_id)
    assert mock_sms_controller.create_message.called == 1
    msg = mock_sms_controller.create_message.call_args[0][0].content
    assert msg == ("[Your Org Name]\nYou have an appointment on Monday Mar 23, "
                   "1:00 pm at Central Park with NY Running Club. Please "
                   "reply 'Yes' to confirm, or 'No' to cancel.")
    reminder = Reminder.query.filter_by(id=reminder_id).one()
    assert reminder.reminder_sent is True
Exemplo n.º 16
0
def test_add_reminder_unique_constraint(mock_send_reminder, new_appointment,
                                        appointment_details):
    client = app.test_client()
    db_session.add(new_appointment)
    db_session.commit()
    dup_num = new_appointment.contact_num
    appointment_details['contact_number'] = dup_num
    resp = client.post('/reminder', data=json.dumps(appointment_details),
                       content_type='application/json')
    data = json.loads(resp.data)
    assert data['message'] == ("unable to create a new reminder. duplicate "
                               "contact_number {}".format(dup_num))
    assert resp.status_code == 400
Exemplo n.º 17
0
def test_send_reminder(mock_sms_controller, new_reminder):
    db_session.add(new_reminder)
    db_session.commit()
    reminder_id = new_reminder.id
    send_reminder(reminder_id)
    assert mock_sms_controller.create_message.called == 1
    msg = mock_sms_controller.create_message.call_args[0][0].content
    assert msg == (
        "[Your Org Name]\nYou have an appointment on Monday Mar 23, "
        "1:00 pm at Central Park with NY Running Club. Please "
        "reply 'Yes' to confirm, or 'No' to cancel.")
    reminder = Reminder.query.filter_by(id=reminder_id).one()
    assert reminder.reminder_sent is True
Exemplo n.º 18
0
def test_add_reminder_unique_constraint(mock_send_reminder, new_appointment,
                                        appointment_details):
    client = app.test_client()
    db_session.add(new_appointment)
    db_session.commit()
    dup_num = new_appointment.contact_num
    appointment_details['contact_number'] = dup_num
    resp = client.post('/reminder',
                       data=json.dumps(appointment_details),
                       content_type='application/json')
    data = json.loads(resp.data)
    assert data['message'] == ("unable to create a new reminder. duplicate "
                               "contact_number {}".format(dup_num))
    assert resp.status_code == 400
Exemplo n.º 19
0
def test_reminder_honors_uniqueness():
    contact = '12223334445'
    appt_str_time = '2016-01-01T13:00+00:00'
    appt_dt = arrow.get(appt_str_time, "YYYY-MM-DDTHH:mmZ")
    notify_win = 24
    location = 'Family Physicians'
    participant = 'Dr Smith'
    reminder0 = Reminder(contact, appt_dt, notify_win, location, participant)
    db_session.add(reminder0)
    db_session.commit()
    reminder1 = Reminder(contact, appt_dt, notify_win, location, participant)
    db_session.add(reminder1)
    with pytest.raises(IntegrityError):
        db_session.commit()
Exemplo n.º 20
0
def test_reminder_init():
    contact = '12223338888'
    appt_str_time = '2016-01-01T13:00+00:00'
    appt_dt = arrow.get(appt_str_time, "YYYY-MM-DDTHH:mmZ")
    notify_win = 24
    location = 'Family Physicians'
    participant = 'Dr Smith'
    reminder = Reminder(contact, appt_dt, notify_win, location, participant)
    db_session.add(reminder)
    db_session.commit()
    assert reminder.contact_num == contact
    assert reminder.id is not None
    assert arrow.get(reminder.appt_user_dt) == appt_dt
    assert arrow.get(reminder.appt_sys_dt) == appt_dt.to('utc')
    assert reminder.location == location
    assert reminder.participant == participant
Exemplo n.º 21
0
def test_reminder_honors_uniqueness():
    contact = '12223334445'
    appt_str_time = '2016-01-01T13:00+00:00'
    appt_dt = arrow.get(appt_str_time, "YYYY-MM-DDTHH:mmZ")
    notify_win = 24
    location = 'Family Physicians'
    participant = 'Dr Smith'
    reminder0 = Reminder(contact, appt_dt, notify_win,
                         location, participant)
    db_session.add(reminder0)
    db_session.commit()
    reminder1 = Reminder(contact, appt_dt, notify_win,
                         location, participant)
    db_session.add(reminder1)
    with pytest.raises(IntegrityError):
        db_session.commit()
Exemplo n.º 22
0
def test_inbound_handler_success(mock_send_reply, new_appointment,
                                 response, status):
    appt_id = new_appointment.id
    db_session.add(new_appointment)
    db_session.commit()
    client = app.test_client()
    inbound_req = {'to': 'myflowroutenumber',
                   'from': new_appointment.contact_num,
                   'body': response,
                   }
    resp = client.post('/', data=json.dumps(inbound_req),
                       content_type='application/json')
    assert mock_send_reply.apply_async.called == 1
    assert resp.status_code == 200
    appt = Reminder.query.filter_by(id=appt_id).one()
    assert appt.will_attend is status
Exemplo n.º 23
0
def send_reply(self, reminder_id, confirm=True):
    """
    Retrieves the reminder from the database, and sends either a confirmation
    or an unparsable message response to the Flowroute SMS client. If that fails,
    the task is re-queued.
    """
    try:
        appt = Reminder.query.filter_by(id=reminder_id).one()
    except NoResultFound:
        log.error({
            "message":
            "Received unknown appointment with id {}.".format(reminder_id),
            "reminder_id":
            reminder_id
        })
        return
    if confirm is None:
        msg_content = UNPARSABLE_RESPONSE
    elif confirm is True:
        msg_content = CONFIRMATION_RESPONSE
    elif confirm is False:
        msg_content = CANCEL_RESPONSE
    message = Message(to=appt.contact_num,
                      from_=FLOWROUTE_NUMBER,
                      content=msg_content)
    try:
        sms_controller.create_message(message)
    except Exception as e:
        strerr = vars(e).get('response_body', None)
        log.critical({
            "message": "Raised an exception sending SMS",
            "exc": e,
            "strerr": strerr,
            "reminder_id": reminder_id
        })
        raise self.retry(exc=e)
    else:
        appt.confirm_sent = True
        db_session.add(appt)
        db_session.commit()
        log.info({
            "message":
            "Confirmation sent to {} for reminder_id {}".format(
                appt.contact_num, reminder_id),
            "reminder_id":
            reminder_id
        })
Exemplo n.º 24
0
def test_reminder_init():
    contact = '12223338888'
    appt_str_time = '2016-01-01T13:00+00:00'
    appt_dt = arrow.get(appt_str_time, "YYYY-MM-DDTHH:mmZ")
    notify_win = 24
    location = 'Family Physicians'
    participant = 'Dr Smith'
    reminder = Reminder(contact, appt_dt, notify_win,
                        location, participant)
    db_session.add(reminder)
    db_session.commit()
    assert reminder.contact_num == contact
    assert reminder.id is not None
    assert arrow.get(reminder.appt_user_dt) == appt_dt
    assert arrow.get(reminder.appt_sys_dt) == appt_dt.to('utc')
    assert reminder.location == location
    assert reminder.participant == participant
Exemplo n.º 25
0
def test_inbound_handler_success(mock_send_reply, new_appointment, response,
                                 status):
    appt_id = new_appointment.id
    db_session.add(new_appointment)
    db_session.commit()
    client = app.test_client()
    inbound_req = {
        'to': 'myflowroutenumber',
        'from': new_appointment.contact_num,
        'body': response,
    }
    resp = client.post('/',
                       data=json.dumps(inbound_req),
                       content_type='application/json')
    assert mock_send_reply.apply_async.called == 1
    assert resp.status_code == 200
    appt = Reminder.query.filter_by(id=appt_id).one()
    assert appt.will_attend is status
Exemplo n.º 26
0
def new_appointments(new_appointment):
    contact_0 = '12223334444'
    appt_str_time_0 = '2016-01-01T13:00+0700'
    notify_win = 24
    location = 'Family Physicians'
    participant_0 = 'Dr Smith'
    reminder_0 = Reminder(contact_0, arrow.get(appt_str_time_0), notify_win,
                          location, participant_0)
    appt_str_time_1 = '2020-01-01T13:00+0000'
    participant_1 = 'Dr Martinez'
    contact_1 = '12223335555'
    reminder_1 = Reminder(contact_1, arrow.get(appt_str_time_1), notify_win,
                          location, participant_1)
    db_session.add(reminder_0)
    db_session.add(new_appointment)
    db_session.commit()
    db_session.add(reminder_1)
    db_session.commit()
    return [reminder_0, reminder_1, new_appointment]
Exemplo n.º 27
0
def new_appointments(new_appointment):
    contact_0 = '12223334444'
    appt_str_time_0 = '2016-01-01T13:00+0700'
    notify_win = 24
    location = 'Family Physicians'
    participant_0 = 'Dr Smith'
    reminder_0 = Reminder(contact_0, arrow.get(appt_str_time_0), notify_win,
                          location, participant_0)
    appt_str_time_1 = '2020-01-01T13:00+0000'
    participant_1 = 'Dr Martinez'
    contact_1 = '12223335555'
    reminder_1 = Reminder(contact_1, arrow.get(appt_str_time_1), notify_win,
                          location, participant_1)
    db_session.add(reminder_0)
    db_session.add(new_appointment)
    db_session.commit()
    db_session.add(reminder_1)
    db_session.commit()
    return [reminder_0, reminder_1, new_appointment]
Exemplo n.º 28
0
def remove_reminder(reminder_id):
    """
    The deletion route for Reminders - takes a reminder_id as an argument
    """
    try:
        reminder = Reminder.query.filter_by(id=reminder_id).one()
    except NoResultFound:
        log.info({"message": "no reminder with id {}".format(reminder_id)})
        return Response(
            response=json.dumps({"message": "unknown reminder id"}),
            status=404, content_type='application/json')
    else:
        db_session.delete(reminder)
        db_session.commit()
        msg = "Successfully deleted reminder with id {}.".format(reminder_id)
        log.info({"message": msg})
        return Response(
            response=json.dumps({"message": msg, "reminder_id": reminder_id}),
            status=200, content_type='application/json')
Exemplo n.º 29
0
def send_reminder(self, reminder_id):
    """
    Retrieves the reminder from the database, passes the message content to the
    Flowroute SMS client for dispatch. If it fails, the task is re-queued.
    """
    try:
        appt = Reminder.query.filter_by(id=reminder_id).one()
    except NoResultFound:
        log.error({
            "message":
            "Received unknown appointment with id {}.".format(reminder_id),
            "reminder_id":
            reminder_id
        })
        return
    msg_body = create_message_body(appt)
    message = Message(to=appt.contact_num,
                      from_=FLOWROUTE_NUMBER,
                      content=msg_body)
    try:
        sms_controller.create_message(message)
    except Exception as e:
        strerr = vars(e).get('response_body', None)
        log.critical({
            "message": "Raised an exception sending SMS",
            "exc": e,
            "strerr": strerr,
            "reminder_id": reminder_id
        })
        raise self.retry(exc=e)
    else:
        log.info({
            "message":
            "Reminder sent to {} for reminder_id {}".format(
                appt.contact_num, reminder_id),
            "reminder_id":
            reminder_id
        })
        appt.reminder_sent = True
        db_session.add(appt)
        db_session.commit()
Exemplo n.º 30
0
def send_reply(self, reminder_id, confirm=True):
    """
    Retrieves the reminder from the database, and sends either a confirmation
    or an unparsable message response to the Flowroute SMS client. If that fails,
    the task is re-queued.
    """
    try:
        appt = Reminder.query.filter_by(id=reminder_id).one()
    except NoResultFound:
        log.error(
            {"message": "Received unknown appointment with id {}.".format(
             reminder_id), "reminder_id": reminder_id})
        return
    if confirm is None:
        msg_content = UNPARSABLE_RESPONSE
    elif confirm is True:
        msg_content = CONFIRMATION_RESPONSE
    elif confirm is False:
        msg_content = CANCEL_RESPONSE
    message = Message(
        to=appt.contact_num,
        from_=FLOWROUTE_NUMBER,
        content=msg_content)
    try:
        sms_controller.create_message(message)
    except Exception as e:
        strerr = vars(e).get('response_body', None)
        log.critical({"message": "Raised an exception sending SMS",
                      "exc": e, "strerr": strerr, "reminder_id": reminder_id})
        raise self.retry(exc=e)
    else:
        appt.confirm_sent = True
        db_session.add(appt)
        db_session.commit()
        log.info(
            {"message": "Confirmation sent to {} for reminder_id {}".format(
             appt.contact_num, reminder_id),
             "reminder_id": reminder_id})
Exemplo n.º 31
0
def remove_reminder(reminder_id):
    """
    The deletion route for Reminders - takes a reminder_id as an argument
    """
    try:
        reminder = Reminder.query.filter_by(id=reminder_id).one()
    except NoResultFound:
        log.info({"message": "no reminder with id {}".format(reminder_id)})
        return Response(response=json.dumps({"message":
                                             "unknown reminder id"}),
                        status=404,
                        content_type='application/json')
    else:
        db_session.delete(reminder)
        db_session.commit()
        msg = "Successfully deleted reminder with id {}.".format(reminder_id)
        log.info({"message": msg})
        return Response(response=json.dumps({
            "message": msg,
            "reminder_id": reminder_id
        }),
                        status=200,
                        content_type='application/json')
Exemplo n.º 32
0
def test_clean_expired():
    contact_0 = '12223334444'
    appt_str_time_0 = '2016-01-01T13:00+00:00'
    notify_win = 24
    location = 'Family Physicians'
    participant_0 = 'Dr Smith'
    appt_dt_0 = arrow.get(appt_str_time_0, "YYYY-MM-DDTHH:mmZ")
    reminder_0 = Reminder(contact_0, appt_dt_0, notify_win, location,
                          participant_0)
    appt_str_time_1 = '2020-01-01T13:00+00:00'
    appt_dt_1 = arrow.get(appt_str_time_1, "YYYY-MM-DDTHH:mmZ")
    participant_1 = 'Dr John'
    contact_1 = '12223339999'
    reminder_1 = Reminder(contact_1, appt_dt_1, notify_win, location,
                          participant_1)
    db_session.add(reminder_0)
    db_session.add(reminder_1)
    db_session.commit()
    stored_reminders = Reminder.query.all()
    assert len(stored_reminders) == 2
    Reminder.clean_expired()
    stored_reminders = Reminder.query.all()
    assert len(stored_reminders) == 1
    assert stored_reminders[0].participant == participant_1
Exemplo n.º 33
0
def test_clean_expired():
    contact_0 = '12223334444'
    appt_str_time_0 = '2016-01-01T13:00+00:00'
    notify_win = 24
    location = 'Family Physicians'
    participant_0 = 'Dr Smith'
    appt_dt_0 = arrow.get(appt_str_time_0, "YYYY-MM-DDTHH:mmZ")
    reminder_0 = Reminder(contact_0, appt_dt_0, notify_win,
                          location, participant_0)
    appt_str_time_1 = '2020-01-01T13:00+00:00'
    appt_dt_1 = arrow.get(appt_str_time_1, "YYYY-MM-DDTHH:mmZ")
    participant_1 = 'Dr John'
    contact_1 = '12223339999'
    reminder_1 = Reminder(contact_1, appt_dt_1, notify_win,
                          location, participant_1)
    db_session.add(reminder_0)
    db_session.add(reminder_1)
    db_session.commit()
    stored_reminders = Reminder.query.all()
    assert len(stored_reminders) == 2
    Reminder.clean_expired()
    stored_reminders = Reminder.query.all()
    assert len(stored_reminders) == 1
    assert stored_reminders[0].participant == participant_1
Exemplo n.º 34
0
def test_get_locale_aware_dt_string(new_reminder, lang, expected, num):
    new_reminder.contact_num = num
    db_session.add(new_reminder)
    db_session.commit()
    msg = get_locale_aware_dt_str(new_reminder.appt_user_dt, language=lang)
    assert msg == expected
Exemplo n.º 35
0
def inbound_handler():
    """
    The inbound request handler for consuming HTTP wrapped SMS content from
    Flowroute's messaging service.

    Validates proper message content, and takes time to clear the expired
    reminders before continuing. Retrieves the reminder based on the
    sender, and marks the 'will_attend' attribute according to whether
    there is 'yes' or 'no' (case insensitive) anywhere in the message.
    Responds to the user with a confirmation message and returns 200.
    """
    req = request.json
    # Take the time to clear out any past reminders
    try:
        virtual_tn = req['to']
        assert len(virtual_tn) <= 18
        sms_from = req['from']
        assert len(sms_from) <= 18
        req['body']
    except (TypeError, KeyError, AssertionError) as e:
        msg = ("Malformed inbound message: {}".format(req))
        log.error({"message": msg, "status": "failed", "exc": str(e)})
        return Response('There was an issue parsing your request.', status=400)
    else:
        Reminder.clean_expired()
        try:
            appt = Reminder.query.filter_by(contact_num=sms_from).one()
        except NoResultFound:
            msg = "No existing un-responded reminder for contact {}.".format(
                sms_from)
            log.info({"message": msg})
            return Response(status=200)
        else:
            message = req['body'].upper()
            if 'YES' in message:
                appt.will_attend = True
                confirm = True
            elif 'NO' in message:
                appt.will_attend = False
                confirm = False
            else:
                confirm = None
            db_session.add(appt)
            try:
                send_reply.apply_async((appt.id, ), {'confirm': confirm})
            except ConnectionError as e:
                log.critical({
                    "message": "unable to connect to redis",
                    "exc": type(e)
                })
                db_session.rollback()
                return Response(status=500)
            else:
                db_session.commit()
                log.info({
                    "message":
                    ("successfully recorded response from {}, scheduled "
                     "SMS confirmation for appointment {}").format(
                         sms_from, appt.id),
                    "reminder_id":
                    appt.id
                })
                return Response(status=200)
Exemplo n.º 36
0
def test_get_locale_aware_dt_string(new_reminder, lang, expected, num):
    new_reminder.contact_num = num
    db_session.add(new_reminder)
    db_session.commit()
    msg = get_locale_aware_dt_str(new_reminder.appt_user_dt, language=lang)
    assert msg == expected
Exemplo n.º 37
0
def add_reminder():
    """
    Adds a new reminder, and schedules an sms message handling celery task.
    If the redis is unavailable and unable to schedule a task the reminder
    is removed and an internal error is raised, otherwise the new reminder
    id is returned.

    Required:
    contact_number : string (The users phone number)
    appointment_time : string (The datetime of the appointment) "YYYY-MM-DDTHH:mmZ"
    notify_window : integer (The hours before the appointment to send reminder)

    Optional:
    location : string (Where the appointment is)
    participant : string (Who the appoinment is with)
    """
    body = request.json
    try:
        contact_num = str(body['contact_number'])
        appt_dt = arrow.get(body['appointment_time'], "YYYY-MM-DDTHH:mmZ")
        notify_win = int(body['notify_window'])
        location = body.get('location', None)
        participant = body.get('participant', None)
    except (KeyError, ParserError):
        raise InvalidAPIUsage(
            ("Required arguments: 'contact_number' (str), "
             "'appointment_time' (str) eg. '2016-01-01T13:00+02:00', "
             "'notify_window' (int)"))
    else:
        Reminder.clean_expired()
        reminder = Reminder(contact_num, appt_dt, notify_win,
                            location, participant)
        db_session.add(reminder)
    try:
        db_session.commit()
    except IntegrityError:
        msg = ("Unable to create a new reminder. Duplicate "
               "contact_number {}.".format(contact_num))
        log.error({"message": msg})
        return Response(json.dumps({"message": msg}), status=400,
                        content_type="application/json")
    else:
        try:
            send_reminder.apply_async(args=[reminder.id],
                                      eta=reminder.notify_sys_dt)
        except ConnectionError as e:
            log.critical({"message": "unable to connect to redis",
                          "exc": type(e)})
            db_session.delete(reminder)
            db_session.commit()
            return Response(json.dumps(
                {"message": ("Unable to create a new reminder."
                             " Redis is unreachable."),
                 "exc": "RedisConnectionError"}),
                status=500, content_type="application/json")

        msg = "Successfully created a reminder with id {}.".format(reminder.id)
        log.info({"message": msg})
        content = json.dumps({"message": msg, "reminder_id": reminder.id})
        return Response(content, status=200,
                        content_type="application/json")
Exemplo n.º 38
0
def add_reminder():
    """
    Adds a new reminder, and schedules an sms message handling celery task.
    If the redis is unavailable and unable to schedule a task the reminder
    is removed and an internal error is raised, otherwise the new reminder
    id is returned.

    Required:
    contact_number : string (The users phone number)
    appointment_time : string (The datetime of the appointment) "YYYY-MM-DDTHH:mmZ"
    notify_window : integer (The hours before the appointment to send reminder)

    Optional:
    location : string (Where the appointment is)
    participant : string (Who the appoinment is with)
    """
    body = request.json
    try:
        contact_num = str(body['contact_number'])
        appt_dt = arrow.get(body['appointment_time'], "YYYY-MM-DDTHH:mmZ")
        notify_win = int(body['notify_window'])
        location = body.get('location', None)
        participant = body.get('participant', None)
    except (KeyError, ParserError):
        raise InvalidAPIUsage(
            ("Required arguments: 'contact_number' (str), "
             "'appointment_time' (str) eg. '2016-01-01T13:00+02:00', "
             "'notify_window' (int)"))
    else:
        Reminder.clean_expired()
        reminder = Reminder(contact_num, appt_dt, notify_win, location,
                            participant)
        db_session.add(reminder)
    try:
        db_session.commit()
    except IntegrityError:
        msg = ("Unable to create a new reminder. Duplicate "
               "contact_number {}.".format(contact_num))
        log.error({"message": msg})
        return Response(json.dumps({"message": msg}),
                        status=400,
                        content_type="application/json")
    else:
        try:
            send_reminder.apply_async(args=[reminder.id],
                                      eta=reminder.notify_sys_dt)
        except ConnectionError as e:
            log.critical({
                "message": "unable to connect to redis",
                "exc": type(e)
            })
            db_session.delete(reminder)
            db_session.commit()
            return Response(json.dumps({
                "message": ("Unable to create a new reminder."
                            " Redis is unreachable."),
                "exc":
                "RedisConnectionError"
            }),
                            status=500,
                            content_type="application/json")

        msg = "Successfully created a reminder with id {}.".format(reminder.id)
        log.info({"message": msg})
        content = json.dumps({"message": msg, "reminder_id": reminder.id})
        return Response(content, status=200, content_type="application/json")