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