From cefeb9874314d9a2c1afb71cda5398df614f1c43 Mon Sep 17 00:00:00 2001 From: PJDeSmijter Date: Sun, 10 Mar 2024 23:04:22 +0100 Subject: [PATCH] course api tests, permission fixes, test fixes --- .../pigeonhole/apps/courses/permissions.py | 29 +-- .../tests/test_models/test_conditions.py | 2 +- .../tests/test_models/test_groups.py | 1 + .../tests/test_models/test_project.py | 1 + .../tests/test_models/test_submissions.py | 1 + .../pigeonhole/tests/test_views/__init__.py | 0 .../tests/test_views/test_course.py | 173 ++++++++++++++++++ 7 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 backend/pigeonhole/tests/test_views/__init__.py create mode 100644 backend/pigeonhole/tests/test_views/test_course.py diff --git a/backend/pigeonhole/apps/courses/permissions.py b/backend/pigeonhole/apps/courses/permissions.py index 201b666e..9e456045 100644 --- a/backend/pigeonhole/apps/courses/permissions.py +++ b/backend/pigeonhole/apps/courses/permissions.py @@ -1,30 +1,19 @@ from rest_framework import permissions -from backend.pigeonhole.apps.users.models import Student, Teacher +from backend.pigeonhole.apps.users.models import Teacher, Student class CourseUserPermissions(permissions.BasePermission): def has_permission(self, request, view): if request.user.is_superuser: return True - if isinstance(request.user, Teacher): - return True - - if isinstance(request.user, Student): - return view.action in ['list', 'retrieve'] - - return False - - def has_object_permission(self, request, view, obj): - if request.user.is_superuser: - return True - if isinstance(request.user, Teacher): - if request.user.is_admin: + if Teacher.objects.filter(id=request.user.id).exists(): + teacher = Teacher.objects.get(id=request.user.id) + if teacher.is_admin: return True - elif Teacher.objects.filter(id=request.user.id, course=obj).exists(): + # Check if the teacher is assigned to the course + course = view.kwargs.get('pk') + if teacher.course.filter(course_id=course).exists(): return True + return view.action in ['list', 'retrieve', 'create'] + elif Student.objects.filter(id=request.user.id).exists(): return view.action in ['list', 'retrieve'] - - if isinstance(request.user, Student): - return view.action in ['list', 'retrieve'] - - return False diff --git a/backend/pigeonhole/tests/test_models/test_conditions.py b/backend/pigeonhole/tests/test_models/test_conditions.py index 37307ab7..b6748042 100644 --- a/backend/pigeonhole/tests/test_models/test_conditions.py +++ b/backend/pigeonhole/tests/test_models/test_conditions.py @@ -34,6 +34,7 @@ def setUp(self): project = Project.objects.create( name="Project", course_id=course, + deadline="2021-12-12 12:12:12", description="Project Description" ) @@ -41,7 +42,6 @@ def setUp(self): self.conditions = Conditions.objects.create( submission_id=project, condition="Condition 1", - deadline="2021-12-12 12:12:12", test_file_location="path/to/test", test_file_type="txt" ) diff --git a/backend/pigeonhole/tests/test_models/test_groups.py b/backend/pigeonhole/tests/test_models/test_groups.py index 0ece53b9..b7d52642 100644 --- a/backend/pigeonhole/tests/test_models/test_groups.py +++ b/backend/pigeonhole/tests/test_models/test_groups.py @@ -47,6 +47,7 @@ def setUp(self): project = Project.objects.create( name="Project", course_id=course, + deadline="2021-12-12 12:12:12", description="Project Description", ) diff --git a/backend/pigeonhole/tests/test_models/test_project.py b/backend/pigeonhole/tests/test_models/test_project.py index 11285c91..4f66e0f1 100644 --- a/backend/pigeonhole/tests/test_models/test_project.py +++ b/backend/pigeonhole/tests/test_models/test_project.py @@ -34,6 +34,7 @@ def setUp(self): self.project = Project.objects.create( name="Project", course_id=course, + deadline="2021-12-12 12:12:12", description="Project Description", ) diff --git a/backend/pigeonhole/tests/test_models/test_submissions.py b/backend/pigeonhole/tests/test_models/test_submissions.py index c6efed08..3dc59031 100644 --- a/backend/pigeonhole/tests/test_models/test_submissions.py +++ b/backend/pigeonhole/tests/test_models/test_submissions.py @@ -37,6 +37,7 @@ def setUp(self): project = Project.objects.create( name="Project", course_id=course, + deadline="2021-12-12 12:12:12", description="Project Description", ) diff --git a/backend/pigeonhole/tests/test_views/__init__.py b/backend/pigeonhole/tests/test_views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/pigeonhole/tests/test_views/test_course.py b/backend/pigeonhole/tests/test_views/test_course.py new file mode 100644 index 00000000..5c3f8bd6 --- /dev/null +++ b/backend/pigeonhole/tests/test_views/test_course.py @@ -0,0 +1,173 @@ +from django.test import TestCase +from rest_framework.test import APIClient +from rest_framework import status +from backend.pigeonhole.apps.users.models import User, Teacher, Student +from backend.pigeonhole.apps.courses.models import Course + +API_ENDPOINT = '/courses/' # Updated the API_ENDPOINT + + +class CourseTestTeacher(TestCase): + def setUp(self): + self.client = APIClient() + + self.course_data = { + 'name': 'Test Course', + 'description': 'This is a test course.' + } + + self.course = Course.objects.create(**self.course_data) + + self.course_not_of_teacher = Course.objects.create(name="Not of Teacher", description="This is not of the teacher") + + # Create a regular user (teacher) + self.user = User.objects.create_user( + username="teacher_username", + email="teacher@gmail.com", + first_name="Kermit", + last_name="The Frog", + ) + + # Create a Teacher instance and use .set() to assign the course + self.teacher = Teacher.objects.create(id=self.user) + self.teacher.course.set([self.course]) + + # Authenticate the test client with the teacher user + self.client.force_authenticate(user=self.user) + + def test_create_course(self): + response = self.client.post(API_ENDPOINT, self.course_data, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(Course.objects.count(), 3) + + def test_update_course(self): + updated_data = { + 'name': 'Updated Course', + 'description': 'This course has been updated.' + } + response = self.client.put(f'{API_ENDPOINT}{self.course.course_id}/', updated_data, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.course.refresh_from_db() + self.assertEqual(self.course.name, updated_data['name']) + self.assertEqual(self.course.description, updated_data['description']) + + # TODO + def test_update_course_not_of_teacher(self): + updated_data = { + 'name': 'Updated Course', + 'description': 'This course has been updated.' + } + response = self.client.put(f'{API_ENDPOINT}{self.course_not_of_teacher.course_id}/', updated_data, format='json') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_delete_course(self): + response = self.client.delete(f'{API_ENDPOINT}{self.course.course_id}/') + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertEqual(Course.objects.count(), 1) + + # TODO + def test_delete_course_not_of_teacher(self): + response = self.client.delete(f'{API_ENDPOINT}{self.course_not_of_teacher.course_id}/') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_list_courses(self): + response = self.client.get(API_ENDPOINT) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(response.data), 1) + + def test_retrieve_course(self): + response = self.client.get(f'{API_ENDPOINT}{self.course.course_id}/') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['name'], self.course.name) + self.assertEqual(response.data['description'], self.course.description) + + +class CourseTestStudent(TestCase): + def setUp(self): + self.client = APIClient() + + # Create a regular user (teacher) + self.user = User.objects.create_user( + username="teacher_username", + email="kermit@gmail.com", + first_name="Kermit", + last_name="The Frog" + ) + + self.course_data = { + 'name': 'Test Course', + 'description': 'This is a test course.' + } + + self.course = Course.objects.create(**self.course_data) + + # Provide a value for the "number" field when creating the Student instance + self.student = Student.objects.create(id=self.user, number=123456) + self.student.course.set([self.course]) + + # Authenticate the test client with the regular user + self.client.force_authenticate(user=self.user) + + def test_create_course(self): + response = self.client.post(API_ENDPOINT, self.course_data, format='json') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(Course.objects.count(), 1) + + def test_update_course(self): + updated_data = { + 'name': 'Updated Course', + 'description': 'This course has been updated.' + } + response = self.client.put(f'{API_ENDPOINT}{self.course.course_id}/', updated_data, format='json') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.course.refresh_from_db() + self.assertNotEqual(self.course.name, updated_data['name']) + self.assertNotEqual(self.course.description, updated_data['description']) + + def test_delete_course(self): + response = self.client.delete(f'{API_ENDPOINT}{self.course.course_id}/') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(Course.objects.count(), 1) + + def test_list_courses(self): + response = self.client.get(API_ENDPOINT) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(response.data), 1) + + +class CourseTestUnauthorized(TestCase): + def setUp(self): + self.client = APIClient() + + self.course_data = { + 'name': 'Test Course', + 'description': 'This is a test course.' + } + + self.course = Course.objects.create(**self.course_data) + + def test_create_course(self): + response = self.client.post(API_ENDPOINT, self.course_data, format='json') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(Course.objects.count(), 1) + + def test_update_course(self): + updated_data = { + 'name': 'Updated Course', + 'description': 'This course has been updated.' + } + response = self.client.put(f'{API_ENDPOINT}{self.course.course_id}/', updated_data, format='json') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.course.refresh_from_db() + self.assertNotEqual(self.course.name, updated_data['name']) + self.assertNotEqual(self.course.description, updated_data['description']) + + def test_delete_course(self): + response = self.client.delete(f'{API_ENDPOINT}{self.course.course_id}/') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(Course.objects.count(), 1) + + def test_list_courses(self): + response = self.client.get(API_ENDPOINT) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(len(response.data), 1) \ No newline at end of file