Add prerequisites handling to CaseCollection and implement user access checks
This commit is contained in:
+66
-1
@@ -71,6 +71,7 @@ from django.utils import timezone
|
||||
import reversion
|
||||
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
|
||||
@@ -948,6 +949,15 @@ class CaseCollection(ExamOrCollectionGenericBase):
|
||||
help_text="Time limit for answering questions in seconds."
|
||||
)
|
||||
|
||||
# Collections that must be completed before this collection can be taken
|
||||
prerequisites = models.ManyToManyField(
|
||||
"self",
|
||||
blank=True,
|
||||
symmetrical=False,
|
||||
related_name="dependents",
|
||||
help_text="Collections that must be completed before this collection can be taken",
|
||||
)
|
||||
|
||||
class COLLECTION_TYPE_CHOICES(models.TextChoices):
|
||||
REVIEW = (
|
||||
"REV",
|
||||
@@ -1105,6 +1115,49 @@ class CaseCollection(ExamOrCollectionGenericBase):
|
||||
kwargs={"pk": self.pk, "case_number": cases.index(case)},
|
||||
)
|
||||
|
||||
def check_user_can_take(self, cid, passcode, user=None, active_only=True):
|
||||
"""
|
||||
Extend base check_user_can_take to also require completion of any
|
||||
prerequisite collections.
|
||||
"""
|
||||
# Perform the normal access checks first
|
||||
super().check_user_can_take(cid, passcode, user=user, active_only=active_only)
|
||||
|
||||
# If there are prerequisites, the user (or CID) must have completed them
|
||||
if not self.prerequisites.exists():
|
||||
return
|
||||
|
||||
for prereq in self.prerequisites.all():
|
||||
# Look up any existing exam record for this user/cid on the prerequisite
|
||||
ct = ContentType.objects.get_for_model(prereq)
|
||||
exam_record = None
|
||||
if cid is not None:
|
||||
# Find CidUser by cid
|
||||
try:
|
||||
cid_user = CidUser.objects.filter(cid=cid).first()
|
||||
except Exception:
|
||||
cid_user = None
|
||||
|
||||
if cid_user is None:
|
||||
exam_record = None
|
||||
else:
|
||||
exam_record = CidUserExam.objects.filter(
|
||||
content_type=ct, object_id=prereq.pk, cid_user=cid_user
|
||||
).first()
|
||||
else:
|
||||
# Check for a normal user_user exam record
|
||||
exam_record = CidUserExam.objects.filter(
|
||||
content_type=ct, object_id=prereq.pk, user_user=user
|
||||
).first()
|
||||
|
||||
if exam_record is None or not getattr(exam_record, "completed", False):
|
||||
# Not allowed to take this collection until prereq completed
|
||||
# Raise the PrerequisiteRequired exception including the prereq object
|
||||
raise PrerequisiteRequired(
|
||||
f"Collection not available until prerequisite '{prereq.name}' is completed.",
|
||||
prereq=prereq,
|
||||
)
|
||||
|
||||
def get_ohif_dicom_json(self, case_title_as_patient_name=True):
|
||||
studies = []
|
||||
for n, case in enumerate(self.cases.all()):
|
||||
@@ -1736,4 +1789,16 @@ class QuestionSchema(models.Model, AuthorMixin):
|
||||
return json.dumps(self.schema)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "{}".format(self.name)
|
||||
return "{}".format(self.name)
|
||||
|
||||
|
||||
class PrerequisiteRequired(Exception):
|
||||
"""Raised when a user attempts to access a collection but has not completed a prerequisite.
|
||||
|
||||
The exception stores an optional `prereq` attribute pointing to the prerequisite
|
||||
CaseCollection instance so views can render a helpful page linking to it.
|
||||
"""
|
||||
|
||||
def __init__(self, message=None, *, prereq=None):
|
||||
super().__init__(message or "Prerequisite required")
|
||||
self.prereq = prereq
|
||||
Reference in New Issue
Block a user