def view_signed_agreement(supplier_id, framework_slug):
    # not properly validating this - all we do is pass it through
    next_status = request.args.get("next_status")

    supplier = data_api_client.get_supplier(supplier_id)['suppliers']
    framework = data_api_client.get_framework(framework_slug)['frameworks']
    if not framework.get('frameworkAgreementVersion'):
        abort(404)
    supplier_framework = data_api_client.get_supplier_framework_info(
        supplier_id, framework_slug)['frameworkInterest']
    if not supplier_framework.get('agreementReturned'):
        abort(404)

    lot_names = []
    if framework["status"] in ("live", "expired"):
        # If the framework is live or expired we don't need to filter drafts, we only care about successful services
        service_iterator = data_api_client.find_services_iter(
            supplier_id=supplier_id, framework=framework_slug)
        for service in service_iterator:
            if service['lotName'] not in lot_names:
                lot_names.append(service['lotName'])
    else:
        # If the framework has not yet become live we need to filter out unsuccessful services
        service_iterator = data_api_client.find_draft_services_iter(
            supplier_id=supplier_id, framework=framework_slug)
        for service in service_iterator:
            if service["status"] == "submitted" and service[
                    'lotName'] not in lot_names:
                lot_names.append(service['lotName'])

    agreements_bucket = s3.S3(current_app.config['DM_AGREEMENTS_BUCKET'])

    if framework_slug in OLD_COUNTERSIGNING_FLOW_FRAMEWORKS:
        is_e_signature_flow = False
        # Fetch path to supplier's signature page
        path = supplier_framework['agreementPath']
        template = "suppliers/view_signed_agreement.html"
    else:
        is_e_signature_flow = True
        # Fetch path to combined countersigned agreement, if available
        path = supplier_framework.get('countersignedPath')
        template = "suppliers/view_esignature_agreement.html"

    url = get_signed_url(agreements_bucket, path,
                         current_app.config['DM_ASSETS_URL']) if path else ""
    agreement_ext = get_extension(path) if path else ""

    if not url:
        current_app.logger.info(f'No agreement file found for {path}')
    return render_template(
        template,
        company_details=get_company_details_from_supplier(supplier),
        supplier=supplier,
        framework=framework,
        supplier_framework=supplier_framework,
        lot_names=list(sorted(lot_names)),
        agreement_url=url,
        agreement_ext=agreement_ext,
        next_status=next_status,
        is_e_signature_flow=is_e_signature_flow)
def signature_upload(framework_slug):
    framework = get_framework(data_api_client, framework_slug)
    return_supplier_framework_info_if_on_framework_or_abort(
        data_api_client, framework_slug)
    agreements_bucket = s3.S3(current_app.config['DM_AGREEMENTS_BUCKET'])
    signature_page = get_most_recently_uploaded_agreement_file_or_none(
        agreements_bucket, framework_slug)
    upload_error = None

    if request.method == 'POST':
        # No file chosen for upload and file already exists on s3 so can use existing and progress
        if not request.files['signature_page'].filename and signature_page:
            return redirect(
                url_for(".contract_review", framework_slug=framework_slug))

        if not file_is_image(
                request.files['signature_page']) and not file_is_pdf(
                    request.files['signature_page']):
            upload_error = "The file must be a PDF, JPG or PNG"
        elif not file_is_less_than_5mb(request.files['signature_page']):
            upload_error = "The file must be less than 5MB"
        elif file_is_empty(request.files['signature_page']):
            upload_error = "The file must not be empty"

        if not upload_error:
            upload_path = get_agreement_document_path(
                framework_slug, current_user.supplier_code, '{}{}'.format(
                    SIGNED_AGREEMENT_PREFIX,
                    get_extension(request.files['signature_page'].filename)))
            agreements_bucket.save(upload_path,
                                   request.files['signature_page'],
                                   acl='private')

            session['signature_page'] = request.files[
                'signature_page'].filename

            data_api_client.create_audit_event(
                audit_type=AuditTypes.upload_signed_agreement,
                user=current_user.email_address,
                object_type="suppliers",
                object_id=current_user.supplier_code,
                data={
                    "upload_signed_agreement":
                    request.files['signature_page'].filename,
                    "upload_path": upload_path
                })

            return redirect(
                url_for(".contract_review", framework_slug=framework_slug))

    status_code = 400 if upload_error else 200
    return render_template_with_csrf(
        "frameworks/signature_upload.html",
        status_code=status_code,
        framework=framework,
        signature_page=signature_page,
        upload_error=upload_error,
    )
Example #3
0
 def test_get_extension(self):
     assert get_extension('what.jpg') == '.jpg'
     assert get_extension('what the.jpg') == '.jpg'
     assert get_extension('what.the.jpg') == '.jpg'
     assert get_extension('what.the..jpg') == '.jpg'
     assert get_extension('what.the.🐈.jpg') == '.jpg'
     assert get_extension('what.the.🐈jpg') == '.🐈jpg'
     assert get_extension('ಠ▃ಠ.jpg') == '.jpg'
def signature_upload(framework_slug):
    framework = get_framework(data_api_client, framework_slug)
    return_supplier_framework_info_if_on_framework_or_abort(data_api_client, framework_slug)
    agreements_bucket = s3.S3(current_app.config['DM_AGREEMENTS_BUCKET'])
    signature_page = get_most_recently_uploaded_agreement_file_or_none(agreements_bucket, framework_slug)
    upload_error = None

    if request.method == 'POST':
        # No file chosen for upload and file already exists on s3 so can use existing and progress
        if not request.files['signature_page'].filename and signature_page:
            return redirect(url_for(".contract_review", framework_slug=framework_slug))

        if not file_is_image(request.files['signature_page']) and not file_is_pdf(request.files['signature_page']):
            upload_error = "The file must be a PDF, JPG or PNG"
        elif not file_is_less_than_5mb(request.files['signature_page']):
            upload_error = "The file must be less than 5MB"
        elif file_is_empty(request.files['signature_page']):
            upload_error = "The file must not be empty"

        if not upload_error:
            upload_path = get_agreement_document_path(
                framework_slug,
                current_user.supplier_code,
                '{}{}'.format(SIGNED_AGREEMENT_PREFIX, get_extension(request.files['signature_page'].filename))
            )
            agreements_bucket.save(
                upload_path,
                request.files['signature_page'],
                acl='private'
            )

            session['signature_page'] = request.files['signature_page'].filename

            data_api_client.create_audit_event(
                audit_type=AuditTypes.upload_signed_agreement,
                user=current_user.email_address,
                object_type="suppliers",
                object_id=current_user.supplier_code,
                data={
                    "upload_signed_agreement": request.files['signature_page'].filename,
                    "upload_path": upload_path
                })

            return redirect(url_for(".contract_review", framework_slug=framework_slug))

    status_code = 400 if upload_error else 200
    return render_template_with_csrf(
        "frameworks/signature_upload.html",
        status_code=status_code,
        framework=framework,
        signature_page=signature_page,
        upload_error=upload_error,
    )
def upload_framework_agreement(framework_slug):
    framework = get_framework(data_api_client, framework_slug, allowed_statuses=['standstill', 'live'])
    supplier_framework = return_supplier_framework_info_if_on_framework_or_abort(data_api_client, framework_slug)

    upload_error = None
    if not file_is_less_than_5mb(request.files['agreement']):
        upload_error = "Document must be less than 5MB"
    elif file_is_empty(request.files['agreement']):
        upload_error = "Document must not be empty"

    if upload_error is not None:
        return render_template_with_csrf(
            "frameworks/agreement.html",
            status_code=400,
            framework=framework,
            supplier_framework=supplier_framework,
            upload_error=upload_error,
            agreement_filename=AGREEMENT_FILENAME
        )

    agreements_bucket = s3.S3(current_app.config['DM_AGREEMENTS_BUCKET'])
    extension = get_extension(request.files['agreement'].filename)

    path = get_agreement_document_path(
        framework_slug,
        current_user.supplier_code,
        '{}{}'.format(SIGNED_AGREEMENT_PREFIX, extension)
    )
    agreements_bucket.save(
        path,
        request.files['agreement'],
        acl='private',
        download_filename='{}-{}-{}{}'.format(
            sanitise_supplier_name(current_user.supplier_name),
            current_user.supplier_code,
            SIGNED_AGREEMENT_PREFIX,
            extension
        )
    )

    data_api_client.register_framework_agreement_returned(
        current_user.supplier_code, framework_slug, current_user.email_address)

    try:
        email_body = render_template(
            'emails/framework_agreement_uploaded.html',
            framework_name=framework['name'],
            supplier_name=current_user.supplier_name,
            supplier_code=current_user.supplier_code,
            user_name=current_user.name
        )
        send_email(
            current_app.config['DM_FRAMEWORK_AGREEMENTS_EMAIL'],
            email_body,
            '{} framework agreement'.format(framework['name']),
            current_app.config["DM_GENERIC_NOREPLY_EMAIL"],
            '{} Supplier'.format(framework['name']),
            ['{}-framework-agreement'.format(framework_slug)],
            reply_to=current_user.email_address,
        )
    except EmailError as e:
        rollbar.report_exc_info()
        current_app.logger.error(
            "Framework agreement email failed to send. "
            "error {error} supplier_code {supplier_code} email_hash {email_hash}",
            extra={'error': six.text_type(e),
                   'supplier_code': current_user.supplier_code,
                   'email_hash': hash_email(current_user.email_address)})
        abort(503, "Framework agreement email failed to send")

    return redirect(url_for('.framework_agreement', framework_slug=framework_slug))
Example #6
0
def signature_upload(framework_slug, agreement_id):
    framework = get_framework(data_api_client,
                              framework_slug,
                              allowed_statuses=['standstill', 'live'])
    # if there's no frameworkAgreementVersion key it means we're pre-G-Cloud 8 and shouldn't be using this route
    if not framework.get('frameworkAgreementVersion'):
        abort(404)
    supplier_framework = return_supplier_framework_info_if_on_framework_or_abort(
        data_api_client, framework_slug)
    agreement = data_api_client.get_framework_agreement(
        agreement_id)['agreement']
    check_agreement_is_related_to_supplier_framework_or_abort(
        agreement, supplier_framework)

    agreements_bucket = s3.S3(current_app.config['DM_AGREEMENTS_BUCKET'])
    signature_page = agreements_bucket.get_key(
        agreement.get('signedAgreementPath'))
    upload_error = None

    if request.method == 'POST':
        # No file chosen for upload and file already exists on s3 so can use existing and progress
        if not request.files['signature_page'].filename and signature_page:
            return redirect(
                url_for(".contract_review",
                        framework_slug=framework_slug,
                        agreement_id=agreement_id))

        if not file_is_image(
                request.files['signature_page']) and not file_is_pdf(
                    request.files['signature_page']):
            upload_error = "The file must be a PDF, JPG or PNG"
        elif not file_is_less_than_5mb(request.files['signature_page']):
            upload_error = "The file must be less than 5MB"
        elif file_is_empty(request.files['signature_page']):
            upload_error = "The file must not be empty"

        if not upload_error:
            extension = get_extension(request.files['signature_page'].filename)
            upload_path = generate_timestamped_document_upload_path(
                framework_slug, current_user.supplier_id, 'agreements',
                '{}{}'.format(SIGNED_AGREEMENT_PREFIX, extension))
            agreements_bucket.save(
                upload_path,
                request.files['signature_page'],
                acl='private',
                download_filename='{}-{}-{}{}'.format(
                    sanitise_supplier_name(current_user.supplier_name),
                    current_user.supplier_id, SIGNED_SIGNATURE_PAGE_PREFIX,
                    extension),
                disposition_type=
                'inline'  # Embeddeding PDFs in admin pages requires 'inline' and not 'attachment'
            )

            data_api_client.update_framework_agreement(
                agreement_id, {"signedAgreementPath": upload_path},
                current_user.email_address)

            session['signature_page'] = request.files[
                'signature_page'].filename

            return redirect(
                url_for(".contract_review",
                        framework_slug=framework_slug,
                        agreement_id=agreement_id))

    return render_template(
        "frameworks/signature_upload.html",
        agreement=agreement,
        framework=framework,
        signature_page=signature_page,
        upload_error=upload_error,
    ), 400 if upload_error else 200
Example #7
0
def upload_framework_agreement(framework_slug):
    """
    This is the route used to upload agreements for pre-G-Cloud 8 frameworks
    """
    framework = get_framework(data_api_client,
                              framework_slug,
                              allowed_statuses=['standstill', 'live'])
    # if there's a frameworkAgreementVersion key it means we're on G-Cloud 8 or higher and shouldn't be using this route
    if framework.get('frameworkAgreementVersion'):
        abort(404)

    supplier_framework = return_supplier_framework_info_if_on_framework_or_abort(
        data_api_client, framework_slug)

    upload_error = None
    if not file_is_less_than_5mb(request.files['agreement']):
        upload_error = "Document must be less than 5MB"
    elif file_is_empty(request.files['agreement']):
        upload_error = "Document must not be empty"

    if upload_error is not None:
        return render_template(
            "frameworks/agreement.html",
            framework=framework,
            supplier_framework=supplier_framework,
            upload_error=upload_error,
            agreement_filename=AGREEMENT_FILENAME,
        ), 400

    agreements_bucket = s3.S3(current_app.config['DM_AGREEMENTS_BUCKET'])
    extension = get_extension(request.files['agreement'].filename)

    path = generate_timestamped_document_upload_path(
        framework_slug, current_user.supplier_id, 'agreements',
        '{}{}'.format(SIGNED_AGREEMENT_PREFIX, extension))
    agreements_bucket.save(
        path,
        request.files['agreement'],
        acl='private',
        download_filename='{}-{}-{}{}'.format(
            sanitise_supplier_name(current_user.supplier_name),
            current_user.supplier_id, SIGNED_AGREEMENT_PREFIX, extension))

    agreement_id = data_api_client.create_framework_agreement(
        current_user.supplier_id, framework_slug,
        current_user.email_address)['agreement']['id']
    data_api_client.update_framework_agreement(agreement_id,
                                               {"signedAgreementPath": path},
                                               current_user.email_address)
    data_api_client.sign_framework_agreement(
        agreement_id, current_user.email_address,
        {"uploaderUserId": current_user.id})

    try:
        email_body = render_template(
            'emails/framework_agreement_uploaded.html',
            framework_name=framework['name'],
            supplier_name=current_user.supplier_name,
            supplier_id=current_user.supplier_id,
            user_name=current_user.name)
        send_email(
            current_app.config['DM_FRAMEWORK_AGREEMENTS_EMAIL'],
            email_body,
            current_app.config['DM_MANDRILL_API_KEY'],
            '{} framework agreement'.format(framework['name']),
            current_app.config["DM_GENERIC_NOREPLY_EMAIL"],
            '{} Supplier'.format(framework['name']),
            ['{}-framework-agreement'.format(framework_slug)],
            reply_to=current_user.email_address,
        )
    except MandrillException as e:
        current_app.logger.error(
            "Framework agreement email failed to send. "
            "error {error} supplier_id {supplier_id} email_hash {email_hash}",
            extra={
                'error': six.text_type(e),
                'supplier_id': current_user.supplier_id,
                'email_hash': hash_email(current_user.email_address)
            })
        abort(503, "Framework agreement email failed to send")

    return redirect(
        url_for('.framework_agreement', framework_slug=framework_slug))
def upload_framework_agreement(framework_slug):
    framework = get_framework(data_api_client,
                              framework_slug,
                              allowed_statuses=['standstill', 'live'])
    supplier_framework = return_supplier_framework_info_if_on_framework_or_abort(
        data_api_client, framework_slug)

    upload_error = None
    if not file_is_less_than_5mb(request.files['agreement']):
        upload_error = "Document must be less than 5MB"
    elif file_is_empty(request.files['agreement']):
        upload_error = "Document must not be empty"

    if upload_error is not None:
        return render_template_with_csrf("frameworks/agreement.html",
                                         status_code=400,
                                         framework=framework,
                                         supplier_framework=supplier_framework,
                                         upload_error=upload_error,
                                         agreement_filename=AGREEMENT_FILENAME)

    agreements_bucket = s3.S3(current_app.config['DM_AGREEMENTS_BUCKET'])
    extension = get_extension(request.files['agreement'].filename)

    path = get_agreement_document_path(
        framework_slug, current_user.supplier_code,
        '{}{}'.format(SIGNED_AGREEMENT_PREFIX, extension))
    agreements_bucket.save(
        path,
        request.files['agreement'],
        acl='private',
        download_filename='{}-{}-{}{}'.format(
            sanitise_supplier_name(current_user.supplier_name),
            current_user.supplier_code, SIGNED_AGREEMENT_PREFIX, extension))

    data_api_client.register_framework_agreement_returned(
        current_user.supplier_code, framework_slug, current_user.email_address)

    try:
        email_body = render_template(
            'emails/framework_agreement_uploaded.html',
            framework_name=framework['name'],
            supplier_name=current_user.supplier_name,
            supplier_code=current_user.supplier_code,
            user_name=current_user.name)
        send_email(
            current_app.config['DM_FRAMEWORK_AGREEMENTS_EMAIL'],
            email_body,
            '{} framework agreement'.format(framework['name']),
            current_app.config["DM_GENERIC_NOREPLY_EMAIL"],
            '{} Supplier'.format(framework['name']),
            ['{}-framework-agreement'.format(framework_slug)],
            reply_to=current_user.email_address,
        )
    except EmailError as e:
        rollbar.report_exc_info()
        current_app.logger.error(
            "Framework agreement email failed to send. "
            "error {error} supplier_code {supplier_code} email_hash {email_hash}",
            extra={
                'error': six.text_type(e),
                'supplier_code': current_user.supplier_code,
                'email_hash': hash_email(current_user.email_address)
            })
        abort(503, "Framework agreement email failed to send")

    return redirect(
        url_for('.framework_agreement', framework_slug=framework_slug))