prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN 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.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `evap/student/views.py`
  Content:
  ```
  1 from collections import OrderedDict
  2 
  3 from django.contrib import messages
  4 from django.core.exceptions import PermissionDenied, SuspiciousOperation
  5 from django.db import transaction
  6 from django.shortcuts import get_object_or_404, redirect, render
  7 from django.utils.translation import ugettext as _
  8 
  9 from evap.evaluation.auth import participant_required
  10 from evap.evaluation.models import Course, Semester
  11 from evap.evaluation.tools import STUDENT_STATES_ORDERED
  12 
  13 from evap.student.forms import QuestionsForm
  14 from evap.student.tools import question_id
  15 
  16 
  17 @participant_required
  18 def index(request):
  19     # retrieve all courses, where the user is a participant and that are not new
  20     courses = list(set(Course.objects.filter(participants=request.user).exclude(state="new")))
  21     voted_courses = list(set(Course.objects.filter(voters=request.user)))
  22     due_courses = list(set(Course.objects.filter(participants=request.user, state='in_evaluation').exclude(voters=request.user)))
  23 
  24     sorter = lambda course: (list(STUDENT_STATES_ORDERED.keys()).index(course.student_state), course.vote_end_date, course.name)
  25     courses.sort(key=sorter)
  26 
  27     semesters = Semester.objects.all()
  28     semester_list = [dict(semester_name=semester.name, id=semester.id, is_active_semester=semester.is_active_semester,
  29         courses=[course for course in courses if course.semester_id == semester.id]) for semester in semesters]
  30 
  31     template_data = dict(
  32         semester_list=semester_list,
  33         voted_courses=voted_courses,
  34         due_courses=due_courses,
  35         can_download_grades=request.user.can_download_grades,
  36     )
  37     return render(request, "student_index.html", template_data)
  38 
  39 
  40 def vote_preview(request, course, for_rendering_in_modal=False):
  41     """
  42         Renders a preview of the voting page for the given course.
  43         Not used by the student app itself, but by staff and contributor.
  44     """
  45     form_groups = helper_create_voting_form_groups(request, course.contributions.all())
  46     course_form_group = form_groups.pop(course.general_contribution)
  47     contributor_form_groups = list((contribution.contributor, contribution.label, form_group, False) for contribution, form_group in form_groups.items())
  48 
  49     template_data = dict(
  50         errors_exist=False,
  51         course_form_group=course_form_group,
  52         contributor_form_groups=contributor_form_groups,
  53         course=course,
  54         preview=True,
  55         for_rendering_in_modal=for_rendering_in_modal)
  56     return render(request, "student_vote.html", template_data)
  57 
  58 
  59 @participant_required
  60 def vote(request, course_id):
  61     # retrieve course and make sure that the user is allowed to vote
  62     course = get_object_or_404(Course, id=course_id)
  63     if not course.can_user_vote(request.user):
  64         raise PermissionDenied
  65 
  66     
  67     # prevent a user from voting on themselves.
  68     contributions_to_vote_on = course.contributions.exclude(contributor=request.user).all()
  69     form_groups = helper_create_voting_form_groups(request, contributions_to_vote_on)
  70 
  71     if not all(all(form.is_valid() for form in form_group) for form_group in form_groups.values()):
  72         errors_exist = any(helper_has_errors(form_group) for form_group in form_groups.values())
  73 
  74         course_form_group = form_groups.pop(course.general_contribution)
  75 
  76         contributor_form_groups = list((contribution.contributor, contribution.label, form_group, helper_has_errors(form_group)) for contribution, form_group in form_groups.items())
  77 
  78         template_data = dict(
  79             errors_exist=errors_exist,
  80             course_form_group=course_form_group,
  81             contributor_form_groups=contributor_form_groups,
  82             course=course,
  83             participants_warning=course.num_participants <= 5,
  84             preview=False,
  85             vote_end_datetime=course.vote_end_datetime,
  86             hours_left_for_evaluation=course.time_left_for_evaluation.seconds//3600,
  87             minutes_left_for_evaluation=(course.time_left_for_evaluation.seconds//60)%60,
  88             evaluation_ends_soon=course.evaluation_ends_soon())
  89         return render(request, "student_vote.html", template_data)
  90 
  91     # all forms are valid, begin vote operation
  92     with transaction.atomic():
  93         # add user to course.voters
  94         # not using course.voters.add(request.user) since it fails silently when done twice.
  95         # manually inserting like this gives us the 'created' return value and ensures at the database level that nobody votes twice.
  96         __, created = course.voters.through.objects.get_or_create(userprofile_id=request.user.pk, course_id=course.pk)
  97         if not created:  # vote already got recorded, bail out
  98             raise SuspiciousOperation("A second vote has been received shortly after the first one.")
  99 
  100         for contribution, form_group in form_groups.items():
  101             for questionnaire_form in form_group:
  102                 questionnaire = questionnaire_form.questionnaire
  103                 for question in questionnaire.question_set.all():
  104                     identifier = question_id(contribution, questionnaire, question)
  105                     value = questionnaire_form.cleaned_data.get(identifier)
  106 
  107                     if question.is_text_question:
  108                         if value:
  109                             question.answer_class.objects.create(
  110                                 contribution=contribution,
  111                                 question=question,
  112                                 answer=value)
  113                     elif question.is_heading_question:
  114                         pass  # ignore these
  115                     else:
  116                         if value != 6:
  117                             answer_counter, __ = question.answer_class.objects.get_or_create(contribution=contribution, question=question, answer=value)
  118                             answer_counter.add_vote()
  119                             answer_counter.save()
  120 
  121         course.course_evaluated.send(sender=Course, request=request, semester=course.semester)
  122 
  123     messages.success(request, _("Your vote was recorded."))
  124     return redirect('student:index')
  125 
  126 
  127 def helper_create_voting_form_groups(request, contributions):
  128     form_groups = OrderedDict()
  129     for contribution in contributions:
  130         questionnaires = contribution.questionnaires.all()
  131         if not questionnaires.exists():
  132             continue
  133         form_groups[contribution] = [QuestionsForm(request.POST or None, contribution=contribution, questionnaire=questionnaire) for questionnaire in questionnaires]
  134     return form_groups
  135 
  136 
  137 def helper_has_errors(form_group):
  138     return any(form.errors for form in form_group)
  139
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: 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 @@
   
   @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 @@
               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 @@
           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):
  
verification_info: {"golden_diff": "diff --git a/evap/student/views.py b/evap/student/views.py\n--- a/evap/student/views.py\n+++ b/evap/student/views.py\n@@ -3,7 +3,9 @@\n from django.contrib import messages\n from django.core.exceptions import PermissionDenied, SuspiciousOperation\n from django.db import transaction\n+from django.http import HttpResponse\n from django.shortcuts import get_object_or_404, redirect, render\n+from django.urls import reverse\n from django.utils.translation import ugettext as _\n \n from evap.evaluation.auth import participant_required\n@@ -13,6 +15,7 @@\n from evap.student.forms import QuestionsForm\n from evap.student.tools import question_id\n \n+SUCCESS_MAGIC_STRING = 'vote submitted successfully'\n \n @participant_required\n def index(request):\n@@ -58,12 +61,11 @@\n \n @participant_required\n def vote(request, course_id):\n-    # retrieve course and make sure that the user is allowed to vote\n+\n     course = get_object_or_404(Course, id=course_id)\n     if not course.can_user_vote(request.user):\n         raise PermissionDenied\n \n-    \n     # prevent a user from voting on themselves.\n     contributions_to_vote_on = course.contributions.exclude(contributor=request.user).all()\n     form_groups = helper_create_voting_form_groups(request, contributions_to_vote_on)\n@@ -85,6 +87,8 @@\n             vote_end_datetime=course.vote_end_datetime,\n             hours_left_for_evaluation=course.time_left_for_evaluation.seconds//3600,\n             minutes_left_for_evaluation=(course.time_left_for_evaluation.seconds//60)%60,\n+            success_magic_string=SUCCESS_MAGIC_STRING,\n+            success_redirect_url=reverse('student:index'),\n             evaluation_ends_soon=course.evaluation_ends_soon())\n         return render(request, \"student_vote.html\", template_data)\n \n@@ -121,7 +125,7 @@\n         course.course_evaluated.send(sender=Course, request=request, semester=course.semester)\n \n     messages.success(request, _(\"Your vote was recorded.\"))\n-    return redirect('student:index')\n+    return HttpResponse(SUCCESS_MAGIC_STRING)\n \n \n def helper_create_voting_form_groups(request, contributions):\n", "issue": "Release Sisyphus data only after successful post\nWhen 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.\r\nThe data should be kept in browser storage until the vote was successfully counted.\nRelease Sisyphus data only after successful post\nWhen 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.\r\nThe data should be kept in browser storage until the vote was successfully counted.\n", "before_files": [{"content": "from collections import OrderedDict\n\nfrom django.contrib import messages\nfrom django.core.exceptions import PermissionDenied, SuspiciousOperation\nfrom django.db import transaction\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.utils.translation import ugettext as _\n\nfrom evap.evaluation.auth import participant_required\nfrom evap.evaluation.models import Course, Semester\nfrom evap.evaluation.tools import STUDENT_STATES_ORDERED\n\nfrom evap.student.forms import QuestionsForm\nfrom evap.student.tools import question_id\n\n\n@participant_required\ndef index(request):\n    # retrieve all courses, where the user is a participant and that are not new\n    courses = list(set(Course.objects.filter(participants=request.user).exclude(state=\"new\")))\n    voted_courses = list(set(Course.objects.filter(voters=request.user)))\n    due_courses = list(set(Course.objects.filter(participants=request.user, state='in_evaluation').exclude(voters=request.user)))\n\n    sorter = lambda course: (list(STUDENT_STATES_ORDERED.keys()).index(course.student_state), course.vote_end_date, course.name)\n    courses.sort(key=sorter)\n\n    semesters = Semester.objects.all()\n    semester_list = [dict(semester_name=semester.name, id=semester.id, is_active_semester=semester.is_active_semester,\n        courses=[course for course in courses if course.semester_id == semester.id]) for semester in semesters]\n\n    template_data = dict(\n        semester_list=semester_list,\n        voted_courses=voted_courses,\n        due_courses=due_courses,\n        can_download_grades=request.user.can_download_grades,\n    )\n    return render(request, \"student_index.html\", template_data)\n\n\ndef vote_preview(request, course, for_rendering_in_modal=False):\n    \"\"\"\n        Renders a preview of the voting page for the given course.\n        Not used by the student app itself, but by staff and contributor.\n    \"\"\"\n    form_groups = helper_create_voting_form_groups(request, course.contributions.all())\n    course_form_group = form_groups.pop(course.general_contribution)\n    contributor_form_groups = list((contribution.contributor, contribution.label, form_group, False) for contribution, form_group in form_groups.items())\n\n    template_data = dict(\n        errors_exist=False,\n        course_form_group=course_form_group,\n        contributor_form_groups=contributor_form_groups,\n        course=course,\n        preview=True,\n        for_rendering_in_modal=for_rendering_in_modal)\n    return render(request, \"student_vote.html\", template_data)\n\n\n@participant_required\ndef vote(request, course_id):\n    # retrieve course and make sure that the user is allowed to vote\n    course = get_object_or_404(Course, id=course_id)\n    if not course.can_user_vote(request.user):\n        raise PermissionDenied\n\n    \n    # prevent a user from voting on themselves.\n    contributions_to_vote_on = course.contributions.exclude(contributor=request.user).all()\n    form_groups = helper_create_voting_form_groups(request, contributions_to_vote_on)\n\n    if not all(all(form.is_valid() for form in form_group) for form_group in form_groups.values()):\n        errors_exist = any(helper_has_errors(form_group) for form_group in form_groups.values())\n\n        course_form_group = form_groups.pop(course.general_contribution)\n\n        contributor_form_groups = list((contribution.contributor, contribution.label, form_group, helper_has_errors(form_group)) for contribution, form_group in form_groups.items())\n\n        template_data = dict(\n            errors_exist=errors_exist,\n            course_form_group=course_form_group,\n            contributor_form_groups=contributor_form_groups,\n            course=course,\n            participants_warning=course.num_participants <= 5,\n            preview=False,\n            vote_end_datetime=course.vote_end_datetime,\n            hours_left_for_evaluation=course.time_left_for_evaluation.seconds//3600,\n            minutes_left_for_evaluation=(course.time_left_for_evaluation.seconds//60)%60,\n            evaluation_ends_soon=course.evaluation_ends_soon())\n        return render(request, \"student_vote.html\", template_data)\n\n    # all forms are valid, begin vote operation\n    with transaction.atomic():\n        # add user to course.voters\n        # not using course.voters.add(request.user) since it fails silently when done twice.\n        # manually inserting like this gives us the 'created' return value and ensures at the database level that nobody votes twice.\n        __, created = course.voters.through.objects.get_or_create(userprofile_id=request.user.pk, course_id=course.pk)\n        if not created:  # vote already got recorded, bail out\n            raise SuspiciousOperation(\"A second vote has been received shortly after the first one.\")\n\n        for contribution, form_group in form_groups.items():\n            for questionnaire_form in form_group:\n                questionnaire = questionnaire_form.questionnaire\n                for question in questionnaire.question_set.all():\n                    identifier = question_id(contribution, questionnaire, question)\n                    value = questionnaire_form.cleaned_data.get(identifier)\n\n                    if question.is_text_question:\n                        if value:\n                            question.answer_class.objects.create(\n                                contribution=contribution,\n                                question=question,\n                                answer=value)\n                    elif question.is_heading_question:\n                        pass  # ignore these\n                    else:\n                        if value != 6:\n                            answer_counter, __ = question.answer_class.objects.get_or_create(contribution=contribution, question=question, answer=value)\n                            answer_counter.add_vote()\n                            answer_counter.save()\n\n        course.course_evaluated.send(sender=Course, request=request, semester=course.semester)\n\n    messages.success(request, _(\"Your vote was recorded.\"))\n    return redirect('student:index')\n\n\ndef helper_create_voting_form_groups(request, contributions):\n    form_groups = OrderedDict()\n    for contribution in contributions:\n        questionnaires = contribution.questionnaires.all()\n        if not questionnaires.exists():\n            continue\n        form_groups[contribution] = [QuestionsForm(request.POST or None, contribution=contribution, questionnaire=questionnaire) for questionnaire in questionnaires]\n    return form_groups\n\n\ndef helper_has_errors(form_group):\n    return any(form.errors for form in form_group)\n", "path": "evap/student/views.py"}], "after_files": [{"content": "from collections import OrderedDict\n\nfrom django.contrib import messages\nfrom django.core.exceptions import PermissionDenied, SuspiciousOperation\nfrom django.db import transaction\nfrom django.http import HttpResponse\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.urls import reverse\nfrom django.utils.translation import ugettext as _\n\nfrom evap.evaluation.auth import participant_required\nfrom evap.evaluation.models import Course, Semester\nfrom evap.evaluation.tools import STUDENT_STATES_ORDERED\n\nfrom evap.student.forms import QuestionsForm\nfrom evap.student.tools import question_id\n\nSUCCESS_MAGIC_STRING = 'vote submitted successfully'\n\n@participant_required\ndef index(request):\n    # retrieve all courses, where the user is a participant and that are not new\n    courses = list(set(Course.objects.filter(participants=request.user).exclude(state=\"new\")))\n    voted_courses = list(set(Course.objects.filter(voters=request.user)))\n    due_courses = list(set(Course.objects.filter(participants=request.user, state='in_evaluation').exclude(voters=request.user)))\n\n    sorter = lambda course: (list(STUDENT_STATES_ORDERED.keys()).index(course.student_state), course.vote_end_date, course.name)\n    courses.sort(key=sorter)\n\n    semesters = Semester.objects.all()\n    semester_list = [dict(semester_name=semester.name, id=semester.id, is_active_semester=semester.is_active_semester,\n        courses=[course for course in courses if course.semester_id == semester.id]) for semester in semesters]\n\n    template_data = dict(\n        semester_list=semester_list,\n        voted_courses=voted_courses,\n        due_courses=due_courses,\n        can_download_grades=request.user.can_download_grades,\n    )\n    return render(request, \"student_index.html\", template_data)\n\n\ndef vote_preview(request, course, for_rendering_in_modal=False):\n    \"\"\"\n        Renders a preview of the voting page for the given course.\n        Not used by the student app itself, but by staff and contributor.\n    \"\"\"\n    form_groups = helper_create_voting_form_groups(request, course.contributions.all())\n    course_form_group = form_groups.pop(course.general_contribution)\n    contributor_form_groups = list((contribution.contributor, contribution.label, form_group, False) for contribution, form_group in form_groups.items())\n\n    template_data = dict(\n        errors_exist=False,\n        course_form_group=course_form_group,\n        contributor_form_groups=contributor_form_groups,\n        course=course,\n        preview=True,\n        for_rendering_in_modal=for_rendering_in_modal)\n    return render(request, \"student_vote.html\", template_data)\n\n\n@participant_required\ndef vote(request, course_id):\n\n    course = get_object_or_404(Course, id=course_id)\n    if not course.can_user_vote(request.user):\n        raise PermissionDenied\n\n    # prevent a user from voting on themselves.\n    contributions_to_vote_on = course.contributions.exclude(contributor=request.user).all()\n    form_groups = helper_create_voting_form_groups(request, contributions_to_vote_on)\n\n    if not all(all(form.is_valid() for form in form_group) for form_group in form_groups.values()):\n        errors_exist = any(helper_has_errors(form_group) for form_group in form_groups.values())\n\n        course_form_group = form_groups.pop(course.general_contribution)\n\n        contributor_form_groups = list((contribution.contributor, contribution.label, form_group, helper_has_errors(form_group)) for contribution, form_group in form_groups.items())\n\n        template_data = dict(\n            errors_exist=errors_exist,\n            course_form_group=course_form_group,\n            contributor_form_groups=contributor_form_groups,\n            course=course,\n            participants_warning=course.num_participants <= 5,\n            preview=False,\n            vote_end_datetime=course.vote_end_datetime,\n            hours_left_for_evaluation=course.time_left_for_evaluation.seconds//3600,\n            minutes_left_for_evaluation=(course.time_left_for_evaluation.seconds//60)%60,\n            success_magic_string=SUCCESS_MAGIC_STRING,\n            success_redirect_url=reverse('student:index'),\n            evaluation_ends_soon=course.evaluation_ends_soon())\n        return render(request, \"student_vote.html\", template_data)\n\n    # all forms are valid, begin vote operation\n    with transaction.atomic():\n        # add user to course.voters\n        # not using course.voters.add(request.user) since it fails silently when done twice.\n        # manually inserting like this gives us the 'created' return value and ensures at the database level that nobody votes twice.\n        __, created = course.voters.through.objects.get_or_create(userprofile_id=request.user.pk, course_id=course.pk)\n        if not created:  # vote already got recorded, bail out\n            raise SuspiciousOperation(\"A second vote has been received shortly after the first one.\")\n\n        for contribution, form_group in form_groups.items():\n            for questionnaire_form in form_group:\n                questionnaire = questionnaire_form.questionnaire\n                for question in questionnaire.question_set.all():\n                    identifier = question_id(contribution, questionnaire, question)\n                    value = questionnaire_form.cleaned_data.get(identifier)\n\n                    if question.is_text_question:\n                        if value:\n                            question.answer_class.objects.create(\n                                contribution=contribution,\n                                question=question,\n                                answer=value)\n                    elif question.is_heading_question:\n                        pass  # ignore these\n                    else:\n                        if value != 6:\n                            answer_counter, __ = question.answer_class.objects.get_or_create(contribution=contribution, question=question, answer=value)\n                            answer_counter.add_vote()\n                            answer_counter.save()\n\n        course.course_evaluated.send(sender=Course, request=request, semester=course.semester)\n\n    messages.success(request, _(\"Your vote was recorded.\"))\n    return HttpResponse(SUCCESS_MAGIC_STRING)\n\n\ndef helper_create_voting_form_groups(request, contributions):\n    form_groups = OrderedDict()\n    for contribution in contributions:\n        questionnaires = contribution.questionnaires.all()\n        if not questionnaires.exists():\n            continue\n        form_groups[contribution] = [QuestionsForm(request.POST or None, contribution=contribution, questionnaire=questionnaire) for questionnaire in questionnaires]\n    return form_groups\n\n\ndef helper_has_errors(form_group):\n    return any(form.errors for form in form_group)\n", "path": "evap/student/views.py"}]}