Allow browsing user scores as admin

This commit is contained in:
Ross
2023-06-05 17:44:32 +01:00
parent fef378a2ac
commit ff00047110
6 changed files with 63 additions and 8 deletions
@@ -70,7 +70,17 @@
<th>Candidate</th> <th>Candidate</th>
{% for cid in cids %} {% for cid in cids %}
{% comment %} <th><a href="{% url exam.app_name|add:':exam_scores_cid_user' exam.pk cid %}">{{cid}}</a></th> {% endcomment %} {% comment %} <th><a href="{% url exam.app_name|add:':exam_scores_cid_user' exam.pk cid %}">{{cid}}</a></th> {% endcomment %}
<th><a href="">{{cids_user_id_map|get_item:cid}}</a></th> <th>
{% if cid|slice:":1" == "u" %}
<a href="{% url exam.app_name|add:':exam_scores_user_admin' exam.pk cid|slice:'2:' %}">
{% else %}
<a href="{% url exam.app_name|add:':exam_scores_cid_user_admin' exam.pk cid|slice:'2:' %}">
{% endif %}
{{cids_user_id_map|get_item:cid}}</a></th>
{% endfor %} {% endfor %}
</tr> </tr>
+10
View File
@@ -229,11 +229,21 @@ def generic_exam_urls(generic_exam_view: GenericExamViews):
generic_exam_view.exam_scores_cid_user, generic_exam_view.exam_scores_cid_user,
name="exam_scores_cid_user", name="exam_scores_cid_user",
), ),
path(
"exam/<int:pk>/scores/<int:cid>/",
generic_exam_view.exam_scores_cid_user_admin,
name="exam_scores_cid_user_admin",
),
path( path(
"exam/<int:pk>/scores/", "exam/<int:pk>/scores/",
generic_exam_view.exam_scores_user, generic_exam_view.exam_scores_user,
name="exam_scores_user", name="exam_scores_user",
), ),
path(
"exam/<int:pk>/scores/<int:user_id>/user",
generic_exam_view.exam_scores_user_admin,
name="exam_scores_user_admin",
),
path( path(
"exam/<int:pk>/toggle_active", "exam/<int:pk>/toggle_active",
generic_exam_view.exam_toggle_active, generic_exam_view.exam_toggle_active,
+14 -1
View File
@@ -1763,7 +1763,17 @@ class ExamViews(View, LoginRequiredMixin):
def exam_scores_user(self, request, pk): def exam_scores_user(self, request, pk):
return self.exam_scores_cid_user(request, pk) return self.exam_scores_cid_user(request, pk)
def exam_scores_cid_user(self, request, pk, cid=None, passcode=""): @method_decorator(user_passes_test(lambda u: u.is_superuser))
def exam_scores_user_admin(self, request, pk, user_id):
user = User.objects.get(id=user_id)
return self.exam_scores_cid_user(request, pk, user=user)
@method_decorator(user_passes_test(lambda u: u.is_superuser))
def exam_scores_cid_user_admin(self, request, pk, cid):
user = CidUser.objects.get(cid=cid)
return self.exam_scores_cid_user(request, pk, cid, user.passcode)
def exam_scores_cid_user(self, request, pk, cid=None, passcode="", user=None):
exam = get_object_or_404(self.Exam, pk=pk) exam = get_object_or_404(self.Exam, pk=pk)
if not exam.exam_mode: if not exam.exam_mode:
@@ -1772,6 +1782,9 @@ class ExamViews(View, LoginRequiredMixin):
if cid is not None and not exam.check_cid_user(cid, passcode, request): if cid is not None and not exam.check_cid_user(cid, passcode, request):
raise Http404("Error accessing exam") raise Http404("Error accessing exam")
if user is not None:
request.user = user
questions = ( questions = (
exam.exam_questions.all() exam.exam_questions.all()
) # .prefetch_related("cid_user_answers", "answers") ) # .prefetch_related("cid_user_answers", "answers")
+1
View File
@@ -97,6 +97,7 @@ urlpatterns = [
path("cid/<int:cid>/<str:passcode>", views.cid_scores, name="cid_scores"), path("cid/<int:cid>/<str:passcode>", views.cid_scores, name="cid_scores"),
path("cid/<int:cid>/", views.cid_scores_admin, name="cid_scores_admin"), path("cid/<int:cid>/", views.cid_scores_admin, name="cid_scores_admin"),
path("user/scores", views.user_scores, name="user_scores"), path("user/scores", views.user_scores, name="user_scores"),
path("user/scores/<int:user_id>", views.user_scores_admin, name="user_scores_admin"),
path("cid/", views.cid_selector, name="cid_selector"), path("cid/", views.cid_selector, name="cid_selector"),
path("cid/request_cid_details/", views.request_cid_details, name="request_cid_details"), path("cid/request_cid_details/", views.request_cid_details, name="request_cid_details"),
# Global url that registers RTS compatible exams # Global url that registers RTS compatible exams
+17 -4
View File
@@ -128,9 +128,17 @@ def cid_results(request, cid):
}, },
) )
@user_passes_test(lambda u: u.is_superuser)
def user_scores_admin(request, user_id):
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
raise Http404("Cid not found")
return user_scores(request, user=user)
@login_required @login_required
def user_scores(request): def user_scores(request, user=None):
# exam = get_object_or_404(Exam, pk=pk) # exam = get_object_or_404(Exam, pk=pk)
# cid = pk # cid = pk
@@ -140,6 +148,10 @@ def user_scores(request):
# if not cid_user or cid_user.passcode != passcode: # if not cid_user or cid_user.passcode != passcode:
# raise Http404("CID / Passcode combination not found") # raise Http404("CID / Passcode combination not found")
# print(cid_user.passcode) # print(cid_user.passcode)
admin = True
if user is None:
user = request.user
admin = False
# questions = exam.exam_questions.all() # questions = exam.exam_questions.all()
EXAM_ANSWER_MAP = { EXAM_ANSWER_MAP = {
@@ -154,7 +166,7 @@ def user_scores(request):
exams = [] exams = []
for exam_type in EXAM_ANSWER_MAP: for exam_type in EXAM_ANSWER_MAP:
UserAnswer, Exam = EXAM_ANSWER_MAP[exam_type] UserAnswer, Exam = EXAM_ANSWER_MAP[exam_type]
exam_answers = UserAnswer.objects.filter(user=request.user) exam_answers = UserAnswer.objects.filter(user=user)
exam_ids = exam_answers.values_list("exam").distinct() exam_ids = exam_answers.values_list("exam").distinct()
exams_to_add = Exam.objects.filter(id__in=exam_ids, **kwargs) exams_to_add = Exam.objects.filter(id__in=exam_ids, **kwargs)
if exams_to_add: if exams_to_add:
@@ -173,7 +185,7 @@ def user_scores(request):
available_exams = [] available_exams = []
for n, t in USER_EXAM_TYPES: for n, t in USER_EXAM_TYPES:
exam_rel = getattr(request.user, t) exam_rel = getattr(user, t)
if exam_rel.exists(): if exam_rel.exists():
temp_exams = exam_rel.filter(exam_mode=True, archive=False).order_by("name") temp_exams = exam_rel.filter(exam_mode=True, archive=False).order_by("name")
available_exams.append((n, temp_exams)) available_exams.append((n, temp_exams))
@@ -191,9 +203,10 @@ def user_scores(request):
# "sba_exams": sba_exams, # "sba_exams": sba_exams,
"all_exams": exams, "all_exams": exams,
# "passcode": passcode, # "passcode": passcode,
"cid_user": request.user, "cid_user": user,
"available_exams": available_exams, "available_exams": available_exams,
"case_collections": [], # case_collections, "case_collections": [], # case_collections,
"admin": admin,
}, },
) )
+10 -2
View File
@@ -2,7 +2,7 @@
{% block content %} {% block content %}
<div class=""> <div class="">
<h2>User: {{ request.user.username }}</h2> <h2>User: {{ cid_user.username }}</h2>
<h3>Assigned exams</h3> <h3>Assigned exams</h3>
<div class="alert alert-dark" role="alert"> <div class="alert alert-dark" role="alert">
<details> <details>
@@ -35,7 +35,15 @@
<h4>{{exam_type|title}}</h4> <h4>{{exam_type|title}}</h4>
<ul class='{{exam_type|lower}}'> <ul class='{{exam_type|lower}}'>
{% for exam in exams %} {% for exam in exams %}
<li class="exam" data-exam-id="{{exam.pk}}"><a href="{% url exam_type|add:':exam_scores_user' pk=exam.pk %}">{{exam.name}}</a> {% if exam.active %}[Active]{% endif %} {% if exam.publish_results %}[Results Published]{% endif %}</li> <li class="exam" data-exam-id="{{exam.pk}}">
{% if admin %}
<a href= "{% url exam_type|add:':exam_scores_user_admin' pk=exam.pk user_id=user.pk %}" >
{% else %}
<a href= "{% url exam_type|add:':exam_scores_user' pk=exam.pk %}" >
{% endif %}
{{exam.name}}</a> {% if exam.active %}[Active]{% endif %} {% if exam.publish_results %}[Results Published]{% endif %}</li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}