From 9aae411cc9cc820eb68d5cc47e2202210bb4a787 Mon Sep 17 00:00:00 2001 From: Zacharis278 Date: Wed, 31 Jul 2024 10:26:27 -0400 Subject: [PATCH] feat: delete allowance api --- edx_exams/apps/api/v1/tests/test_views.py | 26 +++++++++++++++++++++-- edx_exams/apps/api/v1/urls.py | 5 +++++ edx_exams/apps/api/v1/views.py | 16 ++++++++++++++ edx_exams/apps/core/constants.py | 2 ++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/edx_exams/apps/api/v1/tests/test_views.py b/edx_exams/apps/api/v1/tests/test_views.py index e683fa28..e3f0b2ce 100644 --- a/edx_exams/apps/api/v1/tests/test_views.py +++ b/edx_exams/apps/api/v1/tests/test_views.py @@ -1789,16 +1789,18 @@ def setUp(self): course_id=self.course_id, ) - def request_api(self, method, user, course_id, data=None): + def request_api(self, method, user, course_id, data=None, allowance_id=None): """ Helper function to make API request """ - assert method in ['get', 'post'] + assert method in ['get', 'post', 'delete'] headers = self.build_jwt_headers(user) url = reverse( 'api:v1:course-allowances', kwargs={'course_id': course_id} ) + if allowance_id: + url = f'{url}/{allowance_id}' if data: return getattr(self.client, method)(url, json.dumps(data), **headers, content_type='application/json') @@ -1878,6 +1880,26 @@ def test_get_empty_response(self): self.assertEqual(response.status_code, 200) self.assertEqual(response.data, []) + def test_delete(self): + """ + Test that the endpoint deletes an allowance + """ + allowance = StudentAllowanceFactory.create( + exam=self.exam, + user=self.user, + ) + + response = self.request_api('delete', self.user, self.exam.course_id, allowance_id=allowance.id) + self.assertEqual(response.status_code, 204) + self.assertFalse(StudentAllowance.objects.filter(id=allowance.id).exists()) + + def test_delete_not_found(self): + """ + Test that 404 is returned if allowance does not exist + """ + response = self.request_api('delete', self.user, self.exam.course_id, allowance_id=19) + self.assertEqual(response.status_code, 404) + def test_post_allowances(self): """ Test that the endpoint creates allowances for the given request data diff --git a/edx_exams/apps/api/v1/urls.py b/edx_exams/apps/api/v1/urls.py index e5720f18..73db0061 100644 --- a/edx_exams/apps/api/v1/urls.py +++ b/edx_exams/apps/api/v1/urls.py @@ -19,6 +19,11 @@ app_name = 'v1' urlpatterns = [ + re_path( + fr'exams/course_id/{COURSE_ID_PATTERN}/allowances/(?P\d+)', + AllowanceView.as_view(), + name='course-allowance' + ), re_path( fr'exams/course_id/{COURSE_ID_PATTERN}/allowances', AllowanceView.as_view(), diff --git a/edx_exams/apps/api/v1/views.py b/edx_exams/apps/api/v1/views.py index 8f40e044..00645bb5 100644 --- a/edx_exams/apps/api/v1/views.py +++ b/edx_exams/apps/api/v1/views.py @@ -828,6 +828,22 @@ def get(self, request, course_id): allowances = StudentAllowance.get_allowances_for_course(course_id) return Response(AllowanceSerializer(allowances, many=True).data) + def delete(self, request, course_id, allowance_id): # pylint: disable=unused-argument + """ + HTTP DELETE handler. Deletes all allowances for a course. + + TODO: both this and the POST endpoint should be limiting operations by course_id + """ + try: + StudentAllowance.objects.get(id=allowance_id).delete() + except StudentAllowance.DoesNotExist: + return Response( + status=status.HTTP_404_NOT_FOUND, + data={'detail': f'Allowance with id={allowance_id} does not exist.'} + ) + + return Response(status=status.HTTP_204_NO_CONTENT) + def post(self, request, course_id): # pylint: disable=unused-argument """ HTTP POST handler. Creates allowances based on the given list. diff --git a/edx_exams/apps/core/constants.py b/edx_exams/apps/core/constants.py index 8159d000..894f12be 100644 --- a/edx_exams/apps/core/constants.py +++ b/edx_exams/apps/core/constants.py @@ -18,3 +18,5 @@ class Status: USAGE_KEY_PATTERN = r'(?P(?:i4x://?[^/]+/[^/]+/[^/]+/[^@]+(?:@[^/]+)?)|(?:[^/]+))' EXAM_ID_PATTERN = r'(?P\d+)' + +ATTEMPT_ID_PATTERN = r'(?P\d+)'