-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathutils.py
More file actions
191 lines (155 loc) · 6.27 KB
/
utils.py
File metadata and controls
191 lines (155 loc) · 6.27 KB
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
"""
A collection of helper methods and classes
"""
from django.core.exceptions import PermissionDenied
from django.db.models import Count, Q
from django.http import JsonResponse
from django.utils.translation import ugettext_lazy as _
from rest_framework import routers
from ..cms.models import Discipline, GroupAPIKey, Document
from ..cms.utils import get_child_count, document_to_string
class OptionalSlashRouter(routers.DefaultRouter):
"""
Custom router to allow routes with and without trailing slash to work without redirects
"""
def __init__(self):
super().__init__()
self.trailing_slash = "/?"
def get_key(request, keyword="Api-Key"):
"""Retrieve API Key from Authorization header of http request.
Optionally, a custom keyword can be specified. The function
espects the key to be delivered as follows:
{"Authorization": "<keyword> <api-key>}
:param request: get request
:type request: HttpRequest
:param keyword: keyword for api key in authorization header, defaults to "Api-Key"
:type keyword: str, optional
:return: api key in authorization header
:rtype: str
"""
authorization = request.META.get("HTTP_AUTHORIZATION")
if not authorization:
return None
try:
_, key = authorization.split(f"{keyword} ")
except ValueError:
key = None
return key
def get_filtered_discipline_queryset(discipline_view_set):
"""
Returns child disciplines belonging to the discipline id
of the passed discipline view set. Only released and non-empty
objects are returned. The number of training sets contained by
a child is annotated as well.
:param discipline_view_set: A handle to the :class:`DisciplineViewSet`
:type discipline_view_set: class
:return: (filtered) queryset
:rtype: QuerySet
"""
queryset = Discipline.objects.filter(
Q(released=True)
& Q(
id__in=Discipline.objects.get(
id=discipline_view_set.kwargs["discipline_id"]
).get_children()
)
).annotate(
total_training_sets=Count(
"training_sets", filter=Q(training_sets__released=True)
),
)
queryset = get_non_empty_disciplines(queryset)
return queryset
def get_overview_discipline_queryset():
"""Returns the general disciplines created by super users if the are
root nodes and recursively either has at least one sub-discipline or one
training set. Additionally, they need to be released by the creator group.
:return: (filtered) queryset
:rtype: QuerySet
"""
queryset = Discipline.objects.filter(
Q(released=True) & Q(creator_is_admin=True)
).annotate(
total_training_sets=Count(
"training_sets", filter=Q(training_sets__released=True)
),
)
queryset = [obj for obj in queryset if obj.is_root_node()]
queryset = get_non_empty_disciplines(queryset)
return queryset
def get_discipline_by_group_queryset(discipline_view_set):
"""Returns overview of disciplines for a given group id, which must be
in the keyword arguments of the passed discipline view set. All elements are
root nodes and recursively either have at least one sub-discipline or one
training set. Additionally, they need to be released by the creator group.
:param discipline_view_set: A handle to the :class:`DisciplineViewSet`
:type discipline_view_set: class
:return: (filtered) queryset
:rtype: QuerySet
"""
queryset = Discipline.objects.filter(
released=True, created_by=discipline_view_set.kwargs["group_id"]
).annotate(
total_training_sets=Count(
"training_sets", filter=Q(training_sets__released=True)
),
)
queryset = [obj for obj in queryset if obj.is_root_node() and obj.is_valid()]
return queryset
def get_non_empty_disciplines(queryset):
"""
Filters a discipline queryset so that every element recursively either have
at least one sub-discipline or one training set.
:param queryset: Queryset of `~lunes_cms.cms.models.Discipline` objects
:type queryset: QuerySet
:return: (filtered) queryset
:rtype: QuerySet
"""
queryset = [
obj
for obj in queryset
if get_child_count(obj) > 0
or obj.training_sets.filter(released=True).count() > 0
]
return queryset
def check_group_object_permissions(request, group_id):
"""Function to check if the API-Key of the passed request object
matches one of the hashed keys stored in the database of the
corresponding group id.
:param request: current request
:type request: HttpRequest
:param group_id: group id
:type group_id: str
:raises PermissionDenied: Exception if no API-Key is delivered
:raises PermissionDenied: Exception if API-Key doesn't belong to passed group id
"""
key = get_key(request)
api_key_object = GroupAPIKey.get_from_token(key)
if api_key_object.group_id != int(group_id):
raise PermissionDenied()
def find_duplicates_for_word(request, word):
"""
Function to find existing words that match the input in the "word" field of document
:param request: current request
:type request: HttpRequest
:param group_id: input in the "word"field of document
:type group_id: str
:return: Whether any duplicate was found, and some details of the word if found
:rtype: JsonResponse
"""
if duplicate := Document.objects.filter(word=word).first():
training_sets_description = _("This word is assigned to no training set.")
if training_sets := duplicate.training_sets.all():
training_sets_description = ", ".join(
str(training_set) for training_set in training_sets
)
result = {
"message": _("This word is already registered in the system."),
"word": document_to_string(duplicate) + " (" + duplicate.word_type + ")",
"definition": _("Definition: ") + duplicate.definition
if duplicate.definition
else _("Definition: ") + _("No definition is provided for this word."),
"training_sets": _("Training sets: ") + training_sets_description,
}
return JsonResponse(result)
return JsonResponse({"message": _("This word is not yet registered in the system")})