Ejemplo n.º 1
0
def test_get_notification_from_different_api_key_of_same_type_succeeds(client, sample_notification, key_type):
    creation_api_key = ApiKey(service=sample_notification.service,
                              name='creation_api_key',
                              created_by=sample_notification.service.created_by,
                              key_type=key_type)
    save_model_api_key(creation_api_key)

    querying_api_key = ApiKey(service=sample_notification.service,
                              name='querying_api_key',
                              created_by=sample_notification.service.created_by,
                              key_type=key_type)
    save_model_api_key(querying_api_key)

    sample_notification.api_key = creation_api_key
    sample_notification.key_type = key_type
    dao_update_notification(sample_notification)

    response = client.get(
        path='/notifications/{}'.format(sample_notification.id),
        headers=_create_auth_header_from_key(querying_api_key))

    assert response.status_code == 200
    notification = json.loads(response.get_data(as_text=True))['data']['notification']
    assert sample_notification.api_key_id != querying_api_key.id
    assert notification['id'] == str(sample_notification.id)
def send_sms_to_provider(notification):
    service = dao_fetch_service_by_id(notification.service_id)
    provider = provider_to_use(SMS_TYPE, notification.id)
    if notification.status == 'created':
        template_model = dao_get_template_by_id(notification.template_id, notification.template_version)
        template = SMSMessageTemplate(
            template_model.__dict__,
            values=notification.personalisation,
            prefix=service.name,
            sender=service.sms_sender
        )
        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            send_sms_response.apply_async(
                (provider.get_name(), str(notification.id), notification.to), queue='research-mode'
            )
            notification.billable_units = 0
        else:
            provider.send_sms(
                to=validate_and_format_phone_number(notification.to),
                content=str(template),
                reference=str(notification.id),
                sender=service.sms_sender
            )
            notification.billable_units = template.fragment_count

        notification.sent_at = datetime.utcnow()
        notification.sent_by = provider.get_name()
        notification.status = 'sending'
        dao_update_notification(notification)

        current_app.logger.info(
            "SMS {} sent to provider at {}".format(notification.id, notification.sent_at)
        )
        delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000
        statsd_client.timing("sms.total-time", delta_milliseconds)
Ejemplo n.º 3
0
def malware_failure(notification):
    notification.status = NOTIFICATION_VIRUS_SCAN_FAILED
    dao_update_notification(notification)
    raise NotificationTechnicalFailureException(
        "Send {} for notification id {} to provider is not allowed. Notification contains malware".format(
            notification.notification_type,
            notification.id))
def create_letters_pdf(self, notification_id):
    try:
        notification = get_notification_by_id(notification_id, _raise=True)
        pdf_data, billable_units = get_letters_pdf(
            notification.template,
            contact_block=notification.reply_to_text,
            filename=notification.service.letter_branding
            and notification.service.letter_branding.filename,
            values=notification.personalisation)

        upload_letter_pdf(notification, pdf_data)

        if notification.key_type != KEY_TYPE_TEST:
            notification.billable_units = billable_units
            dao_update_notification(notification)

        current_app.logger.info(
            'Letter notification reference {reference}: billable units set to {billable_units}'
            .format(reference=str(notification.reference),
                    billable_units=billable_units))

    except (RequestException, BotoClientError):
        try:
            current_app.logger.exception(
                "Letters PDF notification creation for id: {} failed".format(
                    notification_id))
            self.retry(queue=QueueNames.RETRY)
        except MaxRetriesExceededError:
            current_app.logger.error(
                "RETRY FAILED: task create_letters_pdf failed for notification {}"
                .format(notification_id), )
            update_notification_status_by_id(notification_id,
                                             'technical-failure')
Ejemplo n.º 5
0
def test_get_notification_from_different_api_key_of_same_type_succeeds(notify_api, sample_notification, key_type):
    with notify_api.test_request_context(), notify_api.test_client() as client:
        creation_api_key = ApiKey(service=sample_notification.service,
                                  name='creation_api_key',
                                  created_by=sample_notification.service.created_by,
                                  key_type=key_type)
        save_model_api_key(creation_api_key)

        querying_api_key = ApiKey(service=sample_notification.service,
                                  name='querying_api_key',
                                  created_by=sample_notification.service.created_by,
                                  key_type=key_type)
        save_model_api_key(querying_api_key)

        sample_notification.api_key = creation_api_key
        sample_notification.key_type = key_type
        dao_update_notification(sample_notification)

        response = client.get(
            path='/notifications/{}'.format(sample_notification.id),
            headers=_create_auth_header_from_key(querying_api_key))

        assert response.status_code == 200
        notification = json.loads(response.get_data(as_text=True))['data']['notification']
        assert sample_notification.api_key_id != querying_api_key.id
        assert notification['id'] == str(sample_notification.id)
def technical_failure(notification):
    notification.status = NOTIFICATION_TECHNICAL_FAILURE
    dao_update_notification(notification)
    raise NotificationTechnicalFailureException(
        "Send {} for notification id {} to provider is not allowed: service {} is inactive"
        .format(notification.notification_type, notification.id,
                notification.service_id))
Ejemplo n.º 7
0
def process_precompiled_letter_notifications(*, letter_data, api_key, template, reply_to_text):
    try:
        status = NOTIFICATION_PENDING_VIRUS_CHECK
        letter_content = base64.b64decode(letter_data['content'])
        pages = pdf_page_count(io.BytesIO(letter_content))
    except ValueError:
        raise BadRequestError(message='Cannot decode letter content (invalid base64 encoding)', status_code=400)
    except PdfReadError:
        current_app.logger.exception(msg='Invalid PDF received')
        raise BadRequestError(message='Letter content is not a valid PDF', status_code=400)

    notification = create_letter_notification(letter_data=letter_data,
                                              template=template,
                                              api_key=api_key,
                                              status=status,
                                              reply_to_text=reply_to_text)

    filename = upload_letter_pdf(notification, letter_content, precompiled=True)
    pages_per_sheet = 2
    notification.billable_units = math.ceil(pages / pages_per_sheet)

    dao_update_notification(notification)

    current_app.logger.info('Calling task scan-file for {}'.format(filename))

    # call task to add the filename to anti virus queue
    notify_celery.send_task(
        name=TaskNames.SCAN_FILE,
        kwargs={'filename': filename},
        queue=QueueNames.ANTIVIRUS,
    )

    return notification
Ejemplo n.º 8
0
def update_notification_to_sending(notification, provider):
    notification.sent_at = datetime.utcnow()
    notification.sent_by = provider.get_name()
    # We currently have no callback method for SNS
    # notification.status = NOTIFICATION_SENT if notification.international else NOTIFICATION_SENDING
    notification.status = NOTIFICATION_SENT if notification.notification_type == "sms" else NOTIFICATION_SENDING
    dao_update_notification(notification)
Ejemplo n.º 9
0
def update_notification(notification, provider, international=False):
    notification.sent_at = datetime.utcnow()
    notification.sent_by = provider.get_name()
    if international:
        notification.status = NOTIFICATION_SENT
    else:
        notification.status = NOTIFICATION_SENDING
    dao_update_notification(notification)
Ejemplo n.º 10
0
def fail_pii(notification, pii_type):
    notification.status = NOTIFICATION_CONTAINS_PII
    dao_update_notification(notification)
    raise NotificationTechnicalFailureException(
        "Send {} for notification id {} to provider is not allowed. Notification contains PII: {}".format(
            notification.notification_type,
            notification.id,
            pii_type))
Ejemplo n.º 11
0
def update_notification(notification, provider, status=None):
    notification.sent_at = datetime.utcnow()
    notification.sent_by = provider.get_name()
    if status is not None:
        notification.status = status
    else:
        notification.status = NOTIFICATION_SENDING
    dao_update_notification(notification)
def lookup_va_profile_id(self, notification_id):
    current_app.logger.info(
        f"Retrieving VA Profile ID from MPI for notification {notification_id}"
    )
    notification = notifications_dao.get_notification_by_id(notification_id)

    try:
        va_profile_id = mpi_client.get_va_profile_id(notification)
        notification.recipient_identifiers.set(
            RecipientIdentifier(notification_id=notification.id,
                                id_type=IdentifierType.VA_PROFILE_ID.value,
                                id_value=va_profile_id))
        notifications_dao.dao_update_notification(notification)
        current_app.logger.info(
            f"Successfully updated notification {notification_id} with VA PROFILE ID {va_profile_id}"
        )

    except MpiRetryableException as e:
        current_app.logger.warning(
            f"Received {str(e)} for notification {notification_id}.")
        try:
            self.retry(queue=QueueNames.RETRY)
        except self.MaxRetriesExceededError:
            message = "RETRY FAILED: Max retries reached. " \
                      f"The task lookup_va_profile_id failed for notification {notification_id}. " \
                      "Notification has been updated to technical-failure"

            notifications_dao.update_notification_status_by_id(
                notification_id,
                NOTIFICATION_TECHNICAL_FAILURE,
                status_reason=e.failure_reason)
            raise NotificationTechnicalFailureException(message) from e

    except (BeneficiaryDeceasedException, IdentifierNotFound,
            MultipleActiveVaProfileIdsException) as e:
        message = f"{e.__class__.__name__} - {str(e)}: " \
                  f"Can't proceed after querying MPI for VA Profile ID for {notification_id}. " \
                  "Stopping execution of following tasks. Notification has been updated to permanent-failure."
        current_app.logger.warning(message)
        self.request.chain = None
        notifications_dao.update_notification_status_by_id(
            notification_id,
            NOTIFICATION_PERMANENT_FAILURE,
            status_reason=e.failure_reason)

    except Exception as e:
        message = f"Failed to retrieve VA Profile ID from MPI for notification: {notification_id} " \
                  "Notification has been updated to technical-failure"
        current_app.logger.exception(message)

        status_reason = e.failure_reason if hasattr(
            e, 'failure_reason') else 'Unknown error from MPI'
        notifications_dao.update_notification_status_by_id(
            notification_id,
            NOTIFICATION_TECHNICAL_FAILURE,
            status_reason=status_reason)
        raise NotificationTechnicalFailureException(message) from e
Ejemplo n.º 13
0
def send_sms_to_provider(notification):
    service = notification.service

    if not service.active:
        technical_failure(notification=notification)
        return

    if notification.status == "created":
        provider = provider_to_use(
            SMS_TYPE,
            notification.id,
            notification.international,
            notification.reply_to_text,
        )

        template_dict = dao_get_template_by_id(
            notification.template_id, notification.template_version).__dict__

        template = SMSMessageTemplate(
            template_dict,
            values=notification.personalisation,
            prefix=service.name,
            show_prefix=service.prefix_sms,
        )

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.reference = send_sms_response(provider.get_name(),
                                                       notification.to)
            update_notification_to_sending(notification, provider)

        else:
            try:
                reference = provider.send_sms(
                    to=validate_and_format_phone_number(
                        notification.to,
                        international=notification.international),
                    content=str(template),
                    reference=str(notification.id),
                    sender=notification.reply_to_text,
                )
            except Exception as e:
                notification.billable_units = template.fragment_count
                dao_update_notification(notification)
                dao_toggle_sms_provider(provider.name)
                raise e
            else:
                notification.reference = reference
                notification.billable_units = template.fragment_count
                update_notification_to_sending(notification, provider)

        # Record StatsD stats to compute SLOs
        statsd_client.timing_with_dates("sms.total-time", notification.sent_at,
                                        notification.created_at)
        statsd_key = f"sms.process_type-{template_dict['process_type']}"
        statsd_client.timing_with_dates(statsd_key, notification.sent_at,
                                        notification.created_at)
        statsd_client.incr(statsd_key)
Ejemplo n.º 14
0
def send_sms_to_provider(notification):
    service = notification.service

    if not service.active:
        technical_failure(notification=notification)
        return

    if notification.status == 'created':
        provider = provider_to_use(SMS_TYPE, notification.international)

        template_model = dao_get_template_by_id(notification.template_id,
                                                notification.template_version)

        template = SMSMessageTemplate(
            template_model.__dict__,
            values=notification.personalisation,
            prefix=service.name,
            show_prefix=service.prefix_sms,
        )

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            update_notification_to_sending(notification, provider)
            send_sms_response(provider.get_name(), str(notification.id),
                              notification.to)

        else:
            try:
                provider.send_sms(to=validate_and_format_phone_number(
                    notification.to, international=notification.international),
                                  content=str(template),
                                  reference=str(notification.id),
                                  sender=notification.reply_to_text)
            except Exception as e:
                notification.billable_units = template.fragment_count
                dao_update_notification(notification)
                dao_reduce_sms_provider_priority(
                    provider.get_name(), time_threshold=timedelta(minutes=1))
                raise e
            else:
                notification.billable_units = template.fragment_count
                update_notification_to_sending(notification, provider)

        delta_seconds = (datetime.utcnow() -
                         notification.created_at).total_seconds()
        statsd_client.timing("sms.total-time", delta_seconds)

        if notification.key_type == KEY_TYPE_TEST:
            statsd_client.timing("sms.test-key.total-time", delta_seconds)
        else:
            statsd_client.timing("sms.live-key.total-time", delta_seconds)
            if str(service.id) in current_app.config.get(
                    'HIGH_VOLUME_SERVICE'):
                statsd_client.timing("sms.live-key.high-volume.total-time",
                                     delta_seconds)
            else:
                statsd_client.timing("sms.live-key.not-high-volume.total-time",
                                     delta_seconds)
Ejemplo n.º 15
0
def send_sms_to_provider(notification):
    service = notification.service

    if not service.active:
        technical_failure(notification=notification)
        return

    if notification.status == 'created':
        provider = provider_to_use(SMS_TYPE, notification.id,
                                   notification.international)
        current_app.logger.debug(
            "Starting sending SMS {} to provider at {}".format(
                notification.id, datetime.utcnow()))
        template_model = dao_get_template_by_id(notification.template_id,
                                                notification.template_version)

        template = SMSMessageTemplate(
            template_model.__dict__,
            values=notification.personalisation,
            prefix=service.name,
            show_prefix=service.prefix_sms,
        )

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.billable_units = 0
            update_notification(notification, provider)
            try:
                send_sms_response(provider.get_name(), str(notification.id),
                                  notification.to)
            except HTTPError:
                # when we retry, we only do anything if the notification is in created - it's currently in sending,
                # so set it back so that we actually attempt the callback again
                notification.sent_at = None
                notification.sent_by = None
                notification.status = NOTIFICATION_CREATED
                dao_update_notification(notification)
                raise
        else:
            try:
                provider.send_sms(to=validate_and_format_phone_number(
                    notification.to, international=notification.international),
                                  content=str(template),
                                  reference=str(notification.id),
                                  sender=notification.reply_to_text)
            except Exception as e:
                dao_toggle_sms_provider(provider.name)
                raise e
            else:
                notification.billable_units = template.fragment_count
                update_notification(notification, provider,
                                    notification.international)

        current_app.logger.debug("SMS {} sent to provider {} at {}".format(
            notification.id, provider.get_name(), notification.sent_at))
        delta_milliseconds = (datetime.utcnow() -
                              notification.created_at).total_seconds() * 1000
        statsd_client.timing("sms.total-time", delta_milliseconds)
def test_updating_notification_updates_notification_history(sample_notification):
    hist = NotificationHistory.query.one()
    assert hist.id == sample_notification.id
    assert hist.status == 'created'

    sample_notification.status = 'sending'
    dao_update_notification(sample_notification)

    hist = NotificationHistory.query.one()
    assert hist.id == sample_notification.id
    assert hist.status == 'sending'
Ejemplo n.º 17
0
def update_billable_units_for_letter(self, notification_id, page_count):
    notification = get_notification_by_id(notification_id, _raise=True)

    billable_units = get_billable_units_for_letter_page_count(page_count)

    if notification.key_type != KEY_TYPE_TEST:
        notification.billable_units = billable_units
        dao_update_notification(notification)

        current_app.logger.info(
            f"Letter notification id: {notification_id} reference {notification.reference}: "
            f"billable units set to {billable_units}")
def send_sms_to_provider(notification):
    service = notification.service

    if not service.active:
        technical_failure(notification=notification)
        return

    if notification.status == 'created':
        provider = provider_to_use(SMS_TYPE, notification,
                                   notification.international)

        template_model = dao_get_template_by_id(notification.template_id,
                                                notification.template_version)

        template = SMSMessageTemplate(
            template_model.__dict__,
            values=notification.personalisation,
            prefix=service.name,
            show_prefix=service.prefix_sms,
        )

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.reference = create_uuid()
            update_notification_to_sending(notification, provider)
            send_sms_response(provider.get_name(), str(notification.id),
                              notification.to, notification.reference)

        else:
            try:
                reference = provider.send_sms(
                    to=validate_and_format_phone_number(
                        notification.to,
                        international=notification.international),
                    content=str(template),
                    reference=str(notification.id),
                    sender=notification.reply_to_text)
            except Exception as e:
                notification.billable_units = template.fragment_count
                dao_update_notification(notification)
                dao_toggle_sms_provider(provider.name)
                raise e
            else:
                notification.billable_units = template.fragment_count
                notification.reference = reference
                update_notification_to_sending(notification, provider)
                current_app.logger.info(
                    f"Saved provider reference: {reference} for notification id: {notification.id}"
                )

        delta_milliseconds = (datetime.utcnow() -
                              notification.created_at).total_seconds() * 1000
        statsd_client.timing("sms.total-time", delta_milliseconds)
Ejemplo n.º 19
0
def lookup_contact_info(self, notification_id):
    current_app.logger.info(
        f"Looking up contact information for notification_id:{notification_id}."
    )

    notification = get_notification_by_id(notification_id)

    va_profile_id = notification.recipient_identifiers[
        IdentifierType.VA_PROFILE_ID.value].id_value

    try:
        if EMAIL_TYPE == notification.notification_type:
            recipient = va_profile_client.get_email(va_profile_id)
        elif SMS_TYPE == notification.notification_type:
            recipient = va_profile_client.get_telephone(va_profile_id)
        else:
            raise NotImplementedError(
                f"The task lookup_contact_info failed for notification {notification_id}. "
                f"{notification.notification_type} is not supported")

    except VAProfileRetryableException as e:
        current_app.logger.exception(e)
        try:
            self.retry(queue=QueueNames.RETRY)
        except self.MaxRetriesExceededError:
            message = "RETRY FAILED: Max retries reached. " \
                      f"The task lookup_contact_info failed for notification {notification_id}. " \
                      "Notification has been updated to technical-failure"
            update_notification_status_by_id(notification_id,
                                             NOTIFICATION_TECHNICAL_FAILURE)
            raise NotificationTechnicalFailureException(message) from e

    except NoContactInfoException as e:
        message = f"{e.__class__.__name__} - {str(e)}: " \
                  f"Can't proceed after querying VA Profile for contact information for {notification_id}. " \
                  "Stopping execution of following tasks. Notification has been updated to permanent-failure."
        current_app.logger.warning(message)
        self.request.chain = None
        update_notification_status_by_id(notification_id,
                                         NOTIFICATION_PERMANENT_FAILURE)

    except VAProfileNonRetryableException as e:
        current_app.logger.exception(e)
        message = f"The task lookup_contact_info failed for notification {notification_id}. " \
                  "Notification has been updated to technical-failure"
        update_notification_status_by_id(notification_id,
                                         NOTIFICATION_TECHNICAL_FAILURE)
        raise NotificationTechnicalFailureException(message) from e

    else:
        notification.to = recipient
        dao_update_notification(notification)
def test_should_by_able_to_update_status_by_reference(sample_email_template, ses_provider):
    data = _notification_json(sample_email_template, status='sending')

    notification = Notification(**data)
    dao_create_notification(notification)

    assert Notification.query.get(notification.id).status == "sending"
    notification.reference = 'reference'
    dao_update_notification(notification)

    updated = update_notification_status_by_reference('reference', 'delivered')
    assert updated.status == 'delivered'
    assert Notification.query.get(notification.id).status == 'delivered'
def _process_for_status(notification_status,
                        client_name,
                        provider_reference,
                        detailed_status_code=None):
    # record stats
    if client_name == 'Twilio':
        notification = notifications_dao.update_notification_status_by_reference(
            reference=provider_reference, status=notification_status)
    else:
        notification = notifications_dao.update_notification_status_by_id(
            notification_id=provider_reference,
            status=notification_status,
            sent_by=client_name.lower(),
            detailed_status_code=detailed_status_code)

    if not notification:
        return

    statsd_client.incr('callback.{}.{}'.format(client_name.lower(),
                                               notification_status))

    if notification.sent_at:
        statsd_client.timing_with_dates(
            'callback.{}.elapsed-time'.format(client_name.lower()),
            datetime.utcnow(), notification.sent_at)

    if notification.billable_units == 0:
        service = notification.service
        template_model = dao_get_template_by_id(notification.template_id,
                                                notification.template_version)

        template = SMSMessageTemplate(
            template_model.__dict__,
            values=notification.personalisation,
            prefix=service.name,
            show_prefix=service.prefix_sms,
        )
        notification.billable_units = template.fragment_count
        notifications_dao.dao_update_notification(notification)

    if notification_status != NOTIFICATION_PENDING:
        service_callback_api = get_service_delivery_status_callback_api_for_service(
            service_id=notification.service_id)
        # queue callback task only if the service_callback_api exists
        if service_callback_api:
            encrypted_notification = create_delivery_status_callback_data(
                notification, service_callback_api)
            send_delivery_status_to_service.apply_async(
                [str(notification.id), encrypted_notification],
                queue=QueueNames.CALLBACKS)
def test_should_not_update_status_one_notification_status_is_delivered(notify_db, notify_db_session,
                                                                       sample_email_template,
                                                                       ses_provider):
    notification = sample_notification(notify_db=notify_db, notify_db_session=notify_db_session,
                                       template=sample_email_template,
                                       status='sending')
    assert Notification.query.get(notification.id).status == "sending"

    notification.reference = 'reference'
    dao_update_notification(notification)
    update_notification_status_by_reference('reference', 'delivered')
    assert Notification.query.get(notification.id).status == 'delivered'

    update_notification_status_by_reference('reference', 'failed')
    assert Notification.query.get(notification.id).status == 'delivered'
Ejemplo n.º 23
0
def send_email_to_provider(notification):
    service = dao_fetch_service_by_id(notification.service_id)
    provider = provider_to_use(EMAIL_TYPE, notification.id)
    if notification.status == 'created':
        template_dict = dao_get_template_by_id(notification.template_id, notification.template_version).__dict__

        html_email = HTMLEmailTemplate(
            template_dict,
            values=notification.personalisation,
            **get_html_email_options(service)
        )

        plain_text_email = PlainTextEmailTemplate(
            template_dict,
            values=notification.personalisation
        )

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            reference = str(create_uuid())
            send_email_response.apply_async(
                (provider.get_name(), reference, notification.to), queue='research-mode'
            )
            notification.billable_units = 0
        else:
            from_address = '"{}" <{}@{}>'.format(service.name, service.email_from,
                                                 current_app.config['NOTIFY_EMAIL_DOMAIN'])
            reference = provider.send_email(
                from_address,
                notification.to,
                plain_text_email.subject,
                body=str(plain_text_email),
                html_body=str(html_email),
                reply_to_address=service.reply_to_email_address,
            )

        notification.reference = reference
        notification.sent_at = datetime.utcnow()
        notification.sent_by = provider.get_name(),
        notification.status = 'sending'
        dao_update_notification(notification)

        current_app.logger.info(
            "Email {} sent to provider at {}".format(notification.id, notification.sent_at)
        )
        delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000
        statsd_client.timing("email.total-time", delta_milliseconds)
def _sanitise_precompiled_pdf(self, notification, precompiled_pdf):
    try:
        response = requests_post(
            '{}/precompiled/sanitise'.format(
                current_app.config['TEMPLATE_PREVIEW_API_HOST']),
            data=precompiled_pdf,
            headers={
                'Authorization':
                'Token {}'.format(
                    current_app.config['TEMPLATE_PREVIEW_API_KEY']),
                'Service-ID':
                str(notification.service_id),
                'Notification-ID':
                str(notification.id)
            })
        response.raise_for_status()
        return response.json(), "validation_passed"
    except RequestException as ex:
        if ex.response is not None and ex.response.status_code == 400:
            message = "sanitise_precompiled_pdf validation error for notification: {}. ".format(
                notification.id)
            if response.json().get("message"):
                message += response.json()["message"]
                if response.json().get("invalid_pages"):
                    message += (
                        " on pages: " +
                        ", ".join(map(str,
                                      response.json()["invalid_pages"])))

            current_app.logger.info(message)
            return response.json(), "validation_failed"

        try:
            current_app.logger.exception(
                "sanitise_precompiled_pdf failed for notification: {}".format(
                    notification.id))
            self.retry(queue=QueueNames.RETRY)
        except MaxRetriesExceededError:
            current_app.logger.error(
                "RETRY FAILED: sanitise_precompiled_pdf failed for notification {}"
                .format(notification.id), )

            notification.status = NOTIFICATION_TECHNICAL_FAILURE
            dao_update_notification(notification)
            raise
Ejemplo n.º 25
0
def _sanitise_precompiled_pdf(self, notification, precompiled_pdf):
    try:
        response = requests_post(
            "{}/precompiled/sanitise".format(
                current_app.config["TEMPLATE_PREVIEW_API_HOST"]),
            data=precompiled_pdf,
            headers={
                "Authorization":
                "Token {}".format(
                    current_app.config["TEMPLATE_PREVIEW_API_KEY"]),
                "Service-ID":
                str(notification.service_id),
                "Notification-ID":
                str(notification.id),
            },
        )
        response.raise_for_status()
        return response
    except RequestException as ex:
        if ex.response is not None and ex.response.status_code == 400:
            message = "sanitise_precompiled_pdf validation error for notification: {}. ".format(
                notification.id)
            if "message" in response.json():
                message += response.json()["message"]

            current_app.logger.info(message)
            return None

        try:
            current_app.logger.exception(
                "sanitise_precompiled_pdf failed for notification: {}".format(
                    notification.id))
            self.retry(queue=QueueNames.RETRY)
        except MaxRetriesExceededError:
            current_app.logger.error(
                "RETRY FAILED: sanitise_precompiled_pdf failed for notification {}"
                .format(notification.id), )

            notification.status = NOTIFICATION_TECHNICAL_FAILURE
            dao_update_notification(notification)
            raise
def test_update_notification(sample_notification, sample_template):
    assert sample_notification.status == 'created'
    sample_notification.status = 'failed'
    dao_update_notification(sample_notification)
    notification_from_db = Notification.query.get(sample_notification.id)
    assert notification_from_db.status == 'failed'
def set_notification_sent_by(notification, client_name):
    notification.sent_by = client_name
    dao_update_notification(notification)
def update_notification_to_sending(notification, provider):
    notification.sent_at = datetime.utcnow()
    notification.sent_by = provider.get_name()
    notification.status = NOTIFICATION_SENDING
    dao_update_notification(notification)
Ejemplo n.º 29
0
def send_sms_to_provider(notification):
    service = notification.service

    if not service.active:
        technical_failure(notification=notification)
        return

    if notification.status == 'created':
        # TODO: issue is that this does not get the provider based on who owns
        # the inbound number. The notification.reply_to_text below is the phone
        # number that we should send from, but we need to look at that and see
        # who the provider is.
        # TODO: now that we do get the right provider, the issue is that the
        # reply to text could be different because the service is able to choose
        # the sender when sending a message. So we need to check if the sender
        # ID that was chosen is also an inbound number.
        provider = None
        preferred_provider = get_preferred_sms_provider(service)
        if preferred_provider:
            provider = get_sms_provider_client(preferred_provider,
                                               notification.id)
        else:
            provider = provider_to_use(SMS_TYPE, notification.id,
                                       notification.international)
        current_app.logger.debug(
            "Starting sending SMS {} to provider at {}".format(
                notification.id, datetime.utcnow()))
        template_model = dao_get_template_by_id(notification.template_id,
                                                notification.template_version)

        template = SMSMessageTemplate(
            template_model.__dict__,
            values=notification.personalisation,
            prefix=service.name,
            show_prefix=service.prefix_sms,
        )

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.billable_units = 0
            update_notification(notification, provider)
            try:
                send_sms_response(provider.get_name(), str(notification.id),
                                  notification.to)
            except HTTPError:
                # when we retry, we only do anything if the notification is in created - it's currently in sending,
                # so set it back so that we actually attempt the callback again
                notification.sent_at = None
                notification.sent_by = None
                notification.status = NOTIFICATION_CREATED
                dao_update_notification(notification)
                raise
        else:
            status = None

            try:
                reference, status = provider.send_sms(
                    to=notification.normalised_to,
                    content=str(template),
                    reference=str(notification.id),
                    sender=notification.reply_to_text)

                notification.reference = reference
                notification.billable_units = template.fragment_count

                # An international notification (i.e. a text message with an
                # abroad recipient phone number) instantly get marked as "sent".
                # It might later get marked as "delivered" when the provider
                # status callback is triggered.
                if notification.international:
                    status = NOTIFICATION_SENT
            except Exception as e:
                dao_toggle_sms_provider(provider.name)
                raise e
            else:
                update_notification(notification, provider, status=status)

        current_app.logger.debug("SMS {} sent to provider {} at {}".format(
            notification.id, provider.get_name(), notification.sent_at))
        delta_milliseconds = (datetime.utcnow() -
                              notification.created_at).total_seconds() * 1000
        statsd_client.timing("sms.total-time", delta_milliseconds)
Ejemplo n.º 30
0
def update_notification_to_sending(notification, provider):
    notification.sent_at = datetime.utcnow()
    notification.sent_by = provider.get_name()
    if notification.status not in NOTIFICATION_STATUS_TYPES_COMPLETED:
        notification.status = NOTIFICATION_SENT if notification.international else NOTIFICATION_SENDING
    dao_update_notification(notification)