def sanitise_letter(self, filename):
    try:
        reference = get_reference_from_filename(filename)
        notification = dao_get_notification_by_reference(reference)

        current_app.logger.info('Notification ID {} Virus scan passed: {}'.format(notification.id, filename))

        if notification.status != NOTIFICATION_PENDING_VIRUS_CHECK:
            current_app.logger.info('Sanitise letter called for notification {} which is in {} state'.format(
                notification.id, notification.status))
            return

        notify_celery.send_task(
            name=TaskNames.SANITISE_LETTER,
            kwargs={
                'notification_id': str(notification.id),
                'filename': filename,
                'allow_international_letters': notification.service.has_permission(
                    INTERNATIONAL_LETTERS
                ),
            },
            queue=QueueNames.SANITISE_LETTERS,
        )
    except Exception:
        try:
            current_app.logger.exception(
                "RETRY: calling sanitise_letter task for notification {} failed".format(notification.id)
            )
            self.retry(queue=QueueNames.RETRY)
        except self.MaxRetriesExceededError:
            message = "RETRY FAILED: Max retries reached. " \
                      "The task sanitise_letter failed for notification {}. " \
                      "Notification has been updated to technical-failure".format(notification.id)
            update_notification_status_by_id(notification.id, NOTIFICATION_TECHNICAL_FAILURE)
            raise NotificationTechnicalFailureException(message)
def letter_in_created_state(filename):
    # filename looks like '2018-01-13/NOTIFY.ABCDEF1234567890.D.2.C.C.20180113120000.PDF'
    subfolder = filename.split('/')[0]
    ref = get_reference_from_filename(filename)
    notifications = dao_get_notifications_by_references([ref])
    if notifications:
        if notifications[0].status == NOTIFICATION_CREATED:
            return True
        current_app.logger.info(
            'Collating letters for {} but notification with reference {} already in {}'
            .format(subfolder, ref, notifications[0].status))
    return False
Пример #3
0
def process_virus_scan_passed(filename):
    reference = get_reference_from_filename(filename)
    notification = dao_get_notification_by_reference(reference)
    current_app.logger.info('notification id {} Virus scan passed: {}'.format(
        notification.id, filename))

    is_test_key = notification.key_type == KEY_TYPE_TEST
    move_scanned_pdf_to_test_or_live_pdf_bucket(filename,
                                                is_test_letter=is_test_key)
    update_letter_pdf_status(
        reference,
        NOTIFICATION_DELIVERED if is_test_key else NOTIFICATION_CREATED)
Пример #4
0
def process_virus_scan_error(filename):
    move_failed_pdf(filename, ScanErrorType.ERROR)
    reference = get_reference_from_filename(filename)
    notification = dao_get_notification_by_reference(reference)
    updated_count = update_letter_pdf_status(reference,
                                             NOTIFICATION_TECHNICAL_FAILURE)

    if updated_count != 1:
        raise Exception(
            "There should only be one letter notification for each reference. Found {} notifications"
            .format(updated_count))

    raise VirusScanError('notification id {} Virus scan error: {}'.format(
        notification.id, filename))
def process_virus_scan_failed(filename):
    move_failed_pdf(filename, ScanErrorType.FAILURE)
    reference = get_reference_from_filename(filename)
    notification = dao_get_notification_by_reference(reference)
    updated_count = update_letter_pdf_status(reference, NOTIFICATION_VIRUS_SCAN_FAILED, billable_units=0)

    if updated_count != 1:
        raise Exception(
            "There should only be one letter notification for each reference. Found {} notifications".format(
                updated_count
            )
        )

    error = VirusScanError('notification id {} Virus scan failed: {}'.format(notification.id, filename))
    current_app.logger.exception(error)
    raise error
def process_virus_scan_passed(self, filename):
    reference = get_reference_from_filename(filename)
    notification = dao_get_notification_by_reference(reference)
    current_app.logger.info('notification id {} Virus scan passed: {}'.format(
        notification.id, filename))

    is_test_key = notification.key_type == KEY_TYPE_TEST

    scan_pdf_object = s3.get_s3_object(
        current_app.config['LETTERS_SCAN_BUCKET_NAME'], filename)
    old_pdf = scan_pdf_object.get()['Body'].read()

    sanitise_response, result = _sanitise_precompiled_pdf(
        self, notification, old_pdf)
    new_pdf = None
    if result == 'validation_passed':
        new_pdf = base64.b64decode(sanitise_response["file"].encode())

        redaction_failed_message = sanitise_response.get(
            "redaction_failed_message")
        if redaction_failed_message and not is_test_key:
            current_app.logger.info('{} for notification id {} ({})'.format(
                redaction_failed_message, notification.id, filename))
            copy_redaction_failed_pdf(filename)

    billable_units = get_billable_units_for_letter_page_count(
        sanitise_response.get("page_count"))

    # TODO: Remove this once CYSP update their template to not cross over the margins
    if notification.service_id == UUID(
            'fe44178f-3b45-4625-9f85-2264a36dd9ec'):  # CYSP
        # Check your state pension submit letters with good addresses and notify tags, so just use their supplied pdf
        new_pdf = old_pdf

    if result == 'validation_failed' and not new_pdf:
        current_app.logger.info(
            'Invalid precompiled pdf received {} ({})'.format(
                notification.id, filename))
        _move_invalid_letter_and_update_status(
            notification=notification,
            filename=filename,
            scan_pdf_object=scan_pdf_object,
            message=sanitise_response["message"],
            invalid_pages=sanitise_response.get("invalid_pages"),
            page_count=sanitise_response.get("page_count"))
        return

    current_app.logger.info(
        'notification id {} ({}) sanitised and ready to send'.format(
            notification.id, filename))

    try:
        _upload_pdf_to_test_or_live_pdf_bucket(
            new_pdf,
            filename,
            is_test_letter=is_test_key,
            created_at=notification.created_at)

        update_letter_pdf_status(reference=reference,
                                 status=NOTIFICATION_DELIVERED
                                 if is_test_key else NOTIFICATION_CREATED,
                                 billable_units=billable_units)
        scan_pdf_object.delete()
    except BotoClientError:
        current_app.logger.exception(
            "Error uploading letter to live pdf bucket for notification: {}".
            format(notification.id))
        update_notification_status_by_id(notification.id,
                                         NOTIFICATION_TECHNICAL_FAILURE)
Пример #7
0
def process_virus_scan_passed(self, filename):
    reference = get_reference_from_filename(filename)
    notification = dao_get_notification_by_reference(reference)
    current_app.logger.info("notification id {} Virus scan passed: {}".format(
        notification.id, filename))

    is_test_key = notification.key_type == KEY_TYPE_TEST

    scan_pdf_object = s3.get_s3_object(
        current_app.config["LETTERS_SCAN_BUCKET_NAME"], filename)
    old_pdf = scan_pdf_object.get()["Body"].read()

    try:
        billable_units = get_page_count(old_pdf)
    except PdfReadError:
        current_app.logger.exception(
            msg="Invalid PDF received for notification_id: {}".format(
                notification.id))
        _move_invalid_letter_and_update_status(notification, filename,
                                               scan_pdf_object)
        return

    sanitise_response = _sanitise_precompiled_pdf(self, notification, old_pdf)
    if not sanitise_response:
        new_pdf = None
    else:
        sanitise_response = sanitise_response.json()
        try:
            new_pdf = base64.b64decode(sanitise_response["file"].encode())
        except JSONDecodeError:
            new_pdf = sanitise_response.content

        redaction_failed_message = sanitise_response.get(
            "redaction_failed_message")
        if redaction_failed_message and not is_test_key:
            current_app.logger.info("{} for notification id {} ({})".format(
                redaction_failed_message, notification.id, filename))
            copy_redaction_failed_pdf(filename)

    # TODO: Remove this once CYSP update their template to not cross over the margins
    if notification.service_id == UUID(
            "fe44178f-3b45-4625-9f85-2264a36dd9ec"):  # CYSP
        # Check your state pension submit letters with good addresses and notify tags, so just use their supplied pdf
        new_pdf = old_pdf

    if not new_pdf:
        current_app.logger.info(
            "Invalid precompiled pdf received {} ({})".format(
                notification.id, filename))
        _move_invalid_letter_and_update_status(notification, filename,
                                               scan_pdf_object)
        return
    else:
        current_app.logger.info(
            "Validation was successful for precompiled pdf {} ({})".format(
                notification.id, filename))

    current_app.logger.info(
        "notification id {} ({}) sanitised and ready to send".format(
            notification.id, filename))

    try:
        _upload_pdf_to_test_or_live_pdf_bucket(new_pdf,
                                               filename,
                                               is_test_letter=is_test_key)

        update_letter_pdf_status(
            reference=reference,
            status=NOTIFICATION_DELIVERED
            if is_test_key else NOTIFICATION_CREATED,
            billable_units=billable_units,
        )
        scan_pdf_object.delete()
    except BotoClientError:
        current_app.logger.exception(
            "Error uploading letter to live pdf bucket for notification: {}".
            format(notification.id))
        update_notification_status_by_id(notification.id,
                                         NOTIFICATION_TECHNICAL_FAILURE)