numerous improvements

This commit is contained in:
Ross
2020-12-05 16:04:36 +00:00
parent 2532d16c52
commit 45e038ccd6
9 changed files with 151 additions and 39 deletions
+14
View File
@@ -136,6 +136,9 @@ class AnatomyQuestion(models.Model):
return unmarked_answers return unmarked_answers
def GetUnmarkedAnswerCount(self):
return len(self.GetUnmarkedAnswers())
def GetMarkedAnswers(self): def GetMarkedAnswers(self):
return set([i.get_compare_string() for i in self.answers.all() if i.status != i.MarkOptions.UNMARKED]) 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()]) correct_answers = set([i.answer.lower() for i in self.answers.all()])
@@ -290,3 +293,14 @@ class CidUserAnswer(models.Model):
def get_compare_string(self): 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
+16
View File
@@ -3,6 +3,10 @@ body {
background-color: black; background-color: black;
} }
a, a:link {
color: #3282b8;
}
.warn { .warn {
color: red; color: red;
} }
@@ -108,3 +112,15 @@ button a {
.marking { .marking {
float: right; float: right;
} }
#question-mark-list {
padding: 20px
}
#question-mark-list a {
color: #bbe1fa
}
#question-mark-list li {
padding-bottom: 5px;
}
+14
View File
@@ -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() { function prepAnswerData() {
+13
View File
@@ -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"> <div class="anatomy">
<h1>Exam: {{ exam.name }}</h1> <h1>Exam: {{ exam.name }}</h1>
This exam has {{question_number}} questions. 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: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>--> <!--<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> <a href="{% url 'anatomy:exam_json_recreate' pk=exam.pk %}">Refresh JSON cache</a>
</div> </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 %} {% endblock %}
@@ -1,4 +1,4 @@
{% extends 'anatomy/exams.html' %} {% extends 'anatomy/base.html' %}
{% block content %} {% block content %}
<div class="anatomy"> <div class="anatomy">
+7 -3
View File
@@ -3,11 +3,15 @@
{% block content %} {% block content %}
<div class="anatomy"> <div class="anatomy">
<h2>Marking exam: {{ exam.name }}</h2> <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 %} {% 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> {{ question }}</a><br /> {{ question.GetUnmarkedAnswersString }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
+2
View File
@@ -18,10 +18,12 @@ urlpatterns = [
name="exam_scores_cid"), name="exam_scores_cid"),
path("exam/<int:pk>/scores/<int:sk>/", views.exam_scores_cid_user, path("exam/<int:pk>/scores/<int:sk>/", views.exam_scores_cid_user,
name="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/submit", views.postExamAnswers, name="exam_answers_submit"),
path("exam/", views.exam_list, name="exam_list"), path("exam/", views.exam_list, name="exam_list"),
path("exam/json/", views.active_exams, name="active_exams"), 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>", views.exam_json, name="exam_json"),
path("exam/json/<int:pk>/recreate", views.exam_json_recreate, name="exam_json_recreate"), 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"), path("ajax/exam/flag/", views.flag_question, name="flag_question"),
] ]
+54 -34
View File
@@ -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): def active_exams(request):
exams = Exam.objects.all() exams = Exam.objects.all()
@@ -602,24 +614,21 @@ def exam_scores_cid_user(request, pk, sk):
for q in questions: for q in questions:
# Get user answer # Get user answer
s = q.cid_user_answers.filter(cid=cid) user_answer = q.cid_user_answers.filter(cid=cid).first()
if not s: if not user_answer:
# skip if no answer # skip if no answer
answers_marks.append(0) answers_marks.append(0)
answers.append("") answers.append("")
continue continue
ans = s[0].answer ans = user_answer.answer
if q.answers.filter(answer__iexact=ans, status=Answer.MarkOptions.CORRECT).first() is not None:
a = 2 answer_score = user_answer.get_answer_score()
elif q.answers.filter(answer__iexact=ans, status=Answer.MarkOptions.HALF_MARK).first() is not None:
a = 1
else:
a = 0
correct_answer = q.GetPrimaryAnswer() correct_answer = q.GetPrimaryAnswer()
answers.append(ans) answers.append(ans)
answers_marks.append(a) answers_marks.append(answer_score)
answers_and_marks.append((ans, a, correct_answer)) answers_and_marks.append((ans, answer_score, correct_answer))
total_score = sum(answers_marks) total_score = sum(answers_marks)
@@ -658,39 +667,22 @@ def exam_scores(request, pk):
# Convoluted (probably...) # Convoluted (probably...)
user_names[u] = User.objects.filter(pk=u[0]).first().get_username() user_names[u] = User.objects.filter(pk=u[0]).first().get_username()
for q in questions: for q in questions:
s = q.user_answers.filter(user__in=u) user_answer = q.user_answers.filter(user__in=u).first()
if not s: if not user_answer:
user_answers_marks[u].append(0) user_answers_marks[u].append(0)
user_answers[u].append("") user_answers[u].append("")
continue continue
ans = s[0].answer ans = user_answer.answer
if ans in q.answers.all().values_list("answer", flat=True): answer_score = user_answer.get_answer_score()
a = 2
elif ans in q.half_mark_answers.all().values_list("answer",
flat=True):
a = 1
else:
a = 0
user_answers[u].append(ans) user_answers[u].append(ans)
user_answers_marks[u].append(a) user_answers_marks[u].append(answer_score)
user_answers_and_marks[u].append((ans, a)) user_answers_and_marks[u].append((ans, answer_score))
user_scores = {} user_scores = {}
for user in user_answers_marks: for user in user_answers_marks:
user_scores[user] = sum(user_answers_marks[user]) 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) total = len(questions)
return render( return render(
@@ -706,3 +698,31 @@ def exam_scores(request, pk):
"user_answers_and_marks": user_answers_and_marks, "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,
},
)