Refactor case handling: update URLs and views to support case_number and case_id interchangeably, enhancing backward compatibility and maintainability
This commit is contained in:
+178
-15
@@ -2755,10 +2755,101 @@ def collection_take_start(request, pk, cid=None, passcode=None):
|
||||
)
|
||||
|
||||
|
||||
def _case_number_for_collection_and_caseid(collection_pk, case_id):
|
||||
"""Helper: given a collection PK and a case PK, return the case index (case_number).
|
||||
|
||||
Raises Http404 if the case is not found in the collection.
|
||||
"""
|
||||
collection = get_object_or_404(CaseCollection, pk=collection_pk)
|
||||
try:
|
||||
# attempt to resolve the case object (may raise Http404)
|
||||
case_obj = get_case_for_case_detail(case_id)
|
||||
except Http404:
|
||||
raise
|
||||
try:
|
||||
return collection.get_index_of_case(case_obj)
|
||||
except ValueError:
|
||||
raise Http404(f"Case {case_id} not in collection {collection_pk}")
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_details_by_id(request, exam_id, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(exam_id, case_id)
|
||||
return redirect("atlas:collection_case_details", exam_id=exam_id, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_questions_by_id(request, exam_id, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(exam_id, case_id)
|
||||
return redirect("atlas:collection_case_questions", exam_id=exam_id, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_priors_by_id(request, exam_id, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(exam_id, case_id)
|
||||
return redirect("atlas:collection_case_priors", exam_id=exam_id, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_dicom_json_by_id(request, exam_id, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(exam_id, case_id)
|
||||
return redirect("atlas:collection_case_dicom_json", exam_id=exam_id, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_dicom_json_review_by_id(request, exam_id, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(exam_id, case_id)
|
||||
return redirect("atlas:collection_case_dicom_json_review", exam_id=exam_id, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_view_by_id(request, pk, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(pk, case_id)
|
||||
return redirect("atlas:collection_case_view", pk=pk, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_displaysetup_by_id(request, collection_id, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(collection_id, case_id)
|
||||
return redirect("atlas:collection_case_displaysetup", collection_id=collection_id, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_view_take_by_id(request, pk, case_id, cid, passcode):
|
||||
case_number = _case_number_for_collection_and_caseid(pk, case_id)
|
||||
return redirect("atlas:collection_case_view_take", pk=pk, case_number=case_number, cid=cid, passcode=passcode)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_view_take_user_by_id(request, pk, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(pk, case_id)
|
||||
return redirect("atlas:collection_case_view_take_user", pk=pk, case_number=case_number)
|
||||
|
||||
|
||||
@login_required
|
||||
def redirect_collection_case_view_take_user_answers_by_id(request, pk, case_id):
|
||||
case_number = _case_number_for_collection_and_caseid(pk, case_id)
|
||||
return redirect("atlas:collection_case_view_take_user_answers", pk=pk, case_number=case_number)
|
||||
|
||||
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
def collection_case_priors(request, exam_id, case_id):
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
collection = casedetail.collection
|
||||
# Support either case_number (index) or case_id (case PK) in the URL/kwargs.
|
||||
# Backwards compatibility: callers may pass case_id; prefer case_number when present.
|
||||
casedetail = None
|
||||
collection = None
|
||||
# Try treating the parameter as a case PK first, falling back to case index.
|
||||
try:
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
collection = casedetail.collection
|
||||
except Exception:
|
||||
collection = get_object_or_404(CaseCollection, pk=exam_id)
|
||||
try:
|
||||
case_obj = collection.get_case_by_index(int(case_id))
|
||||
casedetail = CaseDetail.objects.get(case=case_obj, collection=collection)
|
||||
except Exception:
|
||||
raise Http404("Case not found in collection")
|
||||
|
||||
if request.htmx:
|
||||
# Ensure we can render the updated single-card partial and return it so HTMX
|
||||
@@ -2892,9 +2983,17 @@ def collection_case_priors(request, exam_id, case_id):
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
def collection_case_questions(request, exam_id, case_id):
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
|
||||
collection = casedetail.collection
|
||||
# Support either case_number (index) or case_id (case PK)
|
||||
try:
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
collection = casedetail.collection
|
||||
except Exception:
|
||||
collection = get_object_or_404(CaseCollection, pk=exam_id)
|
||||
try:
|
||||
case_obj = collection.get_case_by_index(int(case_id))
|
||||
casedetail = CaseDetail.objects.get(case=case_obj, collection=collection)
|
||||
except Exception:
|
||||
raise Http404("Case not found in collection")
|
||||
|
||||
if not collection.collection_type == "QUE":
|
||||
raise Http404("Collection not in question mode")
|
||||
@@ -3005,9 +3104,19 @@ def collection_case_questions(request, exam_id, case_id):
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
def collection_case_details(request, exam_id, case_id):
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
|
||||
collection = casedetail.collection
|
||||
# Accept either case_number (index into collection) or case_id (case PK).
|
||||
casedetail = None
|
||||
collection = None
|
||||
try:
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
collection = casedetail.collection
|
||||
except Exception:
|
||||
collection = get_object_or_404(CaseCollection, pk=exam_id)
|
||||
try:
|
||||
case_obj = collection.get_case_by_index(int(case_id))
|
||||
casedetail = CaseDetail.objects.get(case=case_obj, collection=collection)
|
||||
except Exception:
|
||||
raise Http404("Case not found in collection")
|
||||
|
||||
if request.method == "POST":
|
||||
form = CaseDetailForm(request.POST, instance=casedetail)
|
||||
@@ -3303,12 +3412,14 @@ def collection_case_view_take_answers(
|
||||
)
|
||||
|
||||
|
||||
def collection_case_view_take_user(request, pk: int, case_number: int):
|
||||
return collection_case_view_take(request, pk, case_number)
|
||||
def collection_case_view_take_user(request, pk, case_number=None, case_id=None):
|
||||
# Accept either case_number (index) or case_id (case PK) and forward both to
|
||||
# the handler. This allows URLs that use either name to keep working.
|
||||
return collection_case_view_take(request, pk, case_number=case_number, cid=None, passcode=None, case_id=case_id)
|
||||
|
||||
|
||||
def collection_case_view_take(
|
||||
request, pk: int, case_number: int, cid=None, passcode=None
|
||||
request, pk, case_number=None, cid=None, passcode=None, case_id=None
|
||||
):
|
||||
"""
|
||||
Displays the page from which the user takes a case in the collection
|
||||
@@ -3328,6 +3439,21 @@ def collection_case_view_take(
|
||||
"""
|
||||
collection = get_object_or_404(CaseCollection, pk=pk)
|
||||
|
||||
# If caller provided a case_id (case PK) instead of a case_number (index),
|
||||
# translate it into the index used by collection.get_case_by_index().
|
||||
if case_id is not None and case_number is None:
|
||||
try:
|
||||
case_obj = get_case_for_case_detail(case_id)
|
||||
except Http404:
|
||||
raise
|
||||
try:
|
||||
case_number = collection.get_index_of_case(case_obj)
|
||||
except ValueError:
|
||||
raise Http404(f"Case {case_id} not in collection {pk}")
|
||||
# Ensure we have a case_number to work with
|
||||
if case_number is None:
|
||||
raise Http404("No case specified")
|
||||
|
||||
form = None
|
||||
answer: None | CidReportAnswer | UserReportAnswer = None
|
||||
|
||||
@@ -3567,7 +3693,7 @@ def collection_case_view_take(
|
||||
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
def collection_case_view(request, pk, case_number):
|
||||
def collection_case_view(request, pk, case_number=None, case_id=None):
|
||||
"""Edit/management overview of the case (as part of the collection)
|
||||
|
||||
Args:
|
||||
@@ -3583,6 +3709,19 @@ def collection_case_view(request, pk, case_number):
|
||||
"""
|
||||
collection = get_object_or_404(CaseCollection, pk=pk)
|
||||
|
||||
# Support either case_number (index) or case_id (case PK) in the URL/kwargs.
|
||||
if case_id is not None and case_number is None:
|
||||
try:
|
||||
case_obj = get_case_for_case_detail(case_id)
|
||||
except Http404:
|
||||
raise
|
||||
try:
|
||||
case_number = collection.get_index_of_case(case_obj)
|
||||
except ValueError:
|
||||
raise Http404(f"Case {case_id} not in collection {pk}")
|
||||
if case_number is None:
|
||||
raise Http404("No case specified")
|
||||
|
||||
form = None
|
||||
answer = None
|
||||
|
||||
@@ -3635,8 +3774,18 @@ def use_dates_as_descriptions(request, pk):
|
||||
def collection_case_dicom_json_review(request, exam_id, case_id):
|
||||
return collection_case_dicom_json(request, exam_id, case_id, review=True)
|
||||
|
||||
|
||||
def collection_case_dicom_json(request, exam_id, case_id, review=False):
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
# Support either case_number (index) or case_id (case PK)
|
||||
try:
|
||||
casedetail = CaseDetail.objects.get(case=case_id, collection=exam_id)
|
||||
except Exception:
|
||||
collection = get_object_or_404(CaseCollection, pk=exam_id)
|
||||
try:
|
||||
case_obj = collection.get_case_by_index(int(case_id))
|
||||
casedetail = CaseDetail.objects.get(case=case_obj, collection=collection)
|
||||
except Exception:
|
||||
raise Http404("Case not found in collection")
|
||||
|
||||
if review:
|
||||
priors = casedetail.caseprior_set.exclude(prior_visibility="NO")
|
||||
@@ -4517,12 +4666,26 @@ def series_bulk_delete(request):
|
||||
|
||||
@user_is_collection_author_or_atlas_editor
|
||||
@csrf_exempt # Only if you have CSRF issues; otherwise, keep CSRF protection
|
||||
def collection_case_displaysetup(request, collection_id, case_id):
|
||||
def collection_case_displaysetup(request, collection_id, case_number=None, case_id=None):
|
||||
"""
|
||||
View to set up the display options for a specific case in a collection.
|
||||
This can include setting which series to display, annotations, etc.
|
||||
"""
|
||||
casedetail = get_object_or_404(CaseDetail, case__pk=case_id, collection__pk=collection_id)
|
||||
# Accept either case_number (index into collection) or case_id (case PK).
|
||||
casedetail = None
|
||||
try:
|
||||
# If a case_id was passed explicitly, try that first
|
||||
if case_id is not None:
|
||||
casedetail = get_object_or_404(CaseDetail, case__pk=case_id, collection__pk=collection_id)
|
||||
else:
|
||||
# Otherwise the route most likely supplied case_number; try resolving by index
|
||||
collection = get_object_or_404(CaseCollection, pk=collection_id)
|
||||
case_obj = collection.get_case_by_index(int(case_number))
|
||||
casedetail = CaseDetail.objects.get(case=case_obj, collection=collection)
|
||||
except Http404:
|
||||
raise
|
||||
except Exception:
|
||||
raise Http404("Case not found in collection")
|
||||
|
||||
if request.method == "POST":
|
||||
data = json.loads(request.body.decode("utf-8"))
|
||||
|
||||
Reference in New Issue
Block a user