Repository: e-valuation/EvaP

Issue:
Release Sisyphus data only after successful post
When a user enters answers on the student vote page and then logs out in another window before submitting the form, Sisyphus releases the form data on the form submit, because a 302 redirect to the login page is not an error case.
The data should be kept in browser storage until the vote was successfully counted.
Release Sisyphus data only after successful post
When a user enters answers on the student vote page and then logs out in another window before submitting the form, Sisyphus releases the form data on the form submit, because a 302 redirect to the login page is not an error case.
The data should be kept in browser storage until the vote was successfully counted.


Discussion:

Resolving patch:
diff --git a/evap/student/views.py b/evap/student/views.py
--- a/evap/student/views.py
+++ b/evap/student/views.py
@@ -3,7 +3,9 @@
 from django.contrib import messages
 from django.core.exceptions import PermissionDenied, SuspiciousOperation
 from django.db import transaction
+from django.http import HttpResponse
 from django.shortcuts import get_object_or_404, redirect, render
+from django.urls import reverse
 from django.utils.translation import ugettext as _
 
 from evap.evaluation.auth import participant_required
@@ -13,6 +15,7 @@
 from evap.student.forms import QuestionsForm
 from evap.student.tools import question_id
 
+SUCCESS_MAGIC_STRING = 'vote submitted successfully'
 
 @participant_required
 def index(request):
@@ -58,12 +61,11 @@ def vote_preview(request, course, for_rendering_in_modal=False):
 
 @participant_required
 def vote(request, course_id):
-    # retrieve course and make sure that the user is allowed to vote
+
     course = get_object_or_404(Course, id=course_id)
     if not course.can_user_vote(request.user):
         raise PermissionDenied
 
-    
     # prevent a user from voting on themselves.
     contributions_to_vote_on = course.contributions.exclude(contributor=request.user).all()
     form_groups = helper_create_voting_form_groups(request, contributions_to_vote_on)
@@ -85,6 +87,8 @@ def vote(request, course_id):
             vote_end_datetime=course.vote_end_datetime,
             hours_left_for_evaluation=course.time_left_for_evaluation.seconds//3600,
             minutes_left_for_evaluation=(course.time_left_for_evaluation.seconds//60)%60,
+            success_magic_string=SUCCESS_MAGIC_STRING,
+            success_redirect_url=reverse('student:index'),
             evaluation_ends_soon=course.evaluation_ends_soon())
         return render(request, "student_vote.html", template_data)
 
@@ -121,7 +125,7 @@ def vote(request, course_id):
         course.course_evaluated.send(sender=Course, request=request, semester=course.semester)
 
     messages.success(request, _("Your vote was recorded."))
-    return redirect('student:index')
+    return HttpResponse(SUCCESS_MAGIC_STRING)
 
 
 def helper_create_voting_form_groups(request, contributions):


Test patch:
diff --git a/evap/student/tests/test_views.py b/evap/student/tests/test_views.py
--- a/evap/student/tests/test_views.py
+++ b/evap/student/tests/test_views.py
@@ -6,6 +6,7 @@
 from evap.evaluation.models import UserProfile, Course, Questionnaire, Question, Contribution, TextAnswer, RatingAnswerCounter
 from evap.evaluation.tests.tools import WebTest, ViewTest
 from evap.student.tools import question_id
+from evap.student.views import SUCCESS_MAGIC_STRING
 
 
 class TestStudentIndexView(ViewTest):
@@ -73,6 +74,7 @@ def test_incomplete_form(self):
         self.fill_form(form, fill_complete=False)
         response = form.submit()
 
+        self.assertEqual(response.status_code, 200)
         self.assertIn("vote for all rating questions", response)
 
         form = page.forms["student-vote-form"]
@@ -89,12 +91,14 @@ def test_answer(self):
         page = self.get_assert_200(self.url, user=self.voting_user1.username)
         form = page.forms["student-vote-form"]
         self.fill_form(form, fill_complete=True)
-        form.submit()
+        response = form.submit()
+        self.assertEqual(SUCCESS_MAGIC_STRING, response.body.decode())
 
         page = self.get_assert_200(self.url, user=self.voting_user2.username)
         form = page.forms["student-vote-form"]
         self.fill_form(form, fill_complete=True)
-        form.submit()
+        response = form.submit()
+        self.assertEqual(SUCCESS_MAGIC_STRING, response.body.decode())
 
         self.assertEqual(len(TextAnswer.objects.all()), 6)
         self.assertEqual(len(RatingAnswerCounter.objects.all()), 4)
@@ -139,3 +143,13 @@ def test_user_cannot_vote_for_themselves(self):
         response = self.get_assert_200(self.url, user=self.voting_user1)
         self.assertTrue(any(contributor == self.contributor1 for contributor, _, _, _ in response.context['contributor_form_groups']),
             "Regular students should see the questionnaire about a contributor")
+
+    def test_user_logged_out(self):
+        page = self.get_assert_200(self.url, user=self.voting_user1.username)
+        form = page.forms["student-vote-form"]
+        self.fill_form(form, fill_complete=True)
+        page = self.get_assert_302(reverse("django-auth-logout"), user=self.voting_user1.username)
+        response = form.submit()
+        self.assertEqual(response.status_code, 302)
+        self.assertNotIn(SUCCESS_MAGIC_STRING, response)
+