start allowing user candidates in longs
This commit is contained in:
+8
-17
@@ -354,7 +354,9 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
|
||||
# We give some users the ability to filter by authors
|
||||
class ExtraExamFilter(BasicExamFilter):
|
||||
author = ModelMultipleChoiceFilter(queryset=User.objects.all(), null_label="No author")
|
||||
author = ModelMultipleChoiceFilter(
|
||||
queryset=User.objects.all(), null_label="No author"
|
||||
)
|
||||
|
||||
self.ExtraExamFilter = ExtraExamFilter
|
||||
|
||||
@@ -476,7 +478,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
def exam_toggle_archived(self, request, pk):
|
||||
print("TOGGLE ARCHIVED", request.POST)
|
||||
if request.method == "POST":
|
||||
|
||||
if not self.check_user_edit_access(request.user):
|
||||
data = {"status": "error, insufficient permission"}
|
||||
return JsonResponse(data, status=400)
|
||||
@@ -500,7 +501,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
@method_decorator(login_required)
|
||||
def exam_toggle_results_published(self, request, pk):
|
||||
if request.method == "POST":
|
||||
|
||||
if not self.check_user_edit_access(request.user):
|
||||
data = {"status": "error, insufficient permission"}
|
||||
return JsonResponse(data, status=400)
|
||||
@@ -525,7 +525,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
@method_decorator(login_required)
|
||||
def exam_toggle_active(self, request, pk):
|
||||
if request.method == "POST":
|
||||
|
||||
if not self.check_user_edit_access(request.user):
|
||||
data = {"status": "error, insufficient permission"}
|
||||
return JsonResponse(data, status=400)
|
||||
@@ -576,7 +575,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
|
||||
@method_decorator(login_required)
|
||||
def exam_list(self, request, all=False):
|
||||
|
||||
if not self.check_user_access(request.user):
|
||||
# raise PermissionDenied
|
||||
exam_list = self.Exam.objects.filter(author__id=request.user.id).order_by(
|
||||
@@ -1041,7 +1039,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
@method_decorator(login_required)
|
||||
def exam_json_edit(self, request, pk):
|
||||
if request.method == "POST":
|
||||
|
||||
if request.user.groups.filter(name="cid_user_manager").exists():
|
||||
# This may give more permissions than we actually want
|
||||
pass
|
||||
@@ -1236,7 +1233,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
|
||||
@method_decorator(login_required)
|
||||
def index(self, request):
|
||||
|
||||
# self.check_user_access(request.user, exam.pk)
|
||||
|
||||
if (
|
||||
@@ -1260,7 +1256,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
exams = self.Exam.objects.filter(author__id=request.user.id)
|
||||
filter = self.BasicExamFilter(request.GET, queryset=exams)
|
||||
|
||||
|
||||
return render(
|
||||
request,
|
||||
"generic/exam_index.html",
|
||||
@@ -1382,7 +1377,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
@method_decorator(csrf_exempt)
|
||||
def post_exam_answers(self, request):
|
||||
if request.method == "POST":
|
||||
|
||||
n = 0
|
||||
|
||||
for answer in json.loads(request.POST.get("answers")):
|
||||
@@ -1444,7 +1438,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
|
||||
match self.app_name:
|
||||
case "rapids":
|
||||
|
||||
# Normal answers are just posted with the answer "Normal"
|
||||
normal = False
|
||||
if posted_answer == "Normal":
|
||||
@@ -1566,7 +1559,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
return self.exam_json_unbased(request, pk, cid, passcode)
|
||||
|
||||
def exam_json(self, request, pk, cid=None, passcode=None):
|
||||
|
||||
exam: ExamBase = get_object_or_404(self.Exam, pk=pk)
|
||||
|
||||
# Check access (for logged in users when inactive)
|
||||
@@ -1643,7 +1635,11 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
"""
|
||||
exam: ExamBase = get_object_or_404(self.Exam, pk=pk)
|
||||
|
||||
if exam.exam_mode and not exam.active and not self.check_user_access(request.user, pk):
|
||||
if (
|
||||
exam.exam_mode
|
||||
and not exam.active
|
||||
and not self.check_user_access(request.user, pk)
|
||||
):
|
||||
raise Http404("No available exam")
|
||||
|
||||
# Check access for users
|
||||
@@ -1719,7 +1715,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
if not exam.check_cid_user(cid, passcode, request, user_id):
|
||||
raise Http404("No available exam")
|
||||
|
||||
|
||||
return redirect("{}:question_json_unbased".format(self.app_name), pk=sk)
|
||||
redirect()
|
||||
|
||||
@@ -1823,7 +1818,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
}
|
||||
|
||||
if self.normalise_score is not None:
|
||||
|
||||
normalised_score = self.normalise_score(total_score)
|
||||
template_context["normalised_score"] = normalised_score
|
||||
|
||||
@@ -1948,7 +1942,6 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
user_scores_normalised = {}
|
||||
user_answer_count = {}
|
||||
for user in user_answers_marks:
|
||||
|
||||
if self.app_name in ("rapids", "anatomy", "sbas"):
|
||||
user_scores[user] = sum(
|
||||
[i for i in user_answers_marks[user] if i != "unmarked"]
|
||||
@@ -2364,7 +2357,6 @@ def users_bulk_delete_supervisors(request):
|
||||
|
||||
@user_is_cid_user_manager
|
||||
def users_bulk_edit_grade(request):
|
||||
|
||||
if request.htmx.trigger == "bulk-edit-grade-button":
|
||||
user_grades = UserGrades.objects.all()
|
||||
|
||||
@@ -2848,7 +2840,6 @@ def create_user(request, context=None):
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
user_profile = UserProfile.objects.get(user=new_user)
|
||||
user_profile.peninsula_trainee = True
|
||||
|
||||
|
||||
@@ -885,6 +885,18 @@ class CidUserAnswer(models.Model):
|
||||
def get_absolute_url(self):
|
||||
return reverse("longs:user_answer_view", kwargs={"pk": self.pk})
|
||||
|
||||
def get_candidate_name(self) -> str:
|
||||
if self.cid is not None:
|
||||
return str(self.cid)
|
||||
else:
|
||||
return self.user.username
|
||||
|
||||
def get_candidate_masked(self) -> str:
|
||||
if self.cid is not None:
|
||||
return str(self.cid)
|
||||
else:
|
||||
return str(self.user.id)
|
||||
|
||||
|
||||
@reversion.register
|
||||
class AnswerMarks(models.Model):
|
||||
|
||||
@@ -38,22 +38,22 @@
|
||||
|
||||
{% if not next_unmarked_id and not unmarked %}
|
||||
<div class="alert alert-info sticky-alert" role="alert">Success! Marking question complete. <br />
|
||||
<a href="{% url 'longs:mark_answer_override' exam_id=exam.pk question_number=question_details.current|add:'-1' cid=cid %}">Set final score</a><br/>
|
||||
<a href="{% url 'longs:mark_answer_override' exam_id=exam.pk question_number=question_details.current|add:'-1' answer_id=answer.id %}">Set final score</a><br/>
|
||||
Return to <a href="{% url 'longs:mark_question_overview' exam.id question_details.current|add:'-1' %}">question
|
||||
overview</a>, <a href="{% url 'longs:mark_overview' pk=exam.pk %}">marking
|
||||
overview</a><br />
|
||||
{% if previous_cid %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' cid=previous_cid %}">Previous
|
||||
{% if previous_answer_id %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' answer_id=previous_answer_id %}">Previous
|
||||
candidate</a>
|
||||
{% endif %}
|
||||
{% if next_cid %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' cid=next_cid %}">Next
|
||||
{% if next_answer_id %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' answer_id=next_answer_id %}">Next
|
||||
candidate</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<span>Marking CID: {{answer.cid}} ({{unmarked|length}} answer(s) left to mark)</span>
|
||||
<span>Marking Candidate: {{answer.get_candidate_masked}} ({{unmarked|length}} answer(s) left to mark)</span>
|
||||
<details closed>
|
||||
<summary title="click to view/hide the question details">Question Details</summary>
|
||||
<p class="pre-whitespace"><b>Description:</b> {{ question.description }}</p>
|
||||
@@ -125,11 +125,11 @@
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
{% if previous_cid %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' cid=previous_cid %}">Previous
|
||||
{% if previous_answer_id %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' answer_id=previous_answer_id %}">Previous
|
||||
candidate</a>
|
||||
{% endif %}
|
||||
{% if next_cid %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' cid=next_cid %}">Next candidate</a>
|
||||
{% if next_answer_id %}
|
||||
<a href="{% url 'longs:mark_answer' exam_id=exam.pk question_number=question_details.current|add:'-1' answer_id=next_answer_id %}">Next candidate</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<ul>
|
||||
{% for answer in user_answers %}
|
||||
<li>
|
||||
<a href="{% url 'longs:mark_answer' exam.id question_details.current|add:'-1' answer.cid %}"
|
||||
<a href="{% url 'longs:mark_answer' exam.id question_details.current|add:'-1' answer.id %}"
|
||||
title="Click to mark"> {{answer.cid}}</a>:
|
||||
Score {{answer.get_answer_score}} [Markers: {{answer.get_markers}}] [Scores: {{answer.get_mark_scores}}]
|
||||
{% if answer.discrepant_answers %}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<ul>
|
||||
{% for answer in user_answers %}
|
||||
<li>
|
||||
<a href="{% url 'longs:mark_answer' exam.id question_details.current|add:'-1' answer.cid %}"
|
||||
title="Click to mark"> {{answer.cid}}</a>:
|
||||
<a href="{% url 'longs:mark_answer' exam.id question_details.current|add:'-1' answer.id %}"
|
||||
title="Click to mark"> {{answer.get_candidate_masked}}</a>:
|
||||
{% if answer.is_marked %}
|
||||
Score {{answer.get_answer_score}}
|
||||
{% else %}
|
||||
|
||||
+2
-2
@@ -68,12 +68,12 @@ urlpatterns = [
|
||||
name="question_review",
|
||||
),
|
||||
path(
|
||||
"exam/<int:exam_id>/<int:question_number>/<int:cid>/mark",
|
||||
"exam/<int:exam_id>/<int:question_number>/<int:answer_id>/mark",
|
||||
views.mark_answer,
|
||||
name="mark_answer",
|
||||
),
|
||||
path(
|
||||
"exam/<int:exam_id>/<int:question_number>/<int:cid>/mark_override",
|
||||
"exam/<int:exam_id>/<int:question_number>/<int:answer_id>/mark_override",
|
||||
views.mark_answer_override,
|
||||
name="mark_answer_override",
|
||||
),
|
||||
|
||||
+27
-23
@@ -625,7 +625,7 @@ def mark_answer_override(request, exam_id, question_number, cid):
|
||||
|
||||
@user_is_long_marker
|
||||
@reversion.create_revision()
|
||||
def mark_answer(request, exam_id, question_number, cid, override=False):
|
||||
def mark_answer(request, exam_id, question_number, answer_id, override=False):
|
||||
exam = get_object_or_404(Exam, pk=exam_id)
|
||||
|
||||
questions = exam.exam_questions.all()
|
||||
@@ -643,25 +643,29 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
|
||||
raise Http404("Exam question does not exist")
|
||||
|
||||
try:
|
||||
answer = question.cid_user_answers.get(cid=cid, exam__id=exam_id)
|
||||
answer = question.cid_user_answers.get(pk=answer_id)
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404("User answer does not exist")
|
||||
|
||||
cid_list = list(
|
||||
question.cid_user_answers.filter(exam__id=exam_id).values_list("cid", flat=True)
|
||||
answer_list = list(
|
||||
question.cid_user_answers.filter(exam__id=exam_id).values_list("id", flat=True)
|
||||
)
|
||||
|
||||
previous_cid = False
|
||||
next_cid = False
|
||||
answer_list.sort()
|
||||
print(answer_list)
|
||||
|
||||
if len(cid_list) > 1:
|
||||
if cid_list[0] == cid:
|
||||
next_cid = cid_list[1]
|
||||
elif cid_list[-1] == cid:
|
||||
previous_cid = cid_list[-2]
|
||||
previous_answer_id = False
|
||||
next_answer_id = False
|
||||
|
||||
if len(answer_list) > 1:
|
||||
if answer_list[0] == answer_id:
|
||||
next_answer_id = answer_list[1]
|
||||
elif answer_list[-1] == answer_id:
|
||||
previous_answer_id = answer_list[-2]
|
||||
else:
|
||||
next_cid = cid_list[cid_list.index(cid) + 1]
|
||||
previous_cid = cid_list[cid_list.index(cid) - 1]
|
||||
print(answer_list.index(answer_id))
|
||||
next_answer_id = answer_list[answer_list.index(answer_id) + 1]
|
||||
previous_answer_id = answer_list[answer_list.index(answer_id) - 1]
|
||||
|
||||
try:
|
||||
if exam.double_mark:
|
||||
@@ -670,9 +674,9 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
|
||||
)
|
||||
else:
|
||||
unmarked = question.get_unmarked_user_answers(exam_pk=exam.id)
|
||||
next_unmarked_id = unmarked[0].cid
|
||||
if next_unmarked_id == cid:
|
||||
next_unmarked_id = unmarked[1].cid
|
||||
next_unmarked_id = unmarked[0].id
|
||||
if next_unmarked_id == answer_id:
|
||||
next_unmarked_id = unmarked[1].id
|
||||
except IndexError:
|
||||
next_unmarked_id = False
|
||||
|
||||
@@ -699,14 +703,14 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
|
||||
"longs:mark_answer",
|
||||
exam_id=exam_id,
|
||||
question_number=question_number,
|
||||
cid=next_unmarked_id,
|
||||
answer_id=next_unmarked_id,
|
||||
)
|
||||
if "save" in request.POST:
|
||||
return redirect(
|
||||
"longs:mark_answer",
|
||||
exam_id=exam_id,
|
||||
question_number=question_number,
|
||||
cid=cid,
|
||||
answer_id=answer_id,
|
||||
)
|
||||
# elif "previous" in request.POST:
|
||||
# return redirect("longs:mark_question_overview", pk=exam_id, sk=n - 1)
|
||||
@@ -749,14 +753,14 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
|
||||
"longs:mark_answer",
|
||||
exam_id=exam_id,
|
||||
question_number=question_number,
|
||||
cid=next_unmarked_id,
|
||||
answer_id=next_unmarked_id,
|
||||
)
|
||||
if "save" in request.POST:
|
||||
return redirect(
|
||||
"longs:mark_answer",
|
||||
exam_id=exam_id,
|
||||
question_number=question_number,
|
||||
cid=cid,
|
||||
answer_id=answer_id,
|
||||
)
|
||||
# elif "previous" in request.POST:
|
||||
# return redirect("longs:mark_question_overview", pk=exam_id, sk=n - 1)
|
||||
@@ -797,9 +801,9 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
|
||||
"question_details": question_details,
|
||||
"next_unmarked_id": next_unmarked_id,
|
||||
"unmarked": unmarked,
|
||||
"previous_cid": previous_cid,
|
||||
"next_cid": next_cid,
|
||||
"cid": cid,
|
||||
"previous_answer_id": previous_answer_id,
|
||||
"next_answer_id": next_answer_id,
|
||||
"answer_id": answer_id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user