Merge branch 'master' of ssh://git.xkjq.uk:30001/ross/rad

This commit is contained in:
Ross
2021-08-08 10:11:23 +01:00
9 changed files with 72 additions and 49 deletions
+10 -10
View File
@@ -238,19 +238,19 @@ def loadJsonAnswer(answer):
if (not isinstance(answer["cid"], int)) or (
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
):
return JsonResponse({"success": False, "error": "cid or eid or answers not defined"})
return False, JsonResponse({"success": False, "error": "cid or eid or answers not defined"})
# The model should catch invalid data but this should be less intensive
max_int = 999999999999999999999
if answer["cid"] > max_int or eid > max_int:
return JsonResponse({"success": False, "error": "invalid cid"})
return False, JsonResponse({"success": False, "error": "invalid cid"})
exam = get_object_or_404(Exam, pk=eid)
if not exam.active:
return JsonResponse(
{"success": False, "error": "No active exam: {}".format(eid)}
)
#if not exam.active:
# return False, JsonResponse(
# {"success": False, "error": "No active exam: {}".format(eid)}
# )
exiting_answers = CidUserAnswer.objects.filter(
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
@@ -272,7 +272,7 @@ def loadJsonAnswer(answer):
ans.full_clean()
ans.save()
return True
return True, None
#@csrf_exempt
@@ -453,7 +453,7 @@ def exam_scores_cid(request, pk):
questions = exam.exam_questions.all()
cids = (
CidUserAnswer.objects.filter(question__in=questions)
CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
.order_by("cid")
.values_list("cid", flat=True)
.distinct()
@@ -473,7 +473,7 @@ def exam_scores_cid(request, pk):
user_names[cid] = cid
for q in questions:
# Get user answer
s = q.cid_user_answers.filter(cid=cid).first()
s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
if not s:
# skip if no answer
user_answers_marks[cid].append(0)
@@ -564,7 +564,7 @@ def exam_scores_cid_user(request, pk, sk):
for q in questions:
# Get user answer
user_answer = q.cid_user_answers.filter(cid=cid).first()
user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
if not user_answer:
# skip if no answer
answers_marks.append(0)
+19 -8
View File
@@ -157,6 +157,10 @@ class ExamViews(View, LoginRequiredMixin):
self.question_type = question_type
self.loadJsonAnswer = loadJsonAnswer
# THis may be better than check_user_access below
#group_map = {"rapids" : "rapid_checker", "anatomy" : "anatomy_checker", "longs":"long_checker"}
#exam_group = group_map[self.app_name]
def check_user_access(self, user):
"""Check if a user should be able to access a view
@@ -174,6 +178,8 @@ class ExamViews(View, LoginRequiredMixin):
return False
if self.app_name == "physics" and not user.groups.filter(name='physic_checker').exists():
return False
if self.app_name == "sbas" and not user.groups.filter(name='sba_checker').exists():
return False
return True
@@ -326,6 +332,7 @@ class ExamViews(View, LoginRequiredMixin):
questions = exam.exam_questions.all()
# TODO: fix showing unmarked answer count from other exams...
return render(
request, "{}/mark_overview.html".format(self.app_name), {"exam": exam, "questions": questions}
)
@@ -384,7 +391,7 @@ class ExamViews(View, LoginRequiredMixin):
active_exams = {"exams": []}
for exam in exams:
if exam.active:
if exam.active or self.check_user_access(request.user):
if exam.json_creation_time:
creation_time = exam.json_creation_time.isoformat()
else:
@@ -401,7 +408,8 @@ class ExamViews(View, LoginRequiredMixin):
"type": self.question_type,
"eid": "{}/{}".format(self.question_type, exam.pk),
"json_creation_time": creation_time,
"exam_json_id": exam.exam_json_id
"exam_json_id": exam.exam_json_id,
"exam_active": exam.active
}
if self.question_type == "long":
@@ -426,13 +434,15 @@ class ExamViews(View, LoginRequiredMixin):
n = 0
for answer in json.loads(request.POST.get("answers")):
ret = self.loadJsonAnswer(answer)
ret_status, ret = self.loadJsonAnswer(answer)
#if ret is not True:
# return ret
if ret:
if ret_status:
n = n + 1
else:
return ret
# print(UserAnswer.objects.filter(exam__id=q["eid"]))
# print(request.urlencode())
@@ -446,17 +456,18 @@ class ExamViews(View, LoginRequiredMixin):
"""
exam = get_object_or_404(self.Exam, pk=pk)
if not exam.active:
if not exam.active and not self.check_user_access(request.user):
raise Http404("No available exam")
exam_json = exam.get_exam_json(based=False)
#exam_json["exam_active"] = False
return JsonResponse(exam_json)
def exam_json(self, request, pk):
exam = get_object_or_404(self.Exam, pk=pk)
if not exam.active:
if not exam.active and not self.check_user_access(request.user):
raise Http404("No available exam")
@@ -504,7 +515,7 @@ class ExamViews(View, LoginRequiredMixin):
question = get_object_or_404(self.Question, pk=sk)
exam = get_object_or_404(self.Exam, pk=pk)
if not exam.active:
if not exam.active and not self.check_user_access(request.user):
raise Http404("No available exam")
@@ -520,7 +531,7 @@ class ExamViews(View, LoginRequiredMixin):
question = get_object_or_404(self.Question, pk=sk)
exam = get_object_or_404(self.Exam, pk=pk)
if not exam.active:
if not exam.active and not self.check_user_access(request.user):
raise Http404("No available exam")
return redirect("{}:question_json_unbased".format(self.app_name), pk=sk)
+3 -1
View File
@@ -32,9 +32,11 @@
<br />
{% for series in question.series.all %}
<div class="series-block">
Series {{forloop.counter0 }}:<br />
Series {{forloop.counter }}:<br />
{{series.get_block}}
</div>
{% empty %}
No series
{% endfor %}
<div>
Author(s): {{question.get_authors}}
+3 -1
View File
@@ -49,7 +49,9 @@
<button type="submit" name="next" class="save btn btn-default" title="Save answer and move to next question">Next answer</button>
<!-- <button type="submit" name="skip" class="save btn btn-default">Skip</button> -->
{% else %}
(no more answers for this question to mark)
{% if not unmarked %}
All question answers marker. <a href="{% url 'longs:mark_overview' pk=exam.pk %}">Return to marking overview</a>
{% endif %}
{% endif %}
</form>
</div>
+14 -12
View File
@@ -571,21 +571,21 @@ def loadJsonAnswer(answer):
if (not isinstance(answer["cid"], int)) or (
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
):
return JsonResponse(
return False, JsonResponse(
{"success": False, "error": "cid or eid or answers not defined"}
)
# The model should catch invalid data but this should be less intensive
max_int = 999999999999999999999
if answer["cid"] > max_int or eid > max_int:
return JsonResponse({"success": False, "error": "invalid cid"})
return False, JsonResponse({"success": False, "error": "invalid cid"})
exam = get_object_or_404(Exam, pk=eid)
if not exam.active:
return JsonResponse(
{"success": False, "error": "No active exam: {}".format(eid)}
)
#if not exam.active:
# return False, JsonResponse(
# {"success": False, "error": "No active exam: {}".format(eid)}
# )
exiting_answers = CidUserAnswer.objects.filter(
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
@@ -627,7 +627,7 @@ def loadJsonAnswer(answer):
ans.full_clean()
ans.save()
return True
return True, None
@login_required
@@ -650,7 +650,7 @@ def mark_answer(request, pk, sk, tk):
raise Http404("Exam question does not exist")
try:
answer = question.cid_user_answers.get(cid=tk)
answer = question.cid_user_answers.get(cid=tk, exam__id=pk)
except ObjectDoesNotExist:
raise Http404("User answer does not exist")
@@ -678,6 +678,8 @@ def mark_answer(request, pk, sk, tk):
if "next" in request.POST:
return redirect("longs:mark_answer", pk=pk, sk=sk, tk=next_unmarked_id)
if "save" in request.POST:
return redirect("longs:mark_answer", pk=pk, sk=sk, tk=tk)
#elif "previous" in request.POST:
# return redirect("longs:mark", pk=pk, sk=n - 1)
@@ -720,7 +722,7 @@ def mark(request, pk, sk):
raise Http404("Exam question does not exist")
user_answers = question.cid_user_answers.all()
user_answers = question.cid_user_answers.filter(exam__id=pk)
return render(
request,
@@ -742,7 +744,7 @@ def exam_scores_cid(request, pk):
questions = exam.exam_questions.all()
cids = (
CidUserAnswer.objects.filter(question__in=questions)
CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
.order_by("cid")
.values_list("cid", flat=True)
.distinct()
@@ -762,7 +764,7 @@ def exam_scores_cid(request, pk):
user_names[cid] = cid
for q in questions:
# Get user answer
s = q.cid_user_answers.filter(cid=cid).first()
s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
if not s:
# skip if no answer, (score 4)
@@ -855,7 +857,7 @@ def exam_scores_cid_user(request, pk, sk):
for q in questions:
# Get user answer
user_answer = q.cid_user_answers.filter(cid=cid).first()
user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
+7 -7
View File
@@ -245,19 +245,19 @@ def exam_take(request, pk):
def loadJsonAnswer(answer):
# As access is not restricted make sure the data appears valid
if (not isinstance(answer["cid"], int)) or (not isinstance(answer["eid"], int)):
return JsonResponse({"success": False, "error": "invalid"})
return False, JsonResponse({"success": False, "error": "invalid"})
# The model should catch invalid data but this should be less intensive
max_int = 10000000
if answer["cid"] > max_int or answer["eid"] > max_int:
return JsonResponse({"success": False})
return False, JsonResponse({"success": False})
exam = get_object_or_404(Exam, pk=answer["eid"])
if not exam.active:
return JsonResponse(
{"success": False, "error": "No active exam: {}".format(answer["eid"])}
)
#if not exam.active:
# return False, JsonResponse(
# {"success": False, "error": "No active exam: {}".format(answer["eid"])}
# )
questions = defaultdict(dict)
@@ -296,6 +296,6 @@ def loadJsonAnswer(answer):
ans.full_clean()
ans.save()
return True
return True, None
PhysicsExamViews = ExamViews(Exam, Question, "physics", "physics", loadJsonAnswer)
+5
View File
@@ -131,6 +131,11 @@ def active_exams(request):
active_exams = {"exams": exams}
if request.user:
active_exams["user"] = request.user.username
else:
active_exams["user"] = False
return JsonResponse(active_exams)
def active_exams_unbased(request):
+10 -10
View File
@@ -580,21 +580,21 @@ def loadJsonAnswer(answer):
if (not isinstance(answer["cid"], int)) or (
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
):
return JsonResponse(
return False, JsonResponse(
{"success": False, "error": "cid or eid or answers not defined"}
)
# The model should catch invalid data but this should be less intensive
max_int = 999999999999999999999
if answer["cid"] > max_int or eid > max_int:
return JsonResponse({"success": False, "error": "invalid cid"})
return False, JsonResponse({"success": False, "error": "invalid cid"})
exam = get_object_or_404(Exam, pk=eid)
if not exam.active:
return JsonResponse(
{"success": False, "error": "No active exam: {}".format(eid)}
)
#if not exam.active:
# return False, JsonResponse(
# {"success": False, "error": "No active exam: {}".format(eid)}
# )
exiting_answers = CidUserAnswer.objects.filter(
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
@@ -631,7 +631,7 @@ def loadJsonAnswer(answer):
ans.full_clean()
ans.save()
return True
return True, None
# @user_passes_test(user_is_admin, login_url="/accounts/login")
@@ -787,7 +787,7 @@ def exam_scores_cid(request, pk):
questions = exam.exam_questions.all()
cids = (
CidUserAnswer.objects.filter(question__in=questions)
CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
.order_by("cid")
.values_list("cid", flat=True)
.distinct()
@@ -807,7 +807,7 @@ def exam_scores_cid(request, pk):
user_names[cid] = cid
for q in questions:
# Get user answer
s = q.cid_user_answers.filter(cid=cid).first()
s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
if not s:
# skip if no answer
@@ -901,7 +901,7 @@ def exam_scores_cid_user(request, pk, sk):
for q in questions:
# Get user answer
user_answer = q.cid_user_answers.filter(cid=cid).first()
user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
if not user_answer or user_answer is None:
# skip if no answer
+1
View File
@@ -16,4 +16,5 @@
{% if request.user.is_staff %}<a href="{% url 'admin:index'%}">Admin</a>{% endif %}
</div>
<p>A radiology resource</p>
<p><a href="http://www.penracourses.org.uk/rts">RTS is available here</a></p>
{% endblock %}