diff --git a/eox_nelp/pearson_vue/api/v1/views.py b/eox_nelp/pearson_vue/api/v1/views.py index 60d97122..934e195e 100644 --- a/eox_nelp/pearson_vue/api/v1/views.py +++ b/eox_nelp/pearson_vue/api/v1/views.py @@ -19,6 +19,7 @@ from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication from eox_core.edxapp_wrapper.bearer_authentication import BearerAuthentication from rest_framework import status +from rest_framework.filters import SearchFilter from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -59,6 +60,8 @@ class PearsonRTENBaseView(CreateModelMixin, ListModelMixin, GenericViewSet): serializer_class = PearsonRTENSerializer queryset = PearsonRTENEvent.objects.all() # pylint: disable=no-member authentication_classes = [BearerAuthentication, JwtAuthentication] + filter_backends = [SearchFilter] + search_fields = ["candidate__username", "course__id"] def dispatch(self, request, *args, **kwargs): """ @@ -133,6 +136,30 @@ def create(self, request, *args, **kwargs): return response + def list(self, request, *args, **kwargs): + """ + Retrieve a list of objects if the user has the necessary permissions. + + This method overrides the default list method to add a permission check. + Only users who are superusers or staff members are allowed to retrieve the list of objects. + If the user does not have the necessary permissions, an HTTP 404 error is raised. + + Args: + request (HttpRequest): The request object containing user information. + *args: Additional positional arguments. + **kwargs: Additional keyword arguments. + + Returns: + Response: The response object containing the list of objects if the user has the necessary permissions. + + Raises: + Http404: If the user does not have the necessary permissions. + """ + if request.user.is_superuser or request.user.is_staff: + return super().list(request, *args, **kwargs) + + raise Http404 + def get_candidate(self): """ Retrieves the candidate user based on the client candidate ID provided in the request data. diff --git a/eox_nelp/pearson_vue/tests/api/v1/test_views.py b/eox_nelp/pearson_vue/tests/api/v1/test_views.py index 03257a90..deddac97 100644 --- a/eox_nelp/pearson_vue/tests/api/v1/test_views.py +++ b/eox_nelp/pearson_vue/tests/api/v1/test_views.py @@ -50,7 +50,7 @@ def setUp(self): # pylint: disable=invalid-name Set up test client. """ self.client = APIClient() - self.user, _ = User.objects.get_or_create(username='testuser', password='12345') + self.user, _ = User.objects.get_or_create(username='testuser', password='12345', is_staff=True) self.client.force_authenticate(user=self.user) self.course_key = CourseKey.from_string("course-v1:test+CS501+2022_T4") self.course, _ = CourseOverview.objects.get_or_create(id=self.course_key) @@ -191,6 +191,25 @@ def test_get_event(self): self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data["count"], len(events)) + def test_get_event_no_permission(self): + """ + Test retrieving an event without the necessary permissions. + + Expected behavior: + - The response returns a 404 status code. + """ + # Create a record to ensure there is at least one element + PearsonRTENEvent.objects.create(event_type=self.event_type, content={}) # pylint: disable=no-member + + # Create non staff user + non_staff_user, _ = User.objects.get_or_create(username='non_staff', password='12345') + self.client.force_authenticate(user=non_staff_user) + + # Attempt to retrieve all the events of the same type + response = self.client.get(reverse(f"pearson-vue-api:v1:{self.event_type}-list"), format="json") + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + @override_settings(PEARSON_RTEN_API_ENABLED=False) def test_create_result_notification_event_disabled(self): """