Repository: e-valuation/EvaP

Issue:
Reviewed single results are shown without information on results page for staff
Staff users can see single results that are not yet published on the results page without any warning about their state.


Discussion:

Resolving patch:
diff --git a/evap/evaluation/models.py b/evap/evaluation/models.py
--- a/evap/evaluation/models.py
+++ b/evap/evaluation/models.py
@@ -315,7 +315,7 @@ def can_staff_edit(self):
 
     @property
     def can_staff_delete(self):
-        return self.can_staff_edit and not self.num_voters > 0
+        return self.can_staff_edit and (not self.num_voters > 0 or self.is_single_result)
 
     @property
     def can_staff_approve(self):
diff --git a/evap/staff/forms.py b/evap/staff/forms.py
--- a/evap/staff/forms.py
+++ b/evap/staff/forms.py
@@ -238,16 +238,11 @@ def save(self, *args, **kw):
         single_result_questionnaire = Questionnaire.single_result_questionnaire()
         single_result_question = single_result_questionnaire.question_set.first()
 
-        if not Contribution.objects.filter(course=self.instance, responsible=True).exists():
-            contribution = Contribution(
-                course=self.instance,
-                contributor=self.cleaned_data['responsible'],
-                responsible=True,
-                can_edit=True,
-                comment_visibility=Contribution.ALL_COMMENTS
-            )
-            contribution.save()
+        contribution, created = Contribution.objects.get_or_create(course=self.instance, responsible=True, can_edit=True, comment_visibility=Contribution.ALL_COMMENTS)
+        contribution.contributor = self.cleaned_data['responsible']
+        if created:
             contribution.questionnaires.add(single_result_questionnaire)
+        contribution.save()
 
         # set answers
         contribution = Contribution.objects.get(course=self.instance, responsible=True)
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -17,7 +17,7 @@
 from django.views.decorators.http import require_POST
 from evap.evaluation.auth import reviewer_required, staff_required
 from evap.evaluation.models import (Contribution, Course, CourseType, Degree, EmailTemplate, FaqQuestion, FaqSection, Question, Questionnaire,
-                                    Semester, TextAnswer, UserProfile)
+                                    RatingAnswerCounter, Semester, TextAnswer, UserProfile)
 from evap.evaluation.tools import STATES_ORDERED, questionnaires_and_contributions, send_publish_notifications, sort_formset
 from evap.grades.tools import are_grades_activated
 from evap.results.exporters import ExcelExporter
@@ -634,6 +634,8 @@ def course_delete(request):
 
     if not course.can_staff_delete:
         raise SuspiciousOperation("Deleting course not allowed")
+    if course.is_single_result:
+        RatingAnswerCounter.objects.filter(contribution__course=course).delete()
     course.delete()
     return HttpResponse()  # 200 OK
 


Test patch:
diff --git a/evap/evaluation/tests/test_models.py b/evap/evaluation/tests/test_models.py
--- a/evap/evaluation/tests/test_models.py
+++ b/evap/evaluation/tests/test_models.py
@@ -7,8 +7,8 @@
 
 from model_mommy import mommy
 
-from evap.evaluation.models import Course, UserProfile, Contribution, Semester, \
-                                   Questionnaire, CourseType, NotArchiveable, EmailTemplate
+from evap.evaluation.models import (Contribution, Course, CourseType, EmailTemplate, NotArchiveable, Questionnaire,
+                                    RatingAnswerCounter, Semester, UserProfile)
 from evap.results.tools import calculate_average_grades_and_deviation
 
 
@@ -116,6 +116,27 @@ def test_responsible_contributors_ordering(self):
         course = Course.objects.get(pk=course.pk)
         self.assertEqual(list(course.responsible_contributors), [responsible2, responsible1])
 
+    def test_single_result_can_be_deleted_only_in_reviewed(self):
+        responsible = mommy.make(UserProfile)
+        course = mommy.make(Course, semester=mommy.make(Semester))
+        contribution = mommy.make(Contribution,
+            course=course, contributor=responsible, responsible=True, can_edit=True, comment_visibility=Contribution.ALL_COMMENTS,
+            questionnaires=[Questionnaire.single_result_questionnaire()]
+        )
+        course.single_result_created()
+        course.publish()
+        course.save()
+
+        self.assertTrue(Course.objects.filter(pk=course.pk).exists())
+        self.assertFalse(course.can_staff_delete)
+
+        course.unpublish()
+        self.assertTrue(course.can_staff_delete)
+
+        RatingAnswerCounter.objects.filter(contribution__course=course).delete()
+        course.delete()
+        self.assertFalse(Course.objects.filter(pk=course.pk).exists())
+
 
 class TestUserProfile(TestCase):
 
diff --git a/evap/staff/tests/test_forms.py b/evap/staff/tests/test_forms.py
--- a/evap/staff/tests/test_forms.py
+++ b/evap/staff/tests/test_forms.py
@@ -12,6 +12,7 @@
 
 
 class CourseEmailFormTests(TestCase):
+
     def test_course_email_form(self):
         """
             Tests the CourseEmailForm with one valid and one invalid input dataset.
@@ -29,6 +30,7 @@ def test_course_email_form(self):
 
 
 class UserFormTests(TestCase):
+
     def test_user_form(self):
         """
             Tests the UserForm with one valid and one invalid input dataset.
@@ -84,6 +86,7 @@ def test_user_with_same_username(self):
 
 
 class SingleResultFormTests(TestCase):
+
     def test_single_result_form_saves_participant_and_voter_count(self):
         responsible = mommy.make(UserProfile)
         course_type = mommy.make(CourseType)
@@ -111,6 +114,38 @@ def test_single_result_form_saves_participant_and_voter_count(self):
         self.assertEqual(course.num_participants, 10)
         self.assertEqual(course.num_voters, 10)
 
+    def test_single_result_form_can_change_responsible(self):
+        responsible = mommy.make(UserProfile)
+        course_type = mommy.make(CourseType)
+        course = Course(semester=mommy.make(Semester))
+        form_data = {
+            "name_de": "qwertz",
+            "name_en": "qwertz",
+            "type": course_type.pk,
+            "degrees": ["1"],
+            "event_date": "02/1/2014",
+            "responsible": responsible.pk,
+            "answer_1": 6,
+            "answer_2": 0,
+            "answer_3": 2,
+            "answer_4": 0,
+            "answer_5": 2,
+            "semester": course.semester.pk
+        }
+        form = SingleResultForm(form_data, instance=course)
+        self.assertTrue(form.is_valid())
+
+        form.save(user=mommy.make(UserProfile))
+        self.assertEqual(course.responsible_contributors[0], responsible)
+
+        new_responsible = mommy.make(UserProfile)
+        form_data["responsible"] = new_responsible.pk
+        form = SingleResultForm(form_data, instance=course)
+        self.assertTrue(form.is_valid())
+
+        form.save(user=mommy.make(UserProfile))
+        self.assertEqual(course.responsible_contributors[0], new_responsible)
+
 
 class ContributionFormsetTests(TestCase):