def test_send_broadcast_event_queues_up_for_active_providers(mocker, notify_api, sample_broadcast_service):
    template = create_template(sample_broadcast_service, BROADCAST_TYPE)
    broadcast_message = create_broadcast_message(template, status=BroadcastStatusType.BROADCASTING)
    event = create_broadcast_event(broadcast_message)

    mock_send_broadcast_provider_message = mocker.patch(
        'app.celery.broadcast_message_tasks.send_broadcast_provider_message',
    )

    with set_config(notify_api, 'ENABLED_CBCS', ['ee', 'vodafone']):
        send_broadcast_event(event.id)

    assert mock_send_broadcast_provider_message.apply_async.call_args_list == [
        call(kwargs={'broadcast_event_id': event.id, 'provider': 'ee'}, queue='broadcast-tasks'),
        call(kwargs={'broadcast_event_id': event.id, 'provider': 'vodafone'}, queue='broadcast-tasks')
    ]
def test_should_allow_international_number_on_sms_notification(
        client, sample_service_full_permissions, mocker):
    mocker.patch('app.celery.provider_tasks.deliver_sms.apply_async')
    template = create_template(sample_service_full_permissions)

    data = {'to': '20-12-1234-1234', 'template': str(template.id)}

    auth_header = create_authorization_header(
        service_id=sample_service_full_permissions.id)

    response = client.post(path='/notifications/sms',
                           data=json.dumps(data),
                           headers=[('Content-Type', 'application/json'),
                                    auth_header])

    assert response.status_code == 201
Esempio n. 3
0
def test_post_letter_notification_returns_403_if_not_allowed_to_send_notification(
        client, notify_db_session, service_args):
    service = create_service(**service_args)
    template = create_template(service, template_type=LETTER_TYPE)

    data = {'template_id': str(template.id), 'personalisation': test_address}

    error_json = letter_request(client,
                                data,
                                service_id=service.id,
                                _expected_status=400)
    assert error_json['status_code'] == 400
    assert error_json['errors'] == [{
        'error': 'BadRequestError',
        'message': 'Cannot send letters'
    }]
Esempio n. 4
0
def test_update_broadcast_message_status(admin_request, sample_service):
    t = create_template(sample_service, BROADCAST_TYPE)
    bm = create_broadcast_message(t, status=BroadcastStatusType.DRAFT)

    response = admin_request.post(
        'broadcast_message.update_broadcast_message_status',
        _data={
            'status': BroadcastStatusType.PENDING_APPROVAL,
            'created_by': str(t.created_by_id)
        },
        service_id=t.service_id,
        broadcast_message_id=bm.id,
        _expected_status=200)

    assert response['status'] == BroadcastStatusType.PENDING_APPROVAL
    assert response['updated_at'] is not None
Esempio n. 5
0
def test_get_broadcast_message(admin_request, sample_service):
    t = create_template(sample_service, BROADCAST_TYPE)
    bm = create_broadcast_message(t, areas=['place A', 'region B'])

    response = admin_request.get('broadcast_message.get_broadcast_message',
                                 service_id=t.service_id,
                                 broadcast_message_id=bm.id,
                                 _expected_status=200)

    assert response['id'] == str(bm.id)
    assert response['template_name'] == t.name
    assert response['status'] == BroadcastStatusType.DRAFT
    assert response['created_at'] is not None
    assert response['starts_at'] is None
    assert response['areas'] == ['place A', 'region B']
    assert response['personalisation'] == {}
def test_check_content_char_count_fails(notify_db_session, show_prefix,
                                        char_count):
    with pytest.raises(BadRequestError) as e:
        service = create_service(prefix_sms=show_prefix)
        t = create_template(service=service,
                            content='a' * char_count,
                            template_type='sms')
        template = templates_dao.dao_get_template_by_id_and_service_id(
            template_id=t.id, service_id=service.id)
        template_with_content = get_template_instance(
            template=template.__dict__, values={})
        check_content_char_count(template_with_content)
    assert e.value.status_code == 400
    assert e.value.message == f'Text messages cannot be longer than {SMS_CHAR_COUNT_LIMIT} characters. ' \
                              f'Your message is {char_count} characters'
    assert e.value.fields == []
Esempio n. 7
0
def test_fetch_billing_data_for_today_includes_data_with_the_right_status(
    notify_db_session,
):
    service = create_service()
    template = create_template(service=service, template_type="email")
    for status in ["created", "technical-failure"]:
        create_notification(template=template, status=status)

    today = convert_utc_to_local_timezone(datetime.utcnow())
    results = fetch_billing_data_for_day(today)
    assert results == []
    for status in ["delivered", "sending", "temporary-failure"]:
        create_notification(template=template, status=status)
    results = fetch_billing_data_for_day(today)
    assert len(results) == 1
    assert results[0].notifications_sent == 3
def test_fetch_billing_data_for_day_is_grouped_by_rate_mulitplier(
        notify_db_session):
    service = create_service()
    template = create_template(service=service)
    create_notification(template=template,
                        status='delivered',
                        rate_multiplier=1)
    create_notification(template=template,
                        status='delivered',
                        rate_multiplier=2)

    today = convert_utc_to_bst(datetime.utcnow())
    results = fetch_billing_data_for_day(today.date())
    assert len(results) == 2
    assert results[0].notifications_sent == 1
    assert results[1].notifications_sent == 1
def test_send_one_off_notification_raises_if_over_limit(
        notify_db_session, mocker):
    service = create_service(message_limit=0)
    template = create_template(service=service)
    mocker.patch(
        'app.service.send_notification.check_service_over_daily_message_limit',
        side_effect=TooManyRequestsError(1))

    post_data = {
        'template_id': str(template.id),
        'to': '07700 900 001',
        'created_by': str(service.created_by_id)
    }

    with pytest.raises(TooManyRequestsError):
        send_one_off_notification(service.id, post_data)
def test_fetch_billing_data_for_day_is_grouped_by_international(
        notify_db_session):
    service = create_service()
    template = create_template(service=service)
    create_notification(template=template,
                        status='delivered',
                        international=True)
    create_notification(template=template,
                        status='delivered',
                        international=False)

    today = convert_utc_to_local_timezone(datetime.utcnow())
    results = fetch_billing_data_for_day(today)
    assert len(results) == 2
    assert results[0].notifications_sent == 1
    assert results[1].notifications_sent == 1
def test_fetch_monthly_billing_for_year_adds_data_for_today(notify_db_session):
    service = create_service()
    template = create_template(service=service, template_type="email")
    for i in range(1, 32):
        create_ft_billing(utc_date='2018-07-{}'.format(i),
                          service=service,
                          template=template,
                          notification_type='email',
                          rate=0.162)
    create_notification(template=template, status='delivered')

    assert db.session.query(FactBilling.bst_date).count() == 31
    results = fetch_monthly_billing_for_year(service_id=service.id,
                                             year=2018)
    assert db.session.query(FactBilling.bst_date).count() == 32
    assert len(results) == 2
def test_should_handle_sms_sender_and_prefix_message(
    mocker, sms_sender, prefix_sms, expected_sender, expected_content, notify_db_session
):
    mocker.patch("app.aws_sns_client.send_sms", return_value="message_id_from_sns")
    service = create_service_with_defined_sms_sender(sms_sender_value=sms_sender, prefix_sms=prefix_sms)
    template = create_template(service, content="bar")
    notification = create_notification(template, reply_to_text=sms_sender)

    send_to_providers.send_sms_to_provider(notification)

    aws_sns_client.send_sms.assert_called_once_with(
        content=expected_content,
        sender=expected_sender,
        to=ANY,
        reference=ANY,
    )
Esempio n. 13
0
def test_get_all_complaints_returns_complaints_for_multiple_services(
        client, notify_db_session):
    service = create_service(service_name="service1")
    template = create_template(service=service)
    notification = create_notification(template=template)
    complaint_1 = create_complaint()  # default service
    complaint_2 = create_complaint(service=service, notification=notification)

    response = client.get("/complaint",
                          headers=[create_authorization_header()])

    assert response.status_code == 200
    assert json.loads(response.get_data(as_text=True))["complaints"] == [
        complaint_2.serialize(),
        complaint_1.serialize(),
    ]
Esempio n. 14
0
def test_get_broadcast_messages_for_service(admin_request,
                                            sample_broadcast_service):
    t = create_template(sample_broadcast_service, BROADCAST_TYPE)

    with freeze_time('2020-01-01 12:00'):
        bm1 = create_broadcast_message(t, personalisation={'foo': 'bar'})
    with freeze_time('2020-01-01 13:00'):
        bm2 = create_broadcast_message(t, personalisation={'foo': 'baz'})

    response = admin_request.get(
        'broadcast_message.get_broadcast_messages_for_service',
        service_id=t.service_id,
        _expected_status=200)

    assert response['broadcast_messages'][0]['id'] == str(bm1.id)
    assert response['broadcast_messages'][1]['id'] == str(bm2.id)
Esempio n. 15
0
def test_validate_template_calls_all_validators(mocker, fake_uuid, sample_service):
    template = create_template(sample_service, template_type="email")
    mock_check_type = mocker.patch('app.notifications.validators.check_template_is_for_notification_type')
    mock_check_if_active = mocker.patch('app.notifications.validators.check_template_is_active')
    mock_create_conent = mocker.patch(
        'app.notifications.validators.create_content_for_notification', return_value="content"
    )
    mock_check_not_empty = mocker.patch('app.notifications.validators.check_notification_content_is_not_empty')
    mock_check_message_is_too_long = mocker.patch('app.notifications.validators.check_content_char_count')
    template, template_with_content = validate_template(template.id, {}, sample_service, "email")

    mock_check_type.assert_called_once_with("email", "email")
    mock_check_if_active.assert_called_once_with(template)
    mock_create_conent.assert_called_once_with(template, {})
    mock_check_not_empty.assert_called_once_with("content")
    mock_check_message_is_too_long.assert_called_once_with("content")
Esempio n. 16
0
def test_dao_fetch_todays_stats_for_all_services_only_includes_today(notify_db_session):
    template = create_template(service=create_service())
    with freeze_time('2001-01-01T23:59:00'):
        # just_before_midnight_yesterday
        create_notification(template=template, to_field='1', status='delivered')

    with freeze_time('2001-01-02T00:01:00'):
        # just_after_midnight_today
        create_notification(template=template, to_field='2', status='failed')

    with freeze_time('2001-01-02T12:00:00'):
        stats = dao_fetch_todays_stats_for_all_services()

    stats = {row.status: row.count for row in stats}
    assert 'delivered' not in stats
    assert stats['failed'] == 1
Esempio n. 17
0
def sample_notification_with_job(notify_db_session):
    service = create_service(check_if_service_exists=True)
    template = create_template(service=service)
    job = create_job(template=template)
    return create_notification(template=template,
                               job=job,
                               job_row_number=None,
                               to_field=None,
                               status='created',
                               reference=None,
                               created_at=None,
                               sent_at=None,
                               billable_units=1,
                               personalisation=None,
                               api_key=None,
                               key_type=KEY_TYPE_NORMAL)
Esempio n. 18
0
def test_send_one_off_notification_raises_if_message_too_long(persist_mock, notify_db_session):
    service = create_service()
    template = create_template(service=service, content="Hello (( Name))\nYour thing is due soon")

    post_data = {
        'template_id': str(template.id),
        'to': '07700 900 001',
        'personalisation': {'name': '🚫' * 1000},
        'created_by': str(service.created_by_id)
    }

    with pytest.raises(BadRequestError) as e:
        send_one_off_notification(service.id, post_data)

    assert e.value.message == f'Text messages cannot be longer than {SMS_CHAR_COUNT_LIMIT} characters. ' \
                              f'Your message is {1029} characters'
Esempio n. 19
0
def test_preview_letter_template_precompiled_png_file_type(
        notify_api,
        client,
        admin_request,
        sample_service,
        mocker
):

    template = create_template(sample_service,
                               template_type='letter',
                               template_name='Pre-compiled PDF',
                               subject='Pre-compiled PDF',
                               hidden=True)

    notification = create_notification(template)

    with set_config_values(notify_api, {
        'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview',
        'TEMPLATE_PREVIEW_API_KEY': 'test-key'
    }):
        with requests_mock.Mocker() as request_mock:

            pdf_content = b'\x00\x01'
            png_content = b'\x00\x02'

            mock_get_letter_pdf = mocker.patch('app.template.rest.get_letter_pdf', return_value=pdf_content)

            mocker.patch('app.template.rest.extract_page_from_pdf', return_value=pdf_content)

            mock_post = request_mock.post(
                'http://localhost/notifications-template-preview/precompiled-preview.png',
                content=png_content,
                headers={'X-pdf-page-count': '1'},
                status_code=200
            )

            resp = admin_request.get(
                'template.preview_letter_template_by_notification_id',
                service_id=notification.service_id,
                notification_id=notification.id,
                file_type='png'
            )

            with pytest.raises(ValueError):
                mock_post.last_request.json()
            assert mock_get_letter_pdf.called_once_with(notification)
            assert base64.b64decode(resp['content']) == png_content
Esempio n. 20
0
def test_send_broadcast_provider_message_sends_cancel_with_references(
        mocker, sample_broadcast_service, provider, provider_capitalised):
    template = create_template(sample_broadcast_service,
                               BROADCAST_TYPE,
                               content='content')

    broadcast_message = create_broadcast_message(
        template,
        areas={
            'areas': ['london'],
            'simple_polygons': [
                [[50.12, 1.2], [50.13, 1.2], [50.14, 1.21]],
            ],
        },
        status=BroadcastStatusType.BROADCASTING)

    alert_event = create_broadcast_event(
        broadcast_message, message_type=BroadcastEventMessageType.ALERT)
    update_event = create_broadcast_event(
        broadcast_message, message_type=BroadcastEventMessageType.UPDATE)
    cancel_event = create_broadcast_event(
        broadcast_message, message_type=BroadcastEventMessageType.CANCEL)

    create_broadcast_provider_message(
        alert_event, provider, status=BroadcastProviderMessageStatus.ACK)
    create_broadcast_provider_message(
        update_event, provider, status=BroadcastProviderMessageStatus.ACK)

    mock_cancel_broadcast = mocker.patch(
        f'app.clients.cbc_proxy.CBCProxy{provider_capitalised}.cancel_broadcast',
    )

    send_broadcast_provider_message(provider=provider,
                                    broadcast_event_id=str(cancel_event.id))

    broadcast_provider_message = cancel_event.get_provider_message(provider)
    assert broadcast_provider_message.status == BroadcastProviderMessageStatus.ACK

    mock_cancel_broadcast.assert_called_once_with(
        identifier=str(broadcast_provider_message.id),
        message_number=mocker.ANY,
        previous_provider_messages=[
            alert_event.get_provider_message(provider),
            update_event.get_provider_message(provider)
        ],
        sent=cancel_event.sent_at_as_cap_datetime_string,
    )
Esempio n. 21
0
def test_preview_letter_template_precompiled_png_template_preview_pdf_error(
        notify_api,
        client,
        admin_request,
        sample_service,
        mocker
):

    template = create_template(sample_service,
                               template_type='letter',
                               template_name='Pre-compiled PDF',
                               subject='Pre-compiled PDF',
                               hidden=True)

    notification = create_notification(template)

    with set_config_values(notify_api, {
        'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview',
        'TEMPLATE_PREVIEW_API_KEY': 'test-key'
    }):
        with requests_mock.Mocker() as request_mock:

            pdf_content = b'\x00\x01'
            png_content = b'\x00\x02'

            mocker.patch('app.template.rest.get_letter_pdf', return_value=pdf_content)

            error_message = "PDF Error message"
            mocker.patch('app.template.rest.extract_page_from_pdf', side_effect=PdfReadError(error_message))

            request_mock.post(
                'http://localhost/notifications-template-preview/precompiled-preview.png',
                content=png_content,
                headers={'X-pdf-page-count': '1'},
                status_code=404
            )

            request = admin_request.get(
                'template.preview_letter_template_by_notification_id',
                service_id=notification.service_id,
                notification_id=notification.id,
                file_type='png',
                _expected_status=500
            )

            assert request['message'] == "Error extracting requested page from PDF file for notification_id {} type " \
                                         "{} {}".format(notification.id, type(PdfReadError()), error_message)
Esempio n. 22
0
def test_send_one_off_notification_calls_persist_correctly_for_letter(
    mocker,
    persist_mock,
    celery_mock,
    notify_db_session
):
    mocker.patch(
        'app.service.send_notification.create_random_identifier',
        return_value='this-is-random-in-real-life',
    )
    service = create_service()
    template = create_template(
        service=service,
        template_type=LETTER_TYPE,
        postage='first',
        subject="Test subject",
        content="Hello (( Name))\nYour thing is due soon",
    )

    post_data = {
        'template_id': str(template.id),
        'to': 'First Last',
        'personalisation': {
            'name': 'foo',
            'address line 1': 'First Last',
            'address line 2': '1 Example Street',
            'postcode': 'SW1A 1AA',
        },
        'created_by': str(service.created_by_id)
    }

    send_one_off_notification(service.id, post_data)

    persist_mock.assert_called_once_with(
        template_id=template.id,
        template_version=template.version,
        template_postage='first',
        recipient=post_data['to'],
        service=template.service,
        personalisation=post_data['personalisation'],
        notification_type=LETTER_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        created_by_id=str(service.created_by_id),
        reply_to_text=None,
        reference='this-is-random-in-real-life',
    )
Esempio n. 23
0
def test_send_broadcast_provider_message_sends_update_with_references(
        mocker, sample_broadcast_service, provider, provider_capitalised):
    template = create_template(sample_broadcast_service,
                               BROADCAST_TYPE,
                               content='content')

    broadcast_message = create_broadcast_message(
        template,
        areas={
            'areas': ['london'],
            'simple_polygons': [
                [[50.12, 1.2], [50.13, 1.2], [50.14, 1.21]],
            ],
        },
        status=BroadcastStatusType.BROADCASTING)

    alert_event = create_broadcast_event(
        broadcast_message, message_type=BroadcastEventMessageType.ALERT)
    create_broadcast_provider_message(
        alert_event, provider, status=BroadcastProviderMessageStatus.ACK)
    update_event = create_broadcast_event(
        broadcast_message, message_type=BroadcastEventMessageType.UPDATE)

    mock_update_broadcast = mocker.patch(
        f'app.clients.cbc_proxy.CBCProxy{provider_capitalised}.update_and_send_broadcast',
    )

    send_broadcast_provider_message(provider=provider,
                                    broadcast_event_id=str(update_event.id))

    broadcast_provider_message = update_event.get_provider_message(provider)
    assert broadcast_provider_message.status == BroadcastProviderMessageStatus.ACK

    mock_update_broadcast.assert_called_once_with(
        identifier=str(broadcast_provider_message.id),
        message_number=mocker.ANY,
        headline="GOV.UK Notify Broadcast",
        description='this is an emergency broadcast message',
        areas=[{
            "polygon": [[50.12, 1.2], [50.13, 1.2], [50.14, 1.21]],
        }],
        previous_provider_messages=[
            alert_event.get_provider_message(provider)
        ],
        sent=update_event.sent_at_as_cap_datetime_string,
        expires=update_event.transmitted_finishes_at_as_cap_datetime_string,
        channel="severe")
Esempio n. 24
0
def test_send_one_off_notification_raises_if_over_limit(
        notify_db_session, mocker):
    service = create_service(message_limit=0)
    template = create_template(service=service)
    mocker.patch(
        "app.service.send_notification.check_service_over_daily_message_limit",
        side_effect=TooManyRequestsError(1),
    )

    post_data = {
        "template_id": str(template.id),
        "to": "6502532222",
        "created_by": str(service.created_by_id),
    }

    with pytest.raises(TooManyRequestsError):
        send_one_off_notification(service.id, post_data)
Esempio n. 25
0
def test_get_yearly_usage_by_monthly_from_ft_billing_populates_deltas(client, notify_db_session):
    service = create_service()
    sms_template = create_template(service=service, template_type="sms")
    create_rate(start_date=datetime.utcnow() - timedelta(days=1), value=0.158, notification_type='sms')

    create_notification(template=sms_template, status='delivered')

    assert FactBilling.query.count() == 0

    response = client.get('service/{}/billing/ft-monthly-usage?year=2018'.format(service.id),
                          headers=[('Content-Type', 'application/json'), create_authorization_header()])

    assert response.status_code == 200
    assert len(json.loads(response.get_data(as_text=True))) == 1
    fact_billing = FactBilling.query.all()
    assert len(fact_billing) == 1
    assert fact_billing[0].notification_type == 'sms'
Esempio n. 26
0
def test_send_one_off_notification_honors_process_type(notify_db_session,
                                                       persist_mock,
                                                       celery_mock,
                                                       process_type):
    service = create_service()
    template = create_template(service=service)
    template.process_type = process_type

    post_data = {
        "template_id": str(template.id),
        "to": "6502532222",
        "created_by": str(service.created_by_id),
    }

    send_one_off_notification(service.id, post_data)

    assert celery_mock.call_args[1]["queue"] == f"{process_type}-tasks"
Esempio n. 27
0
def test_get_last_send_for_api_key(notify_db_session):
    service = create_service(service_name='First Service')
    api_key = create_api_key(service)
    template_email = create_template(service=service, template_type=EMAIL_TYPE)
    total_sends = 10

    last_send = get_last_send_for_api_key(str(api_key.id))
    assert last_send == []

    for x in range(total_sends):
        create_notification(template=template_email, api_key=api_key)

    # the following lines test that a send has occurred within the last second
    last_send = get_last_send_for_api_key(str(api_key.id))[0][0]
    now = datetime.utcnow()
    time_delta = now - last_send
    assert abs(time_delta.total_seconds()) < 1
Esempio n. 28
0
def test_post_notification_with_document_upload(client, notify_db_session, mocker, csv_param):
    service = create_service(service_permissions=[EMAIL_TYPE])
    service.contact_link = '*****@*****.**'
    template = create_template(
        service=service,
        template_type='email',
        content="Document 1: ((first_link)). Document 2: ((second_link))"
    )

    mocker.patch('app.celery.provider_tasks.deliver_email.apply_async')
    document_download_mock = mocker.patch('app.v2.notifications.post_notifications.document_download_client')
    document_download_mock.upload_document.side_effect = lambda service_id, content, is_csv: f'{content}-link'

    data = {
        "email_address": service.users[0].email_address,
        "template_id": template.id,
        "personalisation": {
            "first_link": {"file": "abababab", **csv_param},
            "second_link": {"file": "cdcdcdcd", **csv_param}
        }
    }

    auth_header = create_authorization_header(service_id=service.id)
    response = client.post(
        path="v2/notifications/email",
        data=json.dumps(data),
        headers=[('Content-Type', 'application/json'), auth_header])

    assert response.status_code == 201, response.get_data(as_text=True)
    resp_json = json.loads(response.get_data(as_text=True))
    assert validate(resp_json, post_email_response) == resp_json

    assert document_download_mock.upload_document.call_args_list == [
        call(str(service.id), 'abababab', csv_param.get('is_csv')),
        call(str(service.id), 'cdcdcdcd', csv_param.get('is_csv'))
    ]

    notification = Notification.query.one()
    assert notification.status == NOTIFICATION_CREATED
    assert notification.personalisation == {
        'first_link': 'abababab-link',
        'second_link': 'cdcdcdcd-link'
    }
    assert notification.document_download_count == 2

    assert resp_json['content']['body'] == 'Document 1: abababab-link. Document 2: cdcdcdcd-link'
Esempio n. 29
0
def test_get_jobs_for_service(sample_template):
    one_job = create_job(sample_template)

    other_service = create_service(service_name="other service")
    other_template = create_template(service=other_service)
    other_job = create_job(other_template)

    one_job_from_db = dao_get_jobs_by_service_id(one_job.service_id).items
    other_job_from_db = dao_get_jobs_by_service_id(other_job.service_id).items

    assert len(one_job_from_db) == 1
    assert one_job == one_job_from_db[0]

    assert len(other_job_from_db) == 1
    assert other_job == other_job_from_db[0]

    assert one_job_from_db != other_job_from_db
def archived_service_with_deleted_stuff(client, sample_service):
    with freeze_time('2001-01-01'):
        template = create_template(sample_service, template_name='a')
        api_key = create_api_key(sample_service)

        expire_api_key(sample_service.id, api_key.id)

        template.archived = True
        dao_update_template(template)

    with freeze_time('2002-02-02'):
        auth_header = create_authorization_header()
        response = client.post('/service/{}/archive'.format(sample_service.id), headers=[auth_header])

    assert response.status_code == 204
    assert response.data == b''
    return sample_service