def test_persist_notification_with_optionals(sample_job, sample_api_key, mocker):
    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
    mocked_redis = mocker.patch('app.notifications.process_notifications.redis_store.incr')
    n_id = uuid.uuid4()
    created_at = datetime.datetime(2016, 11, 11, 16, 8, 18)
    persist_notification(template_id=sample_job.template.id,
                         template_version=sample_job.template.version,
                         recipient='+447111111111',
                         service_id=sample_job.service.id,
                         personalisation=None, notification_type='sms',
                         api_key_id=sample_api_key.id,
                         key_type=sample_api_key.key_type,
                         created_at=created_at,
                         job_id=sample_job.id,
                         job_row_number=10,
                         reference="ref from client",
                         notification_id=n_id)
    assert Notification.query.count() == 1
    assert NotificationHistory.query.count() == 1
    persisted_notification = Notification.query.all()[0]
    assert persisted_notification.id == n_id
    persisted_notification.job_id == sample_job.id
    assert persisted_notification.job_row_number == 10
    assert persisted_notification.created_at == created_at
    mocked_redis.assert_called_once_with(str(sample_job.service_id) + "-2016-01-01-count")
    assert persisted_notification.client_reference == "ref from client"
    assert persisted_notification.reference is None
def test_cache_is_not_incremented_on_failure_to_persist_notification(sample_api_key, mocker):
    mocked_redis = mocker.patch('app.notifications.process_notifications.redis_store.incr')
    with pytest.raises(SQLAlchemyError):
        persist_notification(template_id=None,
                             template_version=None,
                             recipient='+447111111111',
                             service_id=sample_api_key.service_id,
                             personalisation=None,
                             notification_type='sms',
                             api_key_id=sample_api_key.id,
                             key_type=sample_api_key.key_type)
    mocked_redis.assert_not_called()
def test_persist_notification_throws_exception_when_missing_template(sample_api_key):
    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
    with pytest.raises(SQLAlchemyError):
        persist_notification(template_id=None,
                             template_version=None,
                             recipient='+447111111111',
                             service_id=sample_api_key.service_id,
                             personalisation=None,
                             notification_type='sms',
                             api_key_id=sample_api_key.id,
                             key_type=sample_api_key.key_type)
    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
def post_email_notification():
    form = validate(request.get_json(), post_email_request)
    service = services_dao.dao_fetch_service_by_id(api_user.service_id)

    check_service_message_limit(api_user.key_type, service)
    service_can_send_to_recipient(form["email_address"], api_user.key_type, service)

    template, template_with_content = __validate_template(form, service, EMAIL_TYPE)
    notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=form["email_address"],
        service_id=service.id,
        personalisation=form.get("personalisation", None),
        notification_type=EMAIL_TYPE,
        api_key_id=api_user.id,
        key_type=api_user.key_type,
        reference=form.get("reference"),
    )

    send_notification_to_queue(notification, service.research_mode)

    resp = create_post_email_response_from_notification(
        notification=notification,
        content=str(template_with_content),
        subject=template_with_content.subject,
        email_from=service.email_from,
        url_root=request.url_root,
    )
    return jsonify(resp), 201
def test_persist_notification_creates_and_save_to_db(sample_template, sample_api_key, sample_job, mocker):
    mocked_redis = mocker.patch('app.notifications.process_notifications.redis_store.incr')

    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
    notification = persist_notification(sample_template.id, sample_template.version, '+447111111111',
                                        sample_template.service.id, {}, 'sms', sample_api_key.id,
                                        sample_api_key.key_type, job_id=sample_job.id,
                                        job_row_number=100, reference="ref")

    assert Notification.query.get(notification.id) is not None
    assert NotificationHistory.query.get(notification.id) is not None

    notification_from_db = Notification.query.one()
    notification_history_from_db = NotificationHistory.query.one()

    assert notification_from_db.id == notification_history_from_db.id
    assert notification_from_db.template_id == notification_history_from_db.template_id
    assert notification_from_db.template_version == notification_history_from_db.template_version
    assert notification_from_db.api_key_id == notification_history_from_db.api_key_id
    assert notification_from_db.key_type == notification_history_from_db.key_type
    assert notification_from_db.key_type == notification_history_from_db.key_type
    assert notification_from_db.billable_units == notification_history_from_db.billable_units
    assert notification_from_db.notification_type == notification_history_from_db.notification_type
    assert notification_from_db.created_at == notification_history_from_db.created_at
    assert not notification_from_db.sent_at
    assert not notification_history_from_db.sent_at
    assert notification_from_db.updated_at == notification_history_from_db.updated_at
    assert notification_from_db.status == notification_history_from_db.status
    assert notification_from_db.reference == notification_history_from_db.reference
    assert notification_from_db.client_reference == notification_history_from_db.client_reference

    mocked_redis.assert_called_once_with(str(sample_template.service_id) + "-2016-01-01-count")
def post_sms_notification():
    form = validate(request.get_json(), post_sms_request)
    service = services_dao.dao_fetch_service_by_id(api_user.service_id)

    check_service_message_limit(api_user.key_type, service)
    service_can_send_to_recipient(form["phone_number"], api_user.key_type, service)

    template, template_with_content = __validate_template(form, service, SMS_TYPE)

    notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=form["phone_number"],
        service_id=service.id,
        personalisation=form.get("personalisation", None),
        notification_type=SMS_TYPE,
        api_key_id=api_user.id,
        key_type=api_user.key_type,
        reference=form.get("reference"),
    )
    send_notification_to_queue(notification, service.research_mode)
    sms_sender = service.sms_sender if service.sms_sender else current_app.config.get("FROM_NUMBER")
    resp = create_post_sms_response_from_notification(
        notification, str(template_with_content), sms_sender, request.url_root
    )
    return jsonify(resp), 201
Example #7
0
def send_user_sms_code(user_id):
    user_to_send_to = get_user_by_id(user_id=user_id)
    verify_code, errors = request_verify_code_schema.load(request.get_json())

    secret_code = create_secret_code()
    create_user_code(user_to_send_to, secret_code, SMS_TYPE)

    mobile = user_to_send_to.mobile_number if verify_code.get('to', None) is None else verify_code.get('to')
    sms_code_template_id = current_app.config['SMS_CODE_TEMPLATE_ID']
    sms_code_template = dao_get_template_by_id(sms_code_template_id)
    notify_service_id = current_app.config['NOTIFY_SERVICE_ID']

    saved_notification = persist_notification(
        template_id=sms_code_template_id,
        template_version=sms_code_template.version,
        recipient=mobile,
        service_id=notify_service_id,
        personalisation={'verify_code': secret_code},
        notification_type=SMS_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL
    )
    # Assume that we never want to observe the Notify service's research mode
    # setting for this notification - we still need to be able to log into the
    # admin even if we're doing user research using this service:
    send_notification_to_queue(saved_notification, False, queue='notify')

    return jsonify({}), 204
Example #8
0
def send_user_confirm_new_email(user_id):
    user_to_send_to = get_user_by_id(user_id=user_id)
    email, errors = email_data_request_schema.load(request.get_json())
    if errors:
        raise InvalidRequest(message=errors, status_code=400)

    template = dao_get_template_by_id(current_app.config['CHANGE_EMAIL_CONFIRMATION_TEMPLATE_ID'])
    notify_service_id = current_app.config['NOTIFY_SERVICE_ID']

    saved_notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=email['email'],
        service_id=notify_service_id,
        personalisation={
            'name': user_to_send_to.name,
            'url': _create_confirmation_url(user=user_to_send_to, email_address=email['email']),
            'feedback_url': current_app.config['ADMIN_BASE_URL'] + '/feedback'
        },
        notification_type=EMAIL_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL
    )

    send_notification_to_queue(saved_notification, False, queue='notify')
    return jsonify({}), 204
Example #9
0
def send_sms(
    self, service_id, notification_id, encrypted_notification, created_at, api_key_id=None, key_type=KEY_TYPE_NORMAL
):
    notification = encryption.decrypt(encrypted_notification)
    service = dao_fetch_service_by_id(service_id)

    if not service_allowed_to_send_to(notification["to"], service, key_type):
        current_app.logger.info("SMS {} failed as restricted service".format(notification_id))
        return

    try:
        saved_notification = persist_notification(
            template_id=notification["template"],
            template_version=notification["template_version"],
            recipient=notification["to"],
            service_id=service.id,
            personalisation=notification.get("personalisation"),
            notification_type=SMS_TYPE,
            api_key_id=api_key_id,
            key_type=key_type,
            created_at=created_at,
            job_id=notification.get("job", None),
            job_row_number=notification.get("row_number", None),
            notification_id=notification_id,
        )

        provider_tasks.deliver_sms.apply_async(
            [str(saved_notification.id)], queue="send-sms" if not service.research_mode else "research-mode"
        )

        current_app.logger.info(
            "SMS {} created at {} for job {}".format(saved_notification.id, created_at, notification.get("job", None))
        )

    except SQLAlchemyError as e:
        if not get_notification_by_id(notification_id):
            # Sometimes, SQS plays the same message twice. We should be able to catch an IntegrityError, but it seems
            # SQLAlchemy is throwing a FlushError. So we check if the notification id already exists then do not
            # send to the retry queue.
            current_app.logger.error(
                "RETRY: send_sms notification for job {} row number {} and notification id {}".format(
                    notification.get("job", None), notification.get("row_number", None), notification_id
                )
            )
            current_app.logger.exception(e)
            try:
                raise self.retry(queue="retry", exc=e)
            except self.MaxRetriesExceededError:
                current_app.logger.error(
                    "RETRY FAILED: send_sms notification for job {} row number {} and notification id {}".format(
                        notification.get("job", None), notification.get("row_number", None), notification_id
                    )
                )
                current_app.logger.exception(e)
def test_persist_notification_increments_cache_if_key_exists(
        sample_template, sample_api_key, mocker):
    mock_incr = mocker.patch(
        'app.notifications.process_notifications.redis_store.incr')
    mocker.patch('app.notifications.process_notifications.redis_store.get',
                 return_value=1)
    mocker.patch(
        'app.notifications.process_notifications.redis_store.get_all_from_hash',
        return_value={sample_template.id, 1})

    persist_notification(template_id=sample_template.id,
                         template_version=sample_template.version,
                         recipient='+447111111122',
                         service=sample_template.service,
                         personalisation={},
                         notification_type='sms',
                         api_key_id=sample_api_key.id,
                         key_type=sample_api_key.key_type,
                         reference="ref2")

    mock_incr.assert_called_once_with(
        str(sample_template.service_id) + "-2016-01-01-count", )
def test_persist_email_notification_stores_normalised_email(
    sample_job,
    sample_api_key,
    mocker,
    recipient,
    expected_recipient_normalised
):
    persist_notification(
        template_id=sample_job.template.id,
        template_version=sample_job.template.version,
        recipient=recipient,
        service=sample_job.service,
        personalisation=None,
        notification_type='email',
        api_key_id=sample_api_key.id,
        key_type=sample_api_key.key_type,
        job_id=sample_job.id,
    )
    persisted_notification = Notification.query.all()[0]

    assert persisted_notification.to == recipient
    assert persisted_notification.normalised_to == expected_recipient_normalised
def test_persist_notification_doesnt_touch_cache_for_old_keys_that_dont_exist(sample_template, sample_api_key, mocker):
    mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr')
    mock_incr_hash_value = mocker.patch('app.notifications.process_notifications.redis_store.increment_hash_value')
    mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=None)
    mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash', return_value=None)

    persist_notification(
        template_id=sample_template.id,
        template_version=sample_template.version,
        recipient='+61412345678',
        service=sample_template.service,
        personalisation={},
        notification_type='sms',
        api_key_id=sample_api_key.id,
        key_type=sample_api_key.key_type,
        reference="ref"
    )
    mock_incr.assert_not_called()
    mock_incr_hash_value.assert_called_once_with(
        "service-{}-template-usage-2016-01-01".format(sample_template.service_id),
        sample_template.id
    )
Example #13
0
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_whitelisted_recipients=False,
    )

    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
    )

    queue_name = QueueNames.PRIORITY if template.process_type == PRIORITY else None
    send_notification_to_queue(
        notification=notification,
        research_mode=service.research_mode,
        queue=queue_name
    )

    return {'id': str(notification.id)}
Example #14
0
def save_email(self,
               service_id,
               notification_id,
               encrypted_notification,
               sender_id=None):
    notification = encryption.decrypt(encrypted_notification)

    service = SerialisedService.from_id(service_id)
    template = SerialisedTemplate.from_id_and_service_id(
        notification['template'],
        service_id=service.id,
        version=notification['template_version'],
    )

    if sender_id:
        reply_to_text = dao_get_reply_to_by_id(service_id,
                                               sender_id).email_address
    else:
        reply_to_text = template.reply_to_text

    if not service_allowed_to_send_to(notification['to'], service,
                                      KEY_TYPE_NORMAL):
        current_app.logger.info(
            "Email {} failed as restricted service".format(notification_id))
        return

    try:
        saved_notification = persist_notification(
            template_id=notification['template'],
            template_version=notification['template_version'],
            recipient=notification['to'],
            service=service,
            personalisation=notification.get('personalisation'),
            notification_type=EMAIL_TYPE,
            api_key_id=None,
            key_type=KEY_TYPE_NORMAL,
            created_at=datetime.utcnow(),
            job_id=notification.get('job', None),
            job_row_number=notification.get('row_number', None),
            notification_id=notification_id,
            reply_to_text=reply_to_text)

        provider_tasks.deliver_email.apply_async(
            [str(saved_notification.id)],
            queue=QueueNames.SEND_EMAIL
            if not service.research_mode else QueueNames.RESEARCH_MODE)

        current_app.logger.debug("Email {} created at {}".format(
            saved_notification.id, saved_notification.created_at))
    except SQLAlchemyError as e:
        handle_exception(self, notification, notification_id, e)
def process_sms_or_email_notification(*,
                                      form,
                                      notification_type,
                                      api_key,
                                      template,
                                      service,
                                      reply_to_text=None):
    form_send_to = form[
        'email_address'] if notification_type == EMAIL_TYPE else form[
            'phone_number']
    send_to = validate_and_format_recipient(
        send_to=form_send_to,
        key_type=api_key.key_type,
        service=service,
        notification_type=notification_type)
    # Do not persist or send notification to the queue if it is a simulated recipient
    simulated = simulated_recipient(send_to, notification_type)

    personalisation = process_document_uploads(form.get('personalisation'),
                                               service,
                                               simulated=simulated)

    notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=form_send_to,
        service=service,
        personalisation=personalisation,
        notification_type=notification_type,
        api_key_id=api_key.id,
        key_type=api_key.key_type,
        client_reference=form.get('reference', None),
        simulated=simulated,
        reply_to_text=reply_to_text,
        recipient_identifier=form.get('recipient_identifier', None))

    scheduled_for = form.get("scheduled_for", None)
    if scheduled_for:
        persist_scheduled_notification(notification.id, form["scheduled_for"])
    else:
        if simulated:
            current_app.logger.debug(
                "POST simulated notification for id: {}".format(
                    notification.id))
        else:
            queue_name = QueueNames.PRIORITY if template.process_type == PRIORITY else None
            send_notification_to_queue(notification=notification,
                                       research_mode=service.research_mode,
                                       queue=queue_name)

    return notification
def test_persist_notification_with_optionals(sample_job, sample_api_key,
                                             mocker):
    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
    mocked_redis = mocker.patch(
        'app.notifications.process_notifications.redis_store.get')
    n_id = uuid.uuid4()
    created_at = datetime.datetime(2016, 11, 11, 16, 8, 18)
    persist_notification(template_id=sample_job.template.id,
                         template_version=sample_job.template.version,
                         recipient='+447111111111',
                         service=sample_job.service,
                         personalisation=None,
                         notification_type='sms',
                         api_key_id=sample_api_key.id,
                         key_type=sample_api_key.key_type,
                         created_at=created_at,
                         job_id=sample_job.id,
                         job_row_number=10,
                         client_reference="ref from client",
                         notification_id=n_id,
                         created_by_id=sample_job.created_by_id)
    assert Notification.query.count() == 1
    assert NotificationHistory.query.count() == 0
    persisted_notification = Notification.query.all()[0]
    assert persisted_notification.id == n_id
    persisted_notification.job_id == sample_job.id
    assert persisted_notification.job_row_number == 10
    assert persisted_notification.created_at == created_at
    mocked_redis.assert_called_once_with(
        str(sample_job.service_id) + "-2016-01-01-count")
    assert persisted_notification.client_reference == "ref from client"
    assert persisted_notification.reference is None
    assert persisted_notification.international is False
    assert persisted_notification.phone_prefix == '44'
    assert persisted_notification.rate_multiplier == 1
    assert persisted_notification.created_by_id == sample_job.created_by_id
    assert not persisted_notification.reply_to_text
def test_persist_letter_notification_finds_correct_postage(
        mocker, notify_db, notify_db_session, postage_argument,
        template_postage, expected_postage):
    service = create_service(service_permissions=[LETTER_TYPE])
    api_key = create_api_key(notify_db, notify_db_session, service=service)
    template = create_template(service,
                               template_type=LETTER_TYPE,
                               postage=template_postage)
    mocker.patch('app.dao.templates_dao.dao_get_template_by_id',
                 return_value=template)
    persist_notification(template_id=template.id,
                         template_version=template.version,
                         template_postage=template.postage,
                         recipient="Jane Doe, 10 Downing Street, London",
                         service=service,
                         personalisation=None,
                         notification_type=LETTER_TYPE,
                         api_key_id=api_key.id,
                         key_type=api_key.key_type,
                         postage=postage_argument)
    persisted_notification = Notification.query.all()[0]

    assert persisted_notification.postage == expected_postage
Example #18
0
def test_persist_notification_doesnt_touch_cache_for_old_keys_that_dont_exist(
        notify_db_session, mocker):
    service = create_service(restricted=True)
    template = create_template(service=service)
    api_key = create_api_key(service=service)
    mock_incr = mocker.patch(
        'app.notifications.process_notifications.redis_store.incr')
    mocker.patch('app.notifications.process_notifications.redis_store.get',
                 return_value=None)
    mocker.patch(
        'app.notifications.process_notifications.redis_store.get_all_from_hash',
        return_value=None)

    persist_notification(template_id=template.id,
                         template_version=template.version,
                         recipient='+447111111111',
                         service=template.service,
                         personalisation={},
                         notification_type='sms',
                         api_key_id=api_key.id,
                         key_type=api_key.key_type,
                         reference="ref")
    mock_incr.assert_not_called()
Example #19
0
def update_service(service_id):
    req_json = request.get_json()
    fetched_service = dao_fetch_service_by_id(service_id)
    # Capture the status change here as Marshmallow changes this later
    service_going_live = fetched_service.restricted and not req_json.get('restricted', True)
    service_go_live_requested = 'go_live_user' in req_json
    current_data = dict(service_schema.dump(fetched_service).data.items())
    current_data.update(request.get_json())

    service = service_schema.load(current_data).data

    if 'email_branding' in req_json:
        email_branding_id = req_json['email_branding']
        service.email_branding = None if not email_branding_id else EmailBranding.query.get(email_branding_id)
    if 'letter_branding' in req_json:
        letter_branding_id = req_json['letter_branding']
        service.letter_branding = None if not letter_branding_id else LetterBranding.query.get(letter_branding_id)
    dao_update_service(service)

    if service_go_live_requested:
        template = dao_get_template_by_id(current_app.config['NOTIFY_ADMIN_OF_GO_LIVE_REQUEST_TEMPLATE_ID'])
        service_url = "{}/services/{}".format(current_app.config['ADMIN_BASE_URL'], str(service.id))
        saved_notification = persist_notification(
            template_id=template.id,
            template_version=template.version,
            recipient=get_or_build_support_email_address(),
            service=template.service,
            personalisation={
                'service_name': service.name,
                'service_dashboard_url': service_url
            },
            notification_type=EMAIL_TYPE,
            api_key_id=None,
            key_type=KEY_TYPE_NORMAL,
            reply_to_text=get_or_build_support_email_address()
        )
        send_notification_to_queue(saved_notification, research_mode=False, queue=QueueNames.NOTIFY)

    if service_going_live:
        send_notification_to_service_users(
            service_id=service_id,
            template_id=current_app.config['SERVICE_NOW_LIVE_TEMPLATE_ID'],
            personalisation={
                'service_name': current_data['name'],
                'message_limit': '{:,}'.format(current_data['message_limit'])
            },
            include_user_fields=['name']
        )

    return jsonify(data=service_schema.dump(fetched_service).data), 200
Example #20
0
def test_persist_notification_does_not_increments_cache_live_service(
    notify_db_session, mocker
):
    service = create_service(restricted=False)
    template = create_template(service=service)
    api_key = create_api_key(service=service)
    mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr')
    mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=1)
    mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash',
                 return_value={template.id, 1})

    persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient='+447111111122',
        service=template.service,
        personalisation={},
        notification_type='sms',
        api_key_id=api_key.id,
        key_type=api_key.key_type,
        reference="ref2")

    assert not mock_incr.called
Example #21
0
def test_persist_notification_increments_cache_if_key_exists_and_for_trial_service(
    notify_db_session, mocker
):
    service = create_service(restricted=True)
    template = create_template(service=service)
    api_key = create_api_key(service=service)
    mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr')
    mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=1)
    mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash',
                 return_value={template.id, 1})

    persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient='+447111111122',
        service=template.service,
        personalisation={},
        notification_type='sms',
        api_key_id=api_key.id,
        key_type=api_key.key_type,
        reference="ref2")

    mock_incr.assert_called_once_with(str(service.id) + "-2016-01-01-count", )
def test_persist_notification_with_international_info_does_not_store_for_email(
    sample_job,
    sample_api_key,
    mocker
):
    persist_notification(
        template_id=sample_job.template.id,
        template_version=sample_job.template.version,
        recipient='*****@*****.**',
        service=sample_job.service,
        personalisation=None,
        notification_type='email',
        api_key_id=sample_api_key.id,
        key_type=sample_api_key.key_type,
        job_id=sample_job.id,
        job_row_number=10,
        client_reference="ref from client"
    )
    persisted_notification = Notification.query.all()[0]

    assert persisted_notification.international is False
    assert persisted_notification.phone_prefix is None
    assert persisted_notification.rate_multiplier is None
def test_persist_notification_doesnt_touch_cache_for_old_keys_that_dont_exist(
        sample_template, sample_api_key, mocker):
    mock_incr = mocker.patch(
        "app.notifications.process_notifications.redis_store.incr")
    mocker.patch("app.notifications.process_notifications.redis_store.get",
                 return_value=None)
    mocker.patch(
        "app.notifications.process_notifications.redis_store.get_all_from_hash",
        return_value=None,
    )

    persist_notification(
        template_id=sample_template.id,
        template_version=sample_template.version,
        recipient="+16502532222",
        service=sample_template.service,
        personalisation={},
        notification_type="sms",
        api_key_id=sample_api_key.id,
        key_type=sample_api_key.key_type,
        reference="ref",
    )
    mock_incr.assert_not_called()
def test_persist_notification_does_not_increment_cache_if_test_key(
        notify_db, notify_db_session, sample_template, sample_job, mocker):
    api_key = create_api_key(notify_db=notify_db,
                             notify_db_session=notify_db_session,
                             service=sample_template.service,
                             key_type='test')
    mocker.patch('app.notifications.process_notifications.redis_store.get',
                 return_value="cache")
    mocker.patch(
        'app.notifications.process_notifications.redis_store.get_all_from_hash',
        return_value="cache")
    daily_limit_cache = mocker.patch(
        'app.notifications.process_notifications.redis_store.incr')
    template_usage_cache = mocker.patch(
        'app.notifications.process_notifications.redis_store.increment_hash_value'
    )

    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
    persist_notification(
        template_id=sample_template.id,
        template_version=sample_template.version,
        recipient='+61412345678',
        service=sample_template.service,
        personalisation={},
        notification_type='sms',
        api_key_id=api_key.id,
        key_type=api_key.key_type,
        job_id=sample_job.id,
        job_row_number=100,
        reference="ref",
    )

    assert Notification.query.count() == 1

    assert not daily_limit_cache.called
    assert not template_usage_cache.called
Example #25
0
def test_should_delete_notification_and_recipient_identifiers_when_bulk_deleting(
        month, delete_run_time, notification_type, expected_count, sample_job,
        sample_api_key, mocker):
    mocker.patch(
        'app.notifications.process_notifications.accept_recipient_identifiers_enabled',
        return_value=True)
    # create one notification a day between 1st and 10th from 11:00 to 19:00 of each type
    for i in range(1, 11):
        past_date = '2016-0{0}-{1:02d}  {1:02d}:00:00.000000'.format(month, i)
        with freeze_time(past_date):
            recipient_identifier = {
                "id_type": IdentifierType.VA_PROFILE_ID.value,
                "id_value": "foo"
            }
            persist_notification(template_id=sample_job.template.id,
                                 template_version=sample_job.template.version,
                                 service=sample_job.service,
                                 personalisation=None,
                                 notification_type=notification_type,
                                 api_key_id=sample_api_key.id,
                                 key_type=sample_api_key.key_type,
                                 recipient_identifier=recipient_identifier,
                                 created_at=datetime.utcnow())

    assert Notification.query.count() == 10
    assert RecipientIdentifier.query.count() == 10

    # Records from before 3rd should be deleted
    with freeze_time(delete_run_time):
        delete_notifications_older_than_retention_by_type(notification_type)

    remaining_notifications = Notification.query.filter_by(
        notification_type=notification_type).all()
    assert len(remaining_notifications) == expected_count

    remaining_recipient_identifiers = len(RecipientIdentifier.query.all())
    assert remaining_recipient_identifiers == expected_count
Example #26
0
def send_letters_volume_email_to_dvla(letters_volumes, date):
    personalisation = {
        'total_volume': 0,
        'first_class_volume': 0,
        'second_class_volume': 0,
        'international_volume': 0,
        'total_sheets': 0,
        'first_class_sheets': 0,
        "second_class_sheets": 0,
        'international_sheets': 0,
        'date': date.strftime("%d %B %Y")
    }
    for item in letters_volumes:
        personalisation['total_volume'] += item.letters_count
        personalisation['total_sheets'] += item.sheets_count
        if f"{item.postage}_class_volume" in personalisation:
            personalisation[
                f"{item.postage}_class_volume"] = item.letters_count
            personalisation[f"{item.postage}_class_sheets"] = item.sheets_count
        else:
            personalisation["international_volume"] += item.letters_count
            personalisation["international_sheets"] += item.sheets_count

    template = dao_get_template_by_id(
        current_app.config['LETTERS_VOLUME_EMAIL_TEMPLATE_ID'])
    recipients = current_app.config['DVLA_EMAIL_ADDRESSES']
    reply_to = template.service.get_default_reply_to_email_address()
    service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID'])

    # avoid circular imports:
    from app.notifications.process_notifications import (
        persist_notification,
        send_notification_to_queue,
    )
    for recipient in recipients:
        saved_notification = persist_notification(
            template_id=template.id,
            template_version=template.version,
            recipient=recipient,
            service=service,
            personalisation=personalisation,
            notification_type=template.template_type,
            api_key_id=None,
            key_type=KEY_TYPE_NORMAL,
            reply_to_text=reply_to)

        send_notification_to_queue(saved_notification,
                                   False,
                                   queue=QueueNames.NOTIFY)
def test_persist_notification_creates_and_save_to_db(sample_template,
                                                     sample_api_key,
                                                     sample_job, mocker):
    mocked_redis = mocker.patch(
        'app.notifications.process_notifications.redis_store.get')

    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
    notification = persist_notification(
        template_id=sample_template.id,
        template_version=sample_template.version,
        recipient='+61412345678',
        service=sample_template.service,
        personalisation={},
        notification_type='sms',
        api_key_id=sample_api_key.id,
        key_type=sample_api_key.key_type,
        job_id=sample_job.id,
        job_row_number=100,
        reference="ref",
        reply_to_text=sample_template.service.get_default_sms_sender())

    assert Notification.query.get(notification.id) is not None
    assert NotificationHistory.query.get(notification.id) is not None

    notification_from_db = Notification.query.one()
    notification_history_from_db = NotificationHistory.query.one()

    assert notification_from_db.id == notification_history_from_db.id
    assert notification_from_db.template_id == notification_history_from_db.template_id
    assert notification_from_db.template_version == notification_history_from_db.template_version
    assert notification_from_db.api_key_id == notification_history_from_db.api_key_id
    assert notification_from_db.key_type == notification_history_from_db.key_type
    assert notification_from_db.key_type == notification_history_from_db.key_type
    assert notification_from_db.billable_units == notification_history_from_db.billable_units
    assert notification_from_db.notification_type == notification_history_from_db.notification_type
    assert notification_from_db.created_at == notification_history_from_db.created_at
    assert not notification_from_db.sent_at
    assert not notification_history_from_db.sent_at
    assert notification_from_db.updated_at == notification_history_from_db.updated_at
    assert notification_from_db.status == notification_history_from_db.status
    assert notification_from_db.reference == notification_history_from_db.reference
    assert notification_from_db.client_reference == notification_history_from_db.client_reference
    assert notification_from_db.created_by_id == notification_history_from_db.created_by_id
    assert notification_from_db.reply_to_text == sample_template.service.get_default_sms_sender(
    )

    mocked_redis.assert_called_once_with(
        str(sample_template.service_id) + "-2016-01-01-count")
Example #28
0
    def _send_notification(template_id, recipient, personalisation):
        template = dao_get_template_by_id(template_id)

        saved_notification = persist_notification(
            template_id=template.id,
            template_version=template.version,
            recipient=recipient,
            service=notify_service,
            personalisation=personalisation,
            notification_type=template.template_type,
            api_key_id=None,
            key_type=KEY_TYPE_NORMAL,
            reply_to_text=notify_service.get_default_reply_to_email_address()
        )
        send_notification_to_queue(saved_notification, research_mode=False, queue=QueueNames.NOTIFY)
Example #29
0
def test_persist_notification_for_international_letter(sample_letter_template, postage):
    notification = persist_notification(
        template_id=sample_letter_template.id,
        template_version=sample_letter_template.version,
        recipient="123 Main Street",
        service=sample_letter_template.service,
        personalisation=None,
        notification_type=sample_letter_template.template_type,
        api_key_id=None,
        key_type="normal",
        billable_units=3,
        postage=postage,
    )
    persisted_notification = Notification.query.get(notification.id)
    assert persisted_notification.postage == postage
    assert persisted_notification.international
Example #30
0
def save_sms(self,
             service_id,
             notification_id,
             encrypted_notification,
             api_key_id=None,
             key_type=KEY_TYPE_NORMAL):
    notification = encryption.decrypt(encrypted_notification)
    service = dao_fetch_service_by_id(service_id)
    template = dao_get_template_by_id(notification['template'], version=notification['template_version'])

    if not service_allowed_to_send_to(notification['to'], service, key_type):
        current_app.logger.debug(
            "SMS {} failed as restricted service".format(notification_id)
        )
        return

    try:
        saved_notification = persist_notification(
            template_id=notification['template'],
            template_version=notification['template_version'],
            recipient=notification['to'],
            service=service,
            personalisation=notification.get('personalisation'),
            notification_type=SMS_TYPE,
            api_key_id=api_key_id,
            key_type=key_type,
            created_at=datetime.utcnow(),
            job_id=notification.get('job', None),
            job_row_number=notification.get('row_number', None),
            notification_id=notification_id,
            reply_to_text=template.get_reply_to_text()
        )

        provider_tasks.deliver_sms.apply_async(
            [str(saved_notification.id)],
            queue=QueueNames.SEND_SMS if not service.research_mode else QueueNames.RESEARCH_MODE
        )

        current_app.logger.debug(
            "SMS {} created at {} for job {}".format(
                saved_notification.id,
                saved_notification.created_at,
                notification.get('job', None))
        )

    except SQLAlchemyError as e:
        handle_exception(self, notification, notification_id, e)
Example #31
0
def update_user_attribute(user_id):
    user_to_update = get_user_by_id(user_id=user_id)
    req_json = request.get_json()
    if 'updated_by' in req_json:
        updated_by = get_user_by_id(user_id=req_json.pop('updated_by'))
    else:
        updated_by = None

    update_dct, errors = user_update_schema_load_json.load(req_json)
    if errors:
        raise InvalidRequest(errors, status_code=400)
    save_user_attribute(user_to_update, update_dict=update_dct)
    if updated_by:
        if 'email_address' in update_dct:
            template = dao_get_template_by_id(
                current_app.config['TEAM_MEMBER_EDIT_EMAIL_TEMPLATE_ID'])
            recipient = user_to_update.email_address
            reply_to = template.service.get_default_reply_to_email_address()
        elif 'mobile_number' in update_dct:
            template = dao_get_template_by_id(
                current_app.config['TEAM_MEMBER_EDIT_MOBILE_TEMPLATE_ID'])
            recipient = user_to_update.mobile_number
            reply_to = template.service.get_default_sms_sender()
        else:
            return jsonify(data=user_to_update.serialize()), 200
        service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID'])

        saved_notification = persist_notification(
            template_id=template.id,
            template_version=template.version,
            recipient=recipient,
            service=service,
            personalisation={
                'name': user_to_update.name,
                'servicemanagername': updated_by.name,
                'email address': user_to_update.email_address
            },
            notification_type=template.template_type,
            api_key_id=None,
            key_type=KEY_TYPE_NORMAL,
            reply_to_text=reply_to)

        send_notification_to_queue(saved_notification,
                                   False,
                                   queue=QueueNames.NOTIFY)
    return jsonify(data=user_to_update.serialize()), 200
Example #32
0
def save_sms(self,
             service_id,
             notification_id,
             encrypted_notification,
             sender_id=None):
    notification = encryption.decrypt(encrypted_notification)
    service = dao_fetch_service_by_id(service_id)
    template = dao_get_template_by_id(notification['template'],
                                      version=notification['template_version'])

    if sender_id:
        reply_to_text = dao_get_service_sms_senders_by_id(
            service_id, sender_id).sms_sender
    else:
        reply_to_text = template.get_reply_to_text()

    if not service_allowed_to_send_to(notification['to'], service,
                                      KEY_TYPE_NORMAL):
        current_app.logger.debug(
            "SMS {} failed as restricted service".format(notification_id))
        return

    try:
        saved_notification = persist_notification(
            template_id=notification['template'],
            template_version=notification['template_version'],
            recipient=notification['to'],
            service=service,
            personalisation=notification.get('personalisation'),
            notification_type=SMS_TYPE,
            api_key_id=None,
            key_type=KEY_TYPE_NORMAL,
            created_at=datetime.utcnow(),
            job_id=notification.get('job', None),
            job_row_number=notification.get('row_number', None),
            notification_id=notification_id,
            reply_to_text=reply_to_text)

        send_notification_to_queue(saved_notification, service.research_mode)

        current_app.logger.debug("SMS {} created at {} for job {}".format(
            saved_notification.id, saved_notification.created_at,
            notification.get('job', None)))

    except SQLAlchemyError as e:
        handle_exception(self, notification, notification_id, e)
def test_exception_thown_by_redis_store_get_should_not_be_fatal(sample_template, sample_api_key, mocker):
    mocker.patch(
        'app.notifications.process_notifications.redis_store.redis_store.incr',
        side_effect=Exception("broken redis"))

    notification = persist_notification(
        sample_template.id,
        sample_template.version,
        '+447111111111',
        sample_template.service.id,
        {},
        'sms',
        sample_api_key.id,
        sample_api_key.key_type)
    assert Notification.query.count() == 1
    assert Notification.query.get(notification.id) is not None
    assert NotificationHistory.query.count() == 1
Example #34
0
def send_notification_to_notify_support(template_id, personalisation=None):
    personalisation = personalisation or {}
    template = dao_get_template_by_id(template_id)
    notify_service = dao_fetch_service_by_id(current_app.config['NOTIFY_SERVICE_ID'])

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

    notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=current_app.config['NOTIFY_SUPPORT_EMAIL'],
        service=notify_service,
        personalisation=personalisation,
        notification_type=template.template_type,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        reply_to_text=notify_service.get_default_reply_to_email_address()
    )
    send_notification_to_queue(notification, False, queue=QueueNames.NOTIFY)
def test_persist_notification_should_not_persist_recipient_identifier_if_none_present_or_toggle_off(
        notify_db, recipient_identifiers_enabled, recipient_identifier,
        sample_job, sample_api_key, mocker):
    mocker.patch(
        'app.notifications.process_notifications.accept_recipient_identifiers_enabled',
        return_value=recipient_identifiers_enabled)

    notification = persist_notification(
        template_id=sample_job.template.id,
        template_version=sample_job.template.version,
        service=sample_job.service,
        personalisation=None,
        notification_type='email',
        api_key_id=sample_api_key.id,
        key_type=sample_api_key.key_type,
        job_id=sample_job.id,
        recipient_identifier=recipient_identifier)

    assert RecipientIdentifier.query.count() == 0
    assert notification.recipient_identifiers == {}
Example #36
0
def verify_reply_to_email_address(service_id):
    email_address, errors = email_data_request_schema.load(request.get_json())
    check_if_reply_to_address_already_in_use(service_id, email_address["email"])
    template = dao_get_template_by_id(current_app.config['REPLY_TO_EMAIL_ADDRESS_VERIFICATION_TEMPLATE_ID'])
    notify_service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID'])
    saved_notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=email_address["email"],
        service=notify_service,
        personalisation='',
        notification_type=template.template_type,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        reply_to_text=notify_service.get_default_reply_to_email_address()
    )

    send_notification_to_queue(saved_notification, False, queue=QueueNames.NOTIFY)

    return jsonify(data={"id": saved_notification.id}), 201
Example #37
0
def test_persist_notification_creates_and_save_to_db(sample_template,
                                                     sample_api_key,
                                                     sample_job):

    assert Notification.query.count() == 0
    assert NotificationHistory.query.count() == 0
    notification = persist_notification(
        template_id=sample_template.id,
        template_version=sample_template.version,
        recipient='+447111111111',
        service=sample_template.service,
        personalisation={},
        notification_type='sms',
        api_key_id=sample_api_key.id,
        key_type=sample_api_key.key_type,
        job_id=sample_job.id,
        job_row_number=100,
        reference="ref",
        reply_to_text=sample_template.service.get_default_sms_sender())

    assert Notification.query.get(notification.id) is not None

    notification_from_db = Notification.query.one()

    assert notification_from_db.id == notification.id
    assert notification_from_db.template_id == notification.template_id
    assert notification_from_db.template_version == notification.template_version
    assert notification_from_db.api_key_id == notification.api_key_id
    assert notification_from_db.key_type == notification.key_type
    assert notification_from_db.key_type == notification.key_type
    assert notification_from_db.billable_units == notification.billable_units
    assert notification_from_db.notification_type == notification.notification_type
    assert notification_from_db.created_at == notification.created_at
    assert not notification_from_db.sent_at
    assert notification_from_db.updated_at == notification.updated_at
    assert notification_from_db.status == notification.status
    assert notification_from_db.reference == notification.reference
    assert notification_from_db.client_reference == notification.client_reference
    assert notification_from_db.created_by_id == notification.created_by_id
    assert notification_from_db.reply_to_text == sample_template.service.get_default_sms_sender(
    )
Example #38
0
def invite_user_to_org(organisation_id):
    data = request.get_json()
    validate(data, post_create_invited_org_user_status_schema)

    invited_org_user = InvitedOrganisationUser(
        email_address=data["email_address"],
        invited_by_id=data["invited_by"],
        organisation_id=organisation_id,
    )
    save_invited_org_user(invited_org_user)

    template = dao_get_template_by_id(
        current_app.config["ORGANISATION_INVITATION_EMAIL_TEMPLATE_ID"])

    saved_notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=invited_org_user.email_address,
        service=template.service,
        personalisation={
            "user_name":
            invited_org_user.invited_by.name,
            "organisation_name":
            invited_org_user.organisation.name,
            "url":
            invited_org_user_url(
                invited_org_user.id,
                data.get("invite_link_host"),
            ),
        },
        notification_type=EMAIL_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        reply_to_text=invited_org_user.invited_by.email_address,
    )

    send_notification_to_queue(saved_notification,
                               research_mode=False,
                               queue=QueueNames.NOTIFY)

    return jsonify(data=invited_org_user.serialize()), 201
Example #39
0
def invite_user_to_org(organisation_id):
    data = request.get_json()
    validate(data, post_create_invited_org_user_status_schema)

    invited_org_user = InvitedOrganisationUser(
        email_address=data['email_address'],
        invited_by_id=data['invited_by'],
        organisation_id=organisation_id)
    save_invited_org_user(invited_org_user)

    template = dao_get_template_by_id(
        current_app.config['ORGANISATION_INVITATION_EMAIL_TEMPLATE_ID'])

    saved_notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=invited_org_user.email_address,
        service=template.service,
        personalisation={
            'user_name': ('The Catalyst Notify team'
                          if invited_org_user.invited_by.platform_admin else
                          invited_org_user.invited_by.name),
            'organisation_name':
            invited_org_user.organisation.name,
            'url':
            invited_org_user_url(
                invited_org_user.id,
                data.get('invite_link_host'),
            ),
        },
        notification_type=EMAIL_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        reply_to_text=invited_org_user.invited_by.email_address)

    send_notification_to_queue(saved_notification,
                               research_mode=False,
                               queue=QueueNames.NOTIFY)

    return jsonify(data=invited_org_user.serialize()), 201
Example #40
0
def create_invited_user(service_id):
    request_json = request.get_json()
    invited_user, errors = invited_user_schema.load(request_json)
    save_invited_user(invited_user)

    if invited_user.service.has_permission(BROADCAST_TYPE):
        template_id = current_app.config[
            'BROADCAST_INVITATION_EMAIL_TEMPLATE_ID']
    else:
        template_id = current_app.config['INVITATION_EMAIL_TEMPLATE_ID']

    template = dao_get_template_by_id(template_id)
    service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID'])

    saved_notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=invited_user.email_address,
        service=service,
        personalisation={
            'user_name':
            invited_user.from_user.name,
            'service_name':
            invited_user.service.name,
            'url':
            invited_user_url(
                invited_user.id,
                request_json.get('invite_link_host'),
            ),
        },
        notification_type=EMAIL_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        reply_to_text=invited_user.from_user.email_address)

    send_notification_to_queue(saved_notification,
                               False,
                               queue=QueueNames.NOTIFY)

    return jsonify(data=invited_user_schema.dump(invited_user).data), 201
Example #41
0
def send_user_email_verification(user_id):
    user_to_send_to = get_user_by_id(user_id=user_id)
    secret_code = create_secret_code()
    create_user_code(user_to_send_to, secret_code, 'email')

    template = dao_get_template_by_id(current_app.config['EMAIL_VERIFY_CODE_TEMPLATE_ID'])

    saved_notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=user_to_send_to.email_address,
        service_id=current_app.config['NOTIFY_SERVICE_ID'],
        personalisation={
            'name': user_to_send_to.name,
            'url': _create_verification_url(user_to_send_to, secret_code)
        },
        notification_type=EMAIL_TYPE,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL
    )

    send_notification_to_queue(saved_notification, False, queue="notify")

    return jsonify({}), 204