Allow editing of an organisation’s details

Adds a user interface for updating all the columns added in
https://github.com/alphagov/notifications-api/pull/2368

Sorry for the mega commit 😓
This commit is contained in:
Chris Hill-Scott
2019-02-19 17:26:16 +00:00
parent 307e959fd6
commit 936883bf7b
19 changed files with 1247 additions and 126 deletions

View File

@@ -7,7 +7,13 @@ from flask import url_for
from notifications_python_client.errors import HTTPError
from app.models.user import InvitedOrgUser
from tests.conftest import ORGANISATION_ID, normalize_spaces
from tests import organisation_json
from tests.conftest import (
ORGANISATION_ID,
active_user_with_permissions,
normalize_spaces,
platform_admin_user,
)
def test_organisation_page_shows_all_organisations(
@@ -467,6 +473,26 @@ def test_verified_org_user_redirects_to_dashboard(
def test_organisation_settings(
client_request,
mock_get_organisation,
organisation_one
):
expected_rows = [
'Label Value Action',
'Organisation name Org 1 Change',
]
page = client_request.get('.organisation_settings', org_id=organisation_one['id'])
assert page.find('h1').text == 'Organisation settings'
rows = page.select('tr')
assert len(rows) == len(expected_rows)
for index, row in enumerate(expected_rows):
assert row == " ".join(rows[index].text.split())
mock_get_organisation.assert_called_with(organisation_one['id'])
def test_organisation_settings_for_platform_admin(
logged_in_platform_admin_client,
mock_get_organisation,
organisation_one
@@ -474,6 +500,14 @@ def test_organisation_settings(
expected_rows = [
'Label Value Action',
'Organisation name Org 1 Change',
'Label Value Action',
'Organisation type Not set Change',
'Crown organisation Yes Change',
'Data sharing and financial agreement Signed Change',
'Default email branding Not set Change',
'Default letter branding Not set Change',
'Known email domains None Change',
]
response = logged_in_platform_admin_client.get(url_for('.organisation_settings', org_id=organisation_one['id']))
@@ -489,6 +523,277 @@ def test_organisation_settings(
mock_get_organisation.assert_called_with(organisation_one['id'])
@pytest.mark.parametrize('endpoint, expected_options, expected_selected', (
(
'.edit_organisation_type',
(
('central', 'Central government'),
('local', 'Local government'),
('nhs', 'NHS'),
),
None,
),
(
'.edit_organisation_crown_status',
(
('crown', 'Yes'),
('non-crown', 'No'),
('unknown', 'Not sure'),
),
'crown',
),
(
'.edit_organisation_agreement',
(
('yes', (
'Yes '
'Users will be told their organisation has already signed the agreement'
)),
('no', (
'No '
'Users will be prompted to sign the agreement before they can go live'
)),
('unknown', (
'No (but we have some service-specific agreements in place) '
'Users wont be prompted to sign the agreement'
)),
),
'no',
),
))
@pytest.mark.parametrize('user', (
pytest.param(
platform_admin_user,
),
pytest.param(
active_user_with_permissions,
marks=pytest.mark.xfail
),
))
def test_view_organisation_settings(
client_request,
fake_uuid,
organisation_one,
mock_get_organisation,
endpoint,
expected_options,
expected_selected,
user,
):
client_request.login(user(fake_uuid))
page = client_request.get(endpoint, org_id=organisation_one['id'])
radios = page.select('input[type=radio]')
for index, option in enumerate(expected_options):
label = page.select_one('label[for={}]'.format(radios[index]['id']))
assert (
radios[index]['value'],
normalize_spaces(label.text),
) == option
if expected_selected:
assert page.select_one('input[checked]')['value'] == expected_selected
else:
assert not page.select_one('input[checked]')
@pytest.mark.parametrize('endpoint, post_data, expected_persisted', (
(
'.edit_organisation_type',
{'organisation_type': 'central'},
{'organisation_type': 'central'},
),
(
'.edit_organisation_type',
{'organisation_type': 'local'},
{'organisation_type': 'local'},
),
(
'.edit_organisation_type',
{'organisation_type': 'nhs'},
{'organisation_type': 'nhs'},
),
(
'.edit_organisation_crown_status',
{'crown_status': 'crown'},
{'crown': True},
),
(
'.edit_organisation_crown_status',
{'crown_status': 'non-crown'},
{'crown': False},
),
(
'.edit_organisation_crown_status',
{'crown_status': 'unknown'},
{'crown': None},
),
(
'.edit_organisation_agreement',
{'agreement_signed': 'yes'},
{'agreement_signed': True},
),
(
'.edit_organisation_agreement',
{'agreement_signed': 'no'},
{'agreement_signed': False},
),
(
'.edit_organisation_agreement',
{'agreement_signed': 'unknown'},
{'agreement_signed': None},
),
))
@pytest.mark.parametrize('user', (
pytest.param(
platform_admin_user,
),
pytest.param(
active_user_with_permissions,
marks=pytest.mark.xfail
),
))
def test_update_organisation_settings(
client_request,
fake_uuid,
organisation_one,
mock_get_organisation,
mock_update_organisation,
endpoint,
post_data,
expected_persisted,
user,
):
client_request.login(user(fake_uuid))
client_request.post(
endpoint,
org_id=organisation_one['id'],
_data=post_data,
_expected_status=302,
_expected_redirect=url_for(
'main.organisation_settings',
org_id=organisation_one['id'],
_external=True,
),
)
mock_update_organisation.assert_called_once_with(
organisation_one['id'],
**expected_persisted,
)
@pytest.mark.parametrize('user', (
pytest.param(
platform_admin_user,
),
pytest.param(
active_user_with_permissions,
marks=pytest.mark.xfail
),
))
def test_view_organisation_domains(
mocker,
client_request,
fake_uuid,
user,
):
client_request.login(user(fake_uuid))
mocker.patch(
'app.organisations_client.get_organisation',
side_effect=lambda org_id: organisation_json(
org_id,
'Org 1',
domains=['example.gov.uk', 'test.example.gov.uk'],
)
)
page = client_request.get(
'main.edit_organisation_domains',
org_id=ORGANISATION_ID,
)
assert [textbox['value'] for textbox in page.select('input[type=text]')] == [
'example.gov.uk',
'test.example.gov.uk',
'',
'',
'',
'',
'',
'',
'',
'',
]
@pytest.mark.parametrize('post_data, expected_persisted', (
(
{
'domains-0': 'example.gov.uk',
'domains-5': 'test.gov.uk',
},
{
'domains': [
'example.gov.uk',
'test.gov.uk',
]
}
),
(
{
'domains-0': '',
'domains-1': '',
'domains-2': '',
},
{
'domains': []
}
),
))
@pytest.mark.parametrize('user', (
pytest.param(
platform_admin_user,
),
pytest.param(
active_user_with_permissions,
marks=pytest.mark.xfail
),
))
def test_update_organisation_domains(
client_request,
fake_uuid,
organisation_one,
mock_get_organisation,
mock_update_organisation,
post_data,
expected_persisted,
user,
):
client_request.login(user(fake_uuid))
client_request.post(
'main.edit_organisation_domains',
org_id=ORGANISATION_ID,
_data=post_data,
_expected_status=302,
_expected_redirect=url_for(
'main.organisation_settings',
org_id=organisation_one['id'],
_external=True,
),
)
mock_update_organisation.assert_called_once_with(
ORGANISATION_ID,
**expected_persisted,
)
def test_update_organisation_name(
logged_in_platform_admin_client,
organisation_one,
@@ -553,7 +858,7 @@ def test_confirm_update_organisation(
organisation_one,
mock_get_organisation,
mock_verify_password,
mock_update_organisation_name,
mock_update_organisation,
mocker
):
with logged_in_platform_admin_client.session_transaction() as session:
@@ -570,7 +875,7 @@ def test_confirm_update_organisation(
assert response.status_code == 302
assert response.location == url_for('.organisation_settings', org_id=organisation_one['id'], _external=True)
mock_update_organisation_name.assert_called_with(
mock_update_organisation.assert_called_with(
organisation_one['id'],
name=session['organisation_name_change']
)

View File

@@ -11,8 +11,14 @@ from notifications_utils.clients.zendesk.zendesk_client import ZendeskClient
import app
from app.utils import email_safe
from tests import sample_uuid, service_json, validate_route_permission
from tests import (
organisation_json,
sample_uuid,
service_json,
validate_route_permission,
)
from tests.conftest import (
ORGANISATION_ID,
SERVICE_ONE_ID,
active_user_no_api_key_permission,
active_user_no_settings_permission,
@@ -2415,20 +2421,44 @@ def test_service_set_letter_branding_platform_admin_only(
(str(UUID(int=1)), 'Land Registry'),
)),
])
@pytest.mark.parametrize('endpoint, extra_args', (
(
'main.service_set_letter_branding',
{'service_id': SERVICE_ONE_ID},
),
(
'main.edit_organisation_letter_branding',
{'org_id': ORGANISATION_ID},
),
))
def test_service_set_letter_branding_prepopulates(
logged_in_platform_admin_client,
mocker,
client_request,
platform_admin_user,
service_one,
mock_get_organisation,
mock_get_all_letter_branding,
letter_branding,
expected_selected,
expected_items,
endpoint,
extra_args,
):
service_one['letter_branding'] = letter_branding
response = logged_in_platform_admin_client.get(
url_for('main.service_set_letter_branding', service_id=service_one['id'])
mocker.patch(
'app.organisations_client.get_organisation',
side_effect=lambda org_id: organisation_json(
org_id,
'Org 1',
letter_branding_id=letter_branding,
)
)
client_request.login(platform_admin_user)
page = client_request.get(
endpoint,
**extra_args,
)
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert len(page.select('input[checked]')) == 1
assert page.select('input[checked]')[0]['value'] == expected_selected
@@ -2446,36 +2476,70 @@ def test_service_set_letter_branding_prepopulates(
(str(UUID(int=1)), str(UUID(int=1))),
('__NONE__', None),
])
@pytest.mark.parametrize('endpoint, extra_args, expected_redirect', (
(
'main.service_set_letter_branding',
{'service_id': SERVICE_ONE_ID},
'main.service_preview_letter_branding',
),
(
'main.edit_organisation_letter_branding',
{'org_id': ORGANISATION_ID},
'main.organisation_preview_letter_branding',
),
))
def test_service_set_letter_branding_redirects_to_preview_page_when_form_submitted(
logged_in_platform_admin_client,
service_one,
client_request,
platform_admin_user,
mock_get_organisation,
mock_get_all_letter_branding,
selected_letter_branding,
expected_post_data
expected_post_data,
endpoint,
extra_args,
expected_redirect,
):
response = logged_in_platform_admin_client.post(
url_for('main.service_set_letter_branding', service_id=service_one['id']),
data={'branding_style': selected_letter_branding},
client_request.login(platform_admin_user)
client_request.post(
endpoint,
_data={'branding_style': selected_letter_branding},
_expected_status=302,
_expected_redirect=url_for(
expected_redirect,
branding_style=expected_post_data,
_external=True,
**extra_args
),
**extra_args
)
assert response.status_code == 302
assert response.location == url_for(
@pytest.mark.parametrize('endpoint, extra_args', (
(
'main.service_preview_letter_branding',
service_id=service_one['id'],
branding_style=expected_post_data,
_external=True)
{'service_id': SERVICE_ONE_ID},
),
(
'main.organisation_preview_letter_branding',
{'org_id': ORGANISATION_ID},
),
))
def test_service_preview_letter_branding_shows_preview_letter(
logged_in_platform_admin_client,
service_one,
client_request,
platform_admin_user,
mock_get_organisation,
mock_get_all_letter_branding,
endpoint,
extra_args,
):
response = logged_in_platform_admin_client.get(
url_for('main.service_preview_letter_branding', service_id=service_one['id'], branding_style='hm-government')
)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
client_request.login(platform_admin_user)
page = client_request.get(
endpoint,
branding_style='hm-government',
**extra_args
)
assert response.status_code == 200
assert page.find('iframe')['src'] == url_for('main.letter_template', branding_style='hm-government')
@@ -2483,21 +2547,60 @@ def test_service_preview_letter_branding_shows_preview_letter(
(str(UUID(int=1)), str(UUID(int=1))),
('__NONE__', None),
])
@pytest.mark.parametrize('endpoint, extra_args, expected_redirect', (
(
'main.service_preview_letter_branding',
{'service_id': SERVICE_ONE_ID},
'main.service_settings',
),
(
'main.organisation_preview_letter_branding',
{'org_id': ORGANISATION_ID},
'main.organisation_settings',
),
))
def test_service_preview_letter_branding_saves(
logged_in_platform_admin_client,
service_one,
client_request,
platform_admin_user,
mock_get_organisation,
mock_update_service,
mock_update_organisation,
mock_get_all_letter_branding,
selected_letter_branding,
expected_post_data
expected_post_data,
endpoint,
extra_args,
expected_redirect,
):
response = logged_in_platform_admin_client.post(
url_for('main.service_preview_letter_branding', service_id=service_one['id']),
data={'branding_style': selected_letter_branding}
client_request.login(platform_admin_user)
client_request.post(
endpoint,
_data={'branding_style': selected_letter_branding},
_expected_status=302,
_expected_redirect=url_for(
expected_redirect,
_external=True,
**extra_args
),
**extra_args
)
assert response.status_code == 302
assert response.location == url_for('main.service_settings', service_id=service_one['id'], _external=True)
mock_update_service.assert_called_once_with(service_one['id'], letter_branding=expected_post_data)
if endpoint == 'main.service_preview_letter_branding':
mock_update_service.assert_called_once_with(
SERVICE_ONE_ID,
letter_branding=expected_post_data,
)
assert mock_update_organisation.called is False
elif endpoint == 'main.organisation_preview_letter_branding':
mock_update_organisation.assert_called_once_with(
ORGANISATION_ID,
letter_branding_id=expected_post_data,
)
assert mock_update_service.called is False
else:
raise Exception
@pytest.mark.parametrize('current_branding, expected_values, expected_labels', [
@@ -2512,20 +2615,41 @@ def test_service_preview_letter_branding_saves(
'org 5', 'GOV.UK', 'org 1', 'org 2', 'org 3', 'org 4',
]),
])
@pytest.mark.parametrize('endpoint, extra_args', (
(
'main.service_set_email_branding',
{'service_id': SERVICE_ONE_ID},
),
(
'main.edit_organisation_email_branding',
{'org_id': ORGANISATION_ID},
),
))
def test_should_show_branding_styles(
logged_in_platform_admin_client,
mocker,
client_request,
platform_admin_user,
service_one,
mock_get_all_email_branding,
current_branding,
expected_values,
expected_labels,
endpoint,
extra_args,
):
service_one['email_branding'] = current_branding
response = logged_in_platform_admin_client.get(url_for(
'main.service_set_email_branding', service_id=service_one['id']
))
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
mocker.patch(
'app.organisations_client.get_organisation',
side_effect=lambda org_id: organisation_json(
org_id,
'Org 1',
email_branding_id=current_branding,
)
)
client_request.login(platform_admin_user)
page = client_request.get(endpoint, **extra_args)
branding_style_choices = page.find_all('input', attrs={"name": "branding_style"})
radio_labels = [
@@ -2551,39 +2675,74 @@ def test_should_show_branding_styles(
app.service_api_client.get_service.assert_called_once_with(service_one['id'])
@pytest.mark.parametrize('endpoint, extra_args, expected_redirect', (
(
'main.service_set_email_branding',
{'service_id': SERVICE_ONE_ID},
'main.service_preview_email_branding',
),
(
'main.edit_organisation_email_branding',
{'org_id': ORGANISATION_ID},
'main.organisation_preview_email_branding',
),
))
def test_should_send_branding_and_organisations_to_preview(
logged_in_platform_admin_client,
client_request,
platform_admin_user,
service_one,
mock_get_organisation,
mock_get_all_email_branding,
mock_update_service,
endpoint,
extra_args,
expected_redirect,
):
response = logged_in_platform_admin_client.post(
url_for(
'main.service_set_email_branding', service_id=service_one['id']
),
client_request.login(platform_admin_user)
client_request.post(
endpoint,
data={
'branding_type': 'org',
'branding_style': '1'
}
},
_expected_status=302,
_expected_location=url_for(
expected_redirect,
branding_style='1',
_external=True,
**extra_args
),
**extra_args
)
assert response.status_code == 302
assert response.location == url_for('main.service_preview_email_branding',
service_id=service_one['id'], branding_style='1',
_external=True)
mock_get_all_email_branding.assert_called_once_with()
@pytest.mark.parametrize('endpoint, extra_args', (
(
'main.service_preview_email_branding',
{'service_id': SERVICE_ONE_ID},
),
(
'main.organisation_preview_email_branding',
{'org_id': ORGANISATION_ID},
),
))
def test_should_preview_email_branding(
logged_in_platform_admin_client,
service_one,
client_request,
platform_admin_user,
mock_get_organisation,
endpoint,
extra_args,
):
response = logged_in_platform_admin_client.get(url_for(
'main.service_preview_email_branding', service_id=service_one['id'],
branding_type='org', branding_style='1'
))
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
client_request.login(platform_admin_user)
page = client_request.get(
endpoint,
branding_type='org',
branding_style='1',
**extra_args
)
iframe = page.find('iframe', attrs={"class": "branding-preview"})
iframeURLComponents = urlparse(iframe['src'])
iframeQString = parse_qs(iframeURLComponents.query)
@@ -2592,37 +2751,66 @@ def test_should_preview_email_branding(
assert iframeURLComponents.path == '/_email'
assert iframeQString['branding_style'] == ['1']
app.service_api_client.get_service.assert_called_once_with(service_one['id'])
@pytest.mark.parametrize('posted_value, submitted_value', (
('1', '1'),
('__NONE__', None),
pytest.param('None', None, marks=pytest.mark.xfail(raises=AssertionError)),
))
@pytest.mark.parametrize('endpoint, extra_args, expected_redirect', (
(
'main.service_preview_email_branding',
{'service_id': SERVICE_ONE_ID},
'main.service_settings',
),
(
'main.organisation_preview_email_branding',
{'org_id': ORGANISATION_ID},
'main.organisation_settings',
),
))
def test_should_set_branding_and_organisations(
logged_in_platform_admin_client,
client_request,
platform_admin_user,
service_one,
mock_get_organisation,
mock_update_service,
mock_update_organisation,
posted_value,
submitted_value,
endpoint,
extra_args,
expected_redirect,
):
response = logged_in_platform_admin_client.post(
url_for(
'main.service_preview_email_branding', service_id=service_one['id']
),
data={
client_request.login(platform_admin_user)
client_request.post(
endpoint,
_data={
'branding_style': posted_value
}
},
_expected_status=302,
_expected_redirect=url_for(
expected_redirect,
_external=True,
**extra_args
),
**extra_args
)
assert response.status_code == 302
assert response.location == url_for('main.service_settings',
service_id=service_one['id'], _external=True)
mock_update_service.assert_called_once_with(
service_one['id'],
email_branding=submitted_value
)
if endpoint == 'main.service_preview_email_branding':
mock_update_service.assert_called_once_with(
SERVICE_ONE_ID,
email_branding=submitted_value,
)
assert mock_update_organisation.called is False
elif endpoint == 'main.organisation_preview_email_branding':
mock_update_organisation.assert_called_once_with(
ORGANISATION_ID,
email_branding_id=submitted_value
)
assert mock_update_service.called is False
else:
raise Exception
@pytest.mark.parametrize('method', ['get', 'post'])