We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Error: view object has no attribute 'redirect'
We have seen this error in the server logs a lot recently. Any internal server error is bad and implies that users end up suddenly on a crash page (HTTP 500 Internal server error). This must be looked into.

```
Internal Server Error: /COURSEKEY/COURSEINSTANCEKEY/toc/

AttributeError at /COURSEKEY/COURSEINSTANCEKEY/toc/
'TableOfContentsView' object has no attribute 'redirect'
```

This occurs on multiple courses (at least, I saw many errors on the courses Y1 and TRAK Y) and on multiple views. `TableOfContentsView` has been common there, but several other view classes have been named in the error logs, at least the following:

* SubmissionView
* ResultsView
* LanguageView
* ModuleView

--- 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/viewbase.py`
Content:
```
1 from django.contrib import messages
2 from django.core.exceptions import PermissionDenied
3 from django.http import Http404
4 from django.shortcuts import get_object_or_404, redirect, render
5 from django.utils import translation
6 from django.utils.translation import gettext_lazy as _
7 from django.utils.translation import get_language, get_language_info
8 
9 from authorization.permissions import ACCESS
10 from exercise.cache.content import CachedContent
11 from lib.helpers import remove_query_param_from_url, update_url_params
12 from lib.viewbase import BaseTemplateView
13 from userprofile.viewbase import UserProfileMixin
14 from exercise.models import LearningObject
15 from .cache.students import CachedStudent
16 from .exceptions import TranslationNotFound
17 from .permissions import (
18     CourseVisiblePermission,
19     CourseModulePermission,
20 )
21 from .models import Course, CourseInstance, CourseModule, UserTagging, Enrollment
22 
23 
24 class CourseMixin(UserProfileMixin):
25     course_kw = "course_slug"
26 
27     def get_resource_objects(self):
28         super().get_resource_objects()
29         self.course = get_object_or_404(
30             Course,
31             url=self._get_kwarg(self.course_kw)
32         )
33         self.note("course")
34 
35 
36 class CourseBaseView(CourseMixin, BaseTemplateView):
37     pass
38 
39 
40 class CourseInstanceBaseMixin(object):
41     course_kw = CourseMixin.course_kw
42     instance_kw = "instance_slug"
43     course_permission_classes = (
44         CourseVisiblePermission,
45     )
46 
47     def get_permissions(self):
48         perms = super().get_permissions()
49         perms.extend((Perm() for Perm in self.course_permission_classes))
50         return perms
51 
52     # get_course_instance_object
53 
54     def get_resource_objects(self):
55         super().get_resource_objects()
56         user = self.request.user
57         instance = self.get_course_instance_object()
58         if instance is not None:
59             self.instance = instance
60             self.course = self.instance.course
61             self.content = CachedContent(self.instance)
62             self.user_course_data = None
63             is_real_user = user.is_authenticated and not user.is_anonymous
64             if is_real_user:
65                 self.user_course_data = self.instance.get_enrollment_for(user)
66             self.is_student = self.instance.is_student(user)
67             self.is_assistant = self.instance.is_assistant(user)
68             self.is_teacher = self.instance.is_teacher(user)
69             self.is_course_staff = self.is_teacher or self.is_assistant
70             self.get_taggings = lambda: CachedStudent(instance, user.id).data['tag_slugs']
71             self.url_without_language = remove_query_param_from_url(self.request.get_full_path(), 'hl')
72             self.query_language = None
73             self.user_language = None
74 
75             self.note(
76                 "course", "instance", "content", "user_course_data", "is_student", "is_assistant",
77                 "is_teacher", "is_course_staff", "get_taggings", "url_without_language",
78                 "query_language", "user_language"
79             )
80 
81             # Try to find a language that is defined for this course instance
82             # and apply it
83             if self.instance.language:
84                 instance_languages = self.instance.language.strip('|').split('|')
85                 instance_def_language = instance_languages[0]
86                 instance_languages = set(instance_languages)
87 
88                 languages = []
89                 if self.user_course_data and self.user_course_data.language:
90                     languages.append(self.user_course_data.language)
91                 if is_real_user and user.userprofile.language:
92                     languages.append(user.userprofile.language)
93                 languages.append(get_language())
94 
95                 query_language = self.request.GET.get('hl')
96                 if query_language:
97                     if query_language[:2] in instance_languages:
98                         language = query_language
99                         if languages:
100                             self.user_language = languages[0]
101                             if self.user_language[:2] != query_language[:2]:
102                                 self.query_language = query_language
103                     else:
104                         raise TranslationNotFound
105                 else:
106                     for lang in languages:
107                         if lang[:2] in instance_languages:
108                             language = lang
109                             break
110                     else:
111                         language = instance_def_language
112 
113                 language = language[:2]
114                 # Override request.LANGUAGE_CODE. It is set in lib/middleware.py
115                 # (class LocaleMiddleware) based on the userprofile.language.
116                 # The middleware can not easily access the course context and
117                 # the language from the enrollment. That is fixed here.
118                 self.request.LANGUAGE_CODE = language
119                 translation.activate(language)
120 
121     def get_access_mode(self):
122         access_mode = super().get_access_mode()
123 
124         if hasattr(self, 'instance'):
125             # Loosen the access mode if instance is public
126             show_for = self.instance.view_content_to
127             is_public = show_for == CourseInstance.VIEW_ACCESS.PUBLIC
128             access_mode_student = access_mode in (ACCESS.STUDENT, ACCESS.ENROLL)
129             if is_public and access_mode_student:
130                 access_mode = ACCESS.ANONYMOUS
131 
132         return access_mode
133 
134     def handle_exception(self, exc):
135         if isinstance(exc, TranslationNotFound):
136             instance_languages = self.instance.language.strip("|").split("|")
137             url = remove_query_param_from_url(self.request.get_full_path(), 'hl')
138             for i, lang in enumerate(instance_languages):
139                 instance_languages[i] = {"name": get_language_info(lang)['name'], "url": update_url_params(url, {'hl' : lang})}
140             return render(self.request, '404.html', {'error_msg': str(exc), 'languages': instance_languages}, status=404)
141         return super().handle_exception(exc)
142 
143 class CourseInstanceMixin(CourseInstanceBaseMixin, UserProfileMixin):
144     def get_course_instance_object(self) -> CourseInstance:
145         return get_object_or_404(
146             CourseInstance.objects.prefetch_related('tabs'),
147             url=self.kwargs[self.instance_kw],
148             course__url=self.kwargs[self.course_kw],
149         )
150 
151     def handle_no_permission(self):
152         if (self.request.user.is_authenticated
153                 and not self.is_student
154                 and not self.is_course_staff
155                 and self.get_access_mode() in [ACCESS.STUDENT, ACCESS.ENROLLED]
156                 and self.instance.view_content_to == CourseInstance.VIEW_ACCESS.ENROLLED):
157             # Redirect the user to the enrollment page instead of showing
158             # a 403 Forbidden error, if:
159             # - the user is signed in but not enrolled or staff
160             # - the page is not a teacher page (e.g. edit course)
161             # - the course is visible only to enrolled students
162             #
163             # If SIS enrollment is applied and course requires enrollment questionnaire,
164             # redirect to the questionnaire instead.
165             enrollment = self.user_course_data
166             if enrollment and enrollment.status == Enrollment.ENROLLMENT_STATUS.PENDING:
167                 exercise = LearningObject.objects.find_enrollment_exercise(
168                     self.instance, self.profile.is_external)
169                 if exercise:
170                     return self.redirect(exercise.get_absolute_url())
171             return redirect(self.instance.get_url('enroll'))
172         return super().handle_no_permission()
173 
174 
175 class CourseInstanceBaseView(CourseInstanceMixin, BaseTemplateView):
176     pass
177 
178 
179 class EnrollableViewMixin(CourseInstanceMixin):
180     access_mode = ACCESS.ENROLL
181 
182     def get_common_objects(self):
183         self.enrolled = self.is_student
184         self.enrollable = (
185             self.profile
186             and self.instance.is_enrollable(self.profile.user)
187         )
188         self.note('enrolled', 'enrollable')
189 
190 
191 class CourseModuleBaseMixin(object):
192     module_kw = "module_slug"
193     module_permissions_classes = (
194         CourseModulePermission,
195     )
196 
197     def get_permissions(self):
198         perms = super().get_permissions()
199         perms.extend((Perm() for Perm in self.module_permissions_classes))
200         return perms
201 
202     # get_course_module_object
203 
204     def get_resource_objects(self):
205         super().get_resource_objects()
206         self.module = self.get_course_module_object()
207         self.note("module")
208 
209 
210 class CourseModuleMixin(CourseModuleBaseMixin, CourseInstanceMixin):
211     def get_course_module_object(self):
212         return get_object_or_404(
213             CourseModule,
214             url=self.kwargs[self.module_kw],
215             course_instance=self.instance
216         )
217 
218 
219 class CourseModuleBaseView(CourseModuleMixin, BaseTemplateView):
220     pass
221
```
--- 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/viewbase.py b/course/viewbase.py
--- a/course/viewbase.py
+++ b/course/viewbase.py
@@ -167,7 +167,7 @@
                 exercise = LearningObject.objects.find_enrollment_exercise(
                     self.instance, self.profile.is_external)
                 if exercise:
-                    return self.redirect(exercise.get_absolute_url())
+                    return redirect(exercise.get_absolute_url())
             return redirect(self.instance.get_url('enroll'))
         return super().handle_no_permission()

{"golden_diff": "diff --git a/course/viewbase.py b/course/viewbase.py\n--- a/course/viewbase.py\n+++ b/course/viewbase.py\n@@ -167,7 +167,7 @@\n                 exercise = LearningObject.objects.find_enrollment_exercise(\n                     self.instance, self.profile.is_external)\n                 if exercise:\n-                    return self.redirect(exercise.get_absolute_url())\n+                    return redirect(exercise.get_absolute_url())\n             return redirect(self.instance.get_url('enroll'))\n         return super().handle_no_permission()\n", "issue": "Error: view object has no attribute 'redirect'\nWe have seen this error in the server logs a lot recently. Any internal server error is bad and implies that users end up suddenly on a crash page (HTTP 500 Internal server error). This must be looked into.\r\n\r\n```\r\nInternal Server Error: /COURSEKEY/COURSEINSTANCEKEY/toc/\r\n\r\nAttributeError at /COURSEKEY/COURSEINSTANCEKEY/toc/\r\n'TableOfContentsView' object has no attribute 'redirect'\r\n```\r\n\r\nThis occurs on multiple courses (at least, I saw many errors on the courses Y1 and TRAK Y) and on multiple views. `TableOfContentsView` has been common there, but several other view classes have been named in the error logs, at least the following:\r\n\r\n* SubmissionView\r\n* ResultsView\r\n* LanguageView\r\n* ModuleView\n", "before_files": [{"content": "from django.contrib import messages\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import Http404\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.utils import translation\nfrom django.utils.translation import gettext_lazy as _\nfrom django.utils.translation import get_language, get_language_info\n\nfrom authorization.permissions import ACCESS\nfrom exercise.cache.content import CachedContent\nfrom lib.helpers import remove_query_param_from_url, update_url_params\nfrom lib.viewbase import BaseTemplateView\nfrom userprofile.viewbase import UserProfileMixin\nfrom exercise.models import LearningObject\nfrom .cache.students import CachedStudent\nfrom .exceptions import TranslationNotFound\nfrom .permissions import (\n    CourseVisiblePermission,\n    CourseModulePermission,\n)\nfrom .models import Course, CourseInstance, CourseModule, UserTagging, Enrollment\n\n\nclass CourseMixin(UserProfileMixin):\n    course_kw = \"course_slug\"\n\n    def get_resource_objects(self):\n        super().get_resource_objects()\n        self.course = get_object_or_404(\n            Course,\n            url=self._get_kwarg(self.course_kw)\n        )\n        self.note(\"course\")\n\n\nclass CourseBaseView(CourseMixin, BaseTemplateView):\n    pass\n\n\nclass CourseInstanceBaseMixin(object):\n    course_kw = CourseMixin.course_kw\n    instance_kw = \"instance_slug\"\n    course_permission_classes = (\n        CourseVisiblePermission,\n    )\n\n    def get_permissions(self):\n        perms = super().get_permissions()\n        perms.extend((Perm() for Perm in self.course_permission_classes))\n        return perms\n\n    # get_course_instance_object\n\n    def get_resource_objects(self):\n        super().get_resource_objects()\n        user = self.request.user\n        instance = self.get_course_instance_object()\n        if instance is not None:\n            self.instance = instance\n            self.course = self.instance.course\n            self.content = CachedContent(self.instance)\n            self.user_course_data = None\n            is_real_user = user.is_authenticated and not user.is_anonymous\n            if is_real_user:\n                self.user_course_data = self.instance.get_enrollment_for(user)\n            self.is_student = self.instance.is_student(user)\n            self.is_assistant = self.instance.is_assistant(user)\n            self.is_teacher = self.instance.is_teacher(user)\n            self.is_course_staff = self.is_teacher or self.is_assistant\n            self.get_taggings = lambda: CachedStudent(instance, user.id).data['tag_slugs']\n            self.url_without_language = remove_query_param_from_url(self.request.get_full_path(), 'hl')\n            self.query_language = None\n            self.user_language = None\n\n            self.note(\n                \"course\", \"instance\", \"content\", \"user_course_data\", \"is_student\", \"is_assistant\",\n                \"is_teacher\", \"is_course_staff\", \"get_taggings\", \"url_without_language\",\n                \"query_language\", \"user_language\"\n            )\n\n            # Try to find a language that is defined for this course instance\n            # and apply it\n            if self.instance.language:\n                instance_languages = self.instance.language.strip('|').split('|')\n                instance_def_language = instance_languages[0]\n                instance_languages = set(instance_languages)\n\n                languages = []\n                if self.user_course_data and self.user_course_data.language:\n                    languages.append(self.user_course_data.language)\n                if is_real_user and user.userprofile.language:\n                    languages.append(user.userprofile.language)\n                languages.append(get_language())\n\n                query_language = self.request.GET.get('hl')\n                if query_language:\n                    if query_language[:2] in instance_languages:\n                        language = query_language\n                        if languages:\n                            self.user_language = languages[0]\n                            if self.user_language[:2] != query_language[:2]:\n                                self.query_language = query_language\n                    else:\n                        raise TranslationNotFound\n                else:\n                    for lang in languages:\n                        if lang[:2] in instance_languages:\n                            language = lang\n                            break\n                    else:\n                        language = instance_def_language\n\n                language = language[:2]\n                # Override request.LANGUAGE_CODE. It is set in lib/middleware.py\n                # (class LocaleMiddleware) based on the userprofile.language.\n                # The middleware can not easily access the course context and\n                # the language from the enrollment. That is fixed here.\n                self.request.LANGUAGE_CODE = language\n                translation.activate(language)\n\n    def get_access_mode(self):\n        access_mode = super().get_access_mode()\n\n        if hasattr(self, 'instance'):\n            # Loosen the access mode if instance is public\n            show_for = self.instance.view_content_to\n            is_public = show_for == CourseInstance.VIEW_ACCESS.PUBLIC\n            access_mode_student = access_mode in (ACCESS.STUDENT, ACCESS.ENROLL)\n            if is_public and access_mode_student:\n                access_mode = ACCESS.ANONYMOUS\n\n        return access_mode\n\n    def handle_exception(self, exc):\n        if isinstance(exc, TranslationNotFound):\n            instance_languages = self.instance.language.strip(\"|\").split(\"|\")\n            url = remove_query_param_from_url(self.request.get_full_path(), 'hl')\n            for i, lang in enumerate(instance_languages):\n                instance_languages[i] = {\"name\": get_language_info(lang)['name'], \"url\": update_url_params(url, {'hl' : lang})}\n            return render(self.request, '404.html', {'error_msg': str(exc), 'languages': instance_languages}, status=404)\n        return super().handle_exception(exc)\n\nclass CourseInstanceMixin(CourseInstanceBaseMixin, UserProfileMixin):\n    def get_course_instance_object(self) -> CourseInstance:\n        return get_object_or_404(\n            CourseInstance.objects.prefetch_related('tabs'),\n            url=self.kwargs[self.instance_kw],\n            course__url=self.kwargs[self.course_kw],\n        )\n\n    def handle_no_permission(self):\n        if (self.request.user.is_authenticated\n                and not self.is_student\n                and not self.is_course_staff\n                and self.get_access_mode() in [ACCESS.STUDENT, ACCESS.ENROLLED]\n                and self.instance.view_content_to == CourseInstance.VIEW_ACCESS.ENROLLED):\n            # Redirect the user to the enrollment page instead of showing\n            # a 403 Forbidden error, if:\n            # - the user is signed in but not enrolled or staff\n            # - the page is not a teacher page (e.g. edit course)\n            # - the course is visible only to enrolled students\n            #\n            # If SIS enrollment is applied and course requires enrollment questionnaire,\n            # redirect to the questionnaire instead.\n            enrollment = self.user_course_data\n            if enrollment and enrollment.status == Enrollment.ENROLLMENT_STATUS.PENDING:\n                exercise = LearningObject.objects.find_enrollment_exercise(\n                    self.instance, self.profile.is_external)\n                if exercise:\n                    return self.redirect(exercise.get_absolute_url())\n            return redirect(self.instance.get_url('enroll'))\n        return super().handle_no_permission()\n\n\nclass CourseInstanceBaseView(CourseInstanceMixin, BaseTemplateView):\n    pass\n\n\nclass EnrollableViewMixin(CourseInstanceMixin):\n    access_mode = ACCESS.ENROLL\n\n    def get_common_objects(self):\n        self.enrolled = self.is_student\n        self.enrollable = (\n            self.profile\n            and self.instance.is_enrollable(self.profile.user)\n        )\n        self.note('enrolled', 'enrollable')\n\n\nclass CourseModuleBaseMixin(object):\n    module_kw = \"module_slug\"\n    module_permissions_classes = (\n        CourseModulePermission,\n    )\n\n    def get_permissions(self):\n        perms = super().get_permissions()\n        perms.extend((Perm() for Perm in self.module_permissions_classes))\n        return perms\n\n    # get_course_module_object\n\n    def get_resource_objects(self):\n        super().get_resource_objects()\n        self.module = self.get_course_module_object()\n        self.note(\"module\")\n\n\nclass CourseModuleMixin(CourseModuleBaseMixin, CourseInstanceMixin):\n    def get_course_module_object(self):\n        return get_object_or_404(\n            CourseModule,\n            url=self.kwargs[self.module_kw],\n            course_instance=self.instance\n        )\n\n\nclass CourseModuleBaseView(CourseModuleMixin, BaseTemplateView):\n    pass\n", "path": "course/viewbase.py"}], "after_files": [{"content": "from django.contrib import messages\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import Http404\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom django.utils import translation\nfrom django.utils.translation import gettext_lazy as _\nfrom django.utils.translation import get_language, get_language_info\n\nfrom authorization.permissions import ACCESS\nfrom exercise.cache.content import CachedContent\nfrom lib.helpers import remove_query_param_from_url, update_url_params\nfrom lib.viewbase import BaseTemplateView\nfrom userprofile.viewbase import UserProfileMixin\nfrom exercise.models import LearningObject\nfrom .cache.students import CachedStudent\nfrom .exceptions import TranslationNotFound\nfrom .permissions import (\n    CourseVisiblePermission,\n    CourseModulePermission,\n)\nfrom .models import Course, CourseInstance, CourseModule, UserTagging, Enrollment\n\n\nclass CourseMixin(UserProfileMixin):\n    course_kw = \"course_slug\"\n\n    def get_resource_objects(self):\n        super().get_resource_objects()\n        self.course = get_object_or_404(\n            Course,\n            url=self._get_kwarg(self.course_kw)\n        )\n        self.note(\"course\")\n\n\nclass CourseBaseView(CourseMixin, BaseTemplateView):\n    pass\n\n\nclass CourseInstanceBaseMixin(object):\n    course_kw = CourseMixin.course_kw\n    instance_kw = \"instance_slug\"\n    course_permission_classes = (\n        CourseVisiblePermission,\n    )\n\n    def get_permissions(self):\n        perms = super().get_permissions()\n        perms.extend((Perm() for Perm in self.course_permission_classes))\n        return perms\n\n    # get_course_instance_object\n\n    def get_resource_objects(self):\n        super().get_resource_objects()\n        user = self.request.user\n        instance = self.get_course_instance_object()\n        if instance is not None:\n            self.instance = instance\n            self.course = self.instance.course\n            self.content = CachedContent(self.instance)\n            self.user_course_data = None\n            is_real_user = user.is_authenticated and not user.is_anonymous\n            if is_real_user:\n                self.user_course_data = self.instance.get_enrollment_for(user)\n            self.is_student = self.instance.is_student(user)\n            self.is_assistant = self.instance.is_assistant(user)\n            self.is_teacher = self.instance.is_teacher(user)\n            self.is_course_staff = self.is_teacher or self.is_assistant\n            self.get_taggings = lambda: CachedStudent(instance, user.id).data['tag_slugs']\n            self.url_without_language = remove_query_param_from_url(self.request.get_full_path(), 'hl')\n            self.query_language = None\n            self.user_language = None\n\n            self.note(\n                \"course\", \"instance\", \"content\", \"user_course_data\", \"is_student\", \"is_assistant\",\n                \"is_teacher\", \"is_course_staff\", \"get_taggings\", \"url_without_language\",\n                \"query_language\", \"user_language\"\n            )\n\n            # Try to find a language that is defined for this course instance\n            # and apply it\n            if self.instance.language:\n                instance_languages = self.instance.language.strip('|').split('|')\n                instance_def_language = instance_languages[0]\n                instance_languages = set(instance_languages)\n\n                languages = []\n                if self.user_course_data and self.user_course_data.language:\n                    languages.append(self.user_course_data.language)\n                if is_real_user and user.userprofile.language:\n                    languages.append(user.userprofile.language)\n                languages.append(get_language())\n\n                query_language = self.request.GET.get('hl')\n                if query_language:\n                    if query_language[:2] in instance_languages:\n                        language = query_language\n                        if languages:\n                            self.user_language = languages[0]\n                            if self.user_language[:2] != query_language[:2]:\n                                self.query_language = query_language\n                    else:\n                        raise TranslationNotFound\n                else:\n                    for lang in languages:\n                        if lang[:2] in instance_languages:\n                            language = lang\n                            break\n                    else:\n                        language = instance_def_language\n\n                language = language[:2]\n                # Override request.LANGUAGE_CODE. It is set in lib/middleware.py\n                # (class LocaleMiddleware) based on the userprofile.language.\n                # The middleware can not easily access the course context and\n                # the language from the enrollment. That is fixed here.\n                self.request.LANGUAGE_CODE = language\n                translation.activate(language)\n\n    def get_access_mode(self):\n        access_mode = super().get_access_mode()\n\n        if hasattr(self, 'instance'):\n            # Loosen the access mode if instance is public\n            show_for = self.instance.view_content_to\n            is_public = show_for == CourseInstance.VIEW_ACCESS.PUBLIC\n            access_mode_student = access_mode in (ACCESS.STUDENT, ACCESS.ENROLL)\n            if is_public and access_mode_student:\n                access_mode = ACCESS.ANONYMOUS\n\n        return access_mode\n\n    def handle_exception(self, exc):\n        if isinstance(exc, TranslationNotFound):\n            instance_languages = self.instance.language.strip(\"|\").split(\"|\")\n            url = remove_query_param_from_url(self.request.get_full_path(), 'hl')\n            for i, lang in enumerate(instance_languages):\n                instance_languages[i] = {\"name\": get_language_info(lang)['name'], \"url\": update_url_params(url, {'hl' : lang})}\n            return render(self.request, '404.html', {'error_msg': str(exc), 'languages': instance_languages}, status=404)\n        return super().handle_exception(exc)\n\nclass CourseInstanceMixin(CourseInstanceBaseMixin, UserProfileMixin):\n    def get_course_instance_object(self) -> CourseInstance:\n        return get_object_or_404(\n            CourseInstance.objects.prefetch_related('tabs'),\n            url=self.kwargs[self.instance_kw],\n            course__url=self.kwargs[self.course_kw],\n        )\n\n    def handle_no_permission(self):\n        if (self.request.user.is_authenticated\n                and not self.is_student\n                and not self.is_course_staff\n                and self.get_access_mode() in [ACCESS.STUDENT, ACCESS.ENROLLED]\n                and self.instance.view_content_to == CourseInstance.VIEW_ACCESS.ENROLLED):\n            # Redirect the user to the enrollment page instead of showing\n            # a 403 Forbidden error, if:\n            # - the user is signed in but not enrolled or staff\n            # - the page is not a teacher page (e.g. edit course)\n            # - the course is visible only to enrolled students\n            #\n            # If SIS enrollment is applied and course requires enrollment questionnaire,\n            # redirect to the questionnaire instead.\n            enrollment = self.user_course_data\n            if enrollment and enrollment.status == Enrollment.ENROLLMENT_STATUS.PENDING:\n                exercise = LearningObject.objects.find_enrollment_exercise(\n                    self.instance, self.profile.is_external)\n                if exercise:\n                    return redirect(exercise.get_absolute_url())\n            return redirect(self.instance.get_url('enroll'))\n        return super().handle_no_permission()\n\n\nclass CourseInstanceBaseView(CourseInstanceMixin, BaseTemplateView):\n    pass\n\n\nclass EnrollableViewMixin(CourseInstanceMixin):\n    access_mode = ACCESS.ENROLL\n\n    def get_common_objects(self):\n        self.enrolled = self.is_student\n        self.enrollable = (\n            self.profile\n            and self.instance.is_enrollable(self.profile.user)\n        )\n        self.note('enrolled', 'enrollable')\n\n\nclass CourseModuleBaseMixin(object):\n    module_kw = \"module_slug\"\n    module_permissions_classes = (\n        CourseModulePermission,\n    )\n\n    def get_permissions(self):\n        perms = super().get_permissions()\n        perms.extend((Perm() for Perm in self.module_permissions_classes))\n        return perms\n\n    # get_course_module_object\n\n    def get_resource_objects(self):\n        super().get_resource_objects()\n        self.module = self.get_course_module_object()\n        self.note(\"module\")\n\n\nclass CourseModuleMixin(CourseModuleBaseMixin, CourseInstanceMixin):\n    def get_course_module_object(self):\n        return get_object_or_404(\n            CourseModule,\n            url=self.kwargs[self.module_kw],\n            course_instance=self.instance\n        )\n\n\nclass CourseModuleBaseView(CourseModuleMixin, BaseTemplateView):\n    pass\n", "path": "course/viewbase.py"}]}