From ff00047110b1ecc1d01f311693d48f676804007b Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 5 Jun 2023 17:44:32 +0100 Subject: [PATCH] Allow browsing user scores as admin --- .../templates/generic/exam_scores_base.html | 12 ++++++++++- generic/urls.py | 10 +++++++++ generic/views.py | 15 ++++++++++++- rad/urls.py | 1 + rad/views.py | 21 +++++++++++++++---- templates/user_scores.html | 12 +++++++++-- 6 files changed, 63 insertions(+), 8 deletions(-) diff --git a/generic/templates/generic/exam_scores_base.html b/generic/templates/generic/exam_scores_base.html index c8c663be..22443086 100644 --- a/generic/templates/generic/exam_scores_base.html +++ b/generic/templates/generic/exam_scores_base.html @@ -70,7 +70,17 @@ Candidate {% for cid in cids %} {% comment %} {{cid}} {% endcomment %} - {{cids_user_id_map|get_item:cid}} + + + {% if cid|slice:":1" == "u" %} + + {% else %} + + + + {% endif %} + + {{cids_user_id_map|get_item:cid}} {% endfor %} diff --git a/generic/urls.py b/generic/urls.py index c059ae17..ebaed53c 100755 --- a/generic/urls.py +++ b/generic/urls.py @@ -229,11 +229,21 @@ def generic_exam_urls(generic_exam_view: GenericExamViews): generic_exam_view.exam_scores_cid_user, name="exam_scores_cid_user", ), + path( + "exam//scores//", + generic_exam_view.exam_scores_cid_user_admin, + name="exam_scores_cid_user_admin", + ), path( "exam//scores/", generic_exam_view.exam_scores_user, name="exam_scores_user", ), + path( + "exam//scores//user", + generic_exam_view.exam_scores_user_admin, + name="exam_scores_user_admin", + ), path( "exam//toggle_active", generic_exam_view.exam_toggle_active, diff --git a/generic/views.py b/generic/views.py index a979fb87..68467d69 100644 --- a/generic/views.py +++ b/generic/views.py @@ -1763,7 +1763,17 @@ class ExamViews(View, LoginRequiredMixin): def exam_scores_user(self, 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) 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): raise Http404("Error accessing exam") + if user is not None: + request.user = user + questions = ( exam.exam_questions.all() ) # .prefetch_related("cid_user_answers", "answers") diff --git a/rad/urls.py b/rad/urls.py index a1e93057..92bb6dc1 100644 --- a/rad/urls.py +++ b/rad/urls.py @@ -97,6 +97,7 @@ urlpatterns = [ path("cid//", views.cid_scores, name="cid_scores"), path("cid//", views.cid_scores_admin, name="cid_scores_admin"), path("user/scores", views.user_scores, name="user_scores"), + path("user/scores/", views.user_scores_admin, name="user_scores_admin"), path("cid/", views.cid_selector, name="cid_selector"), path("cid/request_cid_details/", views.request_cid_details, name="request_cid_details"), # Global url that registers RTS compatible exams diff --git a/rad/views.py b/rad/views.py index b0fec171..2b613a4c 100644 --- a/rad/views.py +++ b/rad/views.py @@ -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 -def user_scores(request): +def user_scores(request, user=None): # exam = get_object_or_404(Exam, pk=pk) # cid = pk @@ -140,6 +148,10 @@ def user_scores(request): # if not cid_user or cid_user.passcode != passcode: # raise Http404("CID / Passcode combination not found") # print(cid_user.passcode) + admin = True + if user is None: + user = request.user + admin = False # questions = exam.exam_questions.all() EXAM_ANSWER_MAP = { @@ -154,7 +166,7 @@ def user_scores(request): exams = [] for exam_type in EXAM_ANSWER_MAP: 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() exams_to_add = Exam.objects.filter(id__in=exam_ids, **kwargs) if exams_to_add: @@ -173,7 +185,7 @@ def user_scores(request): available_exams = [] for n, t in USER_EXAM_TYPES: - exam_rel = getattr(request.user, t) + exam_rel = getattr(user, t) if exam_rel.exists(): temp_exams = exam_rel.filter(exam_mode=True, archive=False).order_by("name") available_exams.append((n, temp_exams)) @@ -191,9 +203,10 @@ def user_scores(request): # "sba_exams": sba_exams, "all_exams": exams, # "passcode": passcode, - "cid_user": request.user, + "cid_user": user, "available_exams": available_exams, "case_collections": [], # case_collections, + "admin": admin, }, ) diff --git a/templates/user_scores.html b/templates/user_scores.html index 8a3d7e9b..845a5096 100644 --- a/templates/user_scores.html +++ b/templates/user_scores.html @@ -2,7 +2,7 @@ {% block content %}
-

User: {{ request.user.username }}

+

User: {{ cid_user.username }}

Assigned exams