We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
A+ front page
The A+ front page should display the name of the course instance in addition to the course name and code; Multiple instances of the same course are hard to separate in the A+ front page because the only different parts are the open/close dates and the image. Course instances have names, so that should be displayed in the front page too. Jaakko has some ideas; contact him!

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `course/views.py`
Content:
```
1 import datetime
2 
3 import icalendar
4 from django.conf import settings
5 from django.contrib import messages
6 from django.core.exceptions import PermissionDenied
7 from django.http import Http404
8 from django.http.response import HttpResponse
9 from django.shortcuts import get_object_or_404, redirect
10 from django.utils import html
11 from django.utils import timezone
12 from django.utils.translation import ugettext_lazy as _
13 
14 from authorization.permissions import ACCESS
15 from exercise.cache.hierarchy import NoSuchContent
16 from exercise.models import LearningObject
17 from lib.helpers import settings_text
18 from lib.viewbase import BaseTemplateView, BaseRedirectMixin, BaseFormView, BaseView
19 from userprofile.viewbase import UserProfileView
20 from .forms import GroupsForm, GroupSelectForm
21 from .models import CourseInstance, Enrollment
22 from .permissions import EnrollInfoVisiblePermission
23 from .renders import group_info_context
24 from .viewbase import CourseModuleBaseView, CourseInstanceMixin, EnrollableViewMixin
25 
26 
27 class HomeView(UserProfileView):
28     access_mode = ACCESS.ANONYMOUS
29     template_name = "course/index.html"
30 
31     def get_common_objects(self):
32         super().get_common_objects()
33         self.welcome_text = settings_text('WELCOME_TEXT')
34         self.internal_user_label = settings_text('INTERNAL_USER_LABEL')
35         self.external_user_label = settings_text('EXTERNAL_USER_LABEL')
36         self.instances = []
37         prio2 = []
38         treshold = timezone.now() - datetime.timedelta(days=10)
39         for instance in CourseInstance.objects.get_visible(self.request.user)\
40                 .filter(ending_time__gte=timezone.now()):
41             if instance.starting_time > treshold:
42                 self.instances += [instance]
43             else:
44                 prio2 += [instance]
45         self.instances += prio2
46         self.note("welcome_text", "internal_user_label", "external_user_label", "instances")
47 
48 
49 class ArchiveView(UserProfileView):
50     access_mode = ACCESS.ANONYMOUS
51     template_name = "course/archive.html"
52 
53     def get_common_objects(self):
54         super().get_common_objects()
55         self.instances = CourseInstance.objects.get_visible(self.request.user)
56         self.note("instances")
57 
58 class InstanceView(EnrollableViewMixin, BaseTemplateView):
59     access_mode = ACCESS.STUDENT
60     # ACCESS.STUDENT requires users to log in, but the access mode is dropped
61     # in public courses. CourseVisiblePermission has more restrictions as well.
62     template_name = "course/course.html"
63 
64     def handle_no_permission(self):
65         if self.request.user.is_authenticated \
66                 and self.instance.view_content_to == CourseInstance.VIEW_ACCESS.ENROLLED:
67             # The course instance is visible to only enrolled students, so
68             # redirect the user to the enroll page instead of showing
69             # a 403 Forbidden error.
70             return redirect(self.instance.get_url('enroll'))
71         return super().handle_no_permission()
72 
73     def get(self, request, *args, **kwargs):
74         # external LTI Tool Providers may return the user to the course instance view
75         # with a message given in GET query parameters
76         lti_error_msg = request.GET.get('lti_errormsg')
77         lti_msg = request.GET.get('lti_msg')
78         # message HTML is not escaped in the templates so escape it here
79         if lti_error_msg:
80             messages.error(request, html.escape(lti_error_msg))
81         elif lti_msg:
82             messages.info(request, html.escape(lti_msg))
83 
84         return super().get(request, *args, **kwargs)
85 
86 
87 class Enroll(EnrollableViewMixin, BaseRedirectMixin, BaseTemplateView):
88     permission_classes = [EnrollInfoVisiblePermission]
89     course_permission_classes = []
90     template_name = "course/enroll.html"
91 
92     def post(self, request, *args, **kwargs):
93 
94         if self.is_student or not self.enrollable:
95             messages.error(self.request, _("You cannot enroll, or have already enrolled, in this course."))
96             raise PermissionDenied()
97 
98         if not self.instance.is_enrollment_open():
99             messages.error(self.request, _("The enrollment is not open."))
100             raise PermissionDenied()
101 
102         # Support enrollment questionnaires.
103         exercise = LearningObject.objects.find_enrollment_exercise(
104             self.instance, self.profile)
105         if exercise:
106             return self.redirect(exercise.get_absolute_url())
107 
108         self.instance.enroll_student(self.request.user)
109         return self.redirect(self.instance.get_absolute_url())
110 
111 
112 class ModuleView(CourseModuleBaseView):
113     template_name = "course/module.html"
114 
115     def get_common_objects(self):
116         super().get_common_objects()
117         self.now = timezone.now()
118         try:
119             self.children = self.content.flat_module(self.module)
120             cur, tree, prev, nex = self.content.find(self.module)
121             self.previous = prev
122             self.current = cur
123             self.next = nex
124         except NoSuchContent:
125             raise Http404
126         self.note('now', 'children', 'previous', 'current', 'next')
127 
128 
129 class CalendarExport(CourseInstanceMixin, BaseView):
130 
131     def get(self, request, *args, **kwargs):
132         cal = icalendar.Calendar()
133         cal.add('prodid', '-// {} calendar //'.format(settings.BRAND_NAME))
134         cal.add('version', '2.0')
135         for module in self.instance.course_modules.all():
136             event = icalendar.Event()
137             event.add('summary', module.name)
138             event.add('dtstart',
139                 module.closing_time - datetime.timedelta(hours=1))
140             event.add('dtend', module.closing_time)
141             event.add('dtstamp', module.closing_time)
142             event['uid'] = "module/" + str(module.id) + "/A+"
143             cal.add_component(event)
144 
145         return HttpResponse(cal.to_ical(),
146             content_type="text/calendar; charset=utf-8")
147 
148 
149 class GroupsView(CourseInstanceMixin, BaseFormView):
150     access_mode = ACCESS.ENROLLED
151     template_name = "course/groups.html"
152     form_class = GroupsForm
153 
154     def get_common_objects(self):
155         super().get_common_objects()
156         self.enrollment = self.instance.get_enrollment_for(self.request.user)
157         self.groups = list(self.profile.groups.filter(course_instance=self.instance))
158         self.note('enrollment','groups')
159 
160     def get_form_kwargs(self):
161         kwargs = super().get_form_kwargs()
162         kwargs["profile"] = self.profile
163         kwargs["instance"] = self.instance
164         kwargs["content"] = self.content
165         return kwargs
166 
167     def get_success_url(self):
168         return self.instance.get_url('groups')
169 
170     def form_valid(self, form):
171         form.save()
172         messages.success(self.request, _("A new student group was created."))
173         return super().form_valid(form)
174 
175 
176 class GroupSelect(CourseInstanceMixin, BaseFormView):
177     access_mode = ACCESS.ENROLLED
178     form_class = GroupSelectForm
179     template_name = "course/_group_info.html"
180 
181     def get_form_kwargs(self):
182         kwargs = super().get_form_kwargs()
183         kwargs["profile"] = self.profile
184         kwargs["instance"] = self.instance
185         return kwargs
186 
187     def get_success_url(self):
188         return self.instance.get_absolute_url()
189 
190     def get(self, request, *args, **kwargs):
191         return self.http_method_not_allowed(request, *args, **kwargs)
192 
193     def form_invalid(self, form):
194         return HttpResponse('Invalid group selection')
195 
196     def form_valid(self, form):
197         enrollment = form.save()
198         if self.request.is_ajax():
199             return self.render_to_response(self.get_context_data(
200                 **group_info_context(enrollment.selected_group, self.profile)))
201         return super().form_valid(form)
202
```
--- 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/course/views.py b/course/views.py
--- a/course/views.py
+++ b/course/views.py
@@ -33,17 +33,42 @@
         self.welcome_text = settings_text('WELCOME_TEXT')
         self.internal_user_label = settings_text('INTERNAL_USER_LABEL')
         self.external_user_label = settings_text('EXTERNAL_USER_LABEL')
-        self.instances = []
-        prio2 = []
-        treshold = timezone.now() - datetime.timedelta(days=10)
-        for instance in CourseInstance.objects.get_visible(self.request.user)\
-                .filter(ending_time__gte=timezone.now()):
-            if instance.starting_time > treshold:
-                self.instances += [instance]
-            else:
-                prio2 += [instance]
-        self.instances += prio2
-        self.note("welcome_text", "internal_user_label", "external_user_label", "instances")
+        my_instances = []
+        all_instances = []
+        end_threshold = timezone.now() - datetime.timedelta(days=30)
+        user = self.request.user
+        is_logged_in = False
+
+        if user and user.is_authenticated:
+            is_logged_in = True
+            for instance in (CourseInstance.objects
+                .filter(course__teachers=user.userprofile,
+                        ending_time__gte=end_threshold)
+                .all()):
+                my_instances.append(instance)
+
+            for instance in user.userprofile.assisting_courses.all().filter(ending_time__gte=end_threshold):
+                if instance not in my_instances:
+                    my_instances.append(instance)
+            
+            for instance in user.userprofile.enrolled.all().filter(ending_time__gte=end_threshold):
+                if instance not in my_instances:
+                    my_instances.append(instance)
+        
+        all_instances = CourseInstance.objects.get_visible(user).filter(ending_time__gte=end_threshold)
+        all_instances = [c for c in all_instances if c not in my_instances]
+        
+        self.all_instances = all_instances
+        self.my_instances = my_instances
+        self.is_logged_in = is_logged_in
+
+        self.note("welcome_text", 
+            "internal_user_label", 
+            "external_user_label",
+            "my_instances",
+            "all_instances",
+            "is_logged_in",
+        )
 
 
 class ArchiveView(UserProfileView):

{"golden_diff": "diff --git a/course/views.py b/course/views.py\n--- a/course/views.py\n+++ b/course/views.py\n@@ -33,17 +33,42 @@\n         self.welcome_text = settings_text('WELCOME_TEXT')\n         self.internal_user_label = settings_text('INTERNAL_USER_LABEL')\n         self.external_user_label = settings_text('EXTERNAL_USER_LABEL')\n-        self.instances = []\n-        prio2 = []\n-        treshold = timezone.now() - datetime.timedelta(days=10)\n-        for instance in CourseInstance.objects.get_visible(self.request.user)\\\n-                .filter(ending_time__gte=timezone.now()):\n-            if instance.starting_time > treshold:\n-                self.instances += [instance]\n-            else:\n-                prio2 += [instance]\n-        self.instances += prio2\n-        self.note(\"welcome_text\", \"internal_user_label\", \"external_user_label\", \"instances\")\n+        my_instances = []\n+        all_instances = []\n+        end_threshold = timezone.now() - datetime.timedelta(days=30)\n+        user = self.request.user\n+        is_logged_in = False\n+\n+        if user and user.is_authenticated:\n+            is_logged_in = True\n+            for instance in (CourseInstance.objects\n+                .filter(course__teachers=user.userprofile,\n+                        ending_time__gte=end_threshold)\n+                .all()):\n+                my_instances.append(instance)\n+\n+            for instance in user.userprofile.assisting_courses.all().filter(ending_time__gte=end_threshold):\n+                if instance not in my_instances:\n+                    my_instances.append(instance)\n+            \n+            for instance in user.userprofile.enrolled.all().filter(ending_time__gte=end_threshold):\n+                if instance not in my_instances:\n+                    my_instances.append(instance)\n+        \n+        all_instances = CourseInstance.objects.get_visible(user).filter(ending_time__gte=end_threshold)\n+        all_instances = [c for c in all_instances if c not in my_instances]\n+        \n+        self.all_instances = all_instances\n+        self.my_instances = my_instances\n+        self.is_logged_in = is_logged_in\n+\n+        self.note(\"welcome_text\", \n+            \"internal_user_label\", \n+            \"external_user_label\",\n+            \"my_instances\",\n+            \"all_instances\",\n+            \"is_logged_in\",\n+        )\n \n \n class ArchiveView(UserProfileView):\n", "issue": "A+ front page\nThe A+ front page should display the name of the course instance in addition to the course name and code; Multiple instances of the same course are hard to separate in the A+ front page because the only different parts are the open/close dates and the image. Course instances have names, so that should be displayed in the front page too. Jaakko has some ideas; contact him!\n", "before_files": [{"content": "import datetime\n\nimport icalendar\nfrom django.conf import settings\nfrom django.contrib import messages\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import Http404\nfrom django.http.response import HttpResponse\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.utils import html\nfrom django.utils import timezone\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom authorization.permissions import ACCESS\nfrom exercise.cache.hierarchy import NoSuchContent\nfrom exercise.models import LearningObject\nfrom lib.helpers import settings_text\nfrom lib.viewbase import BaseTemplateView, BaseRedirectMixin, BaseFormView, BaseView\nfrom userprofile.viewbase import UserProfileView\nfrom .forms import GroupsForm, GroupSelectForm\nfrom .models import CourseInstance, Enrollment\nfrom .permissions import EnrollInfoVisiblePermission\nfrom .renders import group_info_context\nfrom .viewbase import CourseModuleBaseView, CourseInstanceMixin, EnrollableViewMixin\n\n\nclass HomeView(UserProfileView):\n    access_mode = ACCESS.ANONYMOUS\n    template_name = \"course/index.html\"\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.welcome_text = settings_text('WELCOME_TEXT')\n        self.internal_user_label = settings_text('INTERNAL_USER_LABEL')\n        self.external_user_label = settings_text('EXTERNAL_USER_LABEL')\n        self.instances = []\n        prio2 = []\n        treshold = timezone.now() - datetime.timedelta(days=10)\n        for instance in CourseInstance.objects.get_visible(self.request.user)\\\n                .filter(ending_time__gte=timezone.now()):\n            if instance.starting_time > treshold:\n                self.instances += [instance]\n            else:\n                prio2 += [instance]\n        self.instances += prio2\n        self.note(\"welcome_text\", \"internal_user_label\", \"external_user_label\", \"instances\")\n\n\nclass ArchiveView(UserProfileView):\n    access_mode = ACCESS.ANONYMOUS\n    template_name = \"course/archive.html\"\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.instances = CourseInstance.objects.get_visible(self.request.user)\n        self.note(\"instances\")\n\nclass InstanceView(EnrollableViewMixin, BaseTemplateView):\n    access_mode = ACCESS.STUDENT\n    # ACCESS.STUDENT requires users to log in, but the access mode is dropped\n    # in public courses. CourseVisiblePermission has more restrictions as well.\n    template_name = \"course/course.html\"\n\n    def handle_no_permission(self):\n        if self.request.user.is_authenticated \\\n                and self.instance.view_content_to == CourseInstance.VIEW_ACCESS.ENROLLED:\n            # The course instance is visible to only enrolled students, so\n            # redirect the user to the enroll page instead of showing\n            # a 403 Forbidden error.\n            return redirect(self.instance.get_url('enroll'))\n        return super().handle_no_permission()\n\n    def get(self, request, *args, **kwargs):\n        # external LTI Tool Providers may return the user to the course instance view\n        # with a message given in GET query parameters\n        lti_error_msg = request.GET.get('lti_errormsg')\n        lti_msg = request.GET.get('lti_msg')\n        # message HTML is not escaped in the templates so escape it here\n        if lti_error_msg:\n            messages.error(request, html.escape(lti_error_msg))\n        elif lti_msg:\n            messages.info(request, html.escape(lti_msg))\n\n        return super().get(request, *args, **kwargs)\n\n\nclass Enroll(EnrollableViewMixin, BaseRedirectMixin, BaseTemplateView):\n    permission_classes = [EnrollInfoVisiblePermission]\n    course_permission_classes = []\n    template_name = \"course/enroll.html\"\n\n    def post(self, request, *args, **kwargs):\n\n        if self.is_student or not self.enrollable:\n            messages.error(self.request, _(\"You cannot enroll, or have already enrolled, in this course.\"))\n            raise PermissionDenied()\n\n        if not self.instance.is_enrollment_open():\n            messages.error(self.request, _(\"The enrollment is not open.\"))\n            raise PermissionDenied()\n\n        # Support enrollment questionnaires.\n        exercise = LearningObject.objects.find_enrollment_exercise(\n            self.instance, self.profile)\n        if exercise:\n            return self.redirect(exercise.get_absolute_url())\n\n        self.instance.enroll_student(self.request.user)\n        return self.redirect(self.instance.get_absolute_url())\n\n\nclass ModuleView(CourseModuleBaseView):\n    template_name = \"course/module.html\"\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.now = timezone.now()\n        try:\n            self.children = self.content.flat_module(self.module)\n            cur, tree, prev, nex = self.content.find(self.module)\n            self.previous = prev\n            self.current = cur\n            self.next = nex\n        except NoSuchContent:\n            raise Http404\n        self.note('now', 'children', 'previous', 'current', 'next')\n\n\nclass CalendarExport(CourseInstanceMixin, BaseView):\n\n    def get(self, request, *args, **kwargs):\n        cal = icalendar.Calendar()\n        cal.add('prodid', '-// {} calendar //'.format(settings.BRAND_NAME))\n        cal.add('version', '2.0')\n        for module in self.instance.course_modules.all():\n            event = icalendar.Event()\n            event.add('summary', module.name)\n            event.add('dtstart',\n                module.closing_time - datetime.timedelta(hours=1))\n            event.add('dtend', module.closing_time)\n            event.add('dtstamp', module.closing_time)\n            event['uid'] = \"module/\" + str(module.id) + \"/A+\"\n            cal.add_component(event)\n\n        return HttpResponse(cal.to_ical(),\n            content_type=\"text/calendar; charset=utf-8\")\n\n\nclass GroupsView(CourseInstanceMixin, BaseFormView):\n    access_mode = ACCESS.ENROLLED\n    template_name = \"course/groups.html\"\n    form_class = GroupsForm\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.enrollment = self.instance.get_enrollment_for(self.request.user)\n        self.groups = list(self.profile.groups.filter(course_instance=self.instance))\n        self.note('enrollment','groups')\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        kwargs[\"profile\"] = self.profile\n        kwargs[\"instance\"] = self.instance\n        kwargs[\"content\"] = self.content\n        return kwargs\n\n    def get_success_url(self):\n        return self.instance.get_url('groups')\n\n    def form_valid(self, form):\n        form.save()\n        messages.success(self.request, _(\"A new student group was created.\"))\n        return super().form_valid(form)\n\n\nclass GroupSelect(CourseInstanceMixin, BaseFormView):\n    access_mode = ACCESS.ENROLLED\n    form_class = GroupSelectForm\n    template_name = \"course/_group_info.html\"\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        kwargs[\"profile\"] = self.profile\n        kwargs[\"instance\"] = self.instance\n        return kwargs\n\n    def get_success_url(self):\n        return self.instance.get_absolute_url()\n\n    def get(self, request, *args, **kwargs):\n        return self.http_method_not_allowed(request, *args, **kwargs)\n\n    def form_invalid(self, form):\n        return HttpResponse('Invalid group selection')\n\n    def form_valid(self, form):\n        enrollment = form.save()\n        if self.request.is_ajax():\n            return self.render_to_response(self.get_context_data(\n                **group_info_context(enrollment.selected_group, self.profile)))\n        return super().form_valid(form)\n", "path": "course/views.py"}], "after_files": [{"content": "import datetime\n\nimport icalendar\nfrom django.conf import settings\nfrom django.contrib import messages\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import Http404\nfrom django.http.response import HttpResponse\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.utils import html\nfrom django.utils import timezone\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom authorization.permissions import ACCESS\nfrom exercise.cache.hierarchy import NoSuchContent\nfrom exercise.models import LearningObject\nfrom lib.helpers import settings_text\nfrom lib.viewbase import BaseTemplateView, BaseRedirectMixin, BaseFormView, BaseView\nfrom userprofile.viewbase import UserProfileView\nfrom .forms import GroupsForm, GroupSelectForm\nfrom .models import CourseInstance, Enrollment\nfrom .permissions import EnrollInfoVisiblePermission\nfrom .renders import group_info_context\nfrom .viewbase import CourseModuleBaseView, CourseInstanceMixin, EnrollableViewMixin\n\n\nclass HomeView(UserProfileView):\n    access_mode = ACCESS.ANONYMOUS\n    template_name = \"course/index.html\"\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.welcome_text = settings_text('WELCOME_TEXT')\n        self.internal_user_label = settings_text('INTERNAL_USER_LABEL')\n        self.external_user_label = settings_text('EXTERNAL_USER_LABEL')\n        my_instances = []\n        all_instances = []\n        end_threshold = timezone.now() - datetime.timedelta(days=30)\n        user = self.request.user\n        is_logged_in = False\n\n        if user and user.is_authenticated:\n            is_logged_in = True\n            for instance in (CourseInstance.objects\n                .filter(course__teachers=user.userprofile,\n                        ending_time__gte=end_threshold)\n                .all()):\n                my_instances.append(instance)\n\n            for instance in user.userprofile.assisting_courses.all().filter(ending_time__gte=end_threshold):\n                if instance not in my_instances:\n                    my_instances.append(instance)\n            \n            for instance in user.userprofile.enrolled.all().filter(ending_time__gte=end_threshold):\n                if instance not in my_instances:\n                    my_instances.append(instance)\n        \n        all_instances = CourseInstance.objects.get_visible(user).filter(ending_time__gte=end_threshold)\n        all_instances = [c for c in all_instances if c not in my_instances]\n        \n        self.all_instances = all_instances\n        self.my_instances = my_instances\n        self.is_logged_in = is_logged_in\n\n        self.note(\"welcome_text\", \n            \"internal_user_label\", \n            \"external_user_label\",\n            \"my_instances\",\n            \"all_instances\",\n            \"is_logged_in\",\n        )\n\n\nclass ArchiveView(UserProfileView):\n    access_mode = ACCESS.ANONYMOUS\n    template_name = \"course/archive.html\"\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.instances = CourseInstance.objects.get_visible(self.request.user)\n        self.note(\"instances\")\n\nclass InstanceView(EnrollableViewMixin, BaseTemplateView):\n    access_mode = ACCESS.STUDENT\n    # ACCESS.STUDENT requires users to log in, but the access mode is dropped\n    # in public courses. CourseVisiblePermission has more restrictions as well.\n    template_name = \"course/course.html\"\n\n    def handle_no_permission(self):\n        if self.request.user.is_authenticated \\\n                and self.instance.view_content_to == CourseInstance.VIEW_ACCESS.ENROLLED:\n            # The course instance is visible to only enrolled students, so\n            # redirect the user to the enroll page instead of showing\n            # a 403 Forbidden error.\n            return redirect(self.instance.get_url('enroll'))\n        return super().handle_no_permission()\n\n    def get(self, request, *args, **kwargs):\n        # external LTI Tool Providers may return the user to the course instance view\n        # with a message given in GET query parameters\n        lti_error_msg = request.GET.get('lti_errormsg')\n        lti_msg = request.GET.get('lti_msg')\n        # message HTML is not escaped in the templates so escape it here\n        if lti_error_msg:\n            messages.error(request, html.escape(lti_error_msg))\n        elif lti_msg:\n            messages.info(request, html.escape(lti_msg))\n\n        return super().get(request, *args, **kwargs)\n\n\nclass Enroll(EnrollableViewMixin, BaseRedirectMixin, BaseTemplateView):\n    permission_classes = [EnrollInfoVisiblePermission]\n    course_permission_classes = []\n    template_name = \"course/enroll.html\"\n\n    def post(self, request, *args, **kwargs):\n\n        if self.is_student or not self.enrollable:\n            messages.error(self.request, _(\"You cannot enroll, or have already enrolled, in this course.\"))\n            raise PermissionDenied()\n\n        if not self.instance.is_enrollment_open():\n            messages.error(self.request, _(\"The enrollment is not open.\"))\n            raise PermissionDenied()\n\n        # Support enrollment questionnaires.\n        exercise = LearningObject.objects.find_enrollment_exercise(\n            self.instance, self.profile)\n        if exercise:\n            return self.redirect(exercise.get_absolute_url())\n\n        self.instance.enroll_student(self.request.user)\n        return self.redirect(self.instance.get_absolute_url())\n\n\nclass ModuleView(CourseModuleBaseView):\n    template_name = \"course/module.html\"\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.now = timezone.now()\n        try:\n            self.children = self.content.flat_module(self.module)\n            cur, tree, prev, nex = self.content.find(self.module)\n            self.previous = prev\n            self.current = cur\n            self.next = nex\n        except NoSuchContent:\n            raise Http404\n        self.note('now', 'children', 'previous', 'current', 'next')\n\n\nclass CalendarExport(CourseInstanceMixin, BaseView):\n\n    def get(self, request, *args, **kwargs):\n        cal = icalendar.Calendar()\n        cal.add('prodid', '-// {} calendar //'.format(settings.BRAND_NAME))\n        cal.add('version', '2.0')\n        for module in self.instance.course_modules.all():\n            event = icalendar.Event()\n            event.add('summary', module.name)\n            event.add('dtstart',\n                module.closing_time - datetime.timedelta(hours=1))\n            event.add('dtend', module.closing_time)\n            event.add('dtstamp', module.closing_time)\n            event['uid'] = \"module/\" + str(module.id) + \"/A+\"\n            cal.add_component(event)\n\n        return HttpResponse(cal.to_ical(),\n            content_type=\"text/calendar; charset=utf-8\")\n\n\nclass GroupsView(CourseInstanceMixin, BaseFormView):\n    access_mode = ACCESS.ENROLLED\n    template_name = \"course/groups.html\"\n    form_class = GroupsForm\n\n    def get_common_objects(self):\n        super().get_common_objects()\n        self.enrollment = self.instance.get_enrollment_for(self.request.user)\n        self.groups = list(self.profile.groups.filter(course_instance=self.instance))\n        self.note('enrollment','groups')\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        kwargs[\"profile\"] = self.profile\n        kwargs[\"instance\"] = self.instance\n        kwargs[\"content\"] = self.content\n        return kwargs\n\n    def get_success_url(self):\n        return self.instance.get_url('groups')\n\n    def form_valid(self, form):\n        form.save()\n        messages.success(self.request, _(\"A new student group was created.\"))\n        return super().form_valid(form)\n\n\nclass GroupSelect(CourseInstanceMixin, BaseFormView):\n    access_mode = ACCESS.ENROLLED\n    form_class = GroupSelectForm\n    template_name = \"course/_group_info.html\"\n\n    def get_form_kwargs(self):\n        kwargs = super().get_form_kwargs()\n        kwargs[\"profile\"] = self.profile\n        kwargs[\"instance\"] = self.instance\n        return kwargs\n\n    def get_success_url(self):\n        return self.instance.get_absolute_url()\n\n    def get(self, request, *args, **kwargs):\n        return self.http_method_not_allowed(request, *args, **kwargs)\n\n    def form_invalid(self, form):\n        return HttpResponse('Invalid group selection')\n\n    def form_valid(self, form):\n        enrollment = form.save()\n        if self.request.is_ajax():\n            return self.render_to_response(self.get_context_data(\n                **group_info_context(enrollment.selected_group, self.profile)))\n        return super().form_valid(form)\n", "path": "course/views.py"}]}