diff --git a/app/main/views/find_users.py b/app/main/views/find_users.py index 2947b0a41..3016da327 100644 --- a/app/main/views/find_users.py +++ b/app/main/views/find_users.py @@ -1,4 +1,4 @@ -from flask import render_template, request +from flask import flash, redirect, render_template, request, url_for from flask_login import login_required from app import user_api_client @@ -37,3 +37,15 @@ def user_information(user_id): user=user, services=services, ) + + +@main.route("/users//archive", methods=['GET', 'POST']) +@login_required +@user_is_platform_admin +def archive_user(user_id): + if request.method == 'POST': + user_api_client.archive_user(user_id) + return redirect(url_for('.user_information', user_id=user_id)) + else: + flash('There\'s no way to reverse this! Are you sure you want to archive this user?', 'delete') + return user_information(user_id) diff --git a/app/navigation.py b/app/navigation.py index 623d7c7e7..82d73b849 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -80,6 +80,7 @@ class HeaderNavigation(Navigation): }, 'platform-admin': { 'add_organisation', + 'archive_user', 'clear_cache', 'create_email_branding', 'create_letter_branding', @@ -427,6 +428,7 @@ class MainNavigation(Navigation): 'add_service', 'agreement', 'archive_service', + 'archive_user', 'bat_phone', 'callbacks', 'cancel_invited_org_user', @@ -619,6 +621,7 @@ class CaseworkNavigation(Navigation): 'api_integration', 'api_keys', 'archive_service', + 'archive_user', 'bat_phone', 'branding_request', 'callbacks', @@ -902,6 +905,7 @@ class OrgNavigation(Navigation): 'api_integration', 'api_keys', 'archive_service', + 'archive_user', 'bat_phone', 'branding_request', 'callbacks', diff --git a/app/notify_client/user_api_client.py b/app/notify_client/user_api_client.py index f074e995f..091d8f1d5 100644 --- a/app/notify_client/user_api_client.py +++ b/app/notify_client/user_api_client.py @@ -65,6 +65,10 @@ class UserApiClient(NotifyAdminAPIClient): user_data = self.post(url, data=data) return user_data['data'] + @cache.delete('user-{user_id}') + def archive_user(self, user_id): + return self.post('/user/{}/archive'.format(user_id), data=None) + @cache.delete('user-{user_id}') def reset_failed_login_count(self, user_id): url = "/user/{}/reset-failed-login-count".format(user_id) diff --git a/app/templates/views/find-users/user-information.html b/app/templates/views/find-users/user-information.html index 7cfa7b8fd..5149d23a8 100644 --- a/app/templates/views/find-users/user-information.html +++ b/app/templates/views/find-users/user-information.html @@ -38,6 +38,11 @@ {{ user.failed_login_count }} failed login attempts

{% endif %} + + + Archive user + + {% endblock %} diff --git a/tests/app/main/views/test_find_users.py b/tests/app/main/views/test_find_users.py index 5af41fc83..225c85258 100644 --- a/tests/app/main/views/test_find_users.py +++ b/tests/app/main/views/test_find_users.py @@ -1,3 +1,4 @@ +from bs4 import BeautifulSoup from flask import url_for from lxml import html @@ -145,3 +146,33 @@ def test_user_information_page_displays_if_there_are_failed_login_attempts( document = html.fromstring(response.get_data(as_text=True)) assert document.xpath("//p/text()[normalize-space()='2 failed login attempts']") + + +def test_archive_user_prompts_for_confirmation( + logged_in_platform_admin_client, + api_user_active, + mock_get_organisations_and_services_for_user, +): + response = logged_in_platform_admin_client.get( + url_for('main.archive_user', user_id=api_user_active.id) + ) + + assert response.status_code == 200 + page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') + assert 'Are you sure you want to archive this user?' in page.find('div', class_='banner-dangerous').text + + +def test_archive_user_posts_to_user_client( + logged_in_platform_admin_client, + api_user_active, + mocker, +): + mock_user_client = mocker.patch('app.user_api_client.post') + + response = logged_in_platform_admin_client.post( + url_for('main.archive_user', user_id=api_user_active.id) + ) + + assert response.status_code == 302 + assert response.location == url_for('main.user_information', user_id=api_user_active.id, _external=True) + mock_user_client.assert_called_once_with('/user/{}/archive'.format(api_user_active.id), data=None) diff --git a/tests/app/notify_client/test_user_client.py b/tests/app/notify_client/test_user_client.py index 5210a0a3e..1ab9389b0 100644 --- a/tests/app/notify_client/test_user_client.py +++ b/tests/app/notify_client/test_user_client.py @@ -194,6 +194,7 @@ def test_returns_value_from_cache( (user_api_client, 'add_user_to_organisation', [sample_uuid(), user_id], {}), (user_api_client, 'set_user_permissions', [user_id, SERVICE_ONE_ID, []], {}), (user_api_client, 'activate_user', [api_user_pending(sample_uuid())['id']], {}), + (user_api_client, 'archive_user', [user_id], {}), (service_api_client, 'remove_user_from_service', [SERVICE_ONE_ID, user_id], {}), (service_api_client, 'create_service', ['', '', 0, False, user_id, sample_uuid()], {}), (invite_api_client, 'accept_invite', [SERVICE_ONE_ID, user_id], {}),