From 48b291a3422ac763c1aefd8a929b456c97a0cb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ina=20Od=C3=A9n=20=C3=96sterbo?= Date: Sun, 13 Mar 2022 23:55:44 +0100 Subject: [PATCH 1/6] add new endpoint for listing unit users --- dds_web/api/__init__.py | 1 + dds_web/api/user.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/dds_web/api/__init__.py b/dds_web/api/__init__.py index 606ed67ad..0d84495f0 100644 --- a/dds_web/api/__init__.py +++ b/dds_web/api/__init__.py @@ -67,6 +67,7 @@ def output_json(data, code, headers=None): api.add_resource(user.DeleteUserSelf, "/user/delete_self", endpoint="delete_user_self") api.add_resource(user.RemoveUserAssociation, "/user/access/revoke", endpoint="revoke_from_project") api.add_resource(user.UserActivation, "/user/activation", endpoint="user_activation") +api.add_resource(user.UnitUsers, "/unit/users", endpoint="unit_users") # Invoicing ############################################################################ Invoicing # api.add_resource(user.ShowUsage, "/usage", endpoint="usage") diff --git a/dds_web/api/user.py b/dds_web/api/user.py index 64ed21a15..028fca884 100644 --- a/dds_web/api/user.py +++ b/dds_web/api/user.py @@ -884,3 +884,35 @@ def get(self): }, "project_usage": usage, } + + +class UnitUsers(flask_restful.Resource): + """List unit users.""" + + @auth.login_required(role=["Unit Admin", "Unit Personnel"]) + @logging_bind_request + def get(self): + """Get and return unit users within the unit the current user is connected to.""" + unit_users = {} + + if not auth.current_user().is_active: + raise ddserr.AccessDeniedError( + message=( + "Your account has been deactivated. " + "You cannot list the users within your unit." + ) + ) + + keys = ["Name", "Username", "Email", "Role", "Active"] + unit_users = [ + { + "Name": user.name, + "Username": user.username, + "Email": user.primary_email, + "Role": user.role, + "Active": user.is_active, + } + for user in auth.current_user().unit.users + ] + + return {"users": unit_users, "keys": keys, "unit": auth.current_user().unit.name} From d9617f6e0f71ad4763bc6368002e908945ac792e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ina=20Od=C3=A9n=20=C3=96sterbo?= Date: Mon, 14 Mar 2022 08:35:02 +0100 Subject: [PATCH 2/6] added tests for unit users --- tests/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/__init__.py b/tests/__init__.py index 4be019863..37e260d1c 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -148,6 +148,9 @@ class DDSEndpoint: USER_DELETE_SELF = BASE_ENDPOINT + "/user/delete_self" USER_CONFIRM_DELETE = "/confirm_deletion/" + # List users + LIST_UNIT_USERS = BASE_ENDPOINT + "/unit/users" + # Authentication - user and project ENCRYPTED_TOKEN = BASE_ENDPOINT + "/user/encrypted_token" SECOND_FACTOR = BASE_ENDPOINT + "/user/second_factor" From c76d619110526f4fd9d2d0b1884200bdf2a99c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ina=20Od=C3=A9n=20=C3=96sterbo?= Date: Mon, 14 Mar 2022 08:36:53 +0100 Subject: [PATCH 3/6] add tests --- tests/test_users_list.py | 92 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tests/test_users_list.py diff --git a/tests/test_users_list.py b/tests/test_users_list.py new file mode 100644 index 000000000..6cf7ffe87 --- /dev/null +++ b/tests/test_users_list.py @@ -0,0 +1,92 @@ +# IMPORTS ################################################################################ IMPORTS # + +# Standard library +import http +import json +from urllib import response + +# Own +from dds_web import db +from dds_web.api import user +from dds_web.database import models +import tests + +# CONFIG ################################################################################## CONFIG # + +users = { + "Researcher": "researchuser", + "Unit Personnel": "unituser", + "Unit Admin": "unitadmin", + "Super Admin": "superadmin", +} + +# TESTS #################################################################################### TESTS # + + +def get_token(username, client): + return tests.UserAuth(tests.USER_CREDENTIALS[username]).token(client) + + +def test_list_unitusers_with_researcher(client): + """Researchers cannot list unit users.""" + token = get_token(username=users["Researcher"], client=client) + response = client.get(tests.DDSEndpoint.LIST_UNIT_USERS, headers=token) + assert response.status_code == http.HTTPStatus.FORBIDDEN + + +def test_list_unitusers_with_super_admin(client): + """Super admins will be able to list unit users, but not right now.""" + token = get_token(username=users["Super Admin"], client=client) + response = client.get(tests.DDSEndpoint.LIST_UNIT_USERS, headers=token) + assert response.status_code == http.HTTPStatus.FORBIDDEN + + +def test_list_unitusers_with_unit_personnel_and_admin_deactivated(client): + """Unit Personnel should be able to list the users within a unit.""" + # Deactivate user + for u in ["Unit Personnel", "Unit Admin"]: + # Get token + token = get_token(username=users[u], client=client) + + user = models.User.query.get(users[u]) + user.active = False + db.session.commit() + + # Try to list users - should only work if active - not now + response = client.get(tests.DDSEndpoint.LIST_UNIT_USERS, headers=token) + + # Unauth and not forbidden because the user object is not returned from the token + assert response.status_code == http.HTTPStatus.UNAUTHORIZED + + +def test_list_unitusers_with_unit_personnel_and_admin_ok(client): + # Active unit users should be able to list unit users + for u in ["Unit Personnel", "Unit Admin"]: + # Get token + token = get_token(username=users[u], client=client) + + # Get users + response = client.get(tests.DDSEndpoint.LIST_UNIT_USERS, headers=token) + assert response.status_code == http.HTTPStatus.OK + + keys_in_response = response.json["keys"] + unit_in_response = response.json["unit"] + users_in_response = response.json["users"] + + assert keys_in_response + + user_object = models.User.query.get(users[u]) + assert user_object.unit.name == unit_in_response + + all_users = user_object.unit.users + + # ["Name", "Username", "Email", "Role", "Active"] + for dbrow in user_object.unit.users: + expected = { + "Name": dbrow.name, + "Username": dbrow.username, + "Email": dbrow.primary_email, + "Role": dbrow.role, + "Active": dbrow.is_active, + } + assert expected in users_in_response From a1d2f2165dceb5e792babbf799cd8c8c7d971eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ina=20Od=C3=A9n=20=C3=96sterbo?= Date: Mon, 14 Mar 2022 08:39:55 +0100 Subject: [PATCH 4/6] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9548968c..4c84bf619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,3 +46,4 @@ Please add a _short_ line describing the PR you make, if the PR implements a spe - Introduce a separate error message if someone tried to add an unit user to projects individually. ([#1039](https://github.com/ScilifelabDataCentre/dds_web/pull/1039)) - Display an error message when the user makes too many authentication requests. ([#1034](https://github.com/ScilifelabDataCentre/dds_web/pull/1034)) +- New endpoint for Unit Personnel and Admins to list the other Unit Personnel / Admins within their project From 767b38293ed02323ccf077bade6643306d61e9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ina=20Od=C3=A9n=20=C3=96sterbo?= <35953392+inaod568@users.noreply.github.com> Date: Mon, 14 Mar 2022 08:41:50 +0100 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c84bf619..10e568c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,4 +46,4 @@ Please add a _short_ line describing the PR you make, if the PR implements a spe - Introduce a separate error message if someone tried to add an unit user to projects individually. ([#1039](https://github.com/ScilifelabDataCentre/dds_web/pull/1039)) - Display an error message when the user makes too many authentication requests. ([#1034](https://github.com/ScilifelabDataCentre/dds_web/pull/1034)) -- New endpoint for Unit Personnel and Admins to list the other Unit Personnel / Admins within their project +- New endpoint for Unit Personnel and Admins to list the other Unit Personnel / Admins within their project ([#1050](https://github.com/ScilifelabDataCentre/dds_web/pull/1050)) From 66dd210fbacf469c0c0911c8eec7638155b7a96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ina=20Od=C3=A9n=20=C3=96sterbo?= <35953392+inaod568@users.noreply.github.com> Date: Mon, 14 Mar 2022 10:42:06 +0100 Subject: [PATCH 6/6] Update tests/test_users_list.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Linus Östberg --- tests/test_users_list.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_users_list.py b/tests/test_users_list.py index 6cf7ffe87..588a4f334 100644 --- a/tests/test_users_list.py +++ b/tests/test_users_list.py @@ -2,8 +2,6 @@ # Standard library import http -import json -from urllib import response # Own from dds_web import db