numerous improvements
This commit is contained in:
+15
-1
@@ -136,6 +136,9 @@ class AnatomyQuestion(models.Model):
|
||||
|
||||
return unmarked_answers
|
||||
|
||||
def GetUnmarkedAnswerCount(self):
|
||||
return len(self.GetUnmarkedAnswers())
|
||||
|
||||
def GetMarkedAnswers(self):
|
||||
return set([i.get_compare_string() for i in self.answers.all() if i.status != i.MarkOptions.UNMARKED])
|
||||
correct_answers = set([i.answer.lower() for i in self.answers.all()])
|
||||
@@ -289,4 +292,15 @@ class CidUserAnswer(models.Model):
|
||||
self.answer.strip()
|
||||
|
||||
def get_compare_string(self):
|
||||
return self.answer.lower()
|
||||
return self.answer.lower()
|
||||
|
||||
def get_answer_score(self):
|
||||
q = self.question
|
||||
ans = self.answer
|
||||
if q.answers.filter(answer__iexact=ans, status=Answer.MarkOptions.CORRECT).first() is not None:
|
||||
mark = 2
|
||||
elif q.answers.filter(answer__iexact=ans, status=Answer.MarkOptions.HALF_MARK).first() is not None:
|
||||
mark = 1
|
||||
else:
|
||||
mark = 0
|
||||
return mark
|
||||
@@ -3,6 +3,10 @@ body {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
a, a:link {
|
||||
color: #3282b8;
|
||||
}
|
||||
|
||||
.warn {
|
||||
color: red;
|
||||
}
|
||||
@@ -107,4 +111,16 @@ button a {
|
||||
|
||||
.marking {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#question-mark-list {
|
||||
padding: 20px
|
||||
}
|
||||
|
||||
#question-mark-list a {
|
||||
color: #bbe1fa
|
||||
}
|
||||
|
||||
#question-mark-list li {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
@@ -82,6 +82,20 @@ cornerstone.loadAndCacheImage(imageId).then(function(image) {
|
||||
});
|
||||
}
|
||||
|
||||
if ($("#question-mark-list").length) {
|
||||
$(".show-all-button").click(() => {
|
||||
$("#question-mark-list li").show();
|
||||
});
|
||||
$(".show-unmarked-button").click(() => {
|
||||
console.log("TESTIG");
|
||||
$("#question-mark-list li").each((n, el) => {
|
||||
console.log(el);
|
||||
if (el.dataset.markcount < 1) { $(el).hide(); }
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function prepAnswerData() {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{% extends 'anatomy/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="anatomy">
|
||||
<h2>CID: {{ cid }}</h2>
|
||||
The following exams have been found (click to view answers and scores):
|
||||
<ul>
|
||||
{% for exam in exams %}
|
||||
<li><a href="{% url 'anatomy:exam_scores_cid_user' pk=exam.pk sk=cid %}">{{exam.name}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -6,6 +6,10 @@
|
||||
<div class="anatomy">
|
||||
<h1>Exam: {{ exam.name }}</h1>
|
||||
This exam has {{question_number}} questions.
|
||||
|
||||
<div title="Click to enable / disable the exam">
|
||||
Exam active: <input type="checkbox" id="exam-active-switch" {% if exam.active %}checked{% endif %}>
|
||||
</div>
|
||||
<p><button><a href="{% url 'anatomy:mark_overview' pk=exam.pk %}">Mark exam</a></button></p>
|
||||
<!--<p><button><a href="{% url 'anatomy:exam_take' pk=exam.pk sk=0 %}">Click here to start</a></button></p>-->
|
||||
|
||||
@@ -22,4 +26,29 @@ Exams: {{ question.GetExams }} / Modality: {{ question.modality }}
|
||||
<a href="{% url 'anatomy:exam_json_recreate' pk=exam.pk %}">Refresh JSON cache</a>
|
||||
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// send request to change the is_private state on customSwitches toggle
|
||||
$("#exam-active-switch").on("change", function() {
|
||||
$.ajax({
|
||||
url: "{% url 'anatomy:exam_toggle_active' pk=exam.pk %}",
|
||||
data: {
|
||||
csrfmiddlewaretoken: "{{ csrf_token }}",
|
||||
active: this.checked // true if checked else false
|
||||
},
|
||||
type: "POST",
|
||||
dataType : "json",
|
||||
})
|
||||
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
|
||||
.done(function(data) {
|
||||
console.log(data);
|
||||
// show some message according to the response.
|
||||
// For eg. A message box showing that the status has been changed
|
||||
})
|
||||
.always(function() {
|
||||
console.log('[Done]');
|
||||
})
|
||||
})
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'anatomy/exams.html' %}
|
||||
{% extends 'anatomy/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="anatomy">
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
{% block content %}
|
||||
<div class="anatomy">
|
||||
<h2>Marking exam: {{ exam.name }}</h2>
|
||||
Question order will be different on the test system (as it is randomly generated)
|
||||
Question order may be different on the test system (as json order is not guaranteed to be maintained)
|
||||
|
||||
<ul>
|
||||
<div>
|
||||
<button class="show-all-button">Show all</button><button class="show-unmarked-button">Show unmarked</button>
|
||||
</div>
|
||||
|
||||
<ul id="question-mark-list">
|
||||
{% for question in questions.all %}
|
||||
<li><a href="{% url 'anatomy:mark' pk=exam.pk sk=forloop.counter0 %}">Question {{forloop.counter }}:
|
||||
<li data-markcount={{question.GetUnmarkedAnswerCount}}><a href="{% url 'anatomy:mark' pk=exam.pk sk=forloop.counter0 %}">Question {{forloop.counter }}:
|
||||
{{ question }}</a><br /> {{ question.GetUnmarkedAnswersString }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
@@ -18,10 +18,12 @@ urlpatterns = [
|
||||
name="exam_scores_cid"),
|
||||
path("exam/<int:pk>/scores/<int:sk>/", views.exam_scores_cid_user,
|
||||
name="exam_scores_cid_user"),
|
||||
path("exam/<int:pk>/toggle_active", views.exam_toggle_active, name="exam_toggle_active"),
|
||||
path("exam/submit", views.postExamAnswers, name="exam_answers_submit"),
|
||||
path("exam/", views.exam_list, name="exam_list"),
|
||||
path("exam/json/", views.active_exams, name="active_exams"),
|
||||
path("exam/json/<int:pk>", views.exam_json, name="exam_json"),
|
||||
path("exam/json/<int:pk>/recreate", views.exam_json_recreate, name="exam_json_recreate"),
|
||||
path("cid/<int:pk>/scores", views.cid_scores, name="cid_scores"),
|
||||
path("ajax/exam/flag/", views.flag_question, name="flag_question"),
|
||||
]
|
||||
|
||||
+54
-34
@@ -436,6 +436,18 @@ def mark(request, pk, sk):
|
||||
},
|
||||
)
|
||||
|
||||
def exam_toggle_active(request, pk):
|
||||
if request.is_ajax() and request.method=='POST':
|
||||
|
||||
exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
exam.active = True if request.POST.get('active') == 'true' else False
|
||||
exam.save()
|
||||
data = {'status':'success', 'active':exam.active}
|
||||
return JsonResponse(data, status=200)
|
||||
else:
|
||||
data = {'status':'error'}
|
||||
return JsonResponse(data, status=400)
|
||||
|
||||
def active_exams(request):
|
||||
exams = Exam.objects.all()
|
||||
@@ -602,24 +614,21 @@ def exam_scores_cid_user(request, pk, sk):
|
||||
|
||||
for q in questions:
|
||||
# Get user answer
|
||||
s = q.cid_user_answers.filter(cid=cid)
|
||||
if not s:
|
||||
user_answer = q.cid_user_answers.filter(cid=cid).first()
|
||||
if not user_answer:
|
||||
# skip if no answer
|
||||
answers_marks.append(0)
|
||||
answers.append("")
|
||||
continue
|
||||
|
||||
ans = s[0].answer
|
||||
if q.answers.filter(answer__iexact=ans, status=Answer.MarkOptions.CORRECT).first() is not None:
|
||||
a = 2
|
||||
elif q.answers.filter(answer__iexact=ans, status=Answer.MarkOptions.HALF_MARK).first() is not None:
|
||||
a = 1
|
||||
else:
|
||||
a = 0
|
||||
ans = user_answer.answer
|
||||
|
||||
answer_score = user_answer.get_answer_score()
|
||||
|
||||
correct_answer = q.GetPrimaryAnswer()
|
||||
answers.append(ans)
|
||||
answers_marks.append(a)
|
||||
answers_and_marks.append((ans, a, correct_answer))
|
||||
answers_marks.append(answer_score)
|
||||
answers_and_marks.append((ans, answer_score, correct_answer))
|
||||
|
||||
total_score = sum(answers_marks)
|
||||
|
||||
@@ -658,39 +667,22 @@ def exam_scores(request, pk):
|
||||
# Convoluted (probably...)
|
||||
user_names[u] = User.objects.filter(pk=u[0]).first().get_username()
|
||||
for q in questions:
|
||||
s = q.user_answers.filter(user__in=u)
|
||||
if not s:
|
||||
user_answer = q.user_answers.filter(user__in=u).first()
|
||||
if not user_answer:
|
||||
user_answers_marks[u].append(0)
|
||||
user_answers[u].append("")
|
||||
continue
|
||||
|
||||
ans = s[0].answer
|
||||
if ans in q.answers.all().values_list("answer", flat=True):
|
||||
a = 2
|
||||
elif ans in q.half_mark_answers.all().values_list("answer",
|
||||
flat=True):
|
||||
a = 1
|
||||
else:
|
||||
a = 0
|
||||
ans = user_answer.answer
|
||||
answer_score = user_answer.get_answer_score()
|
||||
user_answers[u].append(ans)
|
||||
user_answers_marks[u].append(a)
|
||||
user_answers_and_marks[u].append((ans, a))
|
||||
user_answers_marks[u].append(answer_score)
|
||||
user_answers_and_marks[u].append((ans, answer_score))
|
||||
|
||||
user_scores = {}
|
||||
for user in user_answers_marks:
|
||||
user_scores[user] = sum(user_answers_marks[user])
|
||||
|
||||
# Users with answers
|
||||
#
|
||||
# for q in questions:
|
||||
# answers = q.user_answers.all()
|
||||
#
|
||||
# for ans in answers:
|
||||
# user = ans.user
|
||||
# if ans.answer in q.answers.all().values_list("answer", flat=True):
|
||||
# user_answers[user].append(2)
|
||||
#
|
||||
|
||||
total = len(questions)
|
||||
|
||||
return render(
|
||||
@@ -706,3 +698,31 @@ def exam_scores(request, pk):
|
||||
"user_answers_and_marks": user_answers_and_marks,
|
||||
},
|
||||
)
|
||||
|
||||
def cid_scores(request, pk):
|
||||
#exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
# TODO:Need some kind of test for cid
|
||||
cid = pk
|
||||
|
||||
#questions = exam.exam_questions.all()
|
||||
answers = CidUserAnswer.objects.filter(
|
||||
cid=cid)
|
||||
|
||||
|
||||
if not answers:
|
||||
return Http404("cid not found")
|
||||
|
||||
exam_ids = answers.values_list("exam").distinct()
|
||||
|
||||
exams = Exam.objects.filter(id__in=exam_ids)
|
||||
|
||||
|
||||
return render(
|
||||
request,
|
||||
"anatomy/cid_scores.html",
|
||||
{
|
||||
"exams": exams,
|
||||
"cid": cid,
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user