Repository: e-valuation/EvaP

Issue:
Single results' results are hidden in course detail page if not published
If a single result is shown on a course detail page of another evaluation of the same course, its results are hidden if it's not yet published. Non-published regular evaluations have their results shown, just as all published evaluations do.

The fix is simple, but I wanted to make sure this behavior is not expected...? It seemed inconsistent to me. 

See screenshot. Note how Bar's results are not shown, but "Software Architecture" and "Bar2" have their results shown.

![image](https://user-images.githubusercontent.com/1891915/131266243-2494d449-db7c-4146-ab35-e77d77f25bf7.png)



Discussion:
Nice, this indeed is an inconsistency that should be fixed.

On another matter: The weighting percentages in the screenshot seem broken, shouldn't they add up to 100%?
@karyon do you want to continue working on this?
yes!

Resolving patch:
diff --git a/evap/results/views.py b/evap/results/views.py
--- a/evap/results/views.py
+++ b/evap/results/views.py
@@ -21,12 +21,9 @@
     RatingResult,
     TextResult,
     annotate_distributions_and_grades,
-    calculate_average_distribution,
     can_textanswer_be_seen_by,
-    distribution_to_grade,
     get_evaluations_with_course_result_attributes,
     get_results,
-    get_single_result_rating_result,
 )
 
 
@@ -337,16 +334,9 @@ def get_evaluations_of_course(course, request):
             course_evaluations += course.evaluations.filter(
                 state__in=[Evaluation.State.IN_EVALUATION, Evaluation.State.EVALUATED, Evaluation.State.REVIEWED]
             )
-
+        annotate_distributions_and_grades(course_evaluations)
         course_evaluations = get_evaluations_with_course_result_attributes(course_evaluations)
 
-        for course_evaluation in course_evaluations:
-            if course_evaluation.is_single_result:
-                course_evaluation.single_result_rating_result = get_single_result_rating_result(course_evaluation)
-            else:
-                course_evaluation.distribution = calculate_average_distribution(course_evaluation)
-                course_evaluation.avg_grade = distribution_to_grade(course_evaluation.distribution)
-
     return course_evaluations
 
 


Test patch:
diff --git a/evap/grades/tests.py b/evap/grades/tests.py
--- a/evap/grades/tests.py
+++ b/evap/grades/tests.py
@@ -214,7 +214,7 @@ def test_does_not_crash(self):
 
     def test_403_on_deleted(self):
         baker.make(Semester, pk=1, grade_documents_are_deleted=True)
-        self.app.get("/grades/semester/1", user=self.grade_publisher, status=403)
+        self.app.get(self.url, user=self.grade_publisher, status=403)
 
 
 class GradeCourseViewTest(WebTest):
@@ -231,14 +231,14 @@ def setUpTestData(cls):
     def test_does_not_crash(self):
         semester = baker.make(Semester, pk=1, grade_documents_are_deleted=False)
         baker.make(Evaluation, course=baker.make(Course, pk=1, semester=semester), state=Evaluation.State.PREPARED)
-        self.app.get("/grades/semester/1/course/1", user=self.grade_publisher, status=200)
+        self.app.get(self.url, user=self.grade_publisher, status=200)
 
     def test_403_on_archived_semester(self):
         archived_semester = baker.make(Semester, pk=1, grade_documents_are_deleted=True)
         baker.make(
             Evaluation, course=baker.make(Course, pk=1, semester=archived_semester), state=Evaluation.State.PREPARED
         )
-        self.app.get("/grades/semester/1/course/1", user=self.grade_publisher, status=403)
+        self.app.get(self.url, user=self.grade_publisher, status=403)
 
 
 class GradeEditTest(WebTest):
diff --git a/evap/results/tests/test_tools.py b/evap/results/tests/test_tools.py
--- a/evap/results/tests/test_tools.py
+++ b/evap/results/tests/test_tools.py
@@ -297,7 +297,7 @@ def test_distribution_with_general_grade_question(self):
 
     def test_get_single_result_rating_result(self):
         single_result_evaluation = baker.make(Evaluation, state=Evaluation.State.PUBLISHED, is_single_result=True)
-        questionnaire = Questionnaire.objects.get(name_en=Questionnaire.SINGLE_RESULT_QUESTIONNAIRE_NAME)
+        questionnaire = Questionnaire.single_result_questionnaire()
         contribution = baker.make(
             Contribution,
             contributor=baker.make(UserProfile),
diff --git a/evap/results/tests/test_views.py b/evap/results/tests/test_views.py
--- a/evap/results/tests/test_views.py
+++ b/evap/results/tests/test_views.py
@@ -293,7 +293,7 @@ class TestResultsViewContributionWarning(WebTest):
     @classmethod
     def setUpTestData(cls):
         cls.manager = make_manager()
-        cls.semester = baker.make(Semester, id=3)
+        cls.semester = baker.make(Semester)
         contributor = baker.make(UserProfile)
 
         # Set up an evaluation with one question but no answers
@@ -301,7 +301,6 @@ def setUpTestData(cls):
         student2 = baker.make(UserProfile)
         cls.evaluation = baker.make(
             Evaluation,
-            id=21,
             state=Evaluation.State.PUBLISHED,
             course=baker.make(Course, semester=cls.semester),
             participants=[student1, student2],
@@ -337,12 +336,10 @@ def test_few_answers_evaluation_show_warning(self):
 
 
 class TestResultsSemesterEvaluationDetailView(WebTestStaffMode):
-    url = "/results/semester/2/evaluation/21"
-
     @classmethod
     def setUpTestData(cls):
         cls.manager = make_manager()
-        cls.semester = baker.make(Semester, id=2)
+        cls.semester = baker.make(Semester)
 
         contributor = baker.make(UserProfile, email="contributor@institution.example.com")
         responsible = baker.make(UserProfile, email="responsible@institution.example.com")
@@ -351,7 +348,7 @@ def setUpTestData(cls):
 
         # Normal evaluation with responsible and contributor.
         cls.evaluation = baker.make(
-            Evaluation, id=21, state=Evaluation.State.PUBLISHED, course=baker.make(Course, semester=cls.semester)
+            Evaluation, state=Evaluation.State.PUBLISHED, course=baker.make(Course, semester=cls.semester)
         )
 
         baker.make(
@@ -368,6 +365,8 @@ def setUpTestData(cls):
             role=Contribution.Role.EDITOR,
         )
 
+        cls.url = f"/results/semester/{cls.semester.id}/evaluation/{cls.evaluation.id}"
+
     def test_questionnaire_ordering(self):
         top_questionnaire = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
         contributor_questionnaire = baker.make(Questionnaire, type=Questionnaire.Type.CONTRIBUTOR)
@@ -473,6 +472,48 @@ def test_preview_with_rating_answers(self):
         url = f"/results/semester/{self.semester.id}/evaluation/{evaluation.id}"
         self.app.get(url, user=self.manager)
 
+    def test_unpublished_single_results_show_results(self):
+        """Regression test for #1621"""
+        # make regular evaluation with some answers
+        participants = baker.make(UserProfile, _bulk_create=True, _quantity=20)
+        evaluation = baker.make(
+            Evaluation,
+            state=Evaluation.State.REVIEWED,
+            course=baker.make(Course, semester=self.semester),
+            participants=participants,
+            voters=participants,
+        )
+        questionnaire = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
+        likert_question = baker.make(Question, type=Question.LIKERT, questionnaire=questionnaire, order=1)
+        evaluation.general_contribution.questionnaires.set([questionnaire])
+        make_rating_answer_counters(likert_question, evaluation.general_contribution)
+
+        # make single result
+        evaluation2: Evaluation = baker.make(
+            Evaluation,
+            state=Evaluation.State.REVIEWED,
+            course=evaluation.course,
+            is_single_result=True,
+            name_de="foo",
+            name_en="foo",
+            participants=participants,
+            voters=participants,
+        )
+        evaluation2.general_contribution.questionnaires.set([questionnaire])
+        make_rating_answer_counters(likert_question, evaluation2.general_contribution)
+
+        cache_results(evaluation)
+
+        url = f"/results/semester/{self.semester.id}/evaluation/{evaluation.id}"
+        response = self.app.get(url, user=self.manager)
+
+        # this one is the course result. The two evaluations shouldn't use this
+        self.assertTemplateUsed(response, "distribution_with_grade_disabled.html", count=1)
+        # Both evaluations should use this
+        self.assertTemplateUsed(response, "evaluation_result_widget.html", count=2)
+        # Both evaluations should use this, plus one for the questionnaire
+        self.assertTemplateUsed(response, "distribution_with_grade.html", count=3)
+
 
 class TestResultsSemesterEvaluationDetailViewFewVoters(WebTest):
     @classmethod
@@ -823,7 +864,6 @@ def setUpTestData(cls):
         responsible = baker.make(UserProfile, email="responsible@institution.example.com")
         cls.evaluation = baker.make(
             Evaluation,
-            id=21,
             state=Evaluation.State.PUBLISHED,
             course=baker.make(Course, semester=cls.semester, responsibles=[responsible]),
         )