We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Reward point redemption error message
When users try to redeem 0 reward points they get the error message "You don't have enough reward points". The error message should be something like "You must select the number of reward points you want to redeem" instead.


--- 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/tools.py`
Content:
```
1 from django.conf import settings
2 from django.contrib import messages
3 from django.db import transaction
4 from django.utils.translation import ugettext as _
5 from django.dispatch import receiver
6 
7 from django.contrib.auth.decorators import login_required
8 from evap.evaluation.models import Course
9 
10 from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation
11 
12 @login_required
13 @transaction.atomic
14 def save_redemptions(request, redemptions):
15     total_points_available = reward_points_of_user(request.user)
16     total_points_redeemed = sum(redemptions.values())
17 
18     if total_points_redeemed == 0 or total_points_redeemed > total_points_available:
19         return False
20 
21     for event_id in redemptions:
22         if redemptions[event_id] > 0:
23             redemption = RewardPointRedemption(
24                 user_profile=request.user,
25                 value=redemptions[event_id],
26                 event=RewardPointRedemptionEvent.objects.get(id=event_id)
27             )
28             redemption.save()
29     return True
30 
31 
32 def can_user_use_reward_points(user):
33     return not user.is_external and user.is_participant
34 
35 
36 def reward_points_of_user(user):
37     reward_point_grantings = RewardPointGranting.objects.filter(user_profile=user)
38     reward_point_redemptions = RewardPointRedemption.objects.filter(user_profile=user)
39 
40     count = 0
41     for granting in reward_point_grantings:
42         count += granting.value
43     for redemption in reward_point_redemptions:
44         count -= redemption.value
45 
46     return count
47 
48 
49 @receiver(Course.course_evaluated)
50 def grant_reward_points(sender, **kwargs):
51     # grant reward points if all conditions are fulfilled
52 
53     request = kwargs['request']
54     semester = kwargs['semester']
55     if not can_user_use_reward_points(request.user):
56         return
57     # has the semester been activated for reward points?
58     if not is_semester_activated(semester):
59         return
60     # does the user have at least one required course in this semester?
61     required_courses = Course.objects.filter(participants=request.user, semester=semester, is_required_for_reward=True)
62     if not required_courses.exists():
63         return
64     # does the user not participate in any more required courses in this semester?
65     if required_courses.exclude(voters=request.user).exists():
66         return
67     # did the user not already get reward points for this semester?
68     if not RewardPointGranting.objects.filter(user_profile=request.user, semester=semester):
69         granting = RewardPointGranting(user_profile=request.user, semester=semester, value=settings.REWARD_POINTS_PER_SEMESTER)
70         granting.save()
71         messages.success(request, _("You just have earned reward points for this semester because you evaluated all your courses. Thank you very much!"))
72 
73 
74 def is_semester_activated(semester):
75     try:
76         activation = SemesterActivation.objects.get(semester=semester)
77         return activation.is_active
78     except SemesterActivation.DoesNotExist:
79         return False
80
```

Path: `evap/rewards/views.py`
Content:
```
1 from django.contrib import messages
2 from django.shortcuts import get_object_or_404, redirect, render
3 from django.utils.translation import ugettext as _
4 from django.utils.translation import get_language
5 from django.http import HttpResponse
6 from datetime import datetime
7 from operator import attrgetter
8 
9 from evap.evaluation.auth import reward_user_required, staff_required
10 from evap.evaluation.models import Semester, Course
11 
12 from evap.staff.views import semester_view
13 
14 from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation
15 from evap.rewards.tools import save_redemptions, reward_points_of_user, can_user_use_reward_points
16 from evap.rewards.forms import RewardPointRedemptionEventForm
17 from evap.rewards.exporters import ExcelExporter
18 
19 @reward_user_required
20 def index(request):
21     if request.method == 'POST':
22         redemptions = {}
23         for key, value in request.POST.items():
24             if(key.startswith('points-')):
25                 event_id = int(key.rpartition('-')[2])
26                 redemptions[event_id] = int(value)
27 
28         if save_redemptions(request, redemptions):
29             messages.success(request, _("You successfully redeemed your points."))
30         else:
31             messages.warning(request, _("You don't have enough reward points."))
32 
33     total_points_available = reward_points_of_user(request.user)
34     reward_point_grantings = RewardPointGranting.objects.filter(user_profile=request.user)
35     reward_point_redemptions = RewardPointRedemption.objects.filter(user_profile=request.user)
36     events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now())
37     events = sorted(events, key=lambda event: event.date)
38 
39     reward_point_actions=[]
40     for granting in reward_point_grantings:
41         reward_point_actions.append((granting.granting_time, _('Reward for') + ' ' + granting.semester.name, granting.value, ''))
42     for redemption in reward_point_redemptions:
43         reward_point_actions.append((redemption.redemption_time, redemption.event.name, '', redemption.value))
44 
45     reward_point_actions.sort(key=lambda action: action[0], reverse=True)
46 
47     template_data = dict(
48             reward_point_actions=reward_point_actions,
49             total_points_available=total_points_available,
50             events=events,
51             point_selection=[x for x in range(0,total_points_available+1)])
52     return render(request, "rewards_index.html", template_data)
53 
54 
55 @staff_required
56 def semester_reward_points(request, semester_id):
57     semester = get_object_or_404(Semester, id=semester_id)
58     courses = Course.objects.filter(semester=semester)
59     participants = set()
60     for course in courses:
61         for participant in course.participants.all():
62             if can_user_use_reward_points(participant):
63                 participants.add(participant)
64     participants = sorted(participants, key=attrgetter('last_name', 'first_name'))
65 
66     data = []
67     for participant in participants:
68         number_of_required_courses = Course.objects.filter(semester=semester, participants=participant, is_required_for_reward=True).count()
69         number_of_required_courses_voted_for = Course.objects.filter(semester=semester, voters=participant, is_required_for_reward=True).count()
70         number_of_optional_courses = Course.objects.filter(semester=semester, participants=participant, is_required_for_reward=False).count()
71         number_of_optional_courses_voted_for = Course.objects.filter(semester=semester, voters=participant, is_required_for_reward=False).count()
72         earned_reward_points = RewardPointGranting.objects.filter(semester=semester, user_profile=participant).exists()
73         data.append((participant, number_of_required_courses_voted_for, number_of_required_courses,
74             number_of_optional_courses_voted_for, number_of_optional_courses, earned_reward_points))
75 
76     template_data = dict(semester=semester, data=data, disable_breadcrumb_semester=False)
77     return render(request, "rewards_semester_reward_points_view.html", template_data)
78 
79 
80 @staff_required
81 def reward_point_redemption_events(request):
82     upcoming_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__gte=datetime.now()).order_by('date')
83     past_events = RewardPointRedemptionEvent.objects.filter(redeem_end_date__lt=datetime.now()).order_by('-date')
84     template_data = dict(upcoming_events=upcoming_events, past_events=past_events)
85     return render(request, "rewards_reward_point_redemption_events.html", template_data)
86 
87 
88 @staff_required
89 def reward_point_redemption_event_create(request):
90     event = RewardPointRedemptionEvent()
91     form = RewardPointRedemptionEventForm(request.POST or None, instance=event)
92 
93     if form.is_valid():
94         form.save()
95         messages.success(request, _("Successfully created event."))
96         return redirect('rewards:reward_point_redemption_events')
97     else:
98         return render(request, "rewards_reward_point_redemption_event_form.html", dict(form=form))
99 
100 
101 @staff_required
102 def reward_point_redemption_event_edit(request, event_id):
103     event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)
104     form = RewardPointRedemptionEventForm(request.POST or None, instance=event)
105 
106     if form.is_valid():
107         event = form.save()
108 
109         messages.success(request, _("Successfully updated event."))
110         return redirect('rewards:reward_point_redemption_events')
111     else:
112         return render(request, "rewards_reward_point_redemption_event_form.html", dict(event=event, form=form))
113 
114 
115 @staff_required
116 def reward_point_redemption_event_delete(request, event_id):
117     event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)
118 
119     if event.can_delete:
120         if request.method == 'POST':
121             event.delete()
122             return redirect('rewards:reward_point_redemption_events')
123         else:
124             return render(request, "rewards_reward_point_redemption_event_delete.html", dict(event=event))
125     else:
126         messages.warning(request, _("This event cannot be deleted because some users already redeemed points for it."))
127         return redirect('rewards:reward_point_redemption_events')
128 
129 
130 @staff_required
131 def reward_point_redemption_event_export(request, event_id):
132     event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)
133 
134     filename = _("RewardPoints")+"-%s-%s-%s.xls" % (event.date, event.name, get_language())
135 
136     response = HttpResponse(content_type="application/vnd.ms-excel")
137     response["Content-Disposition"] = "attachment; filename=\"%s\"" % filename
138 
139     ExcelExporter(event.redemptions_by_user()).export(response)
140 
141     return response
142 
143 
144 @staff_required
145 def semester_activation(request, semester_id, active):
146     if active == 'on':
147         active = True
148     else:
149         active = False
150 
151     try:
152         activation = SemesterActivation.objects.filter(semester=Semester.objects.get(id=semester_id)).get()
153         activation.is_active = active
154     except SemesterActivation.DoesNotExist:
155         activation = SemesterActivation(semester=Semester.objects.get(id=semester_id), is_active=active)
156     activation.save()
157 
158     return semester_view(request=request, semester_id=semester_id)
159
```

Path: `evap/rewards/models.py`
Content:
```
1 from django.utils.translation import ugettext_lazy as _
2 from django.db import models
3 
4 from collections import OrderedDict
5 
6 
7 class RewardPointRedemptionEvent(models.Model):
8     name = models.CharField(max_length=1024, verbose_name=_("event name"))
9     date = models.DateField(verbose_name=_("event date"))
10     redeem_end_date = models.DateField(verbose_name=_("redemption end date"))
11 
12     @property
13     def can_delete(self):
14         if RewardPointRedemption.objects.filter(event=self).exists():
15             return False
16         return True
17 
18     def redemptions_by_user(self):
19         redemptions = self.reward_point_redemptions.order_by('user_profile')
20         redemptions_dict = OrderedDict()
21         for redemption in redemptions:
22             if not redemption.user_profile in redemptions_dict:
23                 redemptions_dict[redemption.user_profile] = 0
24             redemptions_dict[redemption.user_profile] += redemption.value
25         return redemptions_dict
26 
27 class RewardPointGranting(models.Model):
28     user_profile = models.ForeignKey('evaluation.UserProfile', related_name="reward_point_grantings")
29     semester = models.ForeignKey('evaluation.Semester', related_name="reward_point_grantings", blank=True, null=True)
30     granting_time = models.DateTimeField(verbose_name=_("granting time"), auto_now_add=True)
31     value = models.IntegerField(verbose_name=_("value"), default=0)
32 
33 class RewardPointRedemption(models.Model):
34     user_profile = models.ForeignKey('evaluation.UserProfile', related_name="reward_point_redemptions")
35     redemption_time = models.DateTimeField(verbose_name=_("redemption time"), auto_now_add=True)
36     value = models.IntegerField(verbose_name=_("value"), default=0)
37     event = models.ForeignKey(RewardPointRedemptionEvent, related_name="reward_point_redemptions")
38 
39 class SemesterActivation(models.Model):
40     semester = models.OneToOneField('evaluation.Semester', related_name='rewards_active')
41     is_active = models.BooleanField(default=False)
42
```
--- 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()

```

diff --git a/evap/rewards/models.py b/evap/rewards/models.py
--- a/evap/rewards/models.py
+++ b/evap/rewards/models.py
@@ -3,6 +3,13 @@
 
 from collections import OrderedDict
 
+class NoPointsSelected(Exception):
+    """An attempt has been made to redeem <= 0 points."""
+    pass
+
+class NotEnoughPoints(Exception):
+    """An attempt has been made to redeem more points than available."""
+    pass
 
 class RewardPointRedemptionEvent(models.Model):
     name = models.CharField(max_length=1024, verbose_name=_("event name"))
diff --git a/evap/rewards/tools.py b/evap/rewards/tools.py
--- a/evap/rewards/tools.py
+++ b/evap/rewards/tools.py
@@ -7,7 +7,7 @@
 from django.contrib.auth.decorators import login_required
 from evap.evaluation.models import Course
 
-from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation
+from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation, NoPointsSelected, NotEnoughPoints
 
 @login_required
 @transaction.atomic
@@ -15,8 +15,11 @@
     total_points_available = reward_points_of_user(request.user)
     total_points_redeemed = sum(redemptions.values())
 
-    if total_points_redeemed == 0 or total_points_redeemed > total_points_available:
-        return False
+    if total_points_redeemed <= 0:
+        raise NoPointsSelected(_("You cannot redeem 0 points."))
+
+    if total_points_redeemed > total_points_available:
+        raise NotEnoughPoints(_("You don't have enough reward points."))
 
     for event_id in redemptions:
         if redemptions[event_id] > 0:
@@ -26,8 +29,6 @@
                 event=RewardPointRedemptionEvent.objects.get(id=event_id)
             )
             redemption.save()
-    return True
-
 
 def can_user_use_reward_points(user):
     return not user.is_external and user.is_participant
diff --git a/evap/rewards/views.py b/evap/rewards/views.py
--- a/evap/rewards/views.py
+++ b/evap/rewards/views.py
@@ -11,7 +11,7 @@
 
 from evap.staff.views import semester_view
 
-from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation
+from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation, NoPointsSelected, NotEnoughPoints
 from evap.rewards.tools import save_redemptions, reward_points_of_user, can_user_use_reward_points
 from evap.rewards.forms import RewardPointRedemptionEventForm
 from evap.rewards.exporters import ExcelExporter
@@ -25,10 +25,11 @@
                 event_id = int(key.rpartition('-')[2])
                 redemptions[event_id] = int(value)
 
-        if save_redemptions(request, redemptions):
+        try:
+            save_redemptions(request, redemptions)
             messages.success(request, _("You successfully redeemed your points."))
-        else:
-            messages.warning(request, _("You don't have enough reward points."))
+        except (NoPointsSelected, NotEnoughPoints) as error:
+            messages.warning(request, error)
 
     total_points_available = reward_points_of_user(request.user)
     reward_point_grantings = RewardPointGranting.objects.filter(user_profile=request.user)

{"golden_diff": "diff --git a/evap/rewards/models.py b/evap/rewards/models.py\n--- a/evap/rewards/models.py\n+++ b/evap/rewards/models.py\n@@ -3,6 +3,13 @@\n \n from collections import OrderedDict\n \n+class NoPointsSelected(Exception):\n+    \"\"\"An attempt has been made to redeem <= 0 points.\"\"\"\n+    pass\n+\n+class NotEnoughPoints(Exception):\n+    \"\"\"An attempt has been made to redeem more points than available.\"\"\"\n+    pass\n \n class RewardPointRedemptionEvent(models.Model):\n     name = models.CharField(max_length=1024, verbose_name=_(\"event name\"))\ndiff --git a/evap/rewards/tools.py b/evap/rewards/tools.py\n--- a/evap/rewards/tools.py\n+++ b/evap/rewards/tools.py\n@@ -7,7 +7,7 @@\n from django.contrib.auth.decorators import login_required\n from evap.evaluation.models import Course\n \n-from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation\n+from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation, NoPointsSelected, NotEnoughPoints\n \n @login_required\n @transaction.atomic\n@@ -15,8 +15,11 @@\n     total_points_available = reward_points_of_user(request.user)\n     total_points_redeemed = sum(redemptions.values())\n \n-    if total_points_redeemed == 0 or total_points_redeemed > total_points_available:\n-        return False\n+    if total_points_redeemed <= 0:\n+        raise NoPointsSelected(_(\"You cannot redeem 0 points.\"))\n+\n+    if total_points_redeemed > total_points_available:\n+        raise NotEnoughPoints(_(\"You don't have enough reward points.\"))\n \n     for event_id in redemptions:\n         if redemptions[event_id] > 0:\n@@ -26,8 +29,6 @@\n                 event=RewardPointRedemptionEvent.objects.get(id=event_id)\n             )\n             redemption.save()\n-    return True\n-\n \n def can_user_use_reward_points(user):\n     return not user.is_external and user.is_participant\ndiff --git a/evap/rewards/views.py b/evap/rewards/views.py\n--- a/evap/rewards/views.py\n+++ b/evap/rewards/views.py\n@@ -11,7 +11,7 @@\n \n from evap.staff.views import semester_view\n \n-from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation\n+from evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation, NoPointsSelected, NotEnoughPoints\n from evap.rewards.tools import save_redemptions, reward_points_of_user, can_user_use_reward_points\n from evap.rewards.forms import RewardPointRedemptionEventForm\n from evap.rewards.exporters import ExcelExporter\n@@ -25,10 +25,11 @@\n                 event_id = int(key.rpartition('-')[2])\n                 redemptions[event_id] = int(value)\n \n-        if save_redemptions(request, redemptions):\n+        try:\n+            save_redemptions(request, redemptions)\n             messages.success(request, _(\"You successfully redeemed your points.\"))\n-        else:\n-            messages.warning(request, _(\"You don't have enough reward points.\"))\n+        except (NoPointsSelected, NotEnoughPoints) 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", "issue": "Reward point redemption error message\nWhen users try to redeem 0 reward points they get the error message \"You don't have enough reward points\". The error message should be something like \"You must select the number of reward points you want to redeem\" instead.\n\n", "before_files": [{"content": "from django.conf import settings\nfrom django.contrib import messages\nfrom django.db import transaction\nfrom django.utils.translation import ugettext as _\nfrom django.dispatch import receiver\n\nfrom django.contrib.auth.decorators import login_required\nfrom evap.evaluation.models import Course\n\nfrom evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation\n\n@login_required\n@transaction.atomic\ndef save_redemptions(request, redemptions):\n    total_points_available = reward_points_of_user(request.user)\n    total_points_redeemed = sum(redemptions.values())\n\n    if total_points_redeemed == 0 or total_points_redeemed > total_points_available:\n        return False\n\n    for event_id in redemptions:\n        if redemptions[event_id] > 0:\n            redemption = RewardPointRedemption(\n                user_profile=request.user,\n                value=redemptions[event_id],\n                event=RewardPointRedemptionEvent.objects.get(id=event_id)\n            )\n            redemption.save()\n    return True\n\n\ndef can_user_use_reward_points(user):\n    return not user.is_external and user.is_participant\n\n\ndef reward_points_of_user(user):\n    reward_point_grantings = RewardPointGranting.objects.filter(user_profile=user)\n    reward_point_redemptions = RewardPointRedemption.objects.filter(user_profile=user)\n\n    count = 0\n    for granting in reward_point_grantings:\n        count += granting.value\n    for redemption in reward_point_redemptions:\n        count -= redemption.value\n\n    return count\n\n\n@receiver(Course.course_evaluated)\ndef grant_reward_points(sender, **kwargs):\n    # grant reward points if all conditions are fulfilled\n\n    request = kwargs['request']\n    semester = kwargs['semester']\n    if not can_user_use_reward_points(request.user):\n        return\n    # has the semester been activated for reward points?\n    if not is_semester_activated(semester):\n        return\n    # does the user have at least one required course in this semester?\n    required_courses = Course.objects.filter(participants=request.user, semester=semester, is_required_for_reward=True)\n    if not required_courses.exists():\n        return\n    # does the user not participate in any more required courses in this semester?\n    if required_courses.exclude(voters=request.user).exists():\n        return\n    # did the user not already get reward points for this semester?\n    if not RewardPointGranting.objects.filter(user_profile=request.user, semester=semester):\n        granting = RewardPointGranting(user_profile=request.user, semester=semester, value=settings.REWARD_POINTS_PER_SEMESTER)\n        granting.save()\n        messages.success(request, _(\"You just have earned reward points for this semester because you evaluated all your courses. Thank you very much!\"))\n\n\ndef is_semester_activated(semester):\n    try:\n        activation = SemesterActivation.objects.get(semester=semester)\n        return activation.is_active\n    except SemesterActivation.DoesNotExist:\n        return False\n", "path": "evap/rewards/tools.py"}, {"content": "from django.contrib import messages\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.utils.translation import ugettext as _\nfrom django.utils.translation import get_language\nfrom django.http import HttpResponse\nfrom datetime import datetime\nfrom operator import attrgetter\n\nfrom evap.evaluation.auth import reward_user_required, staff_required\nfrom evap.evaluation.models import Semester, Course\n\nfrom evap.staff.views import semester_view\n\nfrom evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation\nfrom evap.rewards.tools import save_redemptions, reward_points_of_user, can_user_use_reward_points\nfrom evap.rewards.forms import RewardPointRedemptionEventForm\nfrom evap.rewards.exporters import ExcelExporter\n\n@reward_user_required\ndef index(request):\n    if request.method == 'POST':\n        redemptions = {}\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\n        if save_redemptions(request, redemptions):\n            messages.success(request, _(\"You successfully redeemed your points.\"))\n        else:\n            messages.warning(request, _(\"You don't have enough reward points.\"))\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())\n    events = sorted(events, key=lambda event: event.date)\n\n    reward_point_actions=[]\n    for granting in reward_point_grantings:\n        reward_point_actions.append((granting.granting_time, _('Reward for') + ' ' + granting.semester.name, granting.value, ''))\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            point_selection=[x for x in range(0,total_points_available+1)])\n    return render(request, \"rewards_index.html\", template_data)\n\n\n@staff_required\ndef semester_reward_points(request, semester_id):\n    semester = get_object_or_404(Semester, id=semester_id)\n    courses = Course.objects.filter(semester=semester)\n    participants = set()\n    for course in courses:\n        for participant in course.participants.all():\n            if can_user_use_reward_points(participant):\n                participants.add(participant)\n    participants = sorted(participants, key=attrgetter('last_name', 'first_name'))\n\n    data = []\n    for participant in participants:\n        number_of_required_courses = Course.objects.filter(semester=semester, participants=participant, is_required_for_reward=True).count()\n        number_of_required_courses_voted_for = Course.objects.filter(semester=semester, voters=participant, is_required_for_reward=True).count()\n        number_of_optional_courses = Course.objects.filter(semester=semester, participants=participant, is_required_for_reward=False).count()\n        number_of_optional_courses_voted_for = Course.objects.filter(semester=semester, voters=participant, is_required_for_reward=False).count()\n        earned_reward_points = RewardPointGranting.objects.filter(semester=semester, user_profile=participant).exists()\n        data.append((participant, number_of_required_courses_voted_for, number_of_required_courses,\n            number_of_optional_courses_voted_for, number_of_optional_courses, earned_reward_points))\n\n    template_data = dict(semester=semester, data=data, disable_breadcrumb_semester=False)\n    return render(request, \"rewards_semester_reward_points_view.html\", template_data)\n\n\n@staff_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@staff_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    else:\n        return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(form=form))\n\n\n@staff_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    else:\n        return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(event=event, form=form))\n\n\n@staff_required\ndef reward_point_redemption_event_delete(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n\n    if event.can_delete:\n        if request.method == 'POST':\n            event.delete()\n            return redirect('rewards:reward_point_redemption_events')\n        else:\n            return render(request, \"rewards_reward_point_redemption_event_delete.html\", dict(event=event))\n    else:\n        messages.warning(request, _(\"This event cannot be deleted because some users already redeemed points for it.\"))\n        return redirect('rewards:reward_point_redemption_events')\n\n\n@staff_required\ndef reward_point_redemption_event_export(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n\n    filename = _(\"RewardPoints\")+\"-%s-%s-%s.xls\" % (event.date, event.name, get_language())\n\n    response = HttpResponse(content_type=\"application/vnd.ms-excel\")\n    response[\"Content-Disposition\"] = \"attachment; filename=\\\"%s\\\"\" % filename\n\n    ExcelExporter(event.redemptions_by_user()).export(response)\n\n    return response\n\n\n@staff_required\ndef semester_activation(request, semester_id, active):\n    if active == 'on':\n        active = True\n    else:\n        active = False\n\n    try:\n        activation = SemesterActivation.objects.filter(semester=Semester.objects.get(id=semester_id)).get()\n        activation.is_active = active\n    except SemesterActivation.DoesNotExist:\n        activation = SemesterActivation(semester=Semester.objects.get(id=semester_id), is_active=active)\n    activation.save()\n\n    return semester_view(request=request, semester_id=semester_id)\n", "path": "evap/rewards/views.py"}, {"content": "from django.utils.translation import ugettext_lazy as _\nfrom django.db import models\n\nfrom collections import OrderedDict\n\n\nclass RewardPointRedemptionEvent(models.Model):\n    name = models.CharField(max_length=1024, verbose_name=_(\"event name\"))\n    date = models.DateField(verbose_name=_(\"event date\"))\n    redeem_end_date = models.DateField(verbose_name=_(\"redemption end date\"))\n\n    @property\n    def can_delete(self):\n        if RewardPointRedemption.objects.filter(event=self).exists():\n            return False\n        return True\n\n    def redemptions_by_user(self):\n        redemptions = self.reward_point_redemptions.order_by('user_profile')\n        redemptions_dict = OrderedDict()\n        for redemption in redemptions:\n            if not redemption.user_profile in redemptions_dict:\n                redemptions_dict[redemption.user_profile] = 0\n            redemptions_dict[redemption.user_profile] += redemption.value\n        return redemptions_dict\n\nclass RewardPointGranting(models.Model):\n    user_profile = models.ForeignKey('evaluation.UserProfile', related_name=\"reward_point_grantings\")\n    semester = models.ForeignKey('evaluation.Semester', related_name=\"reward_point_grantings\", blank=True, null=True)\n    granting_time = models.DateTimeField(verbose_name=_(\"granting time\"), auto_now_add=True)\n    value = models.IntegerField(verbose_name=_(\"value\"), default=0)\n\nclass RewardPointRedemption(models.Model):\n    user_profile = models.ForeignKey('evaluation.UserProfile', related_name=\"reward_point_redemptions\")\n    redemption_time = models.DateTimeField(verbose_name=_(\"redemption time\"), auto_now_add=True)\n    value = models.IntegerField(verbose_name=_(\"value\"), default=0)\n    event = models.ForeignKey(RewardPointRedemptionEvent, related_name=\"reward_point_redemptions\")\n\nclass SemesterActivation(models.Model):\n    semester = models.OneToOneField('evaluation.Semester', related_name='rewards_active')\n    is_active = models.BooleanField(default=False)\n", "path": "evap/rewards/models.py"}], "after_files": [{"content": "from django.conf import settings\nfrom django.contrib import messages\nfrom django.db import transaction\nfrom django.utils.translation import ugettext as _\nfrom django.dispatch import receiver\n\nfrom django.contrib.auth.decorators import login_required\nfrom evap.evaluation.models import Course\n\nfrom evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation, NoPointsSelected, NotEnoughPoints\n\n@login_required\n@transaction.atomic\ndef save_redemptions(request, redemptions):\n    total_points_available = reward_points_of_user(request.user)\n    total_points_redeemed = sum(redemptions.values())\n\n    if total_points_redeemed <= 0:\n        raise NoPointsSelected(_(\"You cannot redeem 0 points.\"))\n\n    if total_points_redeemed > total_points_available:\n        raise NotEnoughPoints(_(\"You don't have enough reward points.\"))\n\n    for event_id in redemptions:\n        if redemptions[event_id] > 0:\n            redemption = RewardPointRedemption(\n                user_profile=request.user,\n                value=redemptions[event_id],\n                event=RewardPointRedemptionEvent.objects.get(id=event_id)\n            )\n            redemption.save()\n\ndef can_user_use_reward_points(user):\n    return not user.is_external and user.is_participant\n\n\ndef reward_points_of_user(user):\n    reward_point_grantings = RewardPointGranting.objects.filter(user_profile=user)\n    reward_point_redemptions = RewardPointRedemption.objects.filter(user_profile=user)\n\n    count = 0\n    for granting in reward_point_grantings:\n        count += granting.value\n    for redemption in reward_point_redemptions:\n        count -= redemption.value\n\n    return count\n\n\n@receiver(Course.course_evaluated)\ndef grant_reward_points(sender, **kwargs):\n    # grant reward points if all conditions are fulfilled\n\n    request = kwargs['request']\n    semester = kwargs['semester']\n    if not can_user_use_reward_points(request.user):\n        return\n    # has the semester been activated for reward points?\n    if not is_semester_activated(semester):\n        return\n    # does the user have at least one required course in this semester?\n    required_courses = Course.objects.filter(participants=request.user, semester=semester, is_required_for_reward=True)\n    if not required_courses.exists():\n        return\n    # does the user not participate in any more required courses in this semester?\n    if required_courses.exclude(voters=request.user).exists():\n        return\n    # did the user not already get reward points for this semester?\n    if not RewardPointGranting.objects.filter(user_profile=request.user, semester=semester):\n        granting = RewardPointGranting(user_profile=request.user, semester=semester, value=settings.REWARD_POINTS_PER_SEMESTER)\n        granting.save()\n        messages.success(request, _(\"You just have earned reward points for this semester because you evaluated all your courses. Thank you very much!\"))\n\n\ndef is_semester_activated(semester):\n    try:\n        activation = SemesterActivation.objects.get(semester=semester)\n        return activation.is_active\n    except SemesterActivation.DoesNotExist:\n        return False\n", "path": "evap/rewards/tools.py"}, {"content": "from django.contrib import messages\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.utils.translation import ugettext as _\nfrom django.utils.translation import get_language\nfrom django.http import HttpResponse\nfrom datetime import datetime\nfrom operator import attrgetter\n\nfrom evap.evaluation.auth import reward_user_required, staff_required\nfrom evap.evaluation.models import Semester, Course\n\nfrom evap.staff.views import semester_view\n\nfrom evap.rewards.models import RewardPointGranting, RewardPointRedemption, RewardPointRedemptionEvent, SemesterActivation, NoPointsSelected, NotEnoughPoints\nfrom evap.rewards.tools import save_redemptions, reward_points_of_user, can_user_use_reward_points\nfrom evap.rewards.forms import RewardPointRedemptionEventForm\nfrom evap.rewards.exporters import ExcelExporter\n\n@reward_user_required\ndef index(request):\n    if request.method == 'POST':\n        redemptions = {}\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\n        try:\n            save_redemptions(request, redemptions)\n            messages.success(request, _(\"You successfully redeemed your points.\"))\n        except (NoPointsSelected, NotEnoughPoints) 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())\n    events = sorted(events, key=lambda event: event.date)\n\n    reward_point_actions=[]\n    for granting in reward_point_grantings:\n        reward_point_actions.append((granting.granting_time, _('Reward for') + ' ' + granting.semester.name, granting.value, ''))\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            point_selection=[x for x in range(0,total_points_available+1)])\n    return render(request, \"rewards_index.html\", template_data)\n\n\n@staff_required\ndef semester_reward_points(request, semester_id):\n    semester = get_object_or_404(Semester, id=semester_id)\n    courses = Course.objects.filter(semester=semester)\n    participants = set()\n    for course in courses:\n        for participant in course.participants.all():\n            if can_user_use_reward_points(participant):\n                participants.add(participant)\n    participants = sorted(participants, key=attrgetter('last_name', 'first_name'))\n\n    data = []\n    for participant in participants:\n        number_of_required_courses = Course.objects.filter(semester=semester, participants=participant, is_required_for_reward=True).count()\n        number_of_required_courses_voted_for = Course.objects.filter(semester=semester, voters=participant, is_required_for_reward=True).count()\n        number_of_optional_courses = Course.objects.filter(semester=semester, participants=participant, is_required_for_reward=False).count()\n        number_of_optional_courses_voted_for = Course.objects.filter(semester=semester, voters=participant, is_required_for_reward=False).count()\n        earned_reward_points = RewardPointGranting.objects.filter(semester=semester, user_profile=participant).exists()\n        data.append((participant, number_of_required_courses_voted_for, number_of_required_courses,\n            number_of_optional_courses_voted_for, number_of_optional_courses, earned_reward_points))\n\n    template_data = dict(semester=semester, data=data, disable_breadcrumb_semester=False)\n    return render(request, \"rewards_semester_reward_points_view.html\", template_data)\n\n\n@staff_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@staff_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    else:\n        return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(form=form))\n\n\n@staff_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    else:\n        return render(request, \"rewards_reward_point_redemption_event_form.html\", dict(event=event, form=form))\n\n\n@staff_required\ndef reward_point_redemption_event_delete(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n\n    if event.can_delete:\n        if request.method == 'POST':\n            event.delete()\n            return redirect('rewards:reward_point_redemption_events')\n        else:\n            return render(request, \"rewards_reward_point_redemption_event_delete.html\", dict(event=event))\n    else:\n        messages.warning(request, _(\"This event cannot be deleted because some users already redeemed points for it.\"))\n        return redirect('rewards:reward_point_redemption_events')\n\n\n@staff_required\ndef reward_point_redemption_event_export(request, event_id):\n    event = get_object_or_404(RewardPointRedemptionEvent, id=event_id)\n\n    filename = _(\"RewardPoints\")+\"-%s-%s-%s.xls\" % (event.date, event.name, get_language())\n\n    response = HttpResponse(content_type=\"application/vnd.ms-excel\")\n    response[\"Content-Disposition\"] = \"attachment; filename=\\\"%s\\\"\" % filename\n\n    ExcelExporter(event.redemptions_by_user()).export(response)\n\n    return response\n\n\n@staff_required\ndef semester_activation(request, semester_id, active):\n    if active == 'on':\n        active = True\n    else:\n        active = False\n\n    try:\n        activation = SemesterActivation.objects.filter(semester=Semester.objects.get(id=semester_id)).get()\n        activation.is_active = active\n    except SemesterActivation.DoesNotExist:\n        activation = SemesterActivation(semester=Semester.objects.get(id=semester_id), is_active=active)\n    activation.save()\n\n    return semester_view(request=request, semester_id=semester_id)\n", "path": "evap/rewards/views.py"}, {"content": "from django.utils.translation import ugettext_lazy as _\nfrom django.db import models\n\nfrom collections import OrderedDict\n\nclass NoPointsSelected(Exception):\n    \"\"\"An attempt has been made to redeem <= 0 points.\"\"\"\n    pass\n\nclass NotEnoughPoints(Exception):\n    \"\"\"An attempt has been made to redeem more points than available.\"\"\"\n    pass\n\nclass RewardPointRedemptionEvent(models.Model):\n    name = models.CharField(max_length=1024, verbose_name=_(\"event name\"))\n    date = models.DateField(verbose_name=_(\"event date\"))\n    redeem_end_date = models.DateField(verbose_name=_(\"redemption end date\"))\n\n    @property\n    def can_delete(self):\n        if RewardPointRedemption.objects.filter(event=self).exists():\n            return False\n        return True\n\n    def redemptions_by_user(self):\n        redemptions = self.reward_point_redemptions.order_by('user_profile')\n        redemptions_dict = OrderedDict()\n        for redemption in redemptions:\n            if not redemption.user_profile in redemptions_dict:\n                redemptions_dict[redemption.user_profile] = 0\n            redemptions_dict[redemption.user_profile] += redemption.value\n        return redemptions_dict\n\nclass RewardPointGranting(models.Model):\n    user_profile = models.ForeignKey('evaluation.UserProfile', related_name=\"reward_point_grantings\")\n    semester = models.ForeignKey('evaluation.Semester', related_name=\"reward_point_grantings\", blank=True, null=True)\n    granting_time = models.DateTimeField(verbose_name=_(\"granting time\"), auto_now_add=True)\n    value = models.IntegerField(verbose_name=_(\"value\"), default=0)\n\nclass RewardPointRedemption(models.Model):\n    user_profile = models.ForeignKey('evaluation.UserProfile', related_name=\"reward_point_redemptions\")\n    redemption_time = models.DateTimeField(verbose_name=_(\"redemption time\"), auto_now_add=True)\n    value = models.IntegerField(verbose_name=_(\"value\"), default=0)\n    event = models.ForeignKey(RewardPointRedemptionEvent, related_name=\"reward_point_redemptions\")\n\nclass SemesterActivation(models.Model):\n    semester = models.OneToOneField('evaluation.Semester', related_name='rewards_active')\n    is_active = models.BooleanField(default=False)\n", "path": "evap/rewards/models.py"}]}