Skip to content
Snippets Groups Projects
Commit f265fe8b authored by Jörn Künsemöller's avatar Jörn Künsemöller
Browse files

TMSS-278: add endpoints to get friend of project and current user roles in project plus tests

parent 54716993
Branches
Tags
2 merge requests!634WIP: COBALT commissioning delta,!517TMSS-278: add endpoints to get friend of project and current user roles in project plus tests
...@@ -45,7 +45,10 @@ def get_users_by_role_in_project(role, project): ...@@ -45,7 +45,10 @@ def get_users_by_role_in_project(role, project):
returns the list of users that have the specified role in the specified project returns the list of users that have the specified role in the specified project
""" """
project_persons = get_project_persons() project_persons = get_project_persons()
if project in project_persons:
return project_persons[project][role] return project_persons[project][role]
else:
return []
@cachetools.func.ttl_cache(ttl=600) @cachetools.func.ttl_cache(ttl=600)
......
...@@ -28,7 +28,8 @@ def get_project_roles_for_user(user): ...@@ -28,7 +28,8 @@ def get_project_roles_for_user(user):
try: try:
if user == models.User.objects.get(username='paulus'): if user == models.User.objects.get(username='paulus'):
return ({'project': 'test_user_is_shared_support', 'role': 'shared_support'}, return ({'project': 'test_user_is_shared_support', 'role': 'shared_support'},
{'project': 'test_user_is_contact', 'role': 'contact'}) {'project': 'test_user_is_contact', 'role': 'contact'},
{'project': 'test_user_is_friend', 'role': 'friend_of_project'})
except: except:
pass pass
......
...@@ -25,6 +25,7 @@ from lofar.sas.tmss.tmss.tmssapp.viewsets.lofar_viewset import LOFARViewSet, LOF ...@@ -25,6 +25,7 @@ from lofar.sas.tmss.tmss.tmssapp.viewsets.lofar_viewset import LOFARViewSet, LOF
from lofar.sas.tmss.tmss.tmssapp import models from lofar.sas.tmss.tmss.tmssapp import models
from lofar.sas.tmss.tmss.tmssapp import serializers from lofar.sas.tmss.tmss.tmssapp import serializers
from lofar.sas.tmss.tmss.tmssapp.adapters.reports import create_cycle_report, create_project_report from lofar.sas.tmss.tmss.tmssapp.adapters.reports import create_cycle_report, create_project_report
from lofar.sas.tmss.tmss.tmssapp.adapters.keycloak import get_users_by_role_in_project
from django.http import JsonResponse from django.http import JsonResponse
from datetime import datetime from datetime import datetime
...@@ -32,7 +33,7 @@ from lofar.common.json_utils import get_default_json_object_for_schema ...@@ -32,7 +33,7 @@ from lofar.common.json_utils import get_default_json_object_for_schema
from lofar.common.datetimeutils import formatDatetime from lofar.common.datetimeutils import formatDatetime
from lofar.sas.tmss.tmss.tmssapp.tasks import * from lofar.sas.tmss.tmss.tmssapp.tasks import *
from lofar.sas.tmss.tmss.tmssapp.subtasks import * from lofar.sas.tmss.tmss.tmssapp.subtasks import *
from lofar.sas.tmss.tmss.tmssapp.viewsets.permissions import TMSSDjangoModelPermissions from lofar.sas.tmss.tmss.tmssapp.viewsets.permissions import TMSSDjangoModelPermissions, get_project_roles_for_user
from django.urls import resolve, get_script_prefix,Resolver404 from django.urls import resolve, get_script_prefix,Resolver404
from rest_framework.filters import OrderingFilter from rest_framework.filters import OrderingFilter
...@@ -394,6 +395,28 @@ class ProjectViewSet(LOFARViewSet): ...@@ -394,6 +395,28 @@ class ProjectViewSet(LOFARViewSet):
result = create_project_report(request, project) result = create_project_report(request, project)
return Response(result, status=status.HTTP_200_OK) return Response(result, status=status.HTTP_200_OK)
@swagger_auto_schema(responses={200: 'List of users that have the "friend of project" role for this project',
403: 'forbidden'},
operation_description="Get the list of users that have the 'friend of project' role for this project")
@action(methods=['get'], detail=True, url_name="friend", name="Friend(s) of this project")
def friend(self, request, pk=None):
project = get_object_or_404(models.Project, pk=pk)
result = get_users_by_role_in_project(models.ProjectRole.Choices.FRIEND_OF_PROJECT.value, project.name)
return Response(result, status=status.HTTP_200_OK)
@swagger_auto_schema(responses={200: 'List of roles that the requesting user has in this project',
403: 'forbidden'},
operation_description="Get the list of roles that the requesting user has in this project")
@action(methods=['get'], detail=True, url_name="my_roles", name="My roles in this project")
def my_roles(self, request, pk=None):
project = get_object_or_404(models.Project, pk=pk)
project_roles = get_project_roles_for_user(request.user)
result = []
for project_role in project_roles:
if project.name == project_role['project']:
result.append(project_role['role'])
return Response(result, status=status.HTTP_200_OK)
class ProjectNestedViewSet(LOFARNestedViewSet): class ProjectNestedViewSet(LOFARNestedViewSet):
queryset = models.Project.objects.all() queryset = models.Project.objects.all()
......
...@@ -51,6 +51,9 @@ from lofar.sas.tmss.test.tmss_test_data_rest import TMSSRESTTestDataCreator ...@@ -51,6 +51,9 @@ from lofar.sas.tmss.test.tmss_test_data_rest import TMSSRESTTestDataCreator
from django.test import TestCase from django.test import TestCase
from django.contrib.auth import get_user_model
User = get_user_model()
class ProjectPermissionTestCase(TestCase): class ProjectPermissionTestCase(TestCase):
# This tests that the project permissions are enforced in light of the project roles that are externally provided # This tests that the project permissions are enforced in light of the project roles that are externally provided
# for the user through the user admin. This test does not rely on the project permissions as defined in the system, # for the user through the user admin. This test does not rely on the project permissions as defined in the system,
...@@ -66,7 +69,8 @@ class ProjectPermissionTestCase(TestCase): ...@@ -66,7 +69,8 @@ class ProjectPermissionTestCase(TestCase):
cls.project_permission_patcher = mock.patch('lofar.sas.tmss.tmss.tmssapp.viewsets.get_project_roles_for_user') # todo: fix namespace so we get the get_project_roles that gets actually used cls.project_permission_patcher = mock.patch('lofar.sas.tmss.tmss.tmssapp.viewsets.get_project_roles_for_user') # todo: fix namespace so we get the get_project_roles that gets actually used
cls.project_permission_mock = cls.project_permission_patcher.start() cls.project_permission_mock = cls.project_permission_patcher.start()
cls.project_permission_mock.return_value = ({'project': 'test_user_is_shared_support', 'role': 'shared_support'}, cls.project_permission_mock.return_value = ({'project': 'test_user_is_shared_support', 'role': 'shared_support'},
{'project': 'test_user_is_contact', 'role': 'contact_author'}) {'project': 'test_user_is_contact', 'role': 'contact_author'},
{'project': 'test_user_is_friend', 'role': 'friend_of_project'})
# create some stuff as the standard super user, as setup for the tests below # create some stuff as the standard super user, as setup for the tests below
cls.test_data_creator = TMSSRESTTestDataCreator(BASE_URL, AUTH) cls.test_data_creator = TMSSRESTTestDataCreator(BASE_URL, AUTH)
...@@ -75,8 +79,9 @@ class ProjectPermissionTestCase(TestCase): ...@@ -75,8 +79,9 @@ class ProjectPermissionTestCase(TestCase):
# create projects with magic names for which permission exists (or which have no whitelisted generic name) # create projects with magic names for which permission exists (or which have no whitelisted generic name)
cls.project_shared_support_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name='test_user_is_shared_support', cycle_urls=[cycle_url]), '/project/') cls.project_shared_support_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name='test_user_is_shared_support', cycle_urls=[cycle_url]), '/project/')
cls.project_contact_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name='test_user_is_contact', cycle_urls=[cycle_url]), '/project/') cls.project_contact_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name='test_user_is_contact', cycle_urls=[cycle_url]), '/project/')
cls.project_friend_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name='test_user_is_friend', cycle_urls=[cycle_url]), '/project/')
cls.project_forbidden_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name='forbidden', cycle_urls=[cycle_url]), '/project/') cls.project_forbidden_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name='forbidden', cycle_urls=[cycle_url]), '/project/')
cls.project_keycloak_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.Project(name="2014LOFAROBS", cycle_urls=[cycle_url]), '/project/') # project is known to Keycloak
# user is shared_support # user is shared_support
cls.scheduling_set_shared_support_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.SchedulingSet(project_url=cls.project_shared_support_url), '/scheduling_set/') cls.scheduling_set_shared_support_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.SchedulingSet(project_url=cls.project_shared_support_url), '/scheduling_set/')
...@@ -92,8 +97,10 @@ class ProjectPermissionTestCase(TestCase): ...@@ -92,8 +97,10 @@ class ProjectPermissionTestCase(TestCase):
# create the required permission entries to control what endpoint action requires which project role # create the required permission entries to control what endpoint action requires which project role
shared_support_role_url = BASE_URL + '/project_role/shared_support/' shared_support_role_url = BASE_URL + '/project_role/shared_support/'
friend_of_project_role_url = BASE_URL + '/project_role/friend_of_project/'
cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.ProjectPermission(name='taskdraft', GET=[shared_support_role_url], POST=[shared_support_role_url]), '/project_permission/') cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.ProjectPermission(name='taskdraft', GET=[shared_support_role_url], POST=[shared_support_role_url]), '/project_permission/')
cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.ProjectPermission(name='taskdraft-create_task_blueprint', POST=[shared_support_role_url]), '/project_permission/') cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.ProjectPermission(name='taskdraft-create_task_blueprint', POST=[shared_support_role_url]), '/project_permission/')
cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.ProjectPermission(name='project-my_roles', GET=[shared_support_role_url, friend_of_project_role_url]), '/project_permission/')
cls.task_template_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.TaskTemplate(), '/task_template/') cls.task_template_url = cls.test_data_creator.post_data_and_get_url(cls.test_data_creator.TaskTemplate(), '/task_template/')
...@@ -230,6 +237,37 @@ class ProjectPermissionTestCase(TestCase): ...@@ -230,6 +237,37 @@ class ProjectPermissionTestCase(TestCase):
# todo: add tests for other models with project permissions # todo: add tests for other models with project permissions
def test_project_get_friend_returns_correct_user(self):
"""
Note: This test relies on real data from Keycloak.
"""
r = GET_and_assert_equal_expected_code(self, self.project_keycloak_url + '/friend/', 200)
self.assertEqual(len(r), 2)
for friend in r:
# Todo: find a way to mock the Keycloak response so we can assert more strictly.
self.assertTrue(friend.endswith('@astron.nl')) # redacted expected full email due to GDPR
def test_project_get_friend_returns_403_if_no_permission_for_project(self):
r = GET_and_assert_equal_expected_code(self, self.project_forbidden_url + '/my_roles/', 403, auth=self.auth)
self.assertIn('permission', str(r))
def test_project_get_my_roles_returns_correct_roles(self):
# r = GET_and_assert_equal_expected_code(self, self.project_shared_support_url + '/my_roles/', 200, auth=self.auth)
# expected_reply = ['shared_support']
# self.assertEqual(expected_reply, r)
r = GET_and_assert_equal_expected_code(self, self.project_friend_url + '/my_roles/', 200, auth=self.auth)
expected_reply = ['friend_of_project']
self.assertEqual(expected_reply, r)
def test_project_get_my_roles_returns_403_if_no_permission_for_project(self):
r = GET_and_assert_equal_expected_code(self, self.project_forbidden_url + '/my_roles/', 403, auth=self.auth)
self.assertIn('permission', str(r))
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment