mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-06-19 20:52:32 -04:00
link-services-to-organisations
This commit is contained in:
@@ -885,3 +885,17 @@ class SetTemplateSenderForm(StripWhitespaceForm):
|
||||
self.sender.label.text = 'Select your sender'
|
||||
|
||||
sender = RadioField()
|
||||
|
||||
|
||||
class LinkOrganisationsForm(StripWhitespaceForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.organisations.choices = kwargs['choices']
|
||||
|
||||
organisations = RadioField(
|
||||
'Select an organisation',
|
||||
validators=[
|
||||
DataRequired()
|
||||
]
|
||||
)
|
||||
|
||||
@@ -17,7 +17,6 @@ from notifications_utils.field import Field
|
||||
from notifications_utils.clients import DeskproError
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
from app import service_api_client, deskpro_client
|
||||
from app.main import main
|
||||
from app.utils import user_has_permissions, email_safe, get_cdn_domain
|
||||
from app.main.forms import (
|
||||
@@ -36,8 +35,18 @@ from app.main.forms import (
|
||||
ServiceEditInboundNumberForm,
|
||||
SMSPrefixForm,
|
||||
ServiceSwitchLettersForm,
|
||||
LinkOrganisationsForm,
|
||||
)
|
||||
from app import (
|
||||
service_api_client,
|
||||
deskpro_client,
|
||||
user_api_client,
|
||||
current_service,
|
||||
email_branding_client,
|
||||
inbound_number_client,
|
||||
billing_api_client,
|
||||
organisations_client,
|
||||
)
|
||||
from app import user_api_client, current_service, email_branding_client, inbound_number_client, billing_api_client
|
||||
from notifications_utils.formatters import formatted_list
|
||||
|
||||
|
||||
@@ -46,6 +55,8 @@ from notifications_utils.formatters import formatted_list
|
||||
@user_has_permissions('manage_settings', 'manage_api_keys', admin_override=True, any_=True)
|
||||
def service_settings(service_id):
|
||||
letter_branding_organisations = email_branding_client.get_letter_email_branding()
|
||||
organisation = organisations_client.get_service_organisation(service_id).get('name', None)
|
||||
|
||||
if current_service['email_branding']:
|
||||
email_branding = email_branding_client.get_email_branding(current_service['email_branding'])['email_branding']
|
||||
else:
|
||||
@@ -87,6 +98,7 @@ def service_settings(service_id):
|
||||
sms_sender_count=sms_sender_count,
|
||||
free_sms_fragment_limit=free_sms_fragment_limit,
|
||||
prefix_sms=current_service['prefix_sms'],
|
||||
organisation=organisation,
|
||||
)
|
||||
|
||||
|
||||
@@ -762,6 +774,33 @@ def set_letter_branding(service_id):
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/service-settings/link-service-to-organisation", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_has_permissions(admin_override=True)
|
||||
def link_service_to_organisation(service_id):
|
||||
|
||||
organisations = organisations_client.get_organisations()
|
||||
current_organisation = organisations_client.get_service_organisation(service_id).get('id', None)
|
||||
|
||||
form = LinkOrganisationsForm(
|
||||
choices=convert_dictionary_to_wtforms_choices_format(organisations, 'id', 'name'),
|
||||
organisations=current_organisation
|
||||
)
|
||||
|
||||
if form.validate_on_submit():
|
||||
if form.organisations.data != current_organisation:
|
||||
organisations_client.update_service_organisation(
|
||||
service_id,
|
||||
form.organisations.data
|
||||
)
|
||||
return redirect(url_for('.service_settings', service_id=service_id))
|
||||
|
||||
return render_template(
|
||||
'views/service-settings/link-service-to-organisation.html',
|
||||
form=form,
|
||||
)
|
||||
|
||||
|
||||
def get_branding_as_value_and_label(email_branding):
|
||||
return [
|
||||
(branding['id'], branding['name'])
|
||||
@@ -776,3 +815,9 @@ def get_branding_as_dict(email_branding):
|
||||
'colour': branding['colour']
|
||||
} for branding in email_branding
|
||||
}
|
||||
|
||||
|
||||
def convert_dictionary_to_wtforms_choices_format(dictionary, value, label):
|
||||
return [
|
||||
(item[value], item[label]) for item in dictionary
|
||||
]
|
||||
|
||||
@@ -28,3 +28,15 @@ class OrganisationsClient(NotifyAdminAPIClient):
|
||||
"name": name
|
||||
}
|
||||
return self.post(url="/organisations/{}".format(org_id), data=data)
|
||||
|
||||
def get_service_organisation(self, service_id):
|
||||
return self.get(url="/service/{}/organisation".format(service_id))
|
||||
|
||||
def update_service_organisation(self, service_id, organisation_id):
|
||||
data = {
|
||||
'service_id': service_id
|
||||
}
|
||||
return self.post(
|
||||
url="/organisations/{}/service".format(organisation_id),
|
||||
data=data
|
||||
)
|
||||
|
||||
@@ -14,11 +14,12 @@
|
||||
|
||||
<h1 class="heading-large">{{ '{} an organisation'.format('Update' if organisation else 'Create')}}</h1>
|
||||
<form method="post">
|
||||
{{textbox(form.name)}}
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
back_link=url_for('.organisations'),
|
||||
back_link_text='Back to organisations',
|
||||
) }}
|
||||
{{textbox(form.name)}}
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
back_link=url_for('.organisations'),
|
||||
back_link_text='Back to organisations',
|
||||
) }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
Organisations
|
||||
</h1>
|
||||
<nav class="browse-list">
|
||||
<ul>
|
||||
<ul>
|
||||
{% for org in organisations %}
|
||||
<li class="browse-list-item">
|
||||
<a href="{{ url_for('main.view_organisation', org_id=org['id']) }}" class="browse-list-link">{{ org['name'] }}</a>
|
||||
@@ -24,7 +24,7 @@
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ul>
|
||||
</nav>
|
||||
<div>
|
||||
<a href="{{ url_for('main.add_organisation') }}" class="browse-list-link">Create an organisation</a>
|
||||
|
||||
@@ -12,12 +12,9 @@
|
||||
{% block platform_admin_content %}
|
||||
|
||||
<h1 class="heading-large">
|
||||
<div>{{ organisation['name'] }}</div>
|
||||
{{ organisation['name'] }}
|
||||
</h1>
|
||||
<div class="grid-row">
|
||||
<div class="column-three-quarters">
|
||||
[List of services]
|
||||
</div>
|
||||
</div>
|
||||
<p> [List of services] </p>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -255,6 +255,11 @@
|
||||
field_headings_visible=False,
|
||||
caption_visible=False
|
||||
) %}
|
||||
{% call row() %}
|
||||
{{ text_field('Organisation')}}
|
||||
{{ optional_text_field(organisation or 'Not Set') }}
|
||||
{{ edit_field('Change', url_for('.link_service_to_organisation', service_id=current_service.id)) }}
|
||||
{% endcall %}
|
||||
{% call row() %}
|
||||
{{ text_field('Organisation type')}}
|
||||
{{ optional_text_field(
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/radios.html" import radios %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Link service to organisation
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-large">
|
||||
Link service to organisation
|
||||
</h1>
|
||||
<form method="post">
|
||||
{{ radios(form.organisations) }}
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
back_link=url_for('.service_settings', service_id=current_service.id),
|
||||
back_link_text='Back to settings'
|
||||
) }}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -12,6 +12,7 @@ def get_service_settings_page(
|
||||
service_one,
|
||||
mock_get_inbound_number_for_service,
|
||||
mock_get_letter_email_branding,
|
||||
mock_get_service_organisation,
|
||||
mock_get_free_sms_fragment_limit,
|
||||
no_reply_to_email_addresses,
|
||||
no_letter_contact_blocks,
|
||||
@@ -103,6 +104,7 @@ def test_normal_user_doesnt_see_any_toggle_buttons(
|
||||
service_one,
|
||||
no_reply_to_email_addresses,
|
||||
no_letter_contact_blocks,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_letter_email_branding,
|
||||
mock_get_inbound_number_for_service,
|
||||
|
||||
@@ -54,7 +54,7 @@ def test_view_organisation_shows_the_correct_organisation(
|
||||
assert response.status_code == 200
|
||||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||
|
||||
assert page.select_one('.heading-large div').text == org['name']
|
||||
assert normalize_spaces(page.select_one('.heading-large').text) == org['name']
|
||||
|
||||
|
||||
def test_edit_organisation_shows_the_correct_organisation(
|
||||
|
||||
@@ -83,6 +83,7 @@ def mock_get_service_settings_page_common(
|
||||
'Send letters Off Change',
|
||||
|
||||
'Label Value Action',
|
||||
'Organisation Org 1 Change',
|
||||
'Organisation type Central Change',
|
||||
'Free text message allowance 250,000 Change',
|
||||
'Email branding GOV.UK Change',
|
||||
@@ -97,6 +98,7 @@ def test_should_show_overview(
|
||||
fake_uuid,
|
||||
no_reply_to_email_addresses,
|
||||
no_letter_contact_blocks,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
user,
|
||||
expected_rows,
|
||||
@@ -169,6 +171,7 @@ def test_should_show_overview_for_service_with_more_things_set(
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
single_sms_sender,
|
||||
mock_get_service_organisation,
|
||||
mock_get_email_branding,
|
||||
mock_get_service_settings_page_common,
|
||||
permissions,
|
||||
@@ -201,6 +204,7 @@ def test_letter_contact_block_shows_none_if_not_set(
|
||||
mocker,
|
||||
single_reply_to_email_address,
|
||||
no_letter_contact_blocks,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -221,6 +225,7 @@ def test_escapes_letter_contact_block(
|
||||
mocker,
|
||||
single_reply_to_email_address,
|
||||
single_sms_sender,
|
||||
mock_get_service_organisation,
|
||||
injected_letter_contact_block,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -281,6 +286,7 @@ def test_show_restricted_service(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -315,6 +321,7 @@ def test_show_live_service(
|
||||
mock_get_live_service,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -449,6 +456,7 @@ def test_should_redirect_after_request_to_go_live(
|
||||
active_user_with_permissions,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common
|
||||
):
|
||||
@@ -508,6 +516,7 @@ def test_route_permissions(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
route,
|
||||
mock_get_service_settings_page_common,
|
||||
@@ -565,6 +574,7 @@ def test_route_for_platform_admin(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
route,
|
||||
mock_get_service_settings_page_common,
|
||||
@@ -635,6 +645,7 @@ def test_and_more_hint_appears_on_settings_with_more_than_just_a_single_sender(
|
||||
service_one,
|
||||
multiple_reply_to_email_addresses,
|
||||
multiple_letter_contact_blocks,
|
||||
mock_get_service_organisation,
|
||||
multiple_sms_senders,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -664,6 +675,7 @@ def test_api_ids_dont_show_on_option_pages_with_a_single_sender(
|
||||
client_request,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
sender_list_page,
|
||||
expected_output
|
||||
@@ -1218,6 +1230,7 @@ def test_shows_research_mode_indicator(
|
||||
mocker,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -1237,6 +1250,7 @@ def test_does_not_show_research_mode_indicator(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -1684,6 +1698,7 @@ def test_archive_service_prompts_user(
|
||||
mocker,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -1702,6 +1717,7 @@ def test_cant_archive_inactive_service(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common
|
||||
):
|
||||
@@ -1735,6 +1751,7 @@ def test_suspend_service_prompts_user(
|
||||
mocker,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -1754,6 +1771,7 @@ def test_cant_suspend_inactive_service(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common,
|
||||
):
|
||||
@@ -1771,6 +1789,7 @@ def test_resume_service_after_confirm(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
mocker,
|
||||
mock_get_inbound_number_for_service,
|
||||
):
|
||||
@@ -1789,6 +1808,7 @@ def test_resume_service_prompts_user(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mocker,
|
||||
mock_get_service_settings_page_common,
|
||||
@@ -1810,6 +1830,7 @@ def test_cant_resume_active_service(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mock_get_service_settings_page_common
|
||||
):
|
||||
@@ -1871,6 +1892,7 @@ def test_service_settings_when_inbound_number_is_not_set(
|
||||
service_one,
|
||||
single_reply_to_email_address,
|
||||
single_letter_contact_block,
|
||||
mock_get_service_organisation,
|
||||
single_sms_sender,
|
||||
mocker,
|
||||
mock_get_letter_email_branding,
|
||||
@@ -1993,3 +2015,58 @@ def test_updates_sms_prefixing(
|
||||
service_id=SERVICE_ONE_ID,
|
||||
prefix_sms=expected_api_argument,
|
||||
)
|
||||
|
||||
|
||||
def test_select_organisation(
|
||||
logged_in_platform_admin_client,
|
||||
service_one,
|
||||
mock_get_service_organisation,
|
||||
mock_get_organisations
|
||||
):
|
||||
response = logged_in_platform_admin_client.get(
|
||||
url_for('.link_service_to_organisation', service_id=service_one['id']),
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||
|
||||
assert len(page.select('.multiple-choice')) == 3
|
||||
for i in range(0, 3):
|
||||
assert normalize_spaces(
|
||||
page.select('.multiple-choice label')[i].text
|
||||
) == 'Org {}'.format(i + 1)
|
||||
|
||||
|
||||
def test_update_service_organisation(
|
||||
logged_in_platform_admin_client,
|
||||
service_one,
|
||||
mock_get_service_organisation,
|
||||
mock_get_organisations,
|
||||
mock_update_service_organisation,
|
||||
):
|
||||
response = logged_in_platform_admin_client.post(
|
||||
url_for('.link_service_to_organisation', service_id=service_one['id']),
|
||||
data={'organisations': '7aa5d4e9-4385-4488-a489-07812ba13384'},
|
||||
)
|
||||
|
||||
assert response.status_code == 302
|
||||
mock_update_service_organisation.assert_called_once_with(
|
||||
service_one['id'],
|
||||
'7aa5d4e9-4385-4488-a489-07812ba13384'
|
||||
)
|
||||
|
||||
|
||||
def test_update_service_organisation_does_not_update_if_same_value(
|
||||
logged_in_platform_admin_client,
|
||||
service_one,
|
||||
mock_get_service_organisation,
|
||||
mock_get_organisations,
|
||||
mock_update_service_organisation,
|
||||
):
|
||||
response = logged_in_platform_admin_client.post(
|
||||
url_for('.link_service_to_organisation', service_id=service_one['id']),
|
||||
data={'organisations': '7aa5d4e9-4385-4488-a489-07812ba13383'},
|
||||
)
|
||||
|
||||
assert response.status_code == 302
|
||||
mock_update_service_organisation.called is False
|
||||
|
||||
@@ -2631,3 +2631,62 @@ def mock_update_service_callback_api(mocker):
|
||||
return
|
||||
|
||||
return mocker.patch('app.service_api_client.update_service_callback_api', side_effect=_update_service_callback_api)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_get_organisations(mocker):
|
||||
def _get_organisations():
|
||||
return [
|
||||
{
|
||||
'name': 'Org 1',
|
||||
'id': '7aa5d4e9-4385-4488-a489-07812ba13383',
|
||||
'active': True
|
||||
},
|
||||
{
|
||||
'name': 'Org 2',
|
||||
'id': '7aa5d4e9-4385-4488-a489-07812ba13384',
|
||||
'active': True
|
||||
},
|
||||
{
|
||||
'name': 'Org 3',
|
||||
'id': '7aa5d4e9-4385-4488-a489-07812ba13385',
|
||||
'active': True
|
||||
}
|
||||
]
|
||||
|
||||
return mocker.patch('app.organisations_client.get_organisations', side_effect=_get_organisations)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_get_organisation(mocker):
|
||||
def _get_organisation(organisation_id):
|
||||
return {
|
||||
'name': 'Org 1',
|
||||
'id': organisation_id,
|
||||
'active': True
|
||||
}
|
||||
|
||||
return mocker.patch('app.organisations_client.get_organisation', side_effect=_get_organisation)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_get_service_organisation(mocker):
|
||||
def _get_service_organisation(service_id):
|
||||
return {
|
||||
'name': 'Org 1',
|
||||
'id': '7aa5d4e9-4385-4488-a489-07812ba13383',
|
||||
'active': True
|
||||
}
|
||||
|
||||
return mocker.patch('app.organisations_client.get_service_organisation', side_effect=_get_service_organisation)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_update_service_organisation(mocker):
|
||||
def _update_service_organisation(service_id, organisation_id):
|
||||
return
|
||||
|
||||
return mocker.patch(
|
||||
'app.organisations_client.update_service_organisation',
|
||||
side_effect=_update_service_organisation
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user