From 0cb4294427842dabba01e4b85d8c97267a716471 Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 25 Sep 2021 19:20:47 +0100 Subject: [PATCH] . --- anatomy/models.py | 45 +++++- .../templates/anatomy/exam_scores_user.html | 79 ++++++++-- anatomy/urls.py | 143 +++++++++++++----- anatomy/views.py | 21 ++- rapids/templates/rapids/exam_scores_user.html | 72 ++++----- rapids/urls.py | 12 +- 6 files changed, 280 insertions(+), 92 deletions(-) diff --git a/anatomy/models.py b/anatomy/models.py index c93d8efa..39d243c3 100644 --- a/anatomy/models.py +++ b/anatomy/models.py @@ -213,6 +213,49 @@ class AnatomyQuestion(models.Model): def get_annotations(self): return self.image_annotations + def get_title(self): + return "{}".format(self.description) + + def get_correct_unstripped_answers(self): + return set( + [ + str(i) + for i in self.answers.filter(proposed=False) + if i.status == i.MarkOptions.CORRECT + ] + ) + + def get_question_json(self, based=True): + """Returns a json representation of the question""" + + # Loop through rapidimage associations + images = [] + annotations = [] + feedback_images = [] + + if based: + images.append(image_as_base64(self.image)) + else: + images.append("{}/{}".format(settings.REMOTE_URL, self.image.url)) + + if self.image_annotations: + annotations.append(str(self.image_annotations)) + + + + json = { + "images": images, + #"feedback_image": [], + "annotations": annotations, + "type": "anatomy", + "title": self.get_title(), + "question": str(self.question_type), + } + + json["answers"] = list(self.get_correct_unstripped_answers()) + + return json + @reversion.register class Answer(models.Model): @@ -313,7 +356,7 @@ class Exam(ExamBase): exam_order.append(q.id) exam_questions[q.id] = { - "title": "{}".format(q.description), + "title": q.get_title(), "question": str(q.question_type), "images": [image_as_base64(q.image)], "annotations": [str(q.image_annotations)], diff --git a/anatomy/templates/anatomy/exam_scores_user.html b/anatomy/templates/anatomy/exam_scores_user.html index b626baf3..d8d6005a 100644 --- a/anatomy/templates/anatomy/exam_scores_user.html +++ b/anatomy/templates/anatomy/exam_scores_user.html @@ -1,18 +1,69 @@ {% extends 'anatomy/base.html' %} {% block content %} -
-

Exam: {{ exam.name }}

-

Candidate: {{ cid }}

- Answers: - -
Total mark: {{ total_score }} / {{max_score}} -
- Other exams +
+ Question 1 +
+
+
Answers:
-
-{% endblock %} \ No newline at end of file +
+

Exam: {{ exam.name }}

+

Candidate: {{ cid }}

+ Answers: +
    {% for ans, score, correct_answer in answers_and_marks %} +
  • Question {{forloop.counter}} - Correct answer: {{ correct_answer }}
  • + +
    {{ans}}
    ({{score}}) +
    + View + {% endfor %} +
+
Total mark: {{ total_score }} / {{max_score}} +
+ Other exams +
+
+{% endblock %} +{% block js %} + +{% endblock %} diff --git a/anatomy/urls.py b/anatomy/urls.py index 8ea1e4b2..6b28d006 100644 --- a/anatomy/urls.py +++ b/anatomy/urls.py @@ -7,29 +7,82 @@ app_name = "anatomy" urlpatterns = [ # path('', views.question_list, name='question_list'), path("", views.AnatomyExamViews.index, name="index"), - path("question/", cache_page(60 * 1)(views.AnatomyQuestionView.as_view()), name="anatomy_question_view"), + path( + "question/", + cache_page(60 * 1)(views.AnatomyQuestionView.as_view()), + name="anatomy_question_view", + ), path("question//", views.question_detail, name="question_detail"), - path("question/create/", views.AnatomyQuestionCreate.as_view(), name="anatomy_question_create"), - path("question//update", views.AnatomyQuestionUpdate.as_view(), name="anatomy_question_update"), - path("question//save_annotation", views.question_save_annotation, name="question_save_annotation"), - path("question//answer/", - views.answer_question, - name="answer_question"), - path("question//clone", views.QuestionClone.as_view(), name="question_clone"), - path("question//delete", views.QuestionDelete.as_view(), name="question_delete"), + path( + "question/create/", + views.AnatomyQuestionCreate.as_view(), + name="anatomy_question_create", + ), + path( + "question//update", + views.AnatomyQuestionUpdate.as_view(), + name="anatomy_question_update", + ), + path( + "question//save_annotation", + views.question_save_annotation, + name="question_save_annotation", + ), + path("question//answer/", views.answer_question, name="answer_question"), + path( + "question//clone", views.QuestionClone.as_view(), name="question_clone" + ), + path( + "question//delete", + views.QuestionDelete.as_view(), + name="question_delete", + ), + path( + "exam//review", + views.question_review, + name="question_review", + ), path("exam///mark", views.mark, name="mark"), - path("exam//mark", views.AnatomyExamViews.mark_overview, name="mark_overview"), + path( + "exam//mark", views.AnatomyExamViews.mark_overview, name="mark_overview" + ), path("exam///", views.exam_take, name="exam_take"), - path("exam//question//", views.AnatomyExamViews.exam_question_detail, name="exam_question_detail"), + path( + "exam//question//", + views.AnatomyExamViews.exam_question_detail, + name="exam_question_detail", + ), path("exam//", views.AnatomyExamViews.exam_overview, name="exam_overview"), - path("exam//json_edit", views.AnatomyExamViews.exam_json_edit, name="exam_json_edit"), - path("exam//scores", cache_page(60 * 1)(views.exam_scores_cid), - name="exam_scores_cid"), - path("exam//scores//", views.exam_scores_cid_user, - name="exam_scores_cid_user"), - path("exam//toggle_active", views.AnatomyExamViews.exam_toggle_active, name="exam_toggle_active"), - path("exam//toggle_results_published", views.AnatomyExamViews.exam_toggle_results_published, name="exam_toggle_results_published"), - path("exam/submit", views.AnatomyExamViews.postExamAnswers, name="exam_answers_submit"), + path( + "exam//json_edit", + views.AnatomyExamViews.exam_json_edit, + name="exam_json_edit", + ), + path( + "exam//scores", + cache_page(60 * 1)(views.exam_scores_cid), + name="exam_scores_cid", + ), + path( + "exam//scores//", + views.exam_scores_cid_user, + name="exam_scores_cid_user", + ), + path( + "exam//toggle_active", + views.AnatomyExamViews.exam_toggle_active, + name="exam_toggle_active", + ), + path( + "exam//toggle_results_published", + views.AnatomyExamViews.exam_toggle_results_published, + name="exam_toggle_results_published", + ), + path( + "exam/submit", + views.AnatomyExamViews.postExamAnswers, + name="exam_answers_submit", + ), path("exam/", views.AnatomyExamViews.exam_list, name="exam_list"), path("exam/all", views.AnatomyExamViews.exam_list_all, name="exam_list_all"), path("exam/create", views.ExamCreate.as_view(), name="exam_create"), @@ -37,25 +90,39 @@ urlpatterns = [ path("exam//delete", views.ExamDelete.as_view(), name="exam_delete"), path("exam/json/", views.AnatomyExamViews.active_exams, name="active_exams"), path("exam/json/", views.AnatomyExamViews.exam_json, name="exam_json"), - path("exam/json//recreate", views.AnatomyExamViews.exam_json_recreate, name="exam_json_recreate"), - #path("cid/", views.cid_selector, name="cid_selector"), + path( + "exam/json//recreate", + views.AnatomyExamViews.exam_json_recreate, + name="exam_json_recreate", + ), + # path("cid/", views.cid_selector, name="cid_selector"), path("ajax/exam/flag/", views.flag_question, name="flag_question"), path("body_part/create/", views.create_body_part, name="create_body_part"), - path("body_part/ajax/get_body_part_id", - views.get_body_part_id, - name="get_body_part_id"), - path("structure/create/", - views.create_structure, - name="create_structure"), - path("structure/ajax/get_structure_id", - views.get_structure_id, - name="get_structure_id"), - path("examination/create/", - views.create_examination, - name="create_examination"), - path("examination/ajax/get_examination_id", - views.get_examination_id, - name="get_examination_id"), - path("user_answers/", views.AnatomyUserAnswerView.as_view(), name="anatomy_user_answer_view"), - path("user_answers//delete", views.UserAnswerDelete.as_view(), name="user_answer_delete"), + path( + "body_part/ajax/get_body_part_id", + views.get_body_part_id, + name="get_body_part_id", + ), + path("structure/create/", views.create_structure, name="create_structure"), + path( + "structure/ajax/get_structure_id", + views.get_structure_id, + name="get_structure_id", + ), + path("examination/create/", views.create_examination, name="create_examination"), + path( + "examination/ajax/get_examination_id", + views.get_examination_id, + name="get_examination_id", + ), + path( + "user_answers/", + views.AnatomyUserAnswerView.as_view(), + name="anatomy_user_answer_view", + ), + path( + "user_answers//delete", + views.UserAnswerDelete.as_view(), + name="user_answer_delete", + ), ] diff --git a/anatomy/views.py b/anatomy/views.py index 48330e14..3fc66faf 100644 --- a/anatomy/views.py +++ b/anatomy/views.py @@ -1031,4 +1031,23 @@ class ExamViewSet(RevisionMixin, viewsets.ModelViewSet): class ExamDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView): model = Exam template_name = "exam_confirm_delete.html" - success_url = reverse_lazy("anatomy:index") \ No newline at end of file + success_url = reverse_lazy("anatomy:index") + +def question_review(request, pk): + """ + Return a json representation of the question when the exam is active + """ + if request.is_ajax(): + exam = get_object_or_404(Exam, pk=pk) + + print(request.POST["question_number"]) + print(type(request.POST["question_number"])) + + if not exam.publish_results: + raise Http404 + + question = exam.exam_questions.all()[int(request.POST["question_number"])] + + question_json = question.get_question_json(based=False) + return JsonResponse(question_json) + return JsonResponse({"status": "error"}) \ No newline at end of file diff --git a/rapids/templates/rapids/exam_scores_user.html b/rapids/templates/rapids/exam_scores_user.html index 48635c6c..4b9e5782 100644 --- a/rapids/templates/rapids/exam_scores_user.html +++ b/rapids/templates/rapids/exam_scores_user.html @@ -1,40 +1,40 @@ {% extends 'rapids/base.html' %} {% block content %} -
- Question 1 -
+
+ Question 1 +
+
+
Answers:
-
Answers:
-
-
-

Exam: {{ exam.name }}

-

Candidate: {{ cid }}

- Answers: -
    {% for ans, score, correct_answer in answers_and_marks %} -
  • Question {{forloop.counter}} - Correct answer: +

    Exam: {{ exam.name }}

    +

    Candidate: {{ cid }}

    + Answers: +
      {% for ans, score, correct_answer in answers_and_marks %} +
    • Question {{forloop.counter}} - Correct answer: {{ correct_answer }}
    • - -
      {{ans}}
      ({{score}}) -
      - View + +
      {{ans}}
      ({{score}}) +
      + View {% endfor %} -
    -
    Total mark: {{ total_score }} / {{max_score}} -
    Normalised score: {{ normalised_score }} -
+
Total mark: {{ total_score }} / {{max_score}} +
Normalised score: {{ normalised_score }} +
-
{% endblock %} {% block js %} - -{% endblock %} \ No newline at end of file + }); + +{% endblock %} diff --git a/rapids/urls.py b/rapids/urls.py index dfdccd6e..5a14b5fc 100755 --- a/rapids/urls.py +++ b/rapids/urls.py @@ -17,7 +17,11 @@ urlpatterns = [ path( "question//", views.question_detail, name="question_detail" ), # path("question//json", views.question_json, name="question_json"), - path("question//save_annotation", views.question_save_annotation, name="question_save_annotation"), + path( + "question//save_annotation", + views.question_save_annotation, + name="question_save_annotation", + ), path("question//split", views.rapid_split, name="rapid_split"), path("question//clone", views.RapidClone.as_view(), name="rapid_clone"), # path("verified/", views.verified, name="verified"), @@ -54,7 +58,11 @@ urlpatterns = [ views.RapidExamViews.exam_json_edit, name="exam_json_edit", ), - path("exam//scores", cache_page(60 * 1)(views.exam_scores_cid), name="exam_scores_cid"), + path( + "exam//scores", + cache_page(60 * 1)(views.exam_scores_cid), + name="exam_scores_cid", + ), path( "exam//scores//", views.exam_scores_cid_user,