From b1c1412f5e5550def6568480dc18aa1c6b44e9fe Mon Sep 17 00:00:00 2001
From: Dominik Seeger <dominik.seeger@gmx.net>
Date: Wed, 6 Mar 2019 18:44:57 +0100
Subject: [PATCH] changed model so that exam_id cannot be null

---
 core/migrations/0012_auto_20190306_1611.py    | 19 ++++++++++
 core/models.py                                |  4 +-
 core/tests/test_access_rights.py              | 31 ++++++++++++---
 core/tests/test_commands.py                   |  9 ++++-
 core/tests/test_factory.py                    | 26 ++++++++++---
 core/tests/test_feedback.py                   | 38 ++++++++++++++++---
 core/tests/test_functional_views.py           |  9 ++++-
 core/tests/test_student_page.py               |  6 +++
 .../test_subscription_assignment_service.py   | 26 ++++++++++---
 core/tests/test_tutor_api_endpoints.py        | 15 +++++++-
 core/tests/test_user_account_views.py         |  9 ++++-
 util/factories.py                             |  4 +-
 util/importer.py                              |  4 +-
 13 files changed, 163 insertions(+), 37 deletions(-)
 create mode 100644 core/migrations/0012_auto_20190306_1611.py

diff --git a/core/migrations/0012_auto_20190306_1611.py b/core/migrations/0012_auto_20190306_1611.py
new file mode 100644
index 00000000..54f93ca9
--- /dev/null
+++ b/core/migrations/0012_auto_20190306_1611.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.1.5 on 2019-03-06 16:11
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0011_auto_20181001_1259'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='studentinfo',
+            name='exam',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='students', to='core.ExamType'),
+        ),
+    ]
diff --git a/core/models.py b/core/models.py
index 1f942494..224eca21 100644
--- a/core/models.py
+++ b/core/models.py
@@ -280,9 +280,9 @@ class StudentInfo(models.Model):
                                    max_length=30,
                                    default=random_matrikel_no)
     exam = models.ForeignKey('ExamType',
-                             on_delete=models.SET_NULL,
+                             on_delete=models.CASCADE,
                              related_name='students',
-                             null=True)
+                             null=False)
     user = models.OneToOneField(get_user_model(),
                                 on_delete=models.CASCADE,
                                 related_name='student')
diff --git a/core/tests/test_access_rights.py b/core/tests/test_access_rights.py
index 2d57498d..75c0f5a7 100644
--- a/core/tests/test_access_rights.py
+++ b/core/tests/test_access_rights.py
@@ -5,7 +5,8 @@ from rest_framework.test import (APIRequestFactory, APITestCase,
 
 from core.views import (ExamApiViewSet, StudentReviewerApiViewSet,
                         StudentSelfApiView, TutorApiViewSet)
-from util.factories import GradyUserFactory
+from core.models import ExamType
+from util.factories import GradyUserFactory, make_exams
 
 
 class AccessRightsOfStudentAPIViewTests(APITestCase):
@@ -18,7 +19,12 @@ class AccessRightsOfStudentAPIViewTests(APITestCase):
         cls.user_factory = GradyUserFactory()
 
     def setUp(self):
-        self.student = self.user_factory.make_student()
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.student = self.user_factory.make_student(exam=self.exam)
         self.tutor = self.user_factory.make_tutor()
         self.reviewer = self.user_factory.make_reviewer()
         self.request = self.factory.get(reverse('student-page'))
@@ -53,7 +59,12 @@ class AccessRightsOfTutorAPIViewTests(APITestCase):
         cls.user_factory = GradyUserFactory()
 
     def setUp(self):
-        self.student = self.user_factory.make_student()
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.student = self.user_factory.make_student(exam=self.exam)
         self.tutor = self.user_factory.make_tutor()
         self.reviewer = self.user_factory.make_reviewer()
         self.request = self.factory.get(reverse('tutor-list'))
@@ -89,7 +100,12 @@ class AccessRightsOfStudentReviewerAPIViewTest(APITestCase):
         cls.user_factory = GradyUserFactory()
 
     def setUp(self):
-        self.student = self.user_factory.make_student()
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.student = self.user_factory.make_student(exam=self.exam)
         self.tutor = self.user_factory.make_tutor()
         self.reviewer = self.user_factory.make_reviewer()
         self.request = self.factory.get(reverse('student-list'))
@@ -127,7 +143,12 @@ class AccessRightsOfExamTypeAPIViewTest(APITestCase):
         cls.user_factory = GradyUserFactory()
 
     def setUp(self):
-        self.student = self.user_factory.make_student()
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.student = self.user_factory.make_student(exam=self.exam)
         self.tutor = self.user_factory.make_tutor()
         self.reviewer = self.user_factory.make_reviewer()
         self.request = self.factory.get(reverse('examtype-list'))
diff --git a/core/tests/test_commands.py b/core/tests/test_commands.py
index 97b3ea81..e313c5a3 100644
--- a/core/tests/test_commands.py
+++ b/core/tests/test_commands.py
@@ -5,7 +5,7 @@ from django.contrib.auth import get_user_model
 from django.core.management import call_command
 from django.test import TestCase
 
-from util.factories import GradyUserFactory
+from util.factories import GradyUserFactory, make_exams
 
 
 class CommandsTestCase(TestCase):
@@ -22,7 +22,12 @@ class CommandsTestCase(TestCase):
         self.assertFalse(someone.is_active)
 
     def test_replaceusernames(self):
-        self.factory.make_student(identifier=88884444, username='before')
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.factory.make_student(identifier=88884444, username='before', exam=self.exam)
 
         with tempfile.NamedTemporaryFile() as matno2username:
             matno2username.write(json.dumps({'88884444': 'after'}).encode())
diff --git a/core/tests/test_factory.py b/core/tests/test_factory.py
index 5b582890..c5bfc697 100644
--- a/core/tests/test_factory.py
+++ b/core/tests/test_factory.py
@@ -2,7 +2,7 @@ from django.test import TestCase
 
 from core import models
 from core.models import StudentInfo
-from util.factories import GradyUserFactory
+from util.factories import GradyUserFactory, make_exams
 
 
 class FactoryTestCase(TestCase):
@@ -10,11 +10,15 @@ class FactoryTestCase(TestCase):
     factory = GradyUserFactory()
 
     def test_make_student(self):
-
-        user = self.factory.make_student()
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        user = self.factory.make_student(exam=self.exam)
 
         self.assertEqual(StudentInfo.objects.count(), 1)
-        self.assertEqual(user.student.exam, None)
+        self.assertEqual(user.student.exam.module_reference, "Test Exam 01")
         self.assertEqual(len(str(user.student.matrikel_no)), 8)
 
     def test_can_create_reviewer(self):
@@ -30,9 +34,19 @@ class FactoryTestCase(TestCase):
                       models.UserAccount.objects.all())
 
     def test_can_create_student_user(self):
-        self.assertIn(self.factory.make_student(),
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.assertIn(self.factory.make_student(exam=self.exam),
                       models.UserAccount.objects.all())
 
     def test_can_create_student_info(self):
-        self.assertIn(self.factory.make_student().student,
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.assertIn(self.factory.make_student(exam=self.exam).student,
                       StudentInfo.objects.all())
diff --git a/core/tests/test_feedback.py b/core/tests/test_feedback.py
index 6677eb06..0ab1e532 100644
--- a/core/tests/test_feedback.py
+++ b/core/tests/test_feedback.py
@@ -4,8 +4,8 @@ from rest_framework import status
 from rest_framework.test import APIRequestFactory, APITestCase
 
 from core import models
-from core.models import Feedback, FeedbackComment, Submission, SubmissionType
-from util.factories import GradyUserFactory, make_test_data
+from core.models import Feedback, FeedbackComment, Submission, SubmissionType, ExamType
+from util.factories import GradyUserFactory, make_test_data, make_exams
 
 
 class FeedbackRetrieveTestCase(APITestCase):
@@ -17,7 +17,12 @@ class FeedbackRetrieveTestCase(APITestCase):
     def setUpTestData(cls):
         cls.score = 23
         cls.tutor = cls.factory.make_tutor()
-        cls.student = cls.factory.make_student()
+        cls.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        cls.student = cls.factory.make_student(exam=cls.exam)
         cls.reviewer = cls.factory.make_reviewer()
         cls.tutors = [cls.tutor, cls.reviewer]
         cls.request_factory = APIRequestFactory()
@@ -91,7 +96,12 @@ class FeedbackCreateTestCase(APITestCase):
         cls.url = '/api/feedback/'
         cls.user_factory = GradyUserFactory()
         cls.tutor = cls.user_factory.make_tutor(password='p')
-        cls.student = cls.user_factory.make_student()
+        cls.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        cls.student = cls.user_factory.make_student(exam=cls.exam)
         cls.submission_type = SubmissionType.objects.create(
             name='Cooking some crystal with Jesse',
             full_score=100
@@ -282,6 +292,11 @@ class FeedbackPatchTestCase(APITestCase):
     def setUpTestData(cls):
         cls.burl = '/api/feedback/'
         cls.data = make_test_data({
+            'exams': [{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }],
             'submission_types': [
                 {
                     'name': '01. Sort this or that',
@@ -290,7 +305,10 @@ class FeedbackPatchTestCase(APITestCase):
                     'solution': 'Trivial!'
                 }],
             'students': [
-                {'username': 'student01'}
+                {
+                    'username': 'student01',
+                    'exam': 'Test Exam 01'
+                }
             ],
             'tutors': [
                 {'username': 'tutor01'},
@@ -395,6 +413,11 @@ class FeedbackCommentApiEndpointTest(APITestCase):
     def setUpTestData(cls):
         cls.burl = '/api/feedback/'
         cls.data = make_test_data({
+            'exams': [{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }],
             'submission_types': [
                 {
                     'name': '01. Sort this or that',
@@ -403,7 +426,10 @@ class FeedbackCommentApiEndpointTest(APITestCase):
                     'solution': 'Trivial!'
                 }],
             'students': [
-                {'username': 'student01'}
+                {
+                    'username': 'student01',
+                    'exam': 'Test Exam 01'
+                }
             ],
             'tutors': [
                 {'username': 'tutor01'},
diff --git a/core/tests/test_functional_views.py b/core/tests/test_functional_views.py
index 7763b5c6..1cee60f1 100644
--- a/core/tests/test_functional_views.py
+++ b/core/tests/test_functional_views.py
@@ -3,7 +3,7 @@ from rest_framework.test import (APIRequestFactory, APITestCase,
                                  force_authenticate)
 
 from core.views import get_user_role
-from util.factories import GradyUserFactory
+from util.factories import GradyUserFactory, make_exams
 
 
 class GetUserRoleTest(APITestCase):
@@ -11,7 +11,12 @@ class GetUserRoleTest(APITestCase):
     def setUpTestData(cls):
         cls.factory = APIRequestFactory()
         cls.user_factory = GradyUserFactory()
-        cls.student = cls.user_factory.make_student()
+        cls.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        cls.student = cls.user_factory.make_student(exam=cls.exam)
         cls.tutor = cls.user_factory.make_tutor()
         cls.reviewer = cls.user_factory.make_reviewer()
 
diff --git a/core/tests/test_student_page.py b/core/tests/test_student_page.py
index 41800def..d6c6f97f 100644
--- a/core/tests/test_student_page.py
+++ b/core/tests/test_student_page.py
@@ -130,6 +130,11 @@ class StudentSelfSubmissionsTests(APITestCase):
 
     def setUp(self):
         self.test_data = make_test_data(data_dict={
+            'exams': [{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }],
             'submission_types': [{
                 'name': 'problem01',
                 'full_score': 10,
@@ -138,6 +143,7 @@ class StudentSelfSubmissionsTests(APITestCase):
             }],
             'students': [{
                 'username': 'user01',
+                'exam': 'Test Exam 01'
             }],
             'tutors': [
                 {
diff --git a/core/tests/test_subscription_assignment_service.py b/core/tests/test_subscription_assignment_service.py
index ca576ae9..410dfca7 100644
--- a/core/tests/test_subscription_assignment_service.py
+++ b/core/tests/test_subscription_assignment_service.py
@@ -4,7 +4,7 @@ from rest_framework.test import APIClient, APITestCase
 from core import models
 from core.models import (Submission, SubmissionSubscription, SubmissionType,
                          SubscriptionEnded, SubscriptionTemporarilyEnded, TutorSubmissionAssignment)
-from util.factories import GradyUserFactory, make_test_data
+from util.factories import GradyUserFactory, make_test_data, make_exams
 
 
 class SubmissionSubscriptionRandomTest(APITestCase):
@@ -15,8 +15,13 @@ class SubmissionSubscriptionRandomTest(APITestCase):
 
     def setUp(self):
         self.t = self.user_factory.make_tutor()
-        self.s1 = self.user_factory.make_student()
-        self.s2 = self.user_factory.make_student()
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        self.s1 = self.user_factory.make_student(exam=self.exam)
+        self.s2 = self.user_factory.make_student(exam=self.exam)
 
         self.submission_type = SubmissionType.objects.create(
             name='submission_01', full_score=14)
@@ -97,6 +102,11 @@ class TestApiEndpoints(APITestCase):
     @classmethod
     def setUpTestData(cls):
         cls.data = make_test_data(data_dict={
+            'exams': [{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }],
             'submission_types': [
                 {
                     'name': '01. Sort this or that',
@@ -112,8 +122,14 @@ class TestApiEndpoints(APITestCase):
                 }
             ],
             'students': [
-                {'username': 'student01'},
-                {'username': 'student02'}
+                {
+                    'username': 'student01',
+                    'exam': 'Test Exam 01'
+                },
+                {
+                    'username': 'student02',
+                    'exam': 'Test Exam 01'
+                }
             ],
             'tutors': [
                 {'username': 'tutor01'},
diff --git a/core/tests/test_tutor_api_endpoints.py b/core/tests/test_tutor_api_endpoints.py
index 21001236..689edad5 100644
--- a/core/tests/test_tutor_api_endpoints.py
+++ b/core/tests/test_tutor_api_endpoints.py
@@ -56,14 +56,25 @@ class TutorListTests(APITestCase):
         view = TutorApiViewSet.as_view({'get': 'list'})
 
         data = make_test_data(data_dict={
+            'exams': [{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }],
             'submission_types': [{
                 'name': '01. Sort this or that',
                 'full_score': 35,
                 'description': 'Very complicated',
                 'solution': 'Trivial!'}],
             'students': [
-                {'username': 'student01'},
-                {'username': 'student02'}
+                {
+                    'username': 'student01',
+                    'exam': 'Test Exam 01'
+                },
+                {
+                    'username': 'student02',
+                    'exam': 'Test Exam 01'
+                }
             ],
             'tutors': [
                 {'username': 'tutor01'},
diff --git a/core/tests/test_user_account_views.py b/core/tests/test_user_account_views.py
index bc9e50c0..dbcfec71 100644
--- a/core/tests/test_user_account_views.py
+++ b/core/tests/test_user_account_views.py
@@ -1,7 +1,7 @@
 from rest_framework import status
 from rest_framework.test import (APIClient, APITestCase)
 
-from util.factories import GradyUserFactory
+from util.factories import GradyUserFactory, make_exams
 
 
 class TutorReviewerCanChangePasswordTests(APITestCase):
@@ -75,7 +75,12 @@ class TutorReviewerCanChangePasswordTests(APITestCase):
         self.assertTrue(ret)
 
     def test_student_cant_change_password(self):
-        student = self.user_factory.make_student(password='l')
+        self.exam = make_exams(exams=[{
+                'module_reference': 'Test Exam 01',
+                'total_score': 100,
+                'pass_score': 60,
+            }])[0]
+        student = self.user_factory.make_student(password='l', exam=self.exam)
         res = self._change_password(student)
         self.assertEqual(status.HTTP_403_FORBIDDEN, res.status_code)
         ret = self.client.login(username=student.username,
diff --git a/util/factories.py b/util/factories.py
index 6fedf552..eb1a0411 100644
--- a/util/factories.py
+++ b/util/factories.py
@@ -94,11 +94,9 @@ class GradyUserFactory:
         """ Creates a student. Defaults can be passed via kwargs like in
         relation managers objects.update method. """
         user = self._make_base_user(username, 'Student', **kwargs)
-        student_info = StudentInfo.objects.get_or_create(user=user)[0]
+        student_info = StudentInfo.objects.get_or_create(user=user, exam=exam)[0]
         if identifier:
             student_info.matrikel_no = identifier
-        if exam:
-            student_info.exam = exam
         student_info.save()
         return user
 
diff --git a/util/importer.py b/util/importer.py
index 6a99b6db..5289b87d 100644
--- a/util/importer.py
+++ b/util/importer.py
@@ -378,9 +378,9 @@ def do_load_submissions():
              'submissions.json', is_file=True)
 
     exam_obj = {}
-    if ExamType.objects.all() and \
-            i('Do you want to add module/exam information?', NO):
+    if ExamType.objects.all():
         exam_query_set = ExamType.objects.all()
+        print('Please select the corresponding module')
         print('You have the following choices:\n')
         for j, exam_type in enumerate(exam_query_set):
             print(f'\t[{j}] {exam_type.module_reference}')
-- 
GitLab