From 64cebf50a036d24d61c13948620e588c028e662a Mon Sep 17 00:00:00 2001
From: Ross
Date: Mon, 24 Jun 2024 08:59:15 +0100
Subject: [PATCH] Numerous improvements to case questions
---
atlas/forms.py | 45 +++--
...dback_once_collection_complete_and_more.py | 23 +++
atlas/models.py | 33 ++++
atlas/static/schema/options.json | 5 +
.../atlas/collection_case_detail.html | 34 ++--
.../atlas/collection_case_view_take.html | 103 ++++++++++-
atlas/templates/atlas/collection_detail.html | 6 +-
.../atlas/collection_question_schemas.html | 2 +-
.../atlas/question_schemas_preset.html | 2 +-
atlas/views.py | 166 ++++++++++++++----
requirements.txt | 3 +-
11 files changed, 348 insertions(+), 74 deletions(-)
create mode 100644 atlas/migrations/0054_casecollection_feedback_once_collection_complete_and_more.py
create mode 100644 atlas/static/schema/options.json
diff --git a/atlas/forms.py b/atlas/forms.py
index dc8dbfd5..f7cf597d 100755
--- a/atlas/forms.py
+++ b/atlas/forms.py
@@ -521,9 +521,9 @@ SeriesImageFormSet = inlineformset_factory(
class JsonAnswerForm(Form):
json_answer = JSONSchemaField(
- schema = "schema/report.json",
+ schema = {},
#options = 'schema/options.json'
- options = {}
+ options = 'schema/options.json'
)
class Meta:
fields = ["json_answer"]
@@ -531,16 +531,11 @@ class JsonAnswerForm(Form):
def __init__(self, *args, case_detail, **kwargs):
super(JsonAnswerForm, self).__init__(*args, **kwargs)
if case_detail.question_schema is not None:
- self.fields["json_answer"] = JSONSchemaField(schema=case_detail.question_schema, options={})
+ self.fields["json_answer"] = JSONSchemaField(schema=case_detail.question_schema, options='schema/options.json')
class BaseReportAnswerForm(ModelForm):
- json_answer = JSONSchemaField(
- schema = "schema/report.json",
- #options = 'schema/options.json'
- options = {}
- )
class Meta:
- fields = ["answer", "json_answer"]
+ fields = ["answer"]
widgets = {
# "normal": RadioSelect(
@@ -548,7 +543,7 @@ class BaseReportAnswerForm(ModelForm):
# (False, 'No')])
# "findings": TinyMCE(attrs={"cols": 80, "rows": 20}),
# "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}),
- "answer": Textarea(attrs={"cols": 100, "rows": 5}),
+ "answer": Textarea(attrs={"cols": 100, "rows": 5, "placeholder":"Report text"}),
}
# help_texts = {
@@ -558,9 +553,26 @@ class BaseReportAnswerForm(ModelForm):
def __init__(self, *args, case_detail, **kwargs):
super(BaseReportAnswerForm, self).__init__(*args, **kwargs)
self.fields["answer"].required = False
+
+class BaseQuestionAnswerForm(ModelForm):
+ json_answer = JSONSchemaField(
+ schema = {},
+ options = 'schema/options.json'
+ )
+ class Meta:
+ fields = ["json_answer"]
+ labels = {"json_answer": ""}
+
+ # help_texts = {
+ # "answer": "Write your answer in here."
+ # }
+
+ def __init__(self, *args, case_detail, **kwargs):
+ super(BaseQuestionAnswerForm, self).__init__(*args, **kwargs)
#self.fields["json_answer"].schema = case_detail.question_schema
if case_detail.question_schema is not None:
- self.fields["json_answer"] = JSONSchemaField(schema=case_detail.question_schema, options={})
+ self.fields["json_answer"] = JSONSchemaField(schema=case_detail.question_schema, options="schema/options.json")
+ self.fields["json_answer"].label = ""
class CidReportAnswerForm(BaseReportAnswerForm):
@@ -571,6 +583,14 @@ class UserReportAnswerForm(BaseReportAnswerForm):
class Meta(BaseReportAnswerForm.Meta):
model = UserReportAnswer
+class CidQuestionAnswerForm(BaseQuestionAnswerForm):
+ class Meta(BaseQuestionAnswerForm.Meta):
+ model = CidReportAnswer
+
+class UserQuestionAnswerForm(BaseQuestionAnswerForm):
+ class Meta(BaseQuestionAnswerForm.Meta):
+ model = UserReportAnswer
+
class CidReportAnswerMarkForm(ModelForm):
class Meta:
model = CidReportAnswer
@@ -732,8 +752,7 @@ class AnswerJSONForm(Form):
json = JSONSchemaField(
schema = 'schema/schema.json',
- #options = 'schema/options.json'
- options = {}
+ options = 'schema/options.json'
)
diff --git a/atlas/migrations/0054_casecollection_feedback_once_collection_complete_and_more.py b/atlas/migrations/0054_casecollection_feedback_once_collection_complete_and_more.py
new file mode 100644
index 00000000..a4f4dbc7
--- /dev/null
+++ b/atlas/migrations/0054_casecollection_feedback_once_collection_complete_and_more.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.0.2 on 2024-06-10 22:07
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('atlas', '0053_casedetail_question_answers'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='casecollection',
+ name='feedback_once_collection_complete',
+ field=models.BooleanField(default=True, help_text='If true feedback is only given once the collection is complete. If false feedback is given after each case.'),
+ ),
+ migrations.AlterField(
+ model_name='casecollection',
+ name='collection_type',
+ field=models.CharField(choices=[('REV', 'Review'), ('REP', 'Report'), ('QUE', 'Question'), ('VIV', 'Viva')], default='REP', max_length=3),
+ ),
+ ]
diff --git a/atlas/models.py b/atlas/models.py
index 44a3dad7..9475bd13 100644
--- a/atlas/models.py
+++ b/atlas/models.py
@@ -774,6 +774,8 @@ class CaseCollection(ExamOrCollectionGenericBase):
help_text="If true allows users self complete and review cases in a self directed way.",
)
+ feedback_once_collection_complete = models.BooleanField(default=True, help_text="If true feedback is only given once the collection is complete. If false feedback is given after each case.")
+
class COLLECTION_TYPE_CHOICES(models.TextChoices):
REVIEW = (
"REV",
@@ -783,6 +785,10 @@ class CaseCollection(ExamOrCollectionGenericBase):
"REP",
_("Report"),
)
+ QUESTION = (
+ "QUE",
+ _("Question"),
+ )
VIVA = (
"VIV",
_("Viva"),
@@ -874,6 +880,33 @@ class CaseCollection(ExamOrCollectionGenericBase):
"""Returns the cases in the collection in order of the CaseDetail sort_order"""
return self.cases.all().order_by("casedetail__sort_order")
+ def get_next_case(self, case):
+ cases = list(self.get_cases())
+
+ try:
+ return cases[cases.index(case) + 1]
+ except IndexError:
+ return None
+
+ def get_previous_case(self, case):
+ cases = list(self.get_cases())
+
+ new_index = cases.index(case) - 1
+
+ if new_index < 0:
+ return None
+ else:
+ return cases[new_index]
+
+
+ def get_index_of_case(self, case, case_count=False):
+ cases = list(self.get_cases())
+
+ if case_count:
+ return cases.index(case), len(cases)
+ else:
+ return cases.index(case)
+
def get_case_by_index(
self, case_index: int, case_count=False
) -> Case | Tuple[Case, int]:
diff --git a/atlas/static/schema/options.json b/atlas/static/schema/options.json
new file mode 100644
index 00000000..f75101f1
--- /dev/null
+++ b/atlas/static/schema/options.json
@@ -0,0 +1,5 @@
+{
+ "disable_edit_json": true,
+ "disable_collapse": true,
+ "disable_properties": true
+}
\ No newline at end of file
diff --git a/atlas/templates/atlas/collection_case_detail.html b/atlas/templates/atlas/collection_case_detail.html
index 320eee0d..ab5fc2d0 100644
--- a/atlas/templates/atlas/collection_case_detail.html
+++ b/atlas/templates/atlas/collection_case_detail.html
@@ -3,14 +3,25 @@
{% block content %}
- {{case_detail.collection.name}} / {{case_detail.case.pk}}
+
+
+
+
+
This form allows you to add questions to a case. A example of how the quesiton will be displayed is shown below.
If answers are supplied the question will be automarked
- See https://django-jsonform.readthedocs.io/en/latest/guide/inputs.html for formatting
+ The question system is built using https://github.com/json-editor/json-editor, this allows for highly flexible forms / question design at a cost of some complexity. To help with this a number of preset questions are avalible to choose from (these can then be edited if needed). It is also possible to copy questions from other cases in the collection.
Import schema from:
{% endcomment %}
- Question display
- This shows the form as it will be displayed (with the correct answers). If you wish to edit a correct answer you can change it below.
-
+ {% if case_detail.question_schema %}
+ Question display
+ This shows the form as it will be displayed (with the correct answers). If you wish to edit a correct answer you can change it below.
+
+
+ {% endif %}
{% endblock %}
diff --git a/atlas/templates/atlas/collection_case_view_take.html b/atlas/templates/atlas/collection_case_view_take.html
index d0bde8b0..0a07608b 100644
--- a/atlas/templates/atlas/collection_case_view_take.html
+++ b/atlas/templates/atlas/collection_case_view_take.html
@@ -9,7 +9,7 @@
{% endif %}
- {% if completed %}
+ {% if question_completed %}
REVIEW
{% endif %}
@@ -18,7 +18,7 @@
- {% if not completed %}
+ {% if not question_completed %}
{% if resources %}
Resources
{% endif %}
- {% if completed %}
+ {% if question_completed %}
{% if resources %}
Resources
@@ -127,15 +127,15 @@
{% endif %}