def test_check_service_message_limit_in_cache_over_message_limit_fails(
        notify_db_session, key_type, mocker):
    with freeze_time("2016-01-01 12:00:00.000000"):
        mocker.patch('app.redis_store.get', return_value=5)
        mocker.patch('app.notifications.validators.redis_store.set')
        mocker.patch('app.notifications.validators.services_dao')

        service = create_service(restricted=True, message_limit=4)
        with pytest.raises(TooManyRequestsError) as e:
            check_service_over_daily_message_limit(key_type, service)
        assert e.value.status_code == 429
        assert e.value.message == 'Exceeded send limits (4) for today'
        assert e.value.fields == []
        app.notifications.validators.redis_store.set.assert_not_called()
        assert not app.notifications.validators.services_dao.mock_calls
Example #2
0
def test_check_service_message_limit_skip_statsd_over_message_no_limit_fails(
        app_statsd, notify_db, notify_db_session, mocker):
    # Given
    mocker.patch('app.redis_store.get', return_value=0)
    mocker.patch('app.notifications.validators.redis_store.set')

    # When
    service = create_service(notify_db,
                             notify_db_session,
                             restricted=True,
                             limit=4)
    check_service_over_daily_message_limit("normal", service)

    # Then
    app_statsd.statsd_client.incr.assert_not_called()
Example #3
0
def test_should_set_cache_value_as_value_from_database_if_cache_not_set(
        key_type,
        notify_db,
        notify_db_session,
        sample_service,
        mocker
):
    with freeze_time("2016-01-01 12:00:00.000000"):
        for x in range(5):
            create_notification(notify_db, notify_db_session, service=sample_service)
        mocker.patch('app.notifications.validators.redis_store.get', return_value=None)
        mocker.patch('app.notifications.validators.redis_store.set')
        check_service_over_daily_message_limit(key_type, sample_service)
        app.notifications.validators.redis_store.set.assert_called_with(
            str(sample_service.id) + "-2016-01-01-count", 5, ex=3600
        )
Example #4
0
def test_check_service_message_limit_over_message_limit_fails(key_type, notify_db, notify_db_session, mocker):
    with freeze_time("2016-01-01 12:00:00.000000"):
        mocker.patch('app.redis_store.get', return_value=None)
        mocker.patch('app.notifications.validators.redis_store.set')

        service = create_service(notify_db, notify_db_session, restricted=True, limit=4)
        for x in range(5):
            create_notification(notify_db, notify_db_session, service=service)
        with pytest.raises(TooManyRequestsError) as e:
            check_service_over_daily_message_limit(key_type, service)
        assert e.value.status_code == 429
        assert e.value.message == 'Exceeded send limits (4) for today'
        assert e.value.fields == []
        app.notifications.validators.redis_store.set.assert_called_with(
            str(service.id) + "-2016-01-01-count", 5, ex=3600
        )
Example #5
0
def test_check_service_message_limit_sends_statsd_over_message_limit_fails(
        app_statsd, notify_db, notify_db_session, mocker):
    # Given
    mocker.patch('app.redis_store.get', return_value=5)
    mocker.patch('app.notifications.validators.redis_store.set')

    # When
    service = create_service(notify_db,
                             notify_db_session,
                             restricted=True,
                             limit=4)
    with pytest.raises(TooManyRequestsError):
        check_service_over_daily_message_limit("normal", service)

    # Then
    app_statsd.statsd_client.incr.assert_called_once_with(
        "validators.rate_limit.service_daily")
Example #6
0
def test_should_set_cache_value_as_value_from_database_if_cache_not_set(
        key_type,
        sample_template,
        sample_service,
        mocker
):
    with freeze_time("2016-01-01 12:00:00.000000"):
        current_app.config['API_MESSAGE_LIMIT_ENABLED'] = True

        for x in range(5):
            create_notification(sample_template)
        mocker.patch('app.notifications.validators.redis_store.get', return_value=None)
        mocker.patch('app.notifications.validators.redis_store.set')
        check_service_over_daily_message_limit(key_type, sample_service)
        app.notifications.validators.redis_store.set.assert_called_with(
            str(sample_service.id) + "-2016-01-01-count", 5, ex=3600
        )
def test_check_service_message_limit_in_cache_under_message_limit_passes(
        key_type,
        sample_service,
        mocker):
    mocker.patch('app.notifications.validators.redis_store.get', side_effect=[
        None,  # The serialised service
        1,  # The rolling count
    ])
    mocker.patch('app.notifications.validators.redis_store.set')
    mocker.patch('app.notifications.validators.services_dao')
    serialised_service = SerialisedService.from_id(sample_service.id)
    check_service_over_daily_message_limit(key_type, serialised_service)
    app.notifications.validators.redis_store.set.assert_called_once_with(
        f'service-{serialised_service.id}',
        ANY,
        ex=ANY,
    )
    assert not app.notifications.validators.services_dao.mock_calls
def test_check_service_message_limit_sends_statsd_over_message_limit_fails(
    app_statsd,
    notify_db,
    notify_db_session,
    mocker,
    is_trial_service,
    expected_counter,
):
    mocker.patch("app.redis_store.get", return_value=5)
    mocker.patch("app.notifications.validators.redis_store.set")

    service = create_service(notify_db,
                             notify_db_session,
                             restricted=is_trial_service,
                             limit=4)
    with pytest.raises(TooManyRequestsError):
        check_service_over_daily_message_limit("normal", service)

    app_statsd.statsd_client.incr.assert_called_once_with(expected_counter)
def test_check_service_message_limit_over_message_limit_fails(
        key_type, notify_db, notify_db_session, mocker):
    with freeze_time("2016-01-01 12:00:00.000000"):
        redis_get = mocker.patch("app.redis_store.get",
                                 side_effect=["5", True, None])
        redis_set = mocker.patch("app.redis_store.set")
        send_notification = mocker.patch(
            "app.notifications.validators.send_notification_to_service_users")

        service = create_service(notify_db,
                                 notify_db_session,
                                 restricted=True,
                                 limit=4)
        for x in range(5):
            create_notification(notify_db, notify_db_session, service=service)
        with pytest.raises(TooManyRequestsError) as e:
            check_service_over_daily_message_limit(key_type, service)
        assert e.value.status_code == 429
        assert e.value.message == "Exceeded send limits (4) for today"
        assert e.value.fields == []
        assert redis_get.call_args_list == [
            call(f"{service.id}-2016-01-01-count"),
            call(f"nearing-{service.id}-2016-01-01-count"),
            call(f"over-{service.id}-2016-01-01-count"),
        ]
        assert redis_set.call_args_list == [
            call(f"over-{service.id}-2016-01-01-count",
                 "2016-01-01T12:00:00",
                 ex=86400)
        ]
        send_notification.assert_called_once_with(
            service_id=service.id,
            template_id=current_app.config["REACHED_DAILY_LIMIT_TEMPLATE_ID"],
            personalisation={
                "service_name": service.name,
                "contact_url":
                f"{current_app.config['ADMIN_BASE_URL']}/contact",
                "message_limit_en": "4",
                "message_limit_fr": "4",
            },
            include_user_fields=["name"],
        )
Example #10
0
def test_check_service_message_limit_over_message_limit_fails(key_type, sample_service, mocker):
    with freeze_time("2016-01-01 12:00:00.000000"):
        current_app.config['API_MESSAGE_LIMIT_ENABLED'] = True

        mocker.patch('app.redis_store.get', return_value=None)
        mocker.patch('app.notifications.validators.redis_store.set')

        sample_service.restricted = True
        sample_service.message_limit = 4
        template = create_template(sample_service)

        for x in range(5):
            create_notification(template)
        with pytest.raises(TooManyRequestsError) as e:
            check_service_over_daily_message_limit(key_type, sample_service)
        assert e.value.status_code == 429
        assert e.value.message == 'Exceeded send limits (4) for today'
        assert e.value.fields == []
        app.notifications.validators.redis_store.set.assert_called_with(
            str(sample_service.id) + "-2016-01-01-count", 5, ex=3600
        )
def test_check_service_message_limit_records_nearing_daily_limit(
        notify_db, notify_db_session, mocker):
    with freeze_time("2016-01-01 12:00:00.000000"):
        redis_get = mocker.patch("app.redis_store.get", side_effect=[4, None])
        redis_set = mocker.patch("app.redis_store.set")
        send_notification = mocker.patch(
            "app.notifications.validators.send_notification_to_service_users")

        service = create_service(notify_db,
                                 notify_db_session,
                                 restricted=True,
                                 limit=5)
        for x in range(4):
            create_notification(notify_db, notify_db_session, service=service)

        check_service_over_daily_message_limit("normal", service)

        assert redis_get.call_args_list == [
            call(f"{service.id}-2016-01-01-count"),
            call(f"nearing-{service.id}-2016-01-01-count"),
        ]
        assert redis_set.call_args_list == [
            call(
                f"nearing-{service.id}-2016-01-01-count",
                "2016-01-01T12:00:00",
                ex=86400,
            ),
        ]
        send_notification.assert_called_once_with(
            service_id=service.id,
            template_id=current_app.config["NEAR_DAILY_LIMIT_TEMPLATE_ID"],
            personalisation={
                "service_name": service.name,
                "contact_url":
                f"{current_app.config['ADMIN_BASE_URL']}/contact",
                "message_limit_en": "5",
                "message_limit_fr": "5",
            },
            include_user_fields=["name"],
        )
def send_one_off_notification(service_id, post_data):
    service = dao_fetch_service_by_id(service_id)
    template = dao_get_template_by_id_and_service_id(
        template_id=post_data['template_id'], service_id=service_id)

    personalisation = post_data.get('personalisation', None)

    validate_template(template.id, personalisation, service,
                      template.template_type)

    check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service)

    validate_and_format_recipient(
        send_to=post_data['to'],
        key_type=KEY_TYPE_NORMAL,
        service=service,
        notification_type=template.template_type,
        allow_guest_list_recipients=False,
    )
    postage = None
    if template.template_type == LETTER_TYPE:
        # Validate address and set postage to europe|rest-of-world if international letter,
        # otherwise persist_notification with use template postage
        postage = validate_address(service, personalisation)
        if not postage:
            postage = template.postage
    validate_created_by(service, post_data['created_by'])

    sender_id = post_data.get('sender_id', None)
    reply_to = get_reply_to_text(notification_type=template.template_type,
                                 sender_id=sender_id,
                                 service=service,
                                 template=template)
    notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=post_data['to'],
        service=service,
        personalisation=personalisation,
        notification_type=template.template_type,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        created_by_id=post_data['created_by'],
        reply_to_text=reply_to,
        reference=create_one_off_reference(template.template_type),
        postage=postage)

    queue_name = QueueNames.PRIORITY if template.process_type == PRIORITY else None

    if template.template_type == LETTER_TYPE and service.research_mode:
        _update_notification_status(
            notification,
            NOTIFICATION_DELIVERED,
        )
    else:
        send_notification_to_queue(
            notification=notification,
            research_mode=service.research_mode,
            queue=queue_name,
        )

    return {'id': str(notification.id)}
def send_pdf_letter_notification(service_id, post_data):
    service = dao_fetch_service_by_id(service_id)

    check_service_has_permission(LETTER_TYPE,
                                 [p.permission for p in service.permissions])
    check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service)
    validate_created_by(service, post_data['created_by'])
    validate_and_format_recipient(
        send_to=post_data['recipient_address'],
        key_type=KEY_TYPE_NORMAL,
        service=service,
        notification_type=LETTER_TYPE,
        allow_guest_list_recipients=False,
    )

    template = get_precompiled_letter_template(service.id)
    file_location = 'service-{}/{}.pdf'.format(service.id,
                                               post_data['file_id'])

    try:
        letter = utils_s3download(
            current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location)
    except S3ObjectNotFound as e:
        current_app.logger.exception(
            'Letter {}.pdf not in transient {} bucket'.format(
                post_data['file_id'],
                current_app.config['TRANSIENT_UPLOADED_LETTERS']))
        raise e

    # Getting the page count won't raise an error since admin has already checked the PDF is valid
    page_count = get_page_count(letter.read())
    billable_units = get_billable_units_for_letter_page_count(page_count)

    personalisation = {'address_line_1': post_data['filename']}

    notification = persist_notification(
        notification_id=post_data['file_id'],
        template_id=template.id,
        template_version=template.version,
        recipient=urllib.parse.unquote(post_data['recipient_address']),
        service=service,
        personalisation=personalisation,
        notification_type=LETTER_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        reference=create_one_off_reference(LETTER_TYPE),
        client_reference=post_data['filename'],
        created_by_id=post_data['created_by'],
        billable_units=billable_units,
        postage=post_data['postage'] or template.postage,
    )

    upload_filename = get_letter_pdf_filename(
        reference=notification.reference,
        crown=notification.service.crown,
        created_at=notification.created_at,
        ignore_folder=False,
        postage=notification.postage)

    move_uploaded_pdf_to_letters_bucket(file_location, upload_filename)

    return {'id': str(notification.id)}
Example #14
0
def test_should_not_interact_with_cache_for_test_key(sample_service, mocker):
    mocker.patch('app.notifications.validators.redis_store')
    check_service_over_daily_message_limit('test', sample_service)
    assert not app.notifications.validators.redis_store.mock_calls
Example #15
0
def test_should_not_interact_with_cache_for_test_key(sample_service, mocker):
    mocker.patch('app.notifications.validators.redis_store')
    mocker.patch('app.notifications.validators.redis_store.get', side_effect=[None])
    serialised_service = SerialisedService.from_id(sample_service.id)
    check_service_over_daily_message_limit('test', serialised_service)
    assert not app.notifications.validators.redis_store.mock_calls