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,
        template_postage=template.postage,
        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),
    )

    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)}
示例#2
0
def test_rejects_api_calls_with_international_numbers_if_service_does_not_allow_int_sms(
        key_type,
        notify_db_session,
):
    service = create_service(service_permissions=[SMS_TYPE])
    with pytest.raises(BadRequestError) as e:
        validate_and_format_recipient('+20-12-1234-1234', key_type, service, SMS_TYPE)
    assert e.value.status_code == 400
    assert e.value.message == 'Cannot send to international mobile numbers'
    assert e.value.fields == []
示例#3
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_safelisted_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,
        template_postage=template.postage,
        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),
    )

    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=template.queue_to_use(),
        )

    return {"id": str(notification.id)}
def test_allows_api_calls_with_international_numbers_if_service_does_allow_int_sms(
        key_type, notify_db, notify_db_session):
    service = create_service(notify_db,
                             notify_db_session,
                             permissions=[SMS_TYPE, INTERNATIONAL_SMS_TYPE])
    result = validate_and_format_recipient("+20-12-1234-1234", key_type,
                                           service, SMS_TYPE)
    assert result == "+201212341234"
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)

    additional_email_parameters = {"importance": form.get('importance', None), "cc_address": form.get('cc_address', None)} \
        if notification_type == EMAIL_TYPE else {}

    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,
        additional_email_parameters=additional_email_parameters)

    scheduled_for = form.get("scheduled_for", None)
    if scheduled_for:
        persist_scheduled_notification(notification.id, form["scheduled_for"])
    else:
        if not simulated:
            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)
        else:
            current_app.logger.debug(
                "POST simulated notification for id: {}".format(
                    notification.id))

    return notification
示例#6
0
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)

    notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=form_send_to,
        service=service,
        personalisation=form.get('personalisation', None),
        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,
        status_callback_url=form.get('status_callback_url', None),
        status_callback_bearer_token=form.get('status_callback_bearer_token',
                                              None),
    )

    scheduled_for = form.get("scheduled_for", None)
    if scheduled_for:
        persist_scheduled_notification(notification.id, form["scheduled_for"])
    else:
        if not simulated:
            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)
        else:
            current_app.logger.debug(
                "POST simulated notification for id: {}".format(
                    notification.id))

    return notification
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)}
示例#8
0
def test_rejects_api_calls_with_no_recipient():
    with pytest.raises(BadRequestError) as e:
        validate_and_format_recipient(None, 'key_type', 'service', 'SMS_TYPE')
    assert e.value.status_code == 400
    assert e.value.message == "Recipient can't be empty"
示例#9
0
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, template.id)

    notification = {
        "id": create_uuid(),
        "template": str(template.id),
        "template_version": str(template.version),
        "to": form_send_to,
        "personalisation": personalisation,
        "simulated": simulated,
        "api_key": str(api_key.id),
        "key_type": str(api_key.key_type),
        "client_reference": form.get("reference", None),
    }

    encrypted_notification_data = encryption.encrypt(notification)

    scheduled_for = form.get("scheduled_for", None)
    if scheduled_for:
        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,
        )
        persist_scheduled_notification(notification.id, form["scheduled_for"])

    elif current_app.config["FF_NOTIFICATION_CELERY_PERSISTENCE"] and not simulated:
        # depending on the type route to the appropriate save task
        if notification_type == EMAIL_TYPE:
            current_app.logger.info("calling save email task")
            save_email.apply_async(
                (authenticated_service.id, create_uuid(), encrypted_notification_data),
                queue=QueueNames.DATABASE if not authenticated_service.research_mode else QueueNames.RESEARCH_MODE,
            )
        elif notification_type == SMS_TYPE:
            save_sms.apply_async(
                (authenticated_service.id, create_uuid(), encrypted_notification_data),
                queue=QueueNames.DATABASE if not authenticated_service.research_mode else QueueNames.RESEARCH_MODE,
            )

    else:
        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,
        )
        if not simulated:
            send_notification_to_queue(
                notification=notification,
                research_mode=service.research_mode,
                queue=template.queue_to_use(),
            )
        else:
            current_app.logger.debug("POST simulated notification for id: {}".format(notification.id))

    if not isinstance(notification, Notification):
        notification["template_id"] = notification["template"]
        notification["api_key_id"] = notification["api_key"]
        notification["template_version"] = template.version
        notification["service"] = service
        notification["service_id"] = service.id
        notification["reply_to_text"] = reply_to_text
        del notification["template"]
        del notification["api_key"]
        del notification["simulated"]
        notification = Notification(**notification)

    return notification
示例#10
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_guest_list_recipients=False,
    )
    postage = None
    client_reference = 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
        from app.utils import get_reference_from_personalisation
        client_reference = get_reference_from_personalisation(personalisation)

    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,
        client_reference=client_reference
    )

    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 process_sms_or_email_notification(*,
                                      form,
                                      notification_type,
                                      api_key,
                                      template,
                                      service,
                                      reply_to_text=None):
    notification_id = 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, document_download_count = process_document_uploads(
        form.get('personalisation'), service, simulated=simulated)

    if str(service.id) in current_app.config.get('HIGH_VOLUME_SERVICE') and api_key.key_type == KEY_TYPE_NORMAL \
       and notification_type == EMAIL_TYPE:
        # Put GOV.UK Email notifications onto a queue
        # To take the pressure off the db for API requests put the notification for our high volume service onto a queue
        # the task will then save the notification, then call send_notification_to_queue.
        # We know that this team does not use the GET request, but relies on callbacks to get the status updates.
        try:
            notification_id = uuid.uuid4()
            notification = save_email_to_queue(
                form=form,
                notification_id=str(notification_id),
                notification_type=notification_type,
                api_key=api_key,
                template=template,
                service_id=service.id,
                personalisation=personalisation,
                document_download_count=document_download_count,
                reply_to_text=reply_to_text)
            return notification
        except SQSError:
            # if SQS cannot put the task on the queue, it's probably because the notification body was too long and it
            # went over SQS's 256kb message limit. If so, we
            current_app.logger.info(
                f'Notification {notification_id} failed to save to high volume queue. Using normal flow instead'
            )

    notification = persist_notification(
        notification_id=notification_id,
        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,
        document_download_count=document_download_count)

    scheduled_for = form.get("scheduled_for", None)
    if scheduled_for:
        persist_scheduled_notification(notification.id, form["scheduled_for"])
    else:
        if not simulated:
            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)
        else:
            current_app.logger.debug(
                "POST simulated notification for id: {}".format(
                    notification.id))

    return notification
示例#12
0
def process_sms_or_email_notification(
    *,
    form,
    notification_type,
    template,
    template_with_content,
    template_process_type,
    service,
    reply_to_text=None,
):
    notification_id = uuid.uuid4()
    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_user.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, document_download_count = process_document_uploads(
        form.get('personalisation'), service, simulated=simulated)
    if document_download_count:
        # We changed personalisation which means we need to update the content
        template_with_content.values = personalisation

    # validate content length after url is replaced in personalisation.
    check_is_message_too_long(template_with_content)

    resp = create_response_for_post_notification(
        notification_id=notification_id,
        client_reference=form.get('reference', None),
        template_id=template.id,
        template_version=template.version,
        service_id=service.id,
        notification_type=notification_type,
        reply_to=reply_to_text,
        template_with_content=template_with_content)

    if service.id in current_app.config.get('HIGH_VOLUME_SERVICE') \
        and api_user.key_type == KEY_TYPE_NORMAL \
            and notification_type in [EMAIL_TYPE, SMS_TYPE]:
        # Put service with high volumes of notifications onto a queue
        # To take the pressure off the db for API requests put the notification for our high volume service onto a queue
        # the task will then save the notification, then call send_notification_to_queue.
        # NOTE: The high volume service should be aware that the notification is not immediately
        # available by a GET request, it is recommend they use callbacks to keep track of status updates.
        try:
            save_email_or_sms_to_queue(
                form=form,
                notification_id=str(notification_id),
                notification_type=notification_type,
                api_key=api_user,
                template=template,
                service_id=service.id,
                personalisation=personalisation,
                document_download_count=document_download_count,
                reply_to_text=reply_to_text)
            return resp
        except SQSError:
            # if SQS cannot put the task on the queue, it's probably because the notification body was too long and it
            # went over SQS's 256kb message limit. If so, we
            current_app.logger.info(
                f'Notification {notification_id} failed to save to high volume queue. Using normal flow instead'
            )

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

    if not simulated:
        queue_name = QueueNames.PRIORITY if template_process_type == PRIORITY else None
        send_notification_to_queue_detached(
            key_type=api_user.key_type,
            notification_type=notification_type,
            notification_id=notification_id,
            research_mode=service.research_mode,  # research_mode is deprecated
            queue=queue_name)
    else:
        current_app.logger.debug(
            "POST simulated notification for id: {}".format(notification_id))

    return resp
示例#13
0
def test_allows_api_calls_with_international_numbers_if_service_does_allow_int_sms(
        key_type, sample_service_full_permissions):
    service_model = SerialisedService.from_id(sample_service_full_permissions.id)
    result = validate_and_format_recipient('20-12-1234-1234', key_type, service_model, SMS_TYPE)
    assert result == '201212341234'
示例#14
0
def test_allows_api_calls_with_international_numbers_if_service_does_allow_int_sms(
        key_type, sample_service_full_permissions):
    result = validate_and_format_recipient('+20-12-1234-1234', key_type, sample_service_full_permissions, SMS_TYPE)
    assert result == '+201212341234'