diff --git a/core/tests/test_export.py b/core/tests/test_export.py index f80a5f99765fb5a23d669c3ff18700cd9ef9bed9..30921dd8ace1af155a8eb4f823770090e2c384e0 100644 --- a/core/tests/test_export.py +++ b/core/tests/test_export.py @@ -10,13 +10,15 @@ def make_data(): 'module_reference': 'Test Exam 01', 'total_score': 100, 'pass_score': 60, + 'pass_only': True }], 'submission_types': [ { 'name': '01. Sort', 'full_score': 35, 'description': 'Very complicated', - 'solution': 'Trivial!' + 'solution': 'Trivial!', + 'programming_language': 'Haskell', }, { 'name': '02. Shuffle', @@ -29,6 +31,9 @@ def make_data(): {'username': 'student01', 'exam': 'Test Exam 01'}, {'username': 'student02', 'exam': 'Test Exam 01'} ], + 'tutors': [{ + 'username': 'tutor01' + }], 'reviewers': [ {'username': 'reviewer'} ], @@ -73,6 +78,86 @@ def make_data(): ) +class ExportInstanceTest(APITestCase): + @classmethod + def setUpTestData(cls): + cls.data = make_data() + + def setUp(self): + self.client = APIClient() + self.client.force_login(user=self.data['reviewers'][0]) + self.response = self.client.get('/api/instance/export/') + + def test_can_access(self): + self.assertEqual(status.HTTP_200_OK, self.response.status_code) + + def test_data_is_correct(self): + instance = self.response.json() + + # examTypes fields + self.assertIn('examTypes', instance) + self.assertIn('pk', instance['examTypes'][0]) + self.assertEqual('Test Exam 01', instance['examTypes'][0]['moduleReference']) + self.assertEqual(100, instance['examTypes'][0]['totalScore']) + self.assertEqual(60, instance['examTypes'][0]['passScore']) + self.assertEqual(True, instance['examTypes'][0]['passOnly']) + + # submissionTypes fields + self.assertIn('submissionTypes', instance) + self.assertEquals(2, len(instance['submissionTypes'])) + self.assertIn('pk', instance['submissionTypes'][0]) + self.assertEqual('01. Sort', instance['submissionTypes'][0]['name']) + self.assertEqual(35, instance['submissionTypes'][0]['fullScore']) + self.assertEqual('Very complicated', instance['submissionTypes'][0]['description']) + self.assertEqual('Trivial!', instance['submissionTypes'][0]['solution']) + self.assertEqual('Haskell', instance['submissionTypes'][0]['programmingLanguage']) + + # students fields + self.assertIn('students', instance) + self.assertEqual(2, len(instance['students'])) + self.assertIn('pk', instance['students'][0]) + self.assertIn('userPk', instance['students'][0]) + self.assertIn('exam', instance['students'][0]) + self.assertEqual('student01', instance['students'][1]['user']) + self.assertLess(0, len(instance['students'][1]['submissions'])) + + # students[submissions] nested + self.assertIn('submissions', instance['students'][1]) + self.assertLess(0, len(instance['students'][1]['submissions'])) + self.assertIn('pk', instance['students'][1]['submissions'][0]) + self.assertIn('function blabl', instance['students'][1]['submissions'][0]['text']) + self.assertIn('type', instance['students'][1]['submissions'][0]) + self.assertIn('tests', instance['students'][1]['submissions'][0]) + + # students[submissions][feedback] nested + self.assertIn('feedback', instance['students'][1]['submissions'][0]) + self.assertLess(0, len(instance['students'][1]['submissions'][0]['feedback'])) + self.assertEqual(5, instance['students'][1]['submissions'][0]['feedback']['score']) + self.assertEqual(True, instance['students'][1]['submissions'][0]['feedback']['isFinal']) + self.assertIn('created', instance['students'][1]['submissions'][0]['feedback']) + + # students[submissions][feedback][feedbackLines] nested + self.assertIn('feedbackLines', instance['students'][1]['submissions'][0]['feedback']) + self.assertLess(0, len(instance['students'][1]['submissions'][0]['feedback']['feedbackLines'])) + self.assertIn('1', instance['students'][1]['submissions'][0]['feedback']['feedbackLines']) + self.assertIn('pk', instance['students'][1]['submissions'][0]['feedback']['feedbackLines']['1'][0]) + self.assertEqual('This is very bad!', + instance['students'][1]['submissions'][0]['feedback']['feedbackLines']['1'][0]['text']) + self.assertEqual('reviewer', + instance['students'][1]['submissions'][0]['feedback']['feedbackLines']['1'][0]['ofTutor']) + + # reviewers fields + self.assertIn('reviewers', instance) + self.assertLess(0, len(instance['reviewers'])) + self.assertIn('pk', instance['reviewers'][0]) + self.assertEqual('reviewer', instance['reviewers'][0]['username']) + + # tutors fields + self.assertIn('tutors', instance) + self.assertLess(0, len(instance['tutors'])) + self.assertEqual('tutor01', instance['tutors'][0]['username']) + + class ExportJSONTest(APITestCase): @classmethod def setUpTestData(cls): diff --git a/core/urls.py b/core/urls.py index 2450f5f2d99932b5fb28ae7b918d6ac9679baf32..3357065b0f46f5f39c4349058146d2bb7805fc0b 100644 --- a/core/urls.py +++ b/core/urls.py @@ -46,6 +46,7 @@ regular_views_urlpatterns = [ path('jwt-time-delta/', views.get_jwt_expiration_delta, name='jwt-time-delta'), + path('instance/export/', views.InstanceExport.as_view(), name="instance-export"), path('export/json/', views.StudentJSONExport.as_view(), name='export-json'), re_path(r'swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), diff --git a/core/views/__init__.py b/core/views/__init__.py index da92a342cea53a4b34f29cd090f6fb778d68b864..04a6d8386d6023b90861ebbe9aafdfe34580c1f4 100644 --- a/core/views/__init__.py +++ b/core/views/__init__.py @@ -1,4 +1,4 @@ from .feedback import FeedbackApiView, FeedbackCommentApiView # noqa from .subscription import SubscriptionApiViewSet, AssignmentApiViewSet # noqa from .common_views import * # noqa -from .export import StudentJSONExport # noqa +from .export import StudentJSONExport, InstanceExport # noqa diff --git a/core/views/export.py b/core/views/export.py index 1ac84e7f4d80fdc99eef7f6061b5335b5b2f0973..89a90ab5ee8640020cf68f760e27cfbf1d79048b 100644 --- a/core/views/export.py +++ b/core/views/export.py @@ -3,8 +3,11 @@ from rest_framework.views import APIView import xkcdpass.xkcd_password as xp -from core.models import StudentInfo, UserAccount +from core.models import StudentInfo, UserAccount, ExamType, SubmissionType from core.permissions import IsReviewer +from core.serializers.common_serializers import SubmissionTypeSerializer, ExamSerializer, UserAccountSerializer +from core.serializers.student import StudentExportSerializer +from core.serializers.tutor import TutorSerializer words = xp.generate_wordlist(wordfile=xp.locate_wordfile(), min_length=5, max_length=8) @@ -42,3 +45,24 @@ class StudentJSONExport(APIView): } for student in StudentInfo.get_annotated_score_submission_list()] return Response(content) + + +class InstanceExport(APIView): + permission_classes = (IsReviewer, ) + + def get(self, request): + exam_types_serializer = ExamSerializer(ExamType.objects.all(), many=True) + submission_types_serializer = SubmissionTypeSerializer(SubmissionType.objects.all(), many=True) + tutors_serializer = TutorSerializer(UserAccount.tutors.with_feedback_count(), many=True) + reviewer_serializer = UserAccountSerializer(UserAccount.get_reviewers(), many=True) + student_serializer = StudentExportSerializer(StudentInfo.objects.all(), many=True) + + content = { + "examTypes": exam_types_serializer.data, + "submissionTypes": submission_types_serializer.data, + "students": student_serializer.data, + "tutors": tutors_serializer.data, + "reviewers": reviewer_serializer.data + } + return Response(content) +