allow supervisors to view shared exams

This commit is contained in:
Ross
2024-11-04 15:18:04 +00:00
parent eab6fc9d7e
commit 80358e2113
4 changed files with 120 additions and 36 deletions
+80 -27
View File
@@ -79,6 +79,7 @@ from .forms import (
from .models import (
CidUser,
CidUserExam,
CidUserGroup,
ExamBase,
ExamCollection,
@@ -171,27 +172,34 @@ class CidManagerRequiredMixin(UserPassesTestMixin):
def get_user_exams(user, supervisor_view=False):
EXAM_ANSWER_MAP = {
"physics": (PhysicsUserAnswer, PhysicsExam),
"anatomy": (AnatomyUserAnswer, AnatomyExam),
"rapids": (RapidsUserAnswer, RapidsExam),
"longs": (LongsUserAnswer, LongsExam),
"sbas": (SbasUserAnswer, SbasExam),
"physics": (PhysicsUserAnswer, PhysicsExam, "physics_exams"),
"anatomy": (AnatomyUserAnswer, AnatomyExam, "anatomy_exams"),
"rapids": (RapidsUserAnswer, RapidsExam, "rapids_exams"),
"longs": (LongsUserAnswer, LongsExam, "longs_exams"),
"sbas": (SbasUserAnswer, SbasExam, "sbas_exams"),
}
kwargs = {
"exam_mode": True,
"archive": False
}
kwargs = {"exam_mode": True, "archive": False}
exams = []
if supervisor_view:
kwargs["results_supervisor_visible"] = True
del kwargs["archive"]
exams = []
for exam_type in EXAM_ANSWER_MAP:
UserAnswer, Exam = EXAM_ANSWER_MAP[exam_type]
UserAnswer, Exam, cid_rel = EXAM_ANSWER_MAP[exam_type]
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 supervisor_view:
extra_exam_ids = CidUserExam.objects.filter(
user_user=user,
share_with_supervisor=True,
content_type=ContentType.objects.get_for_model(Exam),
).values_list(cid_rel)
exams_to_add = exams_to_add | Exam.objects.filter(id__in=extra_exam_ids)
if exams_to_add:
exams.append((exam_type, exams_to_add))
@@ -528,7 +536,11 @@ class ExamViews(View, LoginRequiredMixin):
if (exam.open_access and exam.active) or user in exam.get_author_objects():
return True
if user.is_authenticated and exam.active and exam.cid_user_exam.filter(user_user=user):
if (
user.is_authenticated
and exam.active
and exam.cid_user_exam.filter(user_user=user)
):
return True
if marker and user in exam.markers.all():
@@ -2091,14 +2103,18 @@ class ExamViews(View, LoginRequiredMixin):
if not request.user.supervisor == user.userprofile.supervisor:
raise PermissionDenied
return self.exam_scores_cid_user(request, pk, user=user, supervisor=user.userprofile.supervisor.user)
return self.exam_scores_cid_user(
request, pk, user=user, supervisor=user.userprofile.supervisor.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, supervisor=None):
def exam_scores_cid_user(
self, request, pk, cid=None, passcode="", user=None, supervisor=None
):
exam: ExamBase = get_object_or_404(self.Exam, pk=pk)
if not exam.exam_mode:
@@ -2110,11 +2126,11 @@ class ExamViews(View, LoginRequiredMixin):
if supervisor is None:
if not exam.check_cid_user(cid, passcode, request.user):
#TODO clear this up
# TODO clear this up
# Should users be able to access results for exams they do not have access to (if they have results)?
if not self.check_user_access(request.user, pk):
# raise PermissionDenied
#if request.user.supervisor == user.userprofile.supervisor:
# if request.user.supervisor == user.userprofile.supervisor:
# pass
# check for supervisor access
@@ -2122,10 +2138,10 @@ class ExamViews(View, LoginRequiredMixin):
else:
if user is None:
raise Exception("user must be defined")
view_all_results = True
view_all_results = True
if user is not None:
request.user = user
if user is None:
user = request.user
questions = (
exam.get_questions()
@@ -2142,7 +2158,6 @@ class ExamViews(View, LoginRequiredMixin):
answers_marks = []
answers = []
for q in questions:
# Get user answer
if cid is not None:
@@ -2238,6 +2253,8 @@ class ExamViews(View, LoginRequiredMixin):
max_score = len(questions)
cid_user_exam = exam.cid_user_exam.filter(user_user=user).first()
print(user)
print(f"{cid_user_exam=}")
template_context = {
"exam": exam,
@@ -3829,8 +3846,7 @@ def supervisor_overview(request, pk):
if not request.user.supervisor == supervisor:
raise PermissionDenied()
except Supervisor.RelatedObjectDoesNotExist:
raise PermissionDenied()
raise PermissionDenied()
trainees = User.objects.filter(userprofile__supervisor=supervisor)
@@ -3849,7 +3865,7 @@ def supervisor_trainee(request, pk, trainee_id):
if not request.user.supervisor == supervisor:
raise PermissionDenied()
except Supervisor.RelatedObjectDoesNotExist:
raise PermissionDenied()
raise PermissionDenied()
# We do this to check that the supervisor can (should) see the trainee results
trainee = User.objects.get(userprofile__supervisor=supervisor, pk=trainee_id)
@@ -3866,6 +3882,7 @@ def supervisor_trainee(request, pk, trainee_id):
{"supervisor": supervisor, "trainee": trainee, "all_exams": exams},
)
def supervisor_request_account(request):
if request.method == "POST":
email = request.POST.get("email")
@@ -3878,9 +3895,14 @@ def supervisor_request_account(request):
supervisor = Supervisor.objects.get(email=email)
except Supervisor.DoesNotExist:
return HttpResponse(f"Invalid email address ({email})")
if supervisor.user:
return HttpResponse(format_html("User already exists. Reset your password <a href='{}'>here</a>", reverse("password_reset")))
return HttpResponse(
format_html(
"User already exists. Reset your password <a href='{}'>here</a>",
reverse("password_reset"),
)
)
try:
user_account = User.objects.get(email=email)
@@ -3891,13 +3913,44 @@ def supervisor_request_account(request):
first, last = supervisor.name.split(" ", 1)
except ValueError:
first, last = supervisor.name, ""
user_account = User.objects.create_user(email=email, username=email, password=secrets.token_hex(nbytes=16), first_name=first, last_name=last)
user_account = User.objects.create_user(
email=email,
username=email,
password=secrets.token_hex(nbytes=16),
first_name=first,
last_name=last,
)
supervisor.user = user_account
supervisor.save()
return HttpResponse(format_html("Account created, you now need to reset your password <a href='{}'>here</a>", reverse("password_reset")))
return HttpResponse(
format_html(
"Account created, you now need to reset your password <a href='{}'>here</a>",
reverse("password_reset"),
)
)
else:
return render(request, "generic/supervisor_request_account.html", {})
def toggle_share_with_supervisor(request, pk):
if request.htmx:
cid_user_exam = get_object_or_404(CidUserExam, pk=pk)
print(request.user)
print(cid_user_exam)
print(cid_user_exam.user_user)
if request.user != cid_user_exam.user_user:
return HttpResponse("Incorrect permissions")
cid_user_exam.share_with_supervisor = not cid_user_exam.share_with_supervisor
cid_user_exam.save()
return HttpResponse(
f"Shared with supervisor: {cid_user_exam.share_with_supervisor}"
)
else:
raise PermissionDenied()