feat: Enhance case collection and detail forms with timing overrides and custom screens

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Ross
2026-04-30 20:31:16 +01:00
co-authored by Copilot
parent 74cdf14af3
commit 6575c50507
10 changed files with 453 additions and 48 deletions
+59
View File
@@ -1360,6 +1360,10 @@ class CaseCollection(ExamOrCollectionGenericBase):
default=True,
help_text="Enable per-case query and messaging for this collection.",
)
show_results_sharing_information = models.BooleanField(
default=True,
help_text="If true, show result-sharing information on candidate start and overview screens.",
)
question_time_limit = models.PositiveIntegerField(
blank=True,
@@ -1367,6 +1371,39 @@ class CaseCollection(ExamOrCollectionGenericBase):
help_text="Time limit for answering questions in seconds."
)
answer_entry_grace_period = models.PositiveIntegerField(
blank=True,
null=True,
default=0,
help_text="Additional seconds after the case view is locked during which answers can still be entered."
)
start_screen_content = models.TextField(
blank=True,
null=True,
help_text="Optional HTML content shown on the collection start screen (for example embedded resources).",
)
start_screen_resources = models.ManyToManyField(
"Resource",
blank=True,
related_name="start_screen_collections",
help_text="Optional resources shown on the collection start screen.",
)
end_overview_content = models.TextField(
blank=True,
null=True,
help_text="Optional HTML content shown on the collection end overview screen.",
)
end_overview_resources = models.ManyToManyField(
"Resource",
blank=True,
related_name="end_overview_collections",
help_text="Optional resources shown on the collection end overview screen.",
)
# Collections that must be completed before this collection can be taken
prerequisites = models.ManyToManyField(
"self",
@@ -1480,6 +1517,16 @@ 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_effective_case_time_limit(self, casedetail):
if casedetail.question_time_limit_override is not None:
return casedetail.question_time_limit_override
return self.question_time_limit
def get_effective_answer_entry_grace_period(self, casedetail):
if casedetail.answer_entry_grace_period_override is not None:
return casedetail.answer_entry_grace_period_override
return self.answer_entry_grace_period or 0
def get_next_case(self, case):
cases = list(self.get_cases())
@@ -1707,6 +1754,18 @@ class CaseDetail(models.Model):
help_text="This will override the case history for the purpose of the exam/collection."
)
question_time_limit_override = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Optional per-case override for the answer time limit in seconds.",
)
answer_entry_grace_period_override = models.PositiveIntegerField(
null=True,
blank=True,
help_text="Optional per-case override for additional answer-only time in seconds after case view lock.",
)
class Meta:
ordering = ("sort_order",)