add deactivate service button on the service settings page

only visible for platform admins looking at active services.
no way to undo. no confirm button.
This commit is contained in:
Leo Hemsted
2016-11-02 16:53:40 +00:00
parent e89f89bd11
commit a982144821
7 changed files with 140 additions and 110 deletions
+8
View File
@@ -184,6 +184,14 @@ def service_switch_can_send_letters(service_id):
return redirect(url_for('.service_settings', service_id=service_id)) return redirect(url_for('.service_settings', service_id=service_id))
@main.route("/services/<service_id>/service-settings/deactivate", methods=['GET', 'POST'])
@login_required
@user_has_permissions('manage_settings', admin_override=True)
def deactivate_service(service_id):
service_api_client.deactivate_service(service_id)
return redirect(url_for('.service_settings', service_id=service_id))
@main.route("/services/<service_id>/service-settings/set-reply-to-email", methods=['GET', 'POST']) @main.route("/services/<service_id>/service-settings/set-reply-to-email", methods=['GET', 'POST'])
@login_required @login_required
@user_has_permissions('manage_settings', admin_override=True) @user_has_permissions('manage_settings', admin_override=True)
+5 -2
View File
@@ -1,11 +1,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from flask import url_for from flask import url_for
from notifications_python_client.notifications import NotificationsAPIClient from notifications_python_client.base import BaseAPIClient
from app.utils import BrowsableItem from app.utils import BrowsableItem
from app.notify_client import _attach_current_user from app.notify_client import _attach_current_user
class ServiceAPIClient(NotificationsAPIClient): class ServiceAPIClient(BaseAPIClient):
# Fudge assert in the super __init__ so # Fudge assert in the super __init__ so
# we can set those variables later. # we can set those variables later.
def __init__(self): def __init__(self):
@@ -97,6 +97,9 @@ class ServiceAPIClient(NotificationsAPIClient):
def update_service_with_properties(self, service_id, properties): def update_service_with_properties(self, service_id, properties):
return self.update_service(service_id, **properties) return self.update_service(service_id, **properties)
def deactivate_service(self, service_id):
return self.post('/service/{}/deactivate'.format(service_id), data=None)
def remove_user_from_service(self, service_id, user_id): def remove_user_from_service(self, service_id, user_id):
""" """
Remove a user from a service Remove a user from a service
@@ -98,6 +98,13 @@
{{ 'Stop sending letters' if current_service.can_send_letters else 'Allow to send letters' }} {{ 'Stop sending letters' if current_service.can_send_letters else 'Allow to send letters' }}
</a> </a>
</li> </li>
{% if current_service.active %}
<li class="bottom-gutter">
<a href="{{ url_for('.deactivate_service', service_id=current_service.id) }}" class="button">
Deactivate service
</a>
</li>
{% endif %}
</ul> </ul>
{% endif %} {% endif %}
+34 -31
View File
@@ -1,6 +1,7 @@
import uuid import uuid
from collections import OrderedDict from collections import OrderedDict
import pytest
from flask import url_for from flask import url_for
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
@@ -244,48 +245,50 @@ def test_should_redirect_after_revoking_api_key(app_,
mock_get_api_keys.assert_called_once_with(service_id=fake_uuid, key_id=fake_uuid) mock_get_api_keys.assert_called_once_with(service_id=fake_uuid, key_id=fake_uuid)
@pytest.mark.parametrize('route', [
'main.api_keys',
'main.create_api_key',
'main.revoke_api_key'
])
def test_route_permissions(mocker, def test_route_permissions(mocker,
app_, app_,
api_user_active, api_user_active,
service_one, service_one,
mock_get_api_keys): mock_get_api_keys,
routes = [ route):
'main.api_keys',
'main.create_api_key',
'main.revoke_api_key']
with app_.test_request_context(): with app_.test_request_context():
for route in routes: validate_route_permission(
validate_route_permission( mocker,
mocker, app_,
app_, "GET",
"GET", 200,
200, url_for(route, service_id=service_one['id'], key_id=123),
url_for(route, service_id=service_one['id'], key_id=123), ['manage_api_keys'],
['manage_api_keys'], api_user_active,
api_user_active, service_one)
service_one)
@pytest.mark.parametrize('route', [
'main.api_keys',
'main.create_api_key',
'main.revoke_api_key'
])
def test_route_invalid_permissions(mocker, def test_route_invalid_permissions(mocker,
app_, app_,
api_user_active, api_user_active,
service_one, service_one,
mock_get_api_keys): mock_get_api_keys,
routes = [ route):
'main.api_keys',
'main.create_api_key',
'main.revoke_api_key']
with app_.test_request_context(): with app_.test_request_context():
for route in routes: validate_route_permission(
validate_route_permission( mocker,
mocker, app_,
app_, "GET",
"GET", 403,
403, url_for(route, service_id=service_one['id'], key_id=123),
url_for(route, service_id=service_one['id'], key_id=123), ['view_activity'],
['view_activity'], api_user_active,
api_user_active, service_one)
service_one)
def test_should_show_whitelist_page( def test_should_show_whitelist_page(
+9 -15
View File
@@ -440,22 +440,16 @@ def test_route_for_service_permissions(mocker,
mock_get_template_statistics, mock_get_template_statistics,
mock_get_detailed_service, mock_get_detailed_service,
mock_get_usage): mock_get_usage):
routes = [
'main.service_dashboard']
with app_.test_request_context(): with app_.test_request_context():
# Just test that the user is part of the service validate_route_permission(
for route in routes: mocker,
validate_route_permission( app_,
mocker, "GET",
app_, 200,
"GET", url_for('main.service_dashboard', service_id=service_one['id']),
200, ['view_activity'],
url_for( api_user_active,
route, service_one)
service_id=service_one['id']),
['view_activity'],
api_user_active,
service_one)
def test_aggregate_template_stats(): def test_aggregate_template_stats():
+38 -47
View File
@@ -1,12 +1,14 @@
import pytest
import re
from itertools import repeat
from io import BytesIO from io import BytesIO
from os import path from os import path
from glob import glob from glob import glob
from bs4 import BeautifulSoup import re
from itertools import repeat
from functools import partial from functools import partial
import pytest
from bs4 import BeautifulSoup
from flask import url_for from flask import url_for
from tests import validate_route_permission from tests import validate_route_permission
template_types = ['email', 'sms'] template_types = ['email', 'sms']
@@ -447,6 +449,12 @@ def test_check_messages_should_revalidate_file_when_uploading_file(
assert 'There is a problem with your data' in response.get_data(as_text=True) assert 'There is a problem with your data' in response.get_data(as_text=True)
@pytest.mark.parametrize('route, response_code', [
('main.choose_template', 200),
('main.send_messages', 200),
('main.get_example_csv', 200),
('main.send_test', 302)
])
def test_route_permissions(mocker, def test_route_permissions(mocker,
app_, app_,
api_user_active, api_user_active,
@@ -457,35 +465,17 @@ def test_route_permissions(mocker,
mock_get_notifications, mock_get_notifications,
mock_create_job, mock_create_job,
mock_s3_upload, mock_s3_upload,
fake_uuid): fake_uuid,
routes = [ route,
'main.choose_template', response_code):
'main.send_messages',
'main.get_example_csv']
with app_.test_request_context():
for route in routes:
validate_route_permission(
mocker,
app_,
"GET",
200,
url_for(
route,
service_id=service_one['id'],
template_type='sms',
template_id=fake_uuid),
['send_texts', 'send_emails', 'send_letters'],
api_user_active,
service_one)
with app_.test_request_context(): with app_.test_request_context():
validate_route_permission( validate_route_permission(
mocker, mocker,
app_, app_,
"GET", "GET",
302, response_code,
url_for( url_for(
'main.send_test', route,
service_id=service_one['id'], service_id=service_one['id'],
template_type='sms', template_type='sms',
template_id=fake_uuid), template_id=fake_uuid),
@@ -494,6 +484,12 @@ def test_route_permissions(mocker,
service_one) service_one)
@pytest.mark.parametrize('route', [
'main.choose_template',
'main.send_messages',
'main.get_example_csv',
'main.send_test'
])
def test_route_invalid_permissions(mocker, def test_route_invalid_permissions(mocker,
app_, app_,
api_user_active, api_user_active,
@@ -503,27 +499,22 @@ def test_route_invalid_permissions(mocker,
mock_get_jobs, mock_get_jobs,
mock_get_notifications, mock_get_notifications,
mock_create_job, mock_create_job,
fake_uuid): fake_uuid,
routes = [ route):
'main.choose_template',
'main.send_messages',
'main.get_example_csv',
'main.send_test']
with app_.test_request_context(): with app_.test_request_context():
for route in routes: validate_route_permission(
validate_route_permission( mocker,
mocker, app_,
app_, "GET",
"GET", 403,
403, url_for(
url_for( route,
route, service_id=service_one['id'],
service_id=service_one['id'], template_type='sms',
template_type='sms', template_id=fake_uuid),
template_id=fake_uuid), ['blah'],
['blah'], api_user_active,
api_user_active, service_one)
service_one)
def test_route_choose_template_manage_service_permissions(mocker, def test_route_choose_template_manage_service_permissions(mocker,
+39 -15
View File
@@ -416,6 +416,7 @@ def test_route_permissions(mocker, app_, api_user_active, service_one, route):
'main.service_switch_live', 'main.service_switch_live',
'main.service_switch_research_mode', 'main.service_switch_research_mode',
'main.service_switch_can_send_letters', 'main.service_switch_can_send_letters',
'main.deactivate_service',
]) ])
def test_route_invalid_permissions(mocker, app_, api_user_active, service_one, route): def test_route_invalid_permissions(mocker, app_, api_user_active, service_one, route):
with app_.test_request_context(): with app_.test_request_context():
@@ -448,22 +449,23 @@ def test_route_for_platform_admin(mocker, app_, platform_admin_user, service_one
service_one) service_one)
def test_route_for_platform_admin_update_service(mocker, app_, platform_admin_user, service_one): @pytest.mark.parametrize('route', [
routes = [ 'main.service_switch_live',
'main.service_switch_live', 'main.service_switch_research_mode',
'main.service_switch_research_mode', 'main.service_switch_can_send_letters',
'main.service_switch_can_send_letters' 'main.deactivate_service',
] ])
def test_route_for_platform_admin_update_service(mocker, app_, platform_admin_user, service_one, route):
mocker.patch('app.service_api_client.deactivate_service')
with app_.test_request_context(): with app_.test_request_context():
for route in routes: validate_route_permission(mocker,
validate_route_permission(mocker, app_,
app_, "GET",
"GET", 302,
302, url_for(route, service_id=service_one['id']),
url_for(route, service_id=service_one['id']), [],
[], platform_admin_user,
platform_admin_user, service_one)
service_one)
def test_set_reply_to_email_address( def test_set_reply_to_email_address(
@@ -748,3 +750,25 @@ def test_switch_service_disable_letters(client, platform_admin_user, mocker):
assert response.status_code == 302 assert response.status_code == 302
assert response.location == url_for('main.service_settings', service_id=service['id'], _external=True) assert response.location == url_for('main.service_settings', service_id=service['id'], _external=True)
assert mocked_fn.call_args == call(service['id'], {"can_send_letters": False}) assert mocked_fn.call_args == call(service['id'], {"can_send_letters": False})
def test_deactivate_service(client, platform_admin_user, service_one, mocker):
mocked_fn = mocker.patch('app.service_api_client.post', return_value=service_one)
client.login(platform_admin_user, mocker, service_one)
response = client.get(url_for('main.deactivate_service', service_id=service_one['id']))
assert response.status_code == 302
assert response.location == url_for('main.service_settings', service_id=service_one['id'], _external=True)
assert mocked_fn.call_args == call('/service/{}/deactivate'.format(service_one['id']), data=None)
def test_cant_deactivate_inactive_service(client, platform_admin_user, service_one, mocker):
service_one['active'] = False
client.login(platform_admin_user, mocker, service_one)
response = client.get(url_for('main.service_settings', service_id=service_one['id']))
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert 'Deactivate service' not in {a.text for a in page.find_all('a', class_='button')}