mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-05-27 17:39:51 -04:00
Add endpoints to serve the agreement
Rather than making users contact us to get the agreement, we should just let them download it, when we know which version to send them. This commit adds two endpoints: - one to serve a page which links to the agreement - one to serve the agreement itself These pages are not linked to anywhere because the underlying files don’t exist yet. So I haven’t bothered putting real content on the page yet either. I imagine the deploy sequence will be: 1. Upload the files to the buckets in each environment 2. Deploy this code through each enviroment, checking the links work 3. Make another PR to start linking to the endpoints added by this commit
This commit is contained in:
@@ -69,6 +69,7 @@ class Config(object):
|
||||
STATSD_PORT = 8125
|
||||
NOTIFY_ENVIRONMENT = 'development'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-local'
|
||||
MOU_BUCKET_NAME = 'local-mou'
|
||||
ROUTE_SECRET_KEY_1 = os.environ.get('ROUTE_SECRET_KEY_1', '')
|
||||
ROUTE_SECRET_KEY_2 = os.environ.get('ROUTE_SECRET_KEY_2', '')
|
||||
CHECK_PROXY_HEADER = False
|
||||
@@ -82,6 +83,7 @@ class Development(Config):
|
||||
STATSD_ENABLED = False
|
||||
CSV_UPLOAD_BUCKET_NAME = 'development-notifications-csv-upload'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-tools'
|
||||
MOU_BUCKET_NAME = 'notify.tools-mou'
|
||||
|
||||
ADMIN_CLIENT_SECRET = 'dev-notify-secret-key'
|
||||
API_HOST_NAME = 'http://localhost:6011'
|
||||
@@ -98,6 +100,7 @@ class Test(Development):
|
||||
WTF_CSRF_ENABLED = False
|
||||
CSV_UPLOAD_BUCKET_NAME = 'test-notifications-csv-upload'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-test'
|
||||
MOU_BUCKET_NAME = 'test-mou'
|
||||
NOTIFY_ENVIRONMENT = 'test'
|
||||
API_HOST_NAME = 'http://you-forgot-to-mock-an-api-call-to'
|
||||
TEMPLATE_PREVIEW_API_HOST = 'http://localhost:9999'
|
||||
@@ -109,6 +112,7 @@ class Preview(Config):
|
||||
STATSD_ENABLED = True
|
||||
CSV_UPLOAD_BUCKET_NAME = 'preview-notifications-csv-upload'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-preview'
|
||||
MOU_BUCKET_NAME = 'notify.works-mou'
|
||||
NOTIFY_ENVIRONMENT = 'preview'
|
||||
CHECK_PROXY_HEADER = True
|
||||
|
||||
@@ -120,6 +124,7 @@ class Staging(Config):
|
||||
STATSD_ENABLED = True
|
||||
CSV_UPLOAD_BUCKET_NAME = 'staging-notify-csv-upload'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-staging'
|
||||
MOU_BUCKET_NAME = 'staging-notify.works-mou'
|
||||
NOTIFY_ENVIRONMENT = 'staging'
|
||||
CHECK_PROXY_HEADER = True
|
||||
|
||||
@@ -131,6 +136,7 @@ class Live(Config):
|
||||
STATSD_ENABLED = True
|
||||
CSV_UPLOAD_BUCKET_NAME = 'live-notifications-csv-upload'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-production'
|
||||
MOU_BUCKET_NAME = 'notifications.service.gov.uk-mou'
|
||||
NOTIFY_ENVIRONMENT = 'live'
|
||||
CHECK_PROXY_HEADER = False
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ marinemanagement.org.uk:
|
||||
agreement_signed: true
|
||||
cabinet-office.gov.uk:
|
||||
owner: Cabinet Office
|
||||
crown: true
|
||||
agreement_signed: true
|
||||
cica.gsi.gov.uk: cica.gov.uk
|
||||
cica.gov.uk:
|
||||
|
||||
@@ -32,5 +32,6 @@ from app.main.views import ( # noqa
|
||||
conversation,
|
||||
organisations,
|
||||
notifications,
|
||||
inbound_number
|
||||
inbound_number,
|
||||
agreement,
|
||||
)
|
||||
|
||||
@@ -61,6 +61,26 @@ def s3download(service_id, upload_id):
|
||||
return contents
|
||||
|
||||
|
||||
def get_mou(organisation_is_crown):
|
||||
bucket = current_app.config['MOU_BUCKET_NAME']
|
||||
filename = 'crown.pdf' if organisation_is_crown else 'non-crown.pdf'
|
||||
attachment_filename = 'GOV.UK Notify data sharing and financial agreement{}.pdf'.format(
|
||||
'' if organisation_is_crown else ' (non-crown)'
|
||||
)
|
||||
try:
|
||||
key = get_s3_object(bucket, filename)
|
||||
return {
|
||||
'filename_or_fp': key.get()['Body'],
|
||||
'attachment_filename': attachment_filename,
|
||||
'as_attachment': True,
|
||||
}
|
||||
except botocore.exceptions.ClientError as exception:
|
||||
current_app.logger.error("Unable to download s3 file {}/{}".format(
|
||||
bucket, filename
|
||||
))
|
||||
raise exception
|
||||
|
||||
|
||||
def upload_logo(filename, filedata, region, user_id):
|
||||
upload_file_name = LOGO_LOCATION_STRUCTURE.format(
|
||||
temp=TEMP_TAG.format(user_id=user_id),
|
||||
|
||||
26
app/main/views/agreement.py
Normal file
26
app/main/views/agreement.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from flask import render_template, send_file
|
||||
from flask_login import login_required
|
||||
|
||||
from app.main import main
|
||||
from app.main.views.sub_navigation_dictionaries import features_nav
|
||||
from app.main.s3_client import get_mou
|
||||
from app.utils import AgreementInfo
|
||||
|
||||
|
||||
|
||||
@main.route('/agreement')
|
||||
@login_required
|
||||
def agreement():
|
||||
return render_template(
|
||||
'views/agreement.html',
|
||||
crown_status=AgreementInfo.from_current_user().crown_status_or_404,
|
||||
navigation_links=features_nav(),
|
||||
)
|
||||
|
||||
|
||||
@main.route('/agreement.pdf')
|
||||
@login_required
|
||||
def download_agreement():
|
||||
return send_file(**get_mou(
|
||||
AgreementInfo.from_current_user().crown_status_or_404
|
||||
))
|
||||
27
app/templates/views/agreement.html
Normal file
27
app/templates/views/agreement.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{% extends "withoutnav_template.html" %}
|
||||
{% from "components/sub-navigation.html" import sub_navigation %}
|
||||
|
||||
{% block per_page_title %}
|
||||
GOV.UK Notify data sharing and financial agreement
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<div class="grid-row">
|
||||
<div class="column-one-third">
|
||||
{{ sub_navigation(navigation_links) }}
|
||||
</div>
|
||||
<div class="column-two-thirds">
|
||||
|
||||
<h1 class="heading-large">
|
||||
GOV.UK Notify data sharing and financial agreement
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<a href="{{ url_for('main.download_agreement') }}">Download</a>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -464,6 +464,12 @@ class AgreementInfo:
|
||||
else:
|
||||
return 'Can’t tell'
|
||||
|
||||
@property
|
||||
def crown_status_or_404(self):
|
||||
if self.crown_status is None:
|
||||
abort(404)
|
||||
return self.crown_status
|
||||
|
||||
def as_request_for_agreement(self, with_owner=False):
|
||||
if with_owner and self.owner:
|
||||
return (
|
||||
|
||||
103
tests/app/main/views/test_agreement.py
Normal file
103
tests/app/main/views/test_agreement.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
from flask import url_for
|
||||
from tests.conftest import active_user_with_permissions
|
||||
|
||||
|
||||
class _MockS3Object():
|
||||
|
||||
def __init__(self, data=None):
|
||||
self.data = data or b''
|
||||
|
||||
def get(self):
|
||||
return {'Body': BytesIO(self.data)}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('email_address, expected_status', [
|
||||
('test@cabinet-office.gov.uk', 200),
|
||||
('test@aylesburytowncouncil.gov.uk', 200),
|
||||
('test@unknown.gov.uk', 404),
|
||||
])
|
||||
def test_show_agreement_page(
|
||||
client_request,
|
||||
mocker,
|
||||
fake_uuid,
|
||||
email_address,
|
||||
expected_status,
|
||||
):
|
||||
user = active_user_with_permissions(fake_uuid)
|
||||
user.email_address = email_address
|
||||
mocker.patch('app.user_api_client.get_user', return_value=user)
|
||||
client_request.get(
|
||||
'main.agreement',
|
||||
_expected_status=expected_status,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('email_address, expected_file_fetched, expected_file_served', [
|
||||
(
|
||||
'test@cabinet-office.gov.uk',
|
||||
'crown.pdf',
|
||||
'GOV.UK Notify data sharing and financial agreement.pdf',
|
||||
),
|
||||
(
|
||||
'test@aylesburytowncouncil.gov.uk',
|
||||
'non-crown.pdf',
|
||||
'GOV.UK Notify data sharing and financial agreement (non-crown).pdf',
|
||||
),
|
||||
])
|
||||
def test_downloading_agreement(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
fake_uuid,
|
||||
email_address,
|
||||
expected_file_fetched,
|
||||
expected_file_served,
|
||||
):
|
||||
mock_get_s3_object = mocker.patch(
|
||||
'app.main.s3_client.get_s3_object',
|
||||
return_value=_MockS3Object(b'foo')
|
||||
)
|
||||
user = active_user_with_permissions(fake_uuid)
|
||||
user.email_address = email_address
|
||||
mocker.patch('app.user_api_client.get_user', return_value=user)
|
||||
response = logged_in_client.get(url_for('main.download_agreement'))
|
||||
assert response.status_code == 200
|
||||
assert response.get_data() == b'foo'
|
||||
assert response.headers['Content-Type'] == 'application/pdf'
|
||||
assert response.headers['Content-Disposition'] == (
|
||||
'attachment; filename="{}"'.format(expected_file_served)
|
||||
)
|
||||
mock_get_s3_object.assert_called_once_with('test-mou', expected_file_fetched)
|
||||
|
||||
|
||||
def test_agreement_cant_be_downloaded_unknown_crown_status(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
fake_uuid,
|
||||
):
|
||||
mock_get_s3_object = mocker.patch(
|
||||
'app.main.s3_client.get_s3_object',
|
||||
return_value=_MockS3Object()
|
||||
)
|
||||
user = active_user_with_permissions(fake_uuid)
|
||||
user.email_address = 'test@unknown.gov.uk'
|
||||
mocker.patch('app.user_api_client.get_user', return_value=user)
|
||||
response = logged_in_client.get(url_for('main.download_agreement'))
|
||||
assert response.status_code == 404
|
||||
assert mock_get_s3_object.call_args_list == []
|
||||
|
||||
|
||||
def test_agreement_requires_login(
|
||||
client,
|
||||
mocker,
|
||||
):
|
||||
mock_get_s3_object = mocker.patch(
|
||||
'app.main.s3_client.get_s3_object',
|
||||
return_value=_MockS3Object()
|
||||
)
|
||||
response = client.get(url_for('main.download_agreement'))
|
||||
assert response.status_code == 302
|
||||
assert response.location == 'http://localhost/sign-in?next=%2Fagreement.pdf'
|
||||
assert mock_get_s3_object.call_args_list == []
|
||||
Reference in New Issue
Block a user