Add download functionality for case DICOMs and metadata as ZIP
This commit is contained in:
@@ -48,6 +48,10 @@ from django.urls.exceptions import NoReverseMatch
|
||||
from django.http import Http404, JsonResponse
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
import zipfile
|
||||
import os
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
||||
from generic.models import CidUser, CidUserExam, CimarCase, Site
|
||||
from atlas.helpers import get_cases_available_to_user
|
||||
@@ -3373,6 +3377,71 @@ class SeriesImagesZipView(SeriesImagesZipViewBase, SuperuserRequiredMixin):
|
||||
series_object = Series
|
||||
|
||||
|
||||
@login_required
|
||||
def case_download(request, pk):
|
||||
"""Allow a case author (or superuser) to download all linked series DICOMs
|
||||
and a metadata export as a zip file.
|
||||
"""
|
||||
case = get_object_or_404(Case, pk=pk)
|
||||
|
||||
# Only allow superusers or case authors
|
||||
if not (request.user.is_superuser or case.author.filter(id=request.user.id).exists()):
|
||||
raise PermissionDenied()
|
||||
|
||||
temp_file = ContentFile(b"", name=f"case_{case.pk}.zip")
|
||||
with zipfile.ZipFile(temp_file, mode="w", compression=zipfile.ZIP_DEFLATED) as zip_file:
|
||||
metadata = {
|
||||
"case": {
|
||||
"id": case.pk,
|
||||
"title": case.title,
|
||||
"authors": [str(a) for a in case.author.all()],
|
||||
},
|
||||
"series": [],
|
||||
}
|
||||
|
||||
# Iterate ordered series if available, otherwise fall back to related series
|
||||
try:
|
||||
ordered_series = case.get_ordered_series()
|
||||
except Exception:
|
||||
ordered_series = list(case.series.all())
|
||||
|
||||
for series in ordered_series:
|
||||
series_entry = {"pk": series.pk, "description": str(series)}
|
||||
# Prefer series-provided dicom JSON if available
|
||||
try:
|
||||
series_entry["dicom_json"] = series.get_series_dicom_json()
|
||||
except Exception:
|
||||
series_entry["dicom_json"] = None
|
||||
|
||||
images = series.images.filter(removed=False).order_by("position")
|
||||
series_entry["images"] = []
|
||||
for img in images:
|
||||
try:
|
||||
file_obj = img.image.file
|
||||
fname = os.path.split(file_obj.name)[-1]
|
||||
arcname = f"series_{series.pk}/{fname}"
|
||||
zip_file.writestr(arcname, file_obj.read())
|
||||
series_entry["images"].append({"filename": fname, "position": img.position})
|
||||
except Exception:
|
||||
# skip missing files
|
||||
continue
|
||||
|
||||
metadata["series"].append(series_entry)
|
||||
|
||||
# Write metadata.json
|
||||
zip_file.writestr("metadata.json", json.dumps(metadata, default=str, indent=2))
|
||||
|
||||
file_size = temp_file.tell()
|
||||
temp_file.seek(0)
|
||||
|
||||
response = HttpResponse(temp_file, content_type="application/zip")
|
||||
response["Content-Disposition"] = (
|
||||
"attachment; filename=%s" % f"case_{case.pk}.zip"
|
||||
)
|
||||
response["Content-Length"] = file_size
|
||||
return response
|
||||
|
||||
|
||||
# At the moment only the series owner / author can delete findings but anyone can create
|
||||
def create_series_findings(request):
|
||||
# posts = Post.objects.all()
|
||||
|
||||
Reference in New Issue
Block a user