We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Education Exam/Summary count incorrect.
### Describe the bug
For some courses it says there are >500 documents. That's clearly not correct. Something seems to be wrong here: https://github.com/svthalia/concrexit/blob/ce784be158c2e26afa9d389d67065db1cb1a716c/website/education/views.py#L48-L58

### How to reproduce
Go to https://thalia.nu/education/courses/


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `website/education/views.py`
Content:
```
1 """Views provided by the education package."""
2 import os
3 from datetime import date, datetime
4 
5 from django.contrib.auth.decorators import login_required
6 from django.contrib.messages.views import SuccessMessageMixin
7 from django.core.exceptions import PermissionDenied
8 from django.db.models import Count
9 from django.http import HttpResponse
10 from django.shortcuts import redirect
11 from django.urls import reverse_lazy
12 from django.utils import timezone
13 from django.utils.decorators import method_decorator
14 from django.utils.translation import gettext_lazy as _
15 from django.views.generic import CreateView, DetailView, ListView, TemplateView
16 
17 from members.decorators import membership_required
18 from utils.media.services import get_media_url
19 
20 from . import emails
21 from .forms import AddExamForm, AddSummaryForm
22 from .models import Category, Course, Exam, Summary
23 
24 
25 class CourseIndexView(ListView):
26     """Render an overview of the courses."""
27 
28     queryset = (
29         Course.objects.filter(until=None)
30         .prefetch_related("categories", "old_courses")
31         .annotate(summary_count=Count("summary"))
32         .annotate(exam_count=Count("exam"))
33     )
34     template_name = "education/courses.html"
35 
36     def get_ordering(self) -> str:
37         return "name"
38 
39     def get_context_data(self, **kwargs) -> dict:
40         context = super().get_context_data(**kwargs)
41         context.update(
42             {
43                 "courses": (
44                     {
45                         "course_code": x.course_code,
46                         "name": x.name,
47                         "categories": x.categories.all(),
48                         "document_count": sum(
49                             [
50                                 x.summary_count,
51                                 x.exam_count,
52                             ]
53                             + [
54                                 c.summary_set.filter(accepted=True).count()
55                                 + c.exam_set.filter(accepted=True).count()
56                                 for c in x.old_courses.all()
57                             ]
58                         ),
59                         "url": x.get_absolute_url(),
60                     }
61                     for x in context["object_list"]
62                 ),
63                 "categories": Category.objects.all(),
64             }
65         )
66         return context
67 
68 
69 class CourseDetailView(DetailView):
70     """Render the detail page of one specific course."""
71 
72     model = Course
73     context_object_name = "course"
74     template_name = "education/course.html"
75 
76     def get_context_data(self, **kwargs) -> dict:
77         context = super().get_context_data(**kwargs)
78         obj = context["course"]
79         courses = list(obj.old_courses.all())
80         courses.append(obj)
81         items = {}
82         for course in courses:
83             for summary in course.summary_set.filter(accepted=True):
84                 if summary.year not in items:
85                     items[summary.year] = {
86                         "summaries": [],
87                         "exams": [],
88                         "legacy": course if course.pk != obj.pk else None,
89                     }
90                 items[summary.year]["summaries"].append(
91                     {
92                         "year": summary.year,
93                         "name": summary.name,
94                         "language": summary.language,
95                         "id": summary.id,
96                     }
97                 )
98             for exam in course.exam_set.filter(accepted=True):
99                 if exam.year not in items:
100                     items[exam.year] = {
101                         "summaries": [],
102                         "exams": [],
103                         "legacy": course if course.pk != obj.pk else None,
104                     }
105                 items[exam.year]["exams"].append(
106                     {
107                         "type": "exam",
108                         "year": exam.year,
109                         "name": f"{exam.get_type_display()} {exam.name}",
110                         "language": exam.language,
111                         "id": exam.id,
112                     }
113                 )
114         context.update({"items": sorted(items.items(), key=lambda x: x[0])})
115         return context
116 
117 
118 @method_decorator(login_required, "dispatch")
119 @method_decorator(membership_required, "dispatch")
120 class ExamDetailView(DetailView):
121     """Fetch and output the specified exam."""
122 
123     model = Exam
124 
125     def get(self, request, *args, **kwargs) -> HttpResponse:
126         response = super().get(request, *args, **kwargs)
127         obj = response.context_data["object"]
128         obj.download_count += 1
129         obj.save()
130 
131         ext = os.path.splitext(obj.file.name)[1]
132         filename = f"{obj.course.name}-summary{obj.year}{ext}"
133         return redirect(get_media_url(obj.file, filename))
134 
135 
136 @method_decorator(login_required, "dispatch")
137 @method_decorator(membership_required, "dispatch")
138 class SummaryDetailView(DetailView):
139     """Fetch and output the specified summary."""
140 
141     model = Summary
142 
143     def get(self, request, *args, **kwargs) -> HttpResponse:
144         response = super().get(request, *args, **kwargs)
145         obj = response.context_data["object"]
146         obj.download_count += 1
147         obj.save()
148 
149         ext = os.path.splitext(obj.file.name)[1]
150         filename = f"{obj.course.name}-summary{obj.year}{ext}"
151         return redirect(get_media_url(obj.file, filename))
152 
153 
154 @method_decorator(login_required, "dispatch")
155 @method_decorator(membership_required, "dispatch")
156 class ExamCreateView(SuccessMessageMixin, CreateView):
157     """Render the form to submit a new exam."""
158 
159     model = Exam
160     form_class = AddExamForm
161     template_name = "education/add_exam.html"
162     success_url = reverse_lazy("education:submit-exam")
163     success_message = _("Exam submitted successfully.")
164 
165     def get_initial(self) -> dict:
166         initial = super().get_initial()
167         initial["exam_date"] = date.today()
168         initial["course"] = self.kwargs.get("pk", None)
169         return initial
170 
171     def form_valid(self, form) -> HttpResponse:
172         self.object = form.save(commit=False)
173         self.object.uploader = self.request.member
174         self.object.uploader_date = datetime.now()
175         self.object.save()
176         emails.send_document_notification(self.object)
177         return super().form_valid(form)
178 
179 
180 @method_decorator(login_required, "dispatch")
181 @method_decorator(membership_required, "dispatch")
182 class SummaryCreateView(SuccessMessageMixin, CreateView):
183     """Render the form to submit a new summary."""
184 
185     model = Summary
186     form_class = AddSummaryForm
187     template_name = "education/add_summary.html"
188     success_url = reverse_lazy("education:submit-summary")
189     success_message = _("Summary submitted successfully.")
190 
191     def get_initial(self):
192         initial = super().get_initial()
193         initial["author"] = self.request.member.get_full_name()
194         initial["course"] = self.kwargs.get("pk", None)
195         return initial
196 
197     def form_valid(self, form) -> HttpResponse:
198         self.object = form.save(commit=False)
199         self.object.uploader = self.request.member
200         self.object.uploader_date = datetime.now()
201         self.object.save()
202         emails.send_document_notification(self.object)
203         return super().form_valid(form)
204 
205 
206 @method_decorator(login_required, "dispatch")
207 class BookInfoView(TemplateView):
208     """Render a page with information about book sale.
209 
210     Only available to members and to-be members
211     """
212 
213     template_name = "education/books.html"
214 
215     def dispatch(self, request, *args, **kwargs) -> HttpResponse:
216         if request.member.has_active_membership() or (
217             request.member.earliest_membership
218             and request.member.earliest_membership.since > timezone.now().date()
219         ):
220             return super().dispatch(request, *args, **kwargs)
221         raise PermissionDenied
222
```
--- 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/website/education/views.py b/website/education/views.py
--- a/website/education/views.py
+++ b/website/education/views.py
@@ -5,7 +5,6 @@
 from django.contrib.auth.decorators import login_required
 from django.contrib.messages.views import SuccessMessageMixin
 from django.core.exceptions import PermissionDenied
-from django.db.models import Count
 from django.http import HttpResponse
 from django.shortcuts import redirect
 from django.urls import reverse_lazy
@@ -25,11 +24,8 @@
 class CourseIndexView(ListView):
     """Render an overview of the courses."""
 
-    queryset = (
-        Course.objects.filter(until=None)
-        .prefetch_related("categories", "old_courses")
-        .annotate(summary_count=Count("summary"))
-        .annotate(exam_count=Count("exam"))
+    queryset = Course.objects.filter(until=None).prefetch_related(
+        "categories", "old_courses"
     )
     template_name = "education/courses.html"
 
@@ -40,15 +36,15 @@
         context = super().get_context_data(**kwargs)
         context.update(
             {
-                "courses": (
+                "courses": [
                     {
                         "course_code": x.course_code,
                         "name": x.name,
                         "categories": x.categories.all(),
                         "document_count": sum(
                             [
-                                x.summary_count,
-                                x.exam_count,
+                                x.summary_set.filter(accepted=True).count(),
+                                x.exam_set.filter(accepted=True).count(),
                             ]
                             + [
                                 c.summary_set.filter(accepted=True).count()
@@ -59,7 +55,7 @@
                         "url": x.get_absolute_url(),
                     }
                     for x in context["object_list"]
-                ),
+                ],
                 "categories": Category.objects.all(),
             }
         )

{"golden_diff": "diff --git a/website/education/views.py b/website/education/views.py\n--- a/website/education/views.py\n+++ b/website/education/views.py\n@@ -5,7 +5,6 @@\n from django.contrib.auth.decorators import login_required\n from django.contrib.messages.views import SuccessMessageMixin\n from django.core.exceptions import PermissionDenied\n-from django.db.models import Count\n from django.http import HttpResponse\n from django.shortcuts import redirect\n from django.urls import reverse_lazy\n@@ -25,11 +24,8 @@\n class CourseIndexView(ListView):\n     \"\"\"Render an overview of the courses.\"\"\"\n \n-    queryset = (\n-        Course.objects.filter(until=None)\n-        .prefetch_related(\"categories\", \"old_courses\")\n-        .annotate(summary_count=Count(\"summary\"))\n-        .annotate(exam_count=Count(\"exam\"))\n+    queryset = Course.objects.filter(until=None).prefetch_related(\n+        \"categories\", \"old_courses\"\n     )\n     template_name = \"education/courses.html\"\n \n@@ -40,15 +36,15 @@\n         context = super().get_context_data(**kwargs)\n         context.update(\n             {\n-                \"courses\": (\n+                \"courses\": [\n                     {\n                         \"course_code\": x.course_code,\n                         \"name\": x.name,\n                         \"categories\": x.categories.all(),\n                         \"document_count\": sum(\n                             [\n-                                x.summary_count,\n-                                x.exam_count,\n+                                x.summary_set.filter(accepted=True).count(),\n+                                x.exam_set.filter(accepted=True).count(),\n                             ]\n                             + [\n                                 c.summary_set.filter(accepted=True).count()\n@@ -59,7 +55,7 @@\n                         \"url\": x.get_absolute_url(),\n                     }\n                     for x in context[\"object_list\"]\n-                ),\n+                ],\n                 \"categories\": Category.objects.all(),\n             }\n         )\n", "issue": "Education Exam/Summary count incorrect.\n### Describe the bug\r\nFor some courses it says there are >500 documents. That's clearly not correct. Something seems to be wrong here: https://github.com/svthalia/concrexit/blob/ce784be158c2e26afa9d389d67065db1cb1a716c/website/education/views.py#L48-L58\r\n\r\n### How to reproduce\r\nGo to https://thalia.nu/education/courses/\r\n\n", "before_files": [{"content": "\"\"\"Views provided by the education package.\"\"\"\nimport os\nfrom datetime import date, datetime\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.contrib.messages.views import SuccessMessageMixin\nfrom django.core.exceptions import PermissionDenied\nfrom django.db.models import Count\nfrom django.http import HttpResponse\nfrom django.shortcuts import redirect\nfrom django.urls import reverse_lazy\nfrom django.utils import timezone\nfrom django.utils.decorators import method_decorator\nfrom django.utils.translation import gettext_lazy as _\nfrom django.views.generic import CreateView, DetailView, ListView, TemplateView\n\nfrom members.decorators import membership_required\nfrom utils.media.services import get_media_url\n\nfrom . import emails\nfrom .forms import AddExamForm, AddSummaryForm\nfrom .models import Category, Course, Exam, Summary\n\n\nclass CourseIndexView(ListView):\n    \"\"\"Render an overview of the courses.\"\"\"\n\n    queryset = (\n        Course.objects.filter(until=None)\n        .prefetch_related(\"categories\", \"old_courses\")\n        .annotate(summary_count=Count(\"summary\"))\n        .annotate(exam_count=Count(\"exam\"))\n    )\n    template_name = \"education/courses.html\"\n\n    def get_ordering(self) -> str:\n        return \"name\"\n\n    def get_context_data(self, **kwargs) -> dict:\n        context = super().get_context_data(**kwargs)\n        context.update(\n            {\n                \"courses\": (\n                    {\n                        \"course_code\": x.course_code,\n                        \"name\": x.name,\n                        \"categories\": x.categories.all(),\n                        \"document_count\": sum(\n                            [\n                                x.summary_count,\n                                x.exam_count,\n                            ]\n                            + [\n                                c.summary_set.filter(accepted=True).count()\n                                + c.exam_set.filter(accepted=True).count()\n                                for c in x.old_courses.all()\n                            ]\n                        ),\n                        \"url\": x.get_absolute_url(),\n                    }\n                    for x in context[\"object_list\"]\n                ),\n                \"categories\": Category.objects.all(),\n            }\n        )\n        return context\n\n\nclass CourseDetailView(DetailView):\n    \"\"\"Render the detail page of one specific course.\"\"\"\n\n    model = Course\n    context_object_name = \"course\"\n    template_name = \"education/course.html\"\n\n    def get_context_data(self, **kwargs) -> dict:\n        context = super().get_context_data(**kwargs)\n        obj = context[\"course\"]\n        courses = list(obj.old_courses.all())\n        courses.append(obj)\n        items = {}\n        for course in courses:\n            for summary in course.summary_set.filter(accepted=True):\n                if summary.year not in items:\n                    items[summary.year] = {\n                        \"summaries\": [],\n                        \"exams\": [],\n                        \"legacy\": course if course.pk != obj.pk else None,\n                    }\n                items[summary.year][\"summaries\"].append(\n                    {\n                        \"year\": summary.year,\n                        \"name\": summary.name,\n                        \"language\": summary.language,\n                        \"id\": summary.id,\n                    }\n                )\n            for exam in course.exam_set.filter(accepted=True):\n                if exam.year not in items:\n                    items[exam.year] = {\n                        \"summaries\": [],\n                        \"exams\": [],\n                        \"legacy\": course if course.pk != obj.pk else None,\n                    }\n                items[exam.year][\"exams\"].append(\n                    {\n                        \"type\": \"exam\",\n                        \"year\": exam.year,\n                        \"name\": f\"{exam.get_type_display()} {exam.name}\",\n                        \"language\": exam.language,\n                        \"id\": exam.id,\n                    }\n                )\n        context.update({\"items\": sorted(items.items(), key=lambda x: x[0])})\n        return context\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass ExamDetailView(DetailView):\n    \"\"\"Fetch and output the specified exam.\"\"\"\n\n    model = Exam\n\n    def get(self, request, *args, **kwargs) -> HttpResponse:\n        response = super().get(request, *args, **kwargs)\n        obj = response.context_data[\"object\"]\n        obj.download_count += 1\n        obj.save()\n\n        ext = os.path.splitext(obj.file.name)[1]\n        filename = f\"{obj.course.name}-summary{obj.year}{ext}\"\n        return redirect(get_media_url(obj.file, filename))\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass SummaryDetailView(DetailView):\n    \"\"\"Fetch and output the specified summary.\"\"\"\n\n    model = Summary\n\n    def get(self, request, *args, **kwargs) -> HttpResponse:\n        response = super().get(request, *args, **kwargs)\n        obj = response.context_data[\"object\"]\n        obj.download_count += 1\n        obj.save()\n\n        ext = os.path.splitext(obj.file.name)[1]\n        filename = f\"{obj.course.name}-summary{obj.year}{ext}\"\n        return redirect(get_media_url(obj.file, filename))\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass ExamCreateView(SuccessMessageMixin, CreateView):\n    \"\"\"Render the form to submit a new exam.\"\"\"\n\n    model = Exam\n    form_class = AddExamForm\n    template_name = \"education/add_exam.html\"\n    success_url = reverse_lazy(\"education:submit-exam\")\n    success_message = _(\"Exam submitted successfully.\")\n\n    def get_initial(self) -> dict:\n        initial = super().get_initial()\n        initial[\"exam_date\"] = date.today()\n        initial[\"course\"] = self.kwargs.get(\"pk\", None)\n        return initial\n\n    def form_valid(self, form) -> HttpResponse:\n        self.object = form.save(commit=False)\n        self.object.uploader = self.request.member\n        self.object.uploader_date = datetime.now()\n        self.object.save()\n        emails.send_document_notification(self.object)\n        return super().form_valid(form)\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass SummaryCreateView(SuccessMessageMixin, CreateView):\n    \"\"\"Render the form to submit a new summary.\"\"\"\n\n    model = Summary\n    form_class = AddSummaryForm\n    template_name = \"education/add_summary.html\"\n    success_url = reverse_lazy(\"education:submit-summary\")\n    success_message = _(\"Summary submitted successfully.\")\n\n    def get_initial(self):\n        initial = super().get_initial()\n        initial[\"author\"] = self.request.member.get_full_name()\n        initial[\"course\"] = self.kwargs.get(\"pk\", None)\n        return initial\n\n    def form_valid(self, form) -> HttpResponse:\n        self.object = form.save(commit=False)\n        self.object.uploader = self.request.member\n        self.object.uploader_date = datetime.now()\n        self.object.save()\n        emails.send_document_notification(self.object)\n        return super().form_valid(form)\n\n\n@method_decorator(login_required, \"dispatch\")\nclass BookInfoView(TemplateView):\n    \"\"\"Render a page with information about book sale.\n\n    Only available to members and to-be members\n    \"\"\"\n\n    template_name = \"education/books.html\"\n\n    def dispatch(self, request, *args, **kwargs) -> HttpResponse:\n        if request.member.has_active_membership() or (\n            request.member.earliest_membership\n            and request.member.earliest_membership.since > timezone.now().date()\n        ):\n            return super().dispatch(request, *args, **kwargs)\n        raise PermissionDenied\n", "path": "website/education/views.py"}], "after_files": [{"content": "\"\"\"Views provided by the education package.\"\"\"\nimport os\nfrom datetime import date, datetime\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.contrib.messages.views import SuccessMessageMixin\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import HttpResponse\nfrom django.shortcuts import redirect\nfrom django.urls import reverse_lazy\nfrom django.utils import timezone\nfrom django.utils.decorators import method_decorator\nfrom django.utils.translation import gettext_lazy as _\nfrom django.views.generic import CreateView, DetailView, ListView, TemplateView\n\nfrom members.decorators import membership_required\nfrom utils.media.services import get_media_url\n\nfrom . import emails\nfrom .forms import AddExamForm, AddSummaryForm\nfrom .models import Category, Course, Exam, Summary\n\n\nclass CourseIndexView(ListView):\n    \"\"\"Render an overview of the courses.\"\"\"\n\n    queryset = Course.objects.filter(until=None).prefetch_related(\n        \"categories\", \"old_courses\"\n    )\n    template_name = \"education/courses.html\"\n\n    def get_ordering(self) -> str:\n        return \"name\"\n\n    def get_context_data(self, **kwargs) -> dict:\n        context = super().get_context_data(**kwargs)\n        context.update(\n            {\n                \"courses\": [\n                    {\n                        \"course_code\": x.course_code,\n                        \"name\": x.name,\n                        \"categories\": x.categories.all(),\n                        \"document_count\": sum(\n                            [\n                                x.summary_set.filter(accepted=True).count(),\n                                x.exam_set.filter(accepted=True).count(),\n                            ]\n                            + [\n                                c.summary_set.filter(accepted=True).count()\n                                + c.exam_set.filter(accepted=True).count()\n                                for c in x.old_courses.all()\n                            ]\n                        ),\n                        \"url\": x.get_absolute_url(),\n                    }\n                    for x in context[\"object_list\"]\n                ],\n                \"categories\": Category.objects.all(),\n            }\n        )\n        return context\n\n\nclass CourseDetailView(DetailView):\n    \"\"\"Render the detail page of one specific course.\"\"\"\n\n    model = Course\n    context_object_name = \"course\"\n    template_name = \"education/course.html\"\n\n    def get_context_data(self, **kwargs) -> dict:\n        context = super().get_context_data(**kwargs)\n        obj = context[\"course\"]\n        courses = list(obj.old_courses.all())\n        courses.append(obj)\n        items = {}\n        for course in courses:\n            for summary in course.summary_set.filter(accepted=True):\n                if summary.year not in items:\n                    items[summary.year] = {\n                        \"summaries\": [],\n                        \"exams\": [],\n                        \"legacy\": course if course.pk != obj.pk else None,\n                    }\n                items[summary.year][\"summaries\"].append(\n                    {\n                        \"year\": summary.year,\n                        \"name\": summary.name,\n                        \"language\": summary.language,\n                        \"id\": summary.id,\n                    }\n                )\n            for exam in course.exam_set.filter(accepted=True):\n                if exam.year not in items:\n                    items[exam.year] = {\n                        \"summaries\": [],\n                        \"exams\": [],\n                        \"legacy\": course if course.pk != obj.pk else None,\n                    }\n                items[exam.year][\"exams\"].append(\n                    {\n                        \"type\": \"exam\",\n                        \"year\": exam.year,\n                        \"name\": f\"{exam.get_type_display()} {exam.name}\",\n                        \"language\": exam.language,\n                        \"id\": exam.id,\n                    }\n                )\n        context.update({\"items\": sorted(items.items(), key=lambda x: x[0])})\n        return context\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass ExamDetailView(DetailView):\n    \"\"\"Fetch and output the specified exam.\"\"\"\n\n    model = Exam\n\n    def get(self, request, *args, **kwargs) -> HttpResponse:\n        response = super().get(request, *args, **kwargs)\n        obj = response.context_data[\"object\"]\n        obj.download_count += 1\n        obj.save()\n\n        ext = os.path.splitext(obj.file.name)[1]\n        filename = f\"{obj.course.name}-summary{obj.year}{ext}\"\n        return redirect(get_media_url(obj.file, filename))\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass SummaryDetailView(DetailView):\n    \"\"\"Fetch and output the specified summary.\"\"\"\n\n    model = Summary\n\n    def get(self, request, *args, **kwargs) -> HttpResponse:\n        response = super().get(request, *args, **kwargs)\n        obj = response.context_data[\"object\"]\n        obj.download_count += 1\n        obj.save()\n\n        ext = os.path.splitext(obj.file.name)[1]\n        filename = f\"{obj.course.name}-summary{obj.year}{ext}\"\n        return redirect(get_media_url(obj.file, filename))\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass ExamCreateView(SuccessMessageMixin, CreateView):\n    \"\"\"Render the form to submit a new exam.\"\"\"\n\n    model = Exam\n    form_class = AddExamForm\n    template_name = \"education/add_exam.html\"\n    success_url = reverse_lazy(\"education:submit-exam\")\n    success_message = _(\"Exam submitted successfully.\")\n\n    def get_initial(self) -> dict:\n        initial = super().get_initial()\n        initial[\"exam_date\"] = date.today()\n        initial[\"course\"] = self.kwargs.get(\"pk\", None)\n        return initial\n\n    def form_valid(self, form) -> HttpResponse:\n        self.object = form.save(commit=False)\n        self.object.uploader = self.request.member\n        self.object.uploader_date = datetime.now()\n        self.object.save()\n        emails.send_document_notification(self.object)\n        return super().form_valid(form)\n\n\n@method_decorator(login_required, \"dispatch\")\n@method_decorator(membership_required, \"dispatch\")\nclass SummaryCreateView(SuccessMessageMixin, CreateView):\n    \"\"\"Render the form to submit a new summary.\"\"\"\n\n    model = Summary\n    form_class = AddSummaryForm\n    template_name = \"education/add_summary.html\"\n    success_url = reverse_lazy(\"education:submit-summary\")\n    success_message = _(\"Summary submitted successfully.\")\n\n    def get_initial(self):\n        initial = super().get_initial()\n        initial[\"author\"] = self.request.member.get_full_name()\n        initial[\"course\"] = self.kwargs.get(\"pk\", None)\n        return initial\n\n    def form_valid(self, form) -> HttpResponse:\n        self.object = form.save(commit=False)\n        self.object.uploader = self.request.member\n        self.object.uploader_date = datetime.now()\n        self.object.save()\n        emails.send_document_notification(self.object)\n        return super().form_valid(form)\n\n\n@method_decorator(login_required, \"dispatch\")\nclass BookInfoView(TemplateView):\n    \"\"\"Render a page with information about book sale.\n\n    Only available to members and to-be members\n    \"\"\"\n\n    template_name = \"education/books.html\"\n\n    def dispatch(self, request, *args, **kwargs) -> HttpResponse:\n        if request.member.has_active_membership() or (\n            request.member.earliest_membership\n            and request.member.earliest_membership.since > timezone.now().date()\n        ):\n            return super().dispatch(request, *args, **kwargs)\n        raise PermissionDenied\n", "path": "website/education/views.py"}]}