-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathpermissions.py
169 lines (133 loc) · 6.12 KB
/
permissions.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
from django.contrib.auth.models import User
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _
from authorization.permissions import (
ACCESS,
ObjectVisibleBasePermission,
FilterBackend,
)
from course.permissions import JWTExerciseReadPermission, JWTSubmissionReadPermission
from userprofile.models import GraderUser
from .models import (
LearningObject,
BaseExercise,
Submission,
SubmittedFile,
)
class ExerciseVisiblePermissionBase(ObjectVisibleBasePermission):
message = _('EXERCISE_VISIBILITY_PERMISSION_DENIED_MSG')
model = LearningObject
obj_var = 'exercise'
def is_object_visible(self, request, view, exercise): # pylint: disable=arguments-renamed
"""
Find out if Exercise (LearningObject) is visible to user
"""
if view.is_course_staff:
return True
user = request.user
if isinstance(user, GraderUser):
return False
if exercise.status == LearningObject.STATUS.HIDDEN:
self.error_msg(_('EXERCISE_VISIBILITY_ERROR_NOT_VISIBLE'))
return False
if (
exercise.is_submittable
and not exercise.course_module.have_exercises_been_opened()
and exercise.status not in (
LearningObject.STATUS.ENROLLMENT,
LearningObject.STATUS.ENROLLMENT_EXTERNAL,
)):
self.error_msg(
format_lazy(
_('EXERCISE_VISIBILITY_ERROR_NOT_OPEN_YET -- {}'),
exercise.course_module.opening_time
)
)
return False
if exercise.audience == LearningObject.AUDIENCE.REGISTERED_USERS:
if not exercise.course_instance.is_student(user):
self.error_msg(_('EXERCISE_VISIBLITY_ERROR_ONLY_RESISTERED_USERS'))
return False
elif exercise.audience == LearningObject.AUDIENCE.INTERNAL_USERS:
if (not exercise.course_instance.is_student(user)
or user.userprofile.is_external):
self.error_msg(_('EXERCISE_VISIBLITY_ERROR_ONLY_INTERNAL_USERS'))
return False
elif exercise.audience == LearningObject.AUDIENCE.EXTERNAL_USERS:
if (not exercise.course_instance.is_student(user)
or not user.userprofile.is_external):
self.error_msg(_('EXERCISE_VISIBLITY_ERROR_ONLY_EXTERNAL_USERS'))
return False
if not exercise.can_be_shown_as_module_model_solution(user):
self.error_msg(_('MODULE_MODEL_ANSWER_VISIBILITY_PERMISSION_DENIED_MSG'))
return False
return True
ExerciseVisiblePermission = ExerciseVisiblePermissionBase | JWTExerciseReadPermission
class BaseExerciseAssistantPermission(ObjectVisibleBasePermission):
message = _('EXERCISE_ASSISTANT_PERMISSION_DENIED_MSG')
model = BaseExercise
obj_var = 'exercise'
def is_object_visible(self, request, view, exercise): # pylint: disable=arguments-renamed
"""
Make sure views that require assistant are also visible to them.
Also if view is for grading, make sure assistant is allowed to grade.
We expect that AccessModePermission is checked first
"""
access_mode = view.get_access_mode()
is_teacher = view.is_teacher
# NOTE: AccessModePermission will make sure that user
# is assistant when access_mode >= ACCESS.ASSISTANT
if access_mode >= ACCESS.ASSISTANT:
if not (is_teacher or exercise.allow_assistant_viewing):
self.error_msg(_('EXERCISE_ASSISTANT_PERMISSION_ERROR_NO_ASSISTANT_VIEWING'))
return False
if access_mode == ACCESS.GRADING:
if not (is_teacher or exercise.allow_assistant_grading):
self.error_msg(_('EXERCISE_ASSISTANT_PERMISSION_NO_ASSISTANT_GRADING'))
return False
return True
class SubmissionVisiblePermissionBase(ObjectVisibleBasePermission):
message = _('SUBMISSION_VISIBILITY_PERMISSION_DENIED_MSG')
model = Submission
obj_var = 'submission'
def is_object_visible(self, request, view, submission): # pylint: disable=arguments-renamed
if isinstance(request.user, GraderUser):
return False
if not isinstance(request.user, User) or not (view.is_teacher or
(view.is_assistant and submission.exercise.allow_assistant_viewing) or
submission.is_submitter(request.user)):
self.error_msg(_('SUBMISSION_VISIBILITY_ERROR_ONLY_SUBMITTER'))
return False
return True
SubmissionVisiblePermission = SubmissionVisiblePermissionBase | JWTSubmissionReadPermission
class SubmissionVisibleFilter(FilterBackend):
def filter_queryset(self, request, queryset, view):
user = request.user
is_super = user.is_staff or user.is_superuser
if (
issubclass(queryset.model, Submission) and
not view.is_teacher and not is_super
):
if view.is_assistant:
queryset = queryset.filter(exercise__allow_assistant_viewing=True)
else:
queryset = queryset.filter(submitters=user.userprofile)
return queryset
class SubmittedFileVisiblePermission(SubmissionVisiblePermissionBase):
model = SubmittedFile
def is_object_visible(self, request, view, file): # pylint: disable=arguments-renamed
return super().is_object_visible(request, view, file.submission)
class ModelVisiblePermission(ObjectVisibleBasePermission):
message = _('EXERCISE_MODEL_ANSWER_VISIBILITY_PERMISSION_DENIED_MSG')
model = BaseExercise
obj_var = 'exercise'
def is_object_visible(self, request, view, exercise): # pylint: disable=arguments-renamed
"""
Find out if exercise's model answer is visible to user
"""
if view.is_course_staff:
return True
if not exercise.can_show_model_solutions_to_student(request.user):
self.error_msg(_('EXERCISE_MODEL_ANSWER_VISIBILITY_ERROR_NOT_ALLOWED_VIEWING'))
return False
return True