prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Response status code of failed redemption is 200
  As @niklasmohrin remarked in [#1790](https://github.com/e-valuation/EvaP/pull/1790/files#r962983692), in `evap.rewards.views.redeem_reward_points`, the status code of failed redemptions (e.g. due to `NotEnoughPoints` or `RedemptionEventExpired`) is set as 200 OK, even though no redemption points were saved. 
  
  Instead, the status code should be something like 400 Bad Request to underline that something went wrong.
  @niklasmohrin added, that `assertContains`, used in some tests in `evap.rewards.tests.test_views.TestIndexView`, needs to adopted, as it asserts that the status code is 200 by default.
  
  --- 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/rewards/views.py`
  Content:
  ```
  1 from datetime import datetime
  2 
  3 from django.contrib import messages
  4 from django.core.exceptions import BadRequest, SuspiciousOperation
  5 from django.http import HttpResponse
  6 from django.shortcuts import get_object_or_404, redirect, render
  7 from django.utils.translation import get_language
  8 from django.utils.translation import gettext as _
  9 from django.views.decorators.http import require_POST
  10 
  11 from evap.evaluation.auth import manager_required, reward_user_required
  12 from evap.evaluation.models import Semester
  13 from evap.evaluation.tools import AttachmentResponse, get_object_from_dict_pk_entry_or_logged_40x
  14 from evap.rewards.exporters import RewardsExporter
  15 from evap.rewards.forms import RewardPointRedemptionEventForm
  16 from evap.rewards.models import (
  17     NoPointsSelected,
  18     NotEnoughPoints,
  19     RedemptionEventExpired,
  20     RewardPointGranting,
  21     RewardPointRedemption,
  22     RewardPointRedemptionEvent,
  23     SemesterActivation,
  24 )
  25 from evap.rewards.tools import grant_eligible_reward_points_for_semester, reward_points_of_user, save_redemptions
  26 from evap.staff.views import semester_view
  27 
  28 
  29 @reward_user_required
  30 def index(request):
  31     if request.method == "POST":
  32         redemptions = {}
  33         try:
  34             for key, value in request.POST.items():
  35                 if key.startswith("points-"):
  36                     event_id = int(key.rpartition("-")[2])
  37                     redemptions[event_id] = int(value)
  38         except ValueError as e:
  39             raise BadRequest from e
  40 
  41         try:
  42             save_redemptions(request, redemptions)
  43             messages.success(request, _("You successfully redeemed your points."))
  44         except (NoPointsSelected, NotEnoughPoints, RedemptionEventExpired) as error:
  45             messages.warning(request, error)
  46 
  47     total_points_available = reward_points_of_user(request.user)
  48     reward_point_grantings = RewardPointGranting.objects.filter(user_profile=request.user)
  49     reward_point_redemptions = RewardPointRedemption.objects.filter(user_profile=request.user)
  50     events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now()).order_by("date")
  51 
  52     reward_point_actions = []
  53     for granting in reward_point_grantings:
  54         reward_point_actions.append(
  55             (granting.granting_time, _("Reward for") + " " + granting.semester.name, granting.value, "")
  56         )
  57     for redemption in reward_point_redemptions:
  58         reward_point_actions.append((redemption.redemption_time, redemption.event.name, "", redemption.value))
  59 
  60     reward_point_actions.sort(key=lambda action: action[0], reverse=True)
  61 
  62     template_data = dict(
  63         reward_point_actions=reward_point_actions,
  64         total_points_available=total_points_available,
  65         events=events,
  66     )
  67     return render(request, "rewards_index.html", template_data)
  68 
  69 
  70 @manager_required
  71 def reward_point_redemption_events(request):
  72     upcoming_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now()).order_by("date")
  73     past_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__lt=datetime.now()).order_by("-date")
  74     template_data = dict(upcoming_events=upcoming_events, past_events=past_events)
  75     return render(request, "rewards_reward_point_redemption_events.html", template_data)
  76 
  77 
  78 @manager_required
  79 def reward_point_redemption_event_create(request):
  80     event = RewardPointRedemptionEvent()
  81     form = RewardPointRedemptionEventForm(request.POST or None, instance=event)
  82 
  83     if form.is_valid():
  84         form.save()
  85         messages.success(request, _("Successfully created event."))
  86         return redirect("rewards:reward_point_redemption_events")
  87 
  88     return render(request, "rewards_reward_point_redemption_event_form.html", dict(form=form))
  89 
  90 
  91 @manager_required
  92 def reward_point_redemption_event_edit(request, event_id):
  93     event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)
  94     form = RewardPointRedemptionEventForm(request.POST or None, instance=event)
  95 
  96     if form.is_valid():
  97         event = form.save()
  98 
  99         messages.success(request, _("Successfully updated event."))
  100         return redirect("rewards:reward_point_redemption_events")
  101 
  102     return render(request, "rewards_reward_point_redemption_event_form.html", dict(event=event, form=form))
  103 
  104 
  105 @require_POST
  106 @manager_required
  107 def reward_point_redemption_event_delete(request):
  108     event = get_object_from_dict_pk_entry_or_logged_40x(RewardPointRedemptionEvent, request.POST, "event_id")
  109 
  110     if not event.can_delete:
  111         raise SuspiciousOperation("Deleting redemption event not allowed")
  112     event.delete()
  113     return HttpResponse()  # 200 OK
  114 
  115 
  116 @manager_required
  117 def reward_point_redemption_event_export(request, event_id):
  118     event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)
  119 
  120     filename = _("RewardPoints") + f"-{event.date}-{event.name}-{get_language()}.xls"
  121     response = AttachmentResponse(filename, content_type="application/vnd.ms-excel")
  122 
  123     RewardsExporter().export(response, event.redemptions_by_user())
  124 
  125     return response
  126 
  127 
  128 @manager_required
  129 def semester_activation(request, semester_id, active):
  130     semester = get_object_or_404(Semester, id=semester_id)
  131     active = active == "on"
  132 
  133     SemesterActivation.objects.update_or_create(semester=semester, defaults={"is_active": active})
  134     if active:
  135         grant_eligible_reward_points_for_semester(request, semester)
  136 
  137     return semester_view(request=request, semester_id=semester_id)
  138
  ```
  --- 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/rewards/views.py b/evap/rewards/views.py
  --- a/evap/rewards/views.py
  +++ b/evap/rewards/views.py
  @@ -28,6 +28,8 @@
   
   @reward_user_required
   def index(request):
  +    # pylint: disable=too-many-locals
  +    status = 200
       if request.method == "POST":
           redemptions = {}
           try:
  @@ -43,6 +45,7 @@
               messages.success(request, _("You successfully redeemed your points."))
           except (NoPointsSelected, NotEnoughPoints, RedemptionEventExpired) as error:
               messages.warning(request, error)
  +            status = 400
   
       total_points_available = reward_points_of_user(request.user)
       reward_point_grantings = RewardPointGranting.objects.filter(user_profile=request.user)
  @@ -64,7 +67,7 @@
           total_points_available=total_points_available,
           events=events,
       )
  -    return render(request, "rewards_index.html", template_data)
  +    return render(request, "rewards_index.html", template_data, status=status)
   
   
   @manager_required
  
verification_info: {"golden_diff": "diff --git a/evap/rewards/views.py b/evap/rewards/views.py\n--- a/evap/rewards/views.py\n+++ b/evap/rewards/views.py\n@@ -28,6 +28,8 @@\n \n @reward_user_required\n def index(request):\n+    # pylint: disable=too-many-locals\n+    status = 200\n     if request.method == \"POST\":\n         redemptions = {}\n         try:\n@@ -43,6 +45,7 @@\n             messages.success(request, _(\"You successfully redeemed your points.\"))\n         except (NoPointsSelected, NotEnoughPoints, RedemptionEventExpired) as error:\n             messages.warning(request, error)\n+            status = 400\n \n     total_points_available = reward_points_of_user(request.user)\n     reward_point_grantings = RewardPointGranting.objects.filter(user_profile=request.user)\n@@ -64,7 +67,7 @@\n         total_points_available=total_points_available,\n         events=events,\n     )\n-    return render(request, \"rewards_index.html\", template_data)\n+    return render(request, \"rewards_index.html\", template_data, status=status)\n \n \n @manager_required\n", "issue": "Response status code of failed redemption is 200\nAs @niklasmohrin remarked in [#1790](https://github.com/e-valuation/EvaP/pull/1790/files#r962983692), in `evap.rewards.views.redeem_reward_points`, the status code of failed redemptions (e.g. due to `NotEnoughPoints` or `RedemptionEventExpired`) is set as 200 OK, even though no redemption points were saved. \r\n\r\nInstead, the status code should be something like 400 Bad Request to underline that something went wrong.\r\n@niklasmohrin added, that `assertContains`, used in some tests in `evap.rewards.tests.test_views.TestIndexView`, needs to adopted, as it asserts that the status code is 200 by default.\n", "before_files": [{"content": "from datetime import datetime\n\nfrom django.contrib import messages\nfrom django.core.exceptions import BadRequest, SuspiciousOperation\nfrom django.http import HttpResponse\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.utils.translation import get_language\nfrom django.utils.translation import gettext as _\nfrom django.views.decorators.http import require_POST\n\nfrom evap.evaluation.auth import manager_required, reward_user_required\nfrom evap.evaluation.models import Semester\nfrom evap.evaluation.tools import AttachmentResponse, get_object_from_dict_pk_entry_or_logged_40x\nfrom evap.rewards.exporters import RewardsExporter\nfrom evap.rewards.forms import RewardPointRedemptionEventForm\nfrom evap.rewards.models import (\n    NoPointsSelected,\n    NotEnoughPoints,\n    RedemptionEventExpired,\n    RewardPointGranting,\n    RewardPointRedemption,\n    RewardPointRedemptionEvent,\n    SemesterActivation,\n)\nfrom evap.rewards.tools import grant_eligible_reward_points_for_semester, reward_points_of_user, save_redemptions\nfrom evap.staff.views import semester_view\n\n\n@reward_user_required\ndef index(request):\n    if request.method == \"POST\":\n        redemptions = {}\n        try:\n            for key, value in request.POST.items():\n                if key.startswith(\"points-\"):\n                    event_id = int(key.rpartition(\"-\")[2])\n                    redemptions[event_id] = int(value)\n        except ValueError as e:\n            raise BadRequest from e\n\n        try:\n            save_redemptions(request, redemptions)\n            messages.success(request, _(\"You successfully redeemed your points.\"))\n        except (NoPointsSelected, NotEnoughPoints, RedemptionEventExpired) as error:\n            messages.warning(request, error)\n\n    total_points_available = reward_points_of_user(request.user)\n    reward_point_grantings = RewardPointGranting.objects.filter(user_profile=request.user)\n    reward_point_redemptions = RewardPointRedemption.objects.filter(user_profile=request.user)\n    events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now()).order_by(\"date\")\n\n    reward_point_actions = []\n    for granting in reward_point_grantings:\n        reward_point_actions.append(\n            (granting.granting_time, _(\"Reward for\") + \" \" + granting.semester.name, granting.value, \"\")\n        )\n    for redemption in reward_point_redemptions:\n        reward_point_actions.append((redemption.redemption_time, redemption.event.name, \"\", redemption.value))\n\n    reward_point_actions.sort(key=lambda action: action[0], reverse=True)\n\n    template_data = dict(\n        reward_point_actions=reward_point_actions,\n        total_points_available=total_points_available,\n        events=events,\n    )\n    return render(request, \"rewards_index.html\", template_data)\n\n\n@manager_required\ndef reward_point_redemption_events(request):\n    upcoming_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now()).order_by(\"date\")\n    past_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__lt=datetime.now()).order_by(\"-date\")\n    template_data = dict(upcoming_events=upcoming_events, past_events=past_events)\n    return render(request, \"rewards_reward_point_redemption_events.html\", template_data)\n\n\n@manager_required\ndef reward_point_redemption_event_create(request):\n    event = RewardPointRedemptionEvent()\n    form = RewardPointRedemptionEventForm(request.POST or None, instance=event)\n\n    if form.is_valid():\n        form.save()\n        messages.success(request, _(\"Successfully created event.\"))\n        return redirect(\"rewards:reward_point_redemption_events\")\n\n    return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(form=form))\n\n\n@manager_required\ndef reward_point_redemption_event_edit(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n    form = RewardPointRedemptionEventForm(request.POST or None, instance=event)\n\n    if form.is_valid():\n        event = form.save()\n\n        messages.success(request, _(\"Successfully updated event.\"))\n        return redirect(\"rewards:reward_point_redemption_events\")\n\n    return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(event=event, form=form))\n\n\n@require_POST\n@manager_required\ndef reward_point_redemption_event_delete(request):\n    event = get_object_from_dict_pk_entry_or_logged_40x(RewardPointRedemptionEvent, request.POST, \"event_id\")\n\n    if not event.can_delete:\n        raise SuspiciousOperation(\"Deleting redemption event not allowed\")\n    event.delete()\n    return HttpResponse()  # 200 OK\n\n\n@manager_required\ndef reward_point_redemption_event_export(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n\n    filename = _(\"RewardPoints\") + f\"-{event.date}-{event.name}-{get_language()}.xls\"\n    response = AttachmentResponse(filename, content_type=\"application/vnd.ms-excel\")\n\n    RewardsExporter().export(response, event.redemptions_by_user())\n\n    return response\n\n\n@manager_required\ndef semester_activation(request, semester_id, active):\n    semester = get_object_or_404(Semester, id=semester_id)\n    active = active == \"on\"\n\n    SemesterActivation.objects.update_or_create(semester=semester, defaults={\"is_active\": active})\n    if active:\n        grant_eligible_reward_points_for_semester(request, semester)\n\n    return semester_view(request=request, semester_id=semester_id)\n", "path": "evap/rewards/views.py"}], "after_files": [{"content": "from datetime import datetime\n\nfrom django.contrib import messages\nfrom django.core.exceptions import BadRequest, SuspiciousOperation\nfrom django.http import HttpResponse\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.utils.translation import get_language\nfrom django.utils.translation import gettext as _\nfrom django.views.decorators.http import require_POST\n\nfrom evap.evaluation.auth import manager_required, reward_user_required\nfrom evap.evaluation.models import Semester\nfrom evap.evaluation.tools import AttachmentResponse, get_object_from_dict_pk_entry_or_logged_40x\nfrom evap.rewards.exporters import RewardsExporter\nfrom evap.rewards.forms import RewardPointRedemptionEventForm\nfrom evap.rewards.models import (\n    NoPointsSelected,\n    NotEnoughPoints,\n    RedemptionEventExpired,\n    RewardPointGranting,\n    RewardPointRedemption,\n    RewardPointRedemptionEvent,\n    SemesterActivation,\n)\nfrom evap.rewards.tools import grant_eligible_reward_points_for_semester, reward_points_of_user, save_redemptions\nfrom evap.staff.views import semester_view\n\n\n@reward_user_required\ndef index(request):\n    # pylint: disable=too-many-locals\n    status = 200\n    if request.method == \"POST\":\n        redemptions = {}\n        try:\n            for key, value in request.POST.items():\n                if key.startswith(\"points-\"):\n                    event_id = int(key.rpartition(\"-\")[2])\n                    redemptions[event_id] = int(value)\n        except ValueError as e:\n            raise BadRequest from e\n\n        try:\n            save_redemptions(request, redemptions)\n            messages.success(request, _(\"You successfully redeemed your points.\"))\n        except (NoPointsSelected, NotEnoughPoints, RedemptionEventExpired) as error:\n            messages.warning(request, error)\n            status = 400\n\n    total_points_available = reward_points_of_user(request.user)\n    reward_point_grantings = RewardPointGranting.objects.filter(user_profile=request.user)\n    reward_point_redemptions = RewardPointRedemption.objects.filter(user_profile=request.user)\n    events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now()).order_by(\"date\")\n\n    reward_point_actions = []\n    for granting in reward_point_grantings:\n        reward_point_actions.append(\n            (granting.granting_time, _(\"Reward for\") + \" \" + granting.semester.name, granting.value, \"\")\n        )\n    for redemption in reward_point_redemptions:\n        reward_point_actions.append((redemption.redemption_time, redemption.event.name, \"\", redemption.value))\n\n    reward_point_actions.sort(key=lambda action: action[0], reverse=True)\n\n    template_data = dict(\n        reward_point_actions=reward_point_actions,\n        total_points_available=total_points_available,\n        events=events,\n    )\n    return render(request, \"rewards_index.html\", template_data, status=status)\n\n\n@manager_required\ndef reward_point_redemption_events(request):\n    upcoming_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now()).order_by(\"date\")\n    past_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__lt=datetime.now()).order_by(\"-date\")\n    template_data = dict(upcoming_events=upcoming_events, past_events=past_events)\n    return render(request, \"rewards_reward_point_redemption_events.html\", template_data)\n\n\n@manager_required\ndef reward_point_redemption_event_create(request):\n    event = RewardPointRedemptionEvent()\n    form = RewardPointRedemptionEventForm(request.POST or None, instance=event)\n\n    if form.is_valid():\n        form.save()\n        messages.success(request, _(\"Successfully created event.\"))\n        return redirect(\"rewards:reward_point_redemption_events\")\n\n    return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(form=form))\n\n\n@manager_required\ndef reward_point_redemption_event_edit(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n    form = RewardPointRedemptionEventForm(request.POST or None, instance=event)\n\n    if form.is_valid():\n        event = form.save()\n\n        messages.success(request, _(\"Successfully updated event.\"))\n        return redirect(\"rewards:reward_point_redemption_events\")\n\n    return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(event=event, form=form))\n\n\n@require_POST\n@manager_required\ndef reward_point_redemption_event_delete(request):\n    event = get_object_from_dict_pk_entry_or_logged_40x(RewardPointRedemptionEvent, request.POST, \"event_id\")\n\n    if not event.can_delete:\n        raise SuspiciousOperation(\"Deleting redemption event not allowed\")\n    event.delete()\n    return HttpResponse()  # 200 OK\n\n\n@manager_required\ndef reward_point_redemption_event_export(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n\n    filename = _(\"RewardPoints\") + f\"-{event.date}-{event.name}-{get_language()}.xls\"\n    response = AttachmentResponse(filename, content_type=\"application/vnd.ms-excel\")\n\n    RewardsExporter().export(response, event.redemptions_by_user())\n\n    return response\n\n\n@manager_required\ndef semester_activation(request, semester_id, active):\n    semester = get_object_or_404(Semester, id=semester_id)\n    active = active == \"on\"\n\n    SemesterActivation.objects.update_or_create(semester=semester, defaults={\"is_active\": active})\n    if active:\n        grant_eligible_reward_points_for_semester(request, semester)\n\n    return semester_view(request=request, semester_id=semester_id)\n", "path": "evap/rewards/views.py"}]}