Repository: e-valuation/EvaP

Issue:
Prevent text answer updates after publishing evaluation
After an evaluation was published, changes to text answers should not be possible anymore.
The staff text answer page of an evaluation (`staff.views.evaluation_textanswers`) should then not be accessible (the UI doesn't link to it but manually entering the URL is currently possible) and `evaluation_textanswers_update_publish` as well as `evaluation_textanswer_edit` should also raise `PermissionDenied`.


Discussion:

Resolving patch:
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -1421,10 +1421,12 @@ def get_evaluation_and_contributor_textanswer_sections(evaluation, filter_textan
 @reviewer_required
 def evaluation_textanswers(request, semester_id, evaluation_id):
     semester = get_object_or_404(Semester, id=semester_id)
-    if semester.results_are_archived and not request.user.is_manager:
+    if semester.results_are_archived:
         raise PermissionDenied
     evaluation = get_object_or_404(Evaluation, id=evaluation_id, course__semester=semester)
 
+    if evaluation.state == Evaluation.State.PUBLISHED:
+        raise PermissionDenied
     if not evaluation.can_publish_text_results:
         raise PermissionDenied
 
@@ -1476,7 +1478,9 @@ def evaluation_textanswers_update_publish(request):
     evaluation_id = request.POST["evaluation_id"]
 
     evaluation = Evaluation.objects.get(pk=evaluation_id)
-    if evaluation.course.semester.results_are_archived and not request.user.is_manager:
+    if evaluation.state == Evaluation.State.PUBLISHED:
+        raise PermissionDenied
+    if evaluation.course.semester.results_are_archived:
         raise PermissionDenied
     if not evaluation.can_publish_text_results:
         raise PermissionDenied
@@ -1508,10 +1512,12 @@ def evaluation_textanswers_update_publish(request):
 @reviewer_required
 def evaluation_textanswer_edit(request, semester_id, evaluation_id, textanswer_id):
     semester = get_object_or_404(Semester, id=semester_id)
-    if semester.results_are_archived and not request.user.is_manager:
+    if semester.results_are_archived:
         raise PermissionDenied
     evaluation = get_object_or_404(Evaluation, id=evaluation_id, course__semester=semester)
 
+    if evaluation.state == Evaluation.State.PUBLISHED:
+        raise PermissionDenied
     if not evaluation.can_publish_text_results:
         raise PermissionDenied
 


Test patch:
diff --git a/evap/staff/tests/test_views.py b/evap/staff/tests/test_views.py
--- a/evap/staff/tests/test_views.py
+++ b/evap/staff/tests/test_views.py
@@ -2262,6 +2262,22 @@ def test_num_queries_is_constant(self):
             with self.assertNumQueries(FuzzyInt(0, self.num_questions)):
                 self.app.get(self.url, user=self.manager)
 
+    def test_published(self):
+        let_user_vote_for_evaluation(self.app, self.student2, self.evaluation)
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=200)
+        Evaluation.objects.filter(id=self.evaluation.id).update(state=Evaluation.State.PUBLISHED)
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=403)
+
+    def test_archived(self):
+        let_user_vote_for_evaluation(self.app, self.student2, self.evaluation)
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=200)
+        Semester.objects.filter(id=self.evaluation.course.semester.id).update(results_are_archived=True)
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=403)
+
 
 class TestEvaluationTextAnswerEditView(WebTest):
     @classmethod
@@ -2320,6 +2336,21 @@ def test_textanswers_showing_up(self):
             self.text_answer.refresh_from_db()
             self.assertEqual(self.text_answer.answer, "edited answer text")
 
+        # archive and it shouldn't work anymore
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=200)
+        Semester.objects.filter(id=self.evaluation.course.semester.id).update(results_are_archived=True)
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=403)
+        Semester.objects.filter(id=self.evaluation.course.semester.id).update(results_are_archived=False)
+
+        # publish and it shouldn't work anymore
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=200)
+        Evaluation.objects.filter(id=self.evaluation.id).update(state=Evaluation.State.PUBLISHED)
+        with run_in_staff_mode(self):
+            self.app.get(self.url, user=self.manager, status=403)
+
 
 class TestQuestionnaireNewVersionView(WebTestStaffMode):
     url = "/staff/questionnaire/2/new_version"
@@ -2699,6 +2730,18 @@ def test_finishing_review_updates_results(self):
 
         self.assertEqual(len(results.questionnaire_results[0].question_results[1].answers), 1)
 
+    def test_published(self):
+        let_user_vote_for_evaluation(self.app, self.student2, self.evaluation)
+        self.helper(TextAnswer.State.NOT_REVIEWED, TextAnswer.State.PUBLISHED, "publish")
+        Evaluation.objects.filter(id=self.evaluation.id).update(state=Evaluation.State.PUBLISHED)
+        self.helper(TextAnswer.State.NOT_REVIEWED, TextAnswer.State.PUBLISHED, "publish", expect_errors=True)
+
+    def test_archived(self):
+        let_user_vote_for_evaluation(self.app, self.student2, self.evaluation)
+        self.helper(TextAnswer.State.NOT_REVIEWED, TextAnswer.State.PUBLISHED, "publish")
+        Semester.objects.filter(id=self.evaluation.course.semester.id).update(results_are_archived=True)
+        self.helper(TextAnswer.State.NOT_REVIEWED, TextAnswer.State.PUBLISHED, "publish", expect_errors=True)
+
 
 class TestEvaluationTextAnswersSkip(WebTestStaffMode):
     csrf_checks = False