endoreg-db 0.8.4.4__py3-none-any.whl → 0.8.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/management/commands/load_ai_model_data.py +2 -1
- endoreg_db/management/commands/setup_endoreg_db.py +11 -7
- endoreg_db/models/media/pdf/raw_pdf.py +241 -97
- endoreg_db/models/media/video/pipe_1.py +30 -33
- endoreg_db/models/media/video/video_file.py +300 -187
- endoreg_db/models/metadata/model_meta_logic.py +15 -1
- endoreg_db/models/metadata/sensitive_meta_logic.py +391 -70
- endoreg_db/serializers/__init__.py +26 -55
- endoreg_db/serializers/misc/__init__.py +1 -1
- endoreg_db/serializers/misc/file_overview.py +65 -35
- endoreg_db/serializers/misc/{vop_patient_data.py → sensitive_patient_data.py} +1 -1
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/lookup_service.py +228 -58
- endoreg_db/services/lookup_store.py +174 -30
- endoreg_db/services/pdf_import.py +585 -282
- endoreg_db/services/video_import.py +340 -101
- endoreg_db/urls/__init__.py +36 -23
- endoreg_db/urls/label_video_segments.py +2 -0
- endoreg_db/urls/media.py +3 -2
- endoreg_db/views/__init__.py +6 -3
- endoreg_db/views/media/pdf_media.py +3 -1
- endoreg_db/views/media/video_media.py +1 -1
- endoreg_db/views/media/video_segments.py +187 -259
- endoreg_db/views/pdf/__init__.py +5 -8
- endoreg_db/views/pdf/pdf_stream.py +187 -0
- endoreg_db/views/pdf/reimport.py +110 -94
- endoreg_db/views/requirement/lookup.py +171 -287
- endoreg_db/views/video/__init__.py +0 -2
- endoreg_db/views/video/video_examination_viewset.py +202 -289
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.6.1.dist-info}/METADATA +1 -1
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.6.1.dist-info}/RECORD +33 -34
- endoreg_db/views/pdf/pdf_media.py +0 -239
- endoreg_db/views/pdf/pdf_stream_views.py +0 -127
- endoreg_db/views/video/video_media.py +0 -158
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.6.1.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.6.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -258,7 +258,7 @@ endoreg_db/management/commands/import_report.py,sha256=vFst-NeQdL-w62yoH4kDamq-2
|
|
|
258
258
|
endoreg_db/management/commands/import_video.py,sha256=AMvgi1eN0F_hjhgnNNYIFkJtHfjalBfh2lfDxw6VTzE,17980
|
|
259
259
|
endoreg_db/management/commands/import_video_with_classification.py,sha256=ulZH5jvAWu_pJ1kI9B3hbIO1-p_BReY0zbIQDS_d9OI,14726
|
|
260
260
|
endoreg_db/management/commands/init_default_ai_model.py,sha256=98yBigGZ5gkA-b1LPcvzS5x2jAms3pX58fU-TEAcjKw,4669
|
|
261
|
-
endoreg_db/management/commands/load_ai_model_data.py,sha256=
|
|
261
|
+
endoreg_db/management/commands/load_ai_model_data.py,sha256=ba2z-0qWtweUC6iYyiusH3xGDkpkYNNlIjei3QK7YAA,2887
|
|
262
262
|
endoreg_db/management/commands/load_ai_model_label_data.py,sha256=jnm2720TsnRTBKF6guwnjLo7sropW_YoRjgyjo1TUr8,2143
|
|
263
263
|
endoreg_db/management/commands/load_base_db_data.py,sha256=0Go2cYbqfx6MBSeQaHPAq22yeJxOyX25xpmcBcE9Auw,9374
|
|
264
264
|
endoreg_db/management/commands/load_center_data.py,sha256=GQpbe7dxgbTgd66oBqrBXax-os3ibnPmCeSEFDVauPU,2570
|
|
@@ -291,7 +291,7 @@ endoreg_db/management/commands/load_unit_data.py,sha256=tcux-iL-ByT2ApgmHEkLllZS
|
|
|
291
291
|
endoreg_db/management/commands/load_user_groups.py,sha256=D7SK2FvZEHoE4TIXNGCjDw5_12MH9bpGZvoS7eEv0Os,1031
|
|
292
292
|
endoreg_db/management/commands/register_ai_model.py,sha256=KixTfuQR6TUfRmzB5GOos16BFOz7NL4TzLzBkgtPPgE,2510
|
|
293
293
|
endoreg_db/management/commands/reset_celery_schedule.py,sha256=U-m_FNRTw6LAwJoT9RUE4qrhmQXm7AyFToPcHYyJpIE,386
|
|
294
|
-
endoreg_db/management/commands/setup_endoreg_db.py,sha256=
|
|
294
|
+
endoreg_db/management/commands/setup_endoreg_db.py,sha256=vwjb5jH1oBNXtLpPrthbnP1WcwXPgBMoO4K2ZMH5dEI,17886
|
|
295
295
|
endoreg_db/management/commands/start_filewatcher.py,sha256=3jESBqRiYPa9f35--zd70qQaYnyT0tzRO_b_HJuyteQ,4093
|
|
296
296
|
endoreg_db/management/commands/storage_management.py,sha256=NpToX59ndwTFNmnSoeppmiPdMvpjSHH7mAdIe4SvUoI,22396
|
|
297
297
|
endoreg_db/management/commands/summarize_db_content.py,sha256=pOIz3qbY4Ktmh0zV_DKFx971VD0pPx027gCD7a47EL0,10766
|
|
@@ -380,17 +380,17 @@ endoreg_db/models/media/__init__.py,sha256=WuomOKk-3kNGDLKoLO_ltnXbo028JDVlCCScd
|
|
|
380
380
|
endoreg_db/models/media/frame/__init__.py,sha256=25WriZHocR82rbHr_IMIgBt5z-mkV2O0LVWUpJRnQ5E,45
|
|
381
381
|
endoreg_db/models/media/frame/frame.py,sha256=6BvNKTAGsC_Q0S27nrvZ2cySDy3LSu5HCxrNcZwIEsA,4408
|
|
382
382
|
endoreg_db/models/media/pdf/__init__.py,sha256=1fimtZK5LUuP_yqETN6pMj0hxKXuQqeLb1DP5wPmtT4,343
|
|
383
|
-
endoreg_db/models/media/pdf/raw_pdf.py,sha256=
|
|
383
|
+
endoreg_db/models/media/pdf/raw_pdf.py,sha256=aUOGyqFAMcOdfPE_BDGM1_e9vk_YQvZgNcXoSxOR2sg,29963
|
|
384
384
|
endoreg_db/models/media/pdf/report_file.py,sha256=6Vt_TJSB3qaF26qXbyjRSn-s_zN5y4e-PPrN8ZbYS9s,4296
|
|
385
385
|
endoreg_db/models/media/pdf/report_reader/__init__.py,sha256=LiMooVstXRay5qcB-uZW0wxbcdUvPrfAs_xBwWiuuWc,166
|
|
386
386
|
endoreg_db/models/media/pdf/report_reader/report_reader_config.py,sha256=wYVDmPSmNIuCTpaaWqoLVgVZFYW-dqGpnAyVBqRLqXE,3445
|
|
387
387
|
endoreg_db/models/media/pdf/report_reader/report_reader_flag.py,sha256=j9tjbLRenxpWfeaseALl8rV2Dqem9YaM_duS1iJkARU,536
|
|
388
388
|
endoreg_db/models/media/video/__init__.py,sha256=ifW4SXXN2q6wAuFwSP7XlYskpX7UX6uy0py5mpCCOCM,211
|
|
389
389
|
endoreg_db/models/media/video/create_from_file.py,sha256=3n4bbzFteEOFDUuEikP0x-StCKI5R5IhyKC7o3kLZ6Y,15128
|
|
390
|
-
endoreg_db/models/media/video/pipe_1.py,sha256=
|
|
390
|
+
endoreg_db/models/media/video/pipe_1.py,sha256=ljO3vO2mqqTXLZsKjzMTC6-sW4JRWMVRfJcK0n5CjKg,9740
|
|
391
391
|
endoreg_db/models/media/video/pipe_2.py,sha256=DnMxW0uOqSsf7-0n9Rlvn7u89U4Jpkv7n6hFpQfUjkQ,4964
|
|
392
392
|
endoreg_db/models/media/video/refactor_plan.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
393
|
-
endoreg_db/models/media/video/video_file.py,sha256=
|
|
393
|
+
endoreg_db/models/media/video/video_file.py,sha256=VFRgP1QRtuxzE9l74tCW7Kz5leHdv5d5i3aqtH3Y1vA,30281
|
|
394
394
|
endoreg_db/models/media/video/video_file_ai.py,sha256=3ABea52FOF1qlrlxHdYhz_M3Kmqfzqtgq7M0prl-FAo,18819
|
|
395
395
|
endoreg_db/models/media/video/video_file_anonymize.py,sha256=pet1UfSsbSHJJZxq6gDPifAfBWpGyEpD1jEQuSQi0Gg,16027
|
|
396
396
|
endoreg_db/models/media/video/video_file_frames.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -465,10 +465,10 @@ endoreg_db/models/medical/risk/risk_type.py,sha256=kEugcaWSTEWH_Vxq4dcF80Iv1L4_K
|
|
|
465
465
|
endoreg_db/models/metadata/__init__.py,sha256=8I6oLj3YTmeaPGJpL0AWG5gLwp38QzrEggxSkTisv7c,474
|
|
466
466
|
endoreg_db/models/metadata/frame_ocr_result.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
467
467
|
endoreg_db/models/metadata/model_meta.py,sha256=F_r-PTLeNi4J-4EaGCQkGIguhdl7Bwba7_i56ZAjc-4,7589
|
|
468
|
-
endoreg_db/models/metadata/model_meta_logic.py,sha256=
|
|
468
|
+
endoreg_db/models/metadata/model_meta_logic.py,sha256=vAbNDaoZygH8xOCulWlXoHoR1T0BSvr9kIloxjzhfjo,12533
|
|
469
469
|
endoreg_db/models/metadata/pdf_meta.py,sha256=BTmpSgqxmPKi0apcNjyrZAS4AFKCPXVdBd6VBeyyv6E,3174
|
|
470
470
|
endoreg_db/models/metadata/sensitive_meta.py,sha256=ekLHrW-b5uYcjfkRd0EW5ncx5ef8Bu-K6msDkpWCAbk,13034
|
|
471
|
-
endoreg_db/models/metadata/sensitive_meta_logic.py,sha256=
|
|
471
|
+
endoreg_db/models/metadata/sensitive_meta_logic.py,sha256=FRkBX_EgR2cfXO2_7TzllyceJJgU2lfGPkGsPGiLF2E,43119
|
|
472
472
|
endoreg_db/models/metadata/video_meta.py,sha256=c6xWdLW3uNqJ5VPJXHCxXA3mbXw-b0uR54-TOS3qL2Q,14966
|
|
473
473
|
endoreg_db/models/metadata/video_prediction_logic.py,sha256=j5N82mHtiomeeIaf1HA65kT5d0htQfJmbI2bJb8mpxQ,7677
|
|
474
474
|
endoreg_db/models/metadata/video_prediction_meta.py,sha256=EyfctAAAVcW9L0gf76ZBc9-G8MLMcD-tc2kkjaaLH4w,10592
|
|
@@ -517,10 +517,11 @@ endoreg_db/queries/sanity/__init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
517
517
|
endoreg_db/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
518
518
|
endoreg_db/schemas/examination_evaluation.py,sha256=G6uBSQf9ZclwnGvMI-xVPd4IzD6GORUHYYRRCr5Qp6k,844
|
|
519
519
|
endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py,sha256=q06UKC0Nt4sOJphwN9lEaY28ZAvtcMAlOwT5Zq_sblI,31384
|
|
520
|
-
endoreg_db/serializers/__init__.py,sha256=
|
|
520
|
+
endoreg_db/serializers/__init__.py,sha256=LryzaMvorz_qacOnaT8Uu10L8KHHQRtLVaWU-nlQ43g,3589
|
|
521
521
|
endoreg_db/serializers/anonymization.py,sha256=R5hlk6KiHpQ2JshKlFq5gY6Ed4TrarA74hlvll9w-4s,2576
|
|
522
522
|
endoreg_db/serializers/examination_serializer.py,sha256=JPI9diMup9e-nSCH6UwU9KulnSKreg6pOwjKCLHWJfs,281
|
|
523
523
|
endoreg_db/serializers/sensitive_meta_serializer.py,sha256=zF_0HOrdhi9714DExVD1DTsQqDbRIJevkjLU4vZEgYE,10748
|
|
524
|
+
endoreg_db/serializers/video_examination.py,sha256=jotR5PNTA_xEMpqsqdP3PFaie8TO7SGv2Vp18sj8TlY,6937
|
|
524
525
|
endoreg_db/serializers/_old/raw_pdf_meta_validation.py,sha256=hZaPTY4AA4wO7uAA0-DKLueHwtqnNsJqFR8Apdv6wTk,7608
|
|
525
526
|
endoreg_db/serializers/_old/raw_video_meta_validation.py,sha256=Owku2MmHjEZR_FpgKUdaG9In9IRwur53NmhJdser9Bs,7542
|
|
526
527
|
endoreg_db/serializers/_old/video.py,sha256=O7PIt7uJNP5Xy9R9tbWuptCcsrm1dV0382_ymyVgl5w,2634
|
|
@@ -557,12 +558,12 @@ endoreg_db/serializers/meta/sensitive_meta_detail.py,sha256=1i-9Osl9vBH7_KObdm8B
|
|
|
557
558
|
endoreg_db/serializers/meta/sensitive_meta_update.py,sha256=qy7cM2MhQUJST9YcEXuyYmL8oX4kkKCIcyiz2nXHo-g,5591
|
|
558
559
|
endoreg_db/serializers/meta/sensitive_meta_verification.py,sha256=gXH2RfJtVPSgnA3Z58FU6kxTZs6vBI14EEZT7lx2NFE,2289
|
|
559
560
|
endoreg_db/serializers/meta/video_meta.py,sha256=g96J4va5_oIg7rbbVqcyBsy8imgmbiHjysuEEtas0cA,1284
|
|
560
|
-
endoreg_db/serializers/misc/__init__.py,sha256=
|
|
561
|
-
endoreg_db/serializers/misc/file_overview.py,sha256=
|
|
561
|
+
endoreg_db/serializers/misc/__init__.py,sha256=MfG55Bb9sNBajmt-QkTOg1qFNSOEFQ6RWHIA_DVtneE,489
|
|
562
|
+
endoreg_db/serializers/misc/file_overview.py,sha256=ImOTX4a_zjboVyQs2IHBFNqhEfZWDvgcrx1bf2XpL2w,7395
|
|
563
|
+
endoreg_db/serializers/misc/sensitive_patient_data.py,sha256=cewApBYKsk0s9T7CGY_FJmuXAYs3hJV3Ra7oYazKndk,5831
|
|
562
564
|
endoreg_db/serializers/misc/stats.py,sha256=iL8iZseOLeLaoaCDF3MtTQBH3b0yX5ZFkrZbq5MiMGM,1255
|
|
563
565
|
endoreg_db/serializers/misc/translatable_field_mix_in.py,sha256=ZH8ZUE1-No0DLCcIGk445c00jQcX7M6Yldxik-FaGfg,1724
|
|
564
566
|
endoreg_db/serializers/misc/upload_job.py,sha256=e8rXbgs7lkh-NAswLBV2pkEngWdfqHmJcIqS1fM0bJY,2306
|
|
565
|
-
endoreg_db/serializers/misc/vop_patient_data.py,sha256=DHsp8Uc4ZqvxQMlWG3gVtLjxoA-U8eLu51g-yQLA5AY,5823
|
|
566
567
|
endoreg_db/serializers/patient/__init__.py,sha256=ogQGq3jGnFP3L7gK9FbcJodhrzdR6_6xAM89sO9dZjM,185
|
|
567
568
|
endoreg_db/serializers/patient/patient.py,sha256=8GlQw9a6zxhrieuzw0qf2Xryiuj64-Pe-jgYFdGlRdk,3072
|
|
568
569
|
endoreg_db/serializers/patient/patient_dropdown.py,sha256=0hijgjMbgrUo78Em6hNqRMv5XdQJ42pTXmOZClSDtuQ,964
|
|
@@ -595,30 +596,30 @@ endoreg_db/services/__init__.py,sha256=CMLgpzemgjXvKN5HGFD_UVtRAg9XeMIfXvoSu-aUa
|
|
|
595
596
|
endoreg_db/services/anonymization.py,sha256=iM-xW1aJm99G3PmkfZtMJmvoaj99c8OASP5-abBNcy0,8986
|
|
596
597
|
endoreg_db/services/examination_evaluation.py,sha256=jx9IL2PIoBzjiITzs00c1XucE7Ab2LAUydNbErRmtTM,5943
|
|
597
598
|
endoreg_db/services/finding_description_service.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
598
|
-
endoreg_db/services/lookup_service.py,sha256=
|
|
599
|
-
endoreg_db/services/lookup_store.py,sha256=
|
|
600
|
-
endoreg_db/services/pdf_import.py,sha256=
|
|
599
|
+
endoreg_db/services/lookup_service.py,sha256=425eHruJ1JbLxiSiv0bTeVXKLoS0tqK74t70epDKj9o,16176
|
|
600
|
+
endoreg_db/services/lookup_store.py,sha256=k-dxq_0oocXJLzLPENmsvfxxN2whCJyCFPo_2wwIsD8,8962
|
|
601
|
+
endoreg_db/services/pdf_import.py,sha256=a-JwePNsXGZEYyVKHSm77K_Q9xoz5gThAbk4fVfotHI,54693
|
|
601
602
|
endoreg_db/services/polling_coordinator.py,sha256=alnPB-kdMyxbYaxQN9fki9dKrwmAsY3s68bUHWDSNeI,10662
|
|
602
603
|
endoreg_db/services/pseudonym_service.py,sha256=CJhbtRa6K6SPbphgCZgEMi8AFQtB18CUoBDttFnxEoM,3126
|
|
603
604
|
endoreg_db/services/requirements_object.py,sha256=290zf8AEbVtCoHhW4Jr7_ud-RvrqYmb1Nz9UBHtTnc0,6164
|
|
604
605
|
endoreg_db/services/segment_sync.py,sha256=YgHvIHkbW4mqCu0ACf3zjRSZnNfxWwt4gh5syUVXuE0,6400
|
|
605
606
|
endoreg_db/services/storage_aware_video_processor.py,sha256=kKFK64vXLeBSVkp1YJonU3gFDTeXZ8C4qb9QZZB99SE,13420
|
|
606
|
-
endoreg_db/services/video_import.py,sha256=
|
|
607
|
+
endoreg_db/services/video_import.py,sha256=mtEQlHq-n5x-PE1w8CpeCNnkmKpLhbjWflqtK43nBlw,52237
|
|
607
608
|
endoreg_db/tasks/upload_tasks.py,sha256=OJq7DhNwcbWdXzHY8jz5c51BCVkPN5gSWOz-6Fx6W5M,7799
|
|
608
609
|
endoreg_db/tasks/video_ingest.py,sha256=kxFuYkHijINV0VabQKCFVpJRv6eCAw07tviONurDgg8,5265
|
|
609
610
|
endoreg_db/tasks/video_processing_tasks.py,sha256=rZ7Kr49bAR4Q-vALO2SURebrhcJ5hSFGwjF4aULrOao,14089
|
|
610
611
|
endoreg_db/templates/timeline.html,sha256=H9VXKOecCzqcWWkpNIZXFI29ztg-oxV5uvxMglgoClk,6167
|
|
611
612
|
endoreg_db/templates/admin/patient_finding_intervention.html,sha256=F3JUKm3HhWIf_xoZZ-SET5d5ZDlm2jMM8g909w1dnYc,10164
|
|
612
613
|
endoreg_db/templates/admin/start_examination.html,sha256=3K4wirul9KNyB5mN9cpfCSCAyAD6ro19GwxFOY5sZ3A,267
|
|
613
|
-
endoreg_db/urls/__init__.py,sha256=
|
|
614
|
+
endoreg_db/urls/__init__.py,sha256=YpT06IceApAkWfQvNmqMku8F_vozWD4UDl6j3BamS_I,3303
|
|
614
615
|
endoreg_db/urls/anonymization.py,sha256=zLoOOpu4XSha002nOi0fiJUAT8Dff7u7RQFtdU4A6aw,1853
|
|
615
616
|
endoreg_db/urls/auth.py,sha256=t95D8n3fiOhkUiINVGygrW0jiQiJc_XNmfk2S8pcDxk,440
|
|
616
617
|
endoreg_db/urls/classification.py,sha256=2JdHsCSpLs5bZWiTsDpWvyLE_OJkf7LrCCOob7H8M-k,1802
|
|
617
618
|
endoreg_db/urls/examination.py,sha256=IWNIR-hsWKD3nfL27EzMMazcZnOa_imjgk8RL0mql2U,2344
|
|
618
619
|
endoreg_db/urls/files.py,sha256=qfa8mPDNF9SW4z66B26SCtX7WHyoAo1muS1DR2QwST8,192
|
|
619
620
|
endoreg_db/urls/label_video_segment_validate.py,sha256=bGWacxIG4pHnGRbnHL_L91ShKWfKCn5X-YXsHGs6i-I,1044
|
|
620
|
-
endoreg_db/urls/label_video_segments.py,sha256=
|
|
621
|
-
endoreg_db/urls/media.py,sha256=
|
|
621
|
+
endoreg_db/urls/label_video_segments.py,sha256=Xj7Gf-JSq5iB3ubit5aCaLMJcgQXgDmqMSCb-n-CIl8,1144
|
|
622
|
+
endoreg_db/urls/media.py,sha256=VzPx-4XuLQTO73QRWUa3VSw7XzpPN7IXdMOTX3uvFp8,10832
|
|
622
623
|
endoreg_db/urls/patient.py,sha256=VLKFbEiNgpfYLWFisbHidyoUnoQuEzj1U0SgZDpdPDM,588
|
|
623
624
|
endoreg_db/urls/report.py,sha256=9i3sOSofB7_PHGByr3DMghZFtcbjKf_U5PVSlxu9d4I,1917
|
|
624
625
|
endoreg_db/urls/requirements.py,sha256=5d-SD_7nsTA9YXlBeWdZuh-mXh26BkgH29fFBaTLjU8,455
|
|
@@ -682,7 +683,7 @@ endoreg_db/utils/video/names.py,sha256=m268j2Ynt94OYH6dYxeL8gzU5ODtFJD4OmzS7l0nB
|
|
|
682
683
|
endoreg_db/utils/video/streaming_processor.py,sha256=C-39DtxhSnL7B2cObFE5k829VLXl_Fl0KQFrFP368JA,13747
|
|
683
684
|
endoreg_db/utils/video/video_splitter.py,sha256=EZEnhNjaUva_9VxjcjScgRSrxsEuifhBjlwIMLX1qaA,3698
|
|
684
685
|
endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py,sha256=Lu1JuUD44B6yUAR9pcYLlQ-3g66VTktmzStuO0uGIj4,8752
|
|
685
|
-
endoreg_db/views/__init__.py,sha256=
|
|
686
|
+
endoreg_db/views/__init__.py,sha256=7XsOCeLP6x7WbNrmPXNpxh6EO2u3P8mw1v3p_EQEPQc,6607
|
|
686
687
|
endoreg_db/views/anonymization/__init__.py,sha256=s1_r9j0jPJsKHy1-isjFAlRF3Cw0o8EXxyUP7Xv1Kqo,698
|
|
687
688
|
endoreg_db/views/anonymization/media_management.py,sha256=ObiXjPa-KsSGs3IfmABE-TVzQZ2U6yJioFh64T7TtKY,16799
|
|
688
689
|
endoreg_db/views/anonymization/overview.py,sha256=fA4a4tZ4tbnWf3BUP6heAtqmHvinixUnDoI3dqPjTE0,8320
|
|
@@ -716,11 +717,11 @@ endoreg_db/views/label_video_segment/label_video_segment_detail.py,sha256=gs1llC
|
|
|
716
717
|
endoreg_db/views/label_video_segment/update_lvs_from_annotation.py,sha256=an3Bf4Jxap_vZrHW2XZV72fKkQhP3S2fsB3ZjXRjED8,1599
|
|
717
718
|
endoreg_db/views/label_video_segment/validate.py,sha256=1R7Ml-XgzZmzooYbPEnIkjm-u6rlvH-Yu5XGulhZEpI,8951
|
|
718
719
|
endoreg_db/views/media/__init__.py,sha256=JRRICKlyxrVQqN3ORM8WoJzVo2iRq6Mr72d-1REsM0k,1282
|
|
719
|
-
endoreg_db/views/media/pdf_media.py,sha256=
|
|
720
|
+
endoreg_db/views/media/pdf_media.py,sha256=0xUszgT7wbMQ5iW4ak4p_Xg78l1CMntsKqtnCLYp-EE,14573
|
|
720
721
|
endoreg_db/views/media/segments.py,sha256=d995_pLD2W6zdrB3bL9bdHrwS22sZXeG19-SLNU38gU,2613
|
|
721
722
|
endoreg_db/views/media/sensitive_metadata.py,sha256=CuIHLVGkjnBtWJHHERQvRApLzjkFbuRu-HBJEPqnhhQ,10456
|
|
722
|
-
endoreg_db/views/media/video_media.py,sha256=
|
|
723
|
-
endoreg_db/views/media/video_segments.py,sha256=
|
|
723
|
+
endoreg_db/views/media/video_media.py,sha256=rt3DmuxHSH52yWW_r1t5ilq4DJ3w571IpUvyz5ilxz8,9632
|
|
724
|
+
endoreg_db/views/media/video_segments.py,sha256=N1gHYRI4Mdn74Amiv_gcuPessPDtXo65RdLTT70ZOOs,20027
|
|
724
725
|
endoreg_db/views/meta/__init__.py,sha256=cMwPBx55ad5zRX9DILqFm-a_ATc5SRVSMEGyHTC5cOo,470
|
|
725
726
|
endoreg_db/views/meta/available_files_list.py,sha256=CBaYVkj2YKB5n_J0gop0vXHkpgTE9Aamqt4tdCjTN2I,6181
|
|
726
727
|
endoreg_db/views/meta/report_meta.py,sha256=oLFTQ5YCVoCKlcYfbiN89--_9drBhMLeW9Ck_tmq08E,1733
|
|
@@ -756,23 +757,22 @@ endoreg_db/views/patient_finding_location/__init__.py,sha256=RiUqJl22PkM2Iv6UcV8
|
|
|
756
757
|
endoreg_db/views/patient_finding_location/pfl_create.py,sha256=eZEtj4ST_Ue3YURna_x04MUKAeAo3mv_wfcGGlVO07g,2971
|
|
757
758
|
endoreg_db/views/patient_finding_morphology/__init__.py,sha256=Gw4REKbb14tlKGGf__XlS2Pi2ygA0iCh85LYIHndUy0,113
|
|
758
759
|
endoreg_db/views/patient_finding_morphology/pfm_create.py,sha256=-OYTH7iHPuSrYxbUrF7fQ6aAC0ES6UhiQ_Qo7tZi7II,2998
|
|
759
|
-
endoreg_db/views/pdf/__init__.py,sha256=
|
|
760
|
-
endoreg_db/views/pdf/
|
|
761
|
-
endoreg_db/views/pdf/
|
|
762
|
-
endoreg_db/views/pdf/reimport.py,sha256=GNUUFJS56qaegbhCdD4t3ytdp-EGPb5mRvq6BSe5QQ4,6902
|
|
760
|
+
endoreg_db/views/pdf/__init__.py,sha256=bmDbvDLRmhOYTuPHMMaJMJU67js9t_K6Df987wRs4wU,135
|
|
761
|
+
endoreg_db/views/pdf/pdf_stream.py,sha256=QkF7ggSNk-GZGKT_eOnflMv6Fls-piMmbx1FXrUPy04,7429
|
|
762
|
+
endoreg_db/views/pdf/reimport.py,sha256=9tMIsxZ5R83rC-GBcJt78QBLqmYaEBypFd6ToEeTsfk,6939
|
|
763
763
|
endoreg_db/views/report/__init__.py,sha256=mw1WncSWijE73mSzkZPWsQ66ii9icZMLmEEEx9iV4BA,241
|
|
764
764
|
endoreg_db/views/report/report_list.py,sha256=Ziav43FKYux2dsETaX7zUYs-g7__4laHwXEMZSq1Ahs,3940
|
|
765
765
|
endoreg_db/views/report/report_with_secure_url.py,sha256=vMGgngPGvNkPYxhNjSJG6rZKN0yuSoJNl1vZPiAoh6I,1042
|
|
766
766
|
endoreg_db/views/report/start_examination.py,sha256=iYC_40S4aJEGsel1Y4boZFAR5UQTPKp9TIWW3oJwgTc,224
|
|
767
767
|
endoreg_db/views/requirement/__init__.py,sha256=dJzmbtO5-fLyzY3hfV3XHi6BbwElv_cF6R0TpsIaRJw,159
|
|
768
768
|
endoreg_db/views/requirement/evaluate.py,sha256=_P5b6DoJBOnsGtIzL3usR2tTG1GXBRgsvG0LzQ9f9_A,10666
|
|
769
|
-
endoreg_db/views/requirement/lookup.py,sha256=
|
|
769
|
+
endoreg_db/views/requirement/lookup.py,sha256=BNR7Ai6QdPvdfSYZWMRTzwO8dLvVDuxoqD4YHi3LbaM,12544
|
|
770
770
|
endoreg_db/views/requirement/lookup_store.py,sha256=LyohEAfHtPy40zDuJUDyN4S02BB_AOAbPM_CZIcHHRQ,4922
|
|
771
771
|
endoreg_db/views/requirement_lookup/lookup.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
772
772
|
endoreg_db/views/requirement_lookup/lookup_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
773
773
|
endoreg_db/views/stats/__init__.py,sha256=VHxrW0-RAWYki_89jWWJ0TrD7Nb0D3m-VjYV6bvP2k4,259
|
|
774
774
|
endoreg_db/views/stats/stats_views.py,sha256=v9ue1BKXdcApOgyolgNiT3hazx1xSVVvo26r91IozWY,8656
|
|
775
|
-
endoreg_db/views/video/__init__.py,sha256=
|
|
775
|
+
endoreg_db/views/video/__init__.py,sha256=KXne9Hcg_rhWogmnmf_ZpbrpnNfJlhwbF0cqBXhYCEY,1196
|
|
776
776
|
endoreg_db/views/video/correction.py,sha256=VEzpnDPCAhsYatXVRZhGZA5FpFS_t9mENs89zFJsoYo,19750
|
|
777
777
|
endoreg_db/views/video/reimport.py,sha256=gSDBQ_Bam2xpJIj1SIMoLKnoBDBRgQ9V_TZdK9OICrI,8959
|
|
778
778
|
endoreg_db/views/video/segmentation.py,sha256=jzsLB95rYnHALSX2E_QNpAM9BpE1pbteOBxcAr_EjZo,11758
|
|
@@ -782,13 +782,12 @@ endoreg_db/views/video/video_analyze.py,sha256=vxQHnXRFH5Y6IaWEmEnE4Svkz6Vjw1O9N
|
|
|
782
782
|
endoreg_db/views/video/video_apply_mask.py,sha256=spGK4oXMAKhVotJuwZGndbKKws6klveKe35mbX7Rv6k,1630
|
|
783
783
|
endoreg_db/views/video/video_correction.py,sha256=9mFICVvRSxp0WhGv7ib4d4M1hJs1iIhYmTl2OUIXQAg,767
|
|
784
784
|
endoreg_db/views/video/video_download_processed.py,sha256=tp5llYJKyQD0WSr4Fvqi-YrgBw2EPPe23E8F8SZbR4w,2000
|
|
785
|
-
endoreg_db/views/video/video_examination_viewset.py,sha256=
|
|
786
|
-
endoreg_db/views/video/video_media.py,sha256=fvMQmSM1a-3rxpx_wK0wee9sRXV3EZz2bF8jLRAeaIQ,7022
|
|
785
|
+
endoreg_db/views/video/video_examination_viewset.py,sha256=ej6CUK1JGFN7JmZOj25g1heaIIAwh6cf1HaYFmcR9EE,8331
|
|
787
786
|
endoreg_db/views/video/video_meta.py,sha256=C1wBMTtQb_yzEUrhFGAy2UHEWMk_CbU75WXX_5z00sE,1021
|
|
788
787
|
endoreg_db/views/video/video_processing_history.py,sha256=mhFuS8RG5GV8E-lTtuD0qrq-bIpnUFp8vy9aERfC-J8,770
|
|
789
788
|
endoreg_db/views/video/video_remove_frames.py,sha256=2FmvNrSPM0fUXiBxINN6vBUUDCqDlBkNcGR3WsLDgKo,1696
|
|
790
789
|
endoreg_db/views/video/video_stream.py,sha256=kLyuf0ORTmsLeYUQkTQ6iRYqlIQozWhMMR3Lhfe_trk,12148
|
|
791
|
-
endoreg_db-0.8.
|
|
792
|
-
endoreg_db-0.8.
|
|
793
|
-
endoreg_db-0.8.
|
|
794
|
-
endoreg_db-0.8.
|
|
790
|
+
endoreg_db-0.8.6.1.dist-info/METADATA,sha256=x0wow7qLlIoTyTfPlAhaEQCeJAlL2H_0uigFCE5A4rU,14719
|
|
791
|
+
endoreg_db-0.8.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
792
|
+
endoreg_db-0.8.6.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
793
|
+
endoreg_db-0.8.6.1.dist-info/RECORD,,
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
from django.http import FileResponse, Http404, StreamingHttpResponse
|
|
2
|
-
import mimetypes
|
|
3
|
-
import os
|
|
4
|
-
import logging
|
|
5
|
-
import re
|
|
6
|
-
from ...models import RawPdfFile
|
|
7
|
-
from ...serializers._old.raw_pdf_meta_validation import PDFFileForMetaSerializer, SensitiveMetaUpdateSerializer
|
|
8
|
-
from rest_framework.views import APIView
|
|
9
|
-
from rest_framework.response import Response
|
|
10
|
-
from rest_framework import status
|
|
11
|
-
from ...models import SensitiveMeta
|
|
12
|
-
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
|
13
|
-
from django.utils.decorators import method_decorator
|
|
14
|
-
from django.db import transaction
|
|
15
|
-
from django.urls import reverse
|
|
16
|
-
from django.utils.encoding import iri_to_uri
|
|
17
|
-
from endoreg_db.utils.paths import PDF_DIR, STORAGE_DIR
|
|
18
|
-
from .pdf_stream_views import ClosingFileWrapper
|
|
19
|
-
|
|
20
|
-
logger = logging.getLogger(__name__)
|
|
21
|
-
_RANGE_RE = re.compile(r"bytes=(\d+)-(\d*)")
|
|
22
|
-
|
|
23
|
-
class PDFMediaView(APIView):
|
|
24
|
-
"""
|
|
25
|
-
Unified API for PDFs to support frontend flows:
|
|
26
|
-
- Without `id`: returns next PDF metadata (including anonymized_text) and stream URLs
|
|
27
|
-
- With `id`: streams the PDF (original by default; `?variant=anonymized` for anonymized)
|
|
28
|
-
- Integrates with Media Management expectations (clean deletion after validation is handled elsewhere)
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
def get(self, request):
|
|
32
|
-
"""
|
|
33
|
-
Handles both:
|
|
34
|
-
- Fetching PDF metadata (if `id` is NOT provided)
|
|
35
|
-
- Streaming the actual PDF file (if `id` is provided)
|
|
36
|
-
"""
|
|
37
|
-
pdf_id = request.GET.get("id")
|
|
38
|
-
last_id = request.GET.get("last_id")
|
|
39
|
-
|
|
40
|
-
if pdf_id:
|
|
41
|
-
return self.serve_pdf_file(pdf_id)
|
|
42
|
-
else:
|
|
43
|
-
return self.fetch_pdf_metadata(last_id)
|
|
44
|
-
|
|
45
|
-
def fetch_pdf_metadata(self, last_id):
|
|
46
|
-
"""
|
|
47
|
-
Fetches the first or next available PDF metadata and provides stream URLs.
|
|
48
|
-
"""
|
|
49
|
-
pdf_entry = PDFFileForMetaSerializer.get_next_pdf(last_id)
|
|
50
|
-
if pdf_entry is None:
|
|
51
|
-
return Response({"error": "No more PDFs available."}, status=status.HTTP_404_NOT_FOUND)
|
|
52
|
-
|
|
53
|
-
serialized_pdf = PDFFileForMetaSerializer(pdf_entry, context={'request': self.request})
|
|
54
|
-
|
|
55
|
-
# Build stream URLs pointing to this unified endpoint
|
|
56
|
-
try:
|
|
57
|
-
media_url = reverse('pdf_media')
|
|
58
|
-
except Exception:
|
|
59
|
-
media_url = "/api/pdf/media/"
|
|
60
|
-
stream_url = f"{media_url}?id={pdf_entry.id}"
|
|
61
|
-
anon_stream_url = f"{media_url}?id={pdf_entry.id}&variant=anonymized"
|
|
62
|
-
|
|
63
|
-
data = dict(serialized_pdf.data)
|
|
64
|
-
data.update({
|
|
65
|
-
'stream_url': iri_to_uri(self.request.build_absolute_uri(stream_url)),
|
|
66
|
-
'anonymized_stream_url': iri_to_uri(self.request.build_absolute_uri(anon_stream_url)),
|
|
67
|
-
'pdf_id': pdf_entry.id,
|
|
68
|
-
'has_anonymized': bool(getattr(pdf_entry, 'anonymized_file', None) and getattr(pdf_entry.anonymized_file, 'name', None)),
|
|
69
|
-
})
|
|
70
|
-
return Response(data, status=status.HTTP_200_OK)
|
|
71
|
-
|
|
72
|
-
@method_decorator(xframe_options_sameorigin)
|
|
73
|
-
def serve_pdf_file(self, pdf_id):
|
|
74
|
-
"""
|
|
75
|
-
Streams the actual PDF file (original or anonymized) with Range support.
|
|
76
|
-
Query param `variant=anonymized` selects anonymized file; default is original.
|
|
77
|
-
"""
|
|
78
|
-
variant = (self.request.GET.get('variant') or 'original').lower()
|
|
79
|
-
range_header = self.request.headers.get("Range")
|
|
80
|
-
|
|
81
|
-
try:
|
|
82
|
-
pdf_entry = RawPdfFile.objects.get(id=pdf_id)
|
|
83
|
-
except RawPdfFile.DoesNotExist:
|
|
84
|
-
return Response({"error": "Invalid PDF ID."}, status=status.HTTP_400_BAD_REQUEST)
|
|
85
|
-
|
|
86
|
-
# Choose file according to variant
|
|
87
|
-
file_field = None
|
|
88
|
-
if variant == 'anonymized' and getattr(pdf_entry, 'anonymized_file', None):
|
|
89
|
-
file_field = pdf_entry.anonymized_file
|
|
90
|
-
else:
|
|
91
|
-
file_field = pdf_entry.file
|
|
92
|
-
|
|
93
|
-
if not file_field:
|
|
94
|
-
return Response({"error": "PDF file not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
95
|
-
|
|
96
|
-
# Resolve path and attempt self-heal for originals
|
|
97
|
-
try:
|
|
98
|
-
file_path = file_field.path
|
|
99
|
-
except Exception:
|
|
100
|
-
file_path = None
|
|
101
|
-
|
|
102
|
-
if not file_path or not os.path.exists(file_path):
|
|
103
|
-
if variant != 'anonymized':
|
|
104
|
-
# Try to self-heal original reference to sensitive storage
|
|
105
|
-
sensitive_path = os.path.join(str(PDF_DIR), "sensitive", f"{pdf_entry.pdf_hash}.pdf")
|
|
106
|
-
if os.path.exists(sensitive_path):
|
|
107
|
-
try:
|
|
108
|
-
relative_name = os.path.relpath(sensitive_path, str(STORAGE_DIR))
|
|
109
|
-
if getattr(pdf_entry.file, 'name', None) != relative_name:
|
|
110
|
-
pdf_entry.file.name = relative_name
|
|
111
|
-
pdf_entry.save(update_fields=['file'])
|
|
112
|
-
logger.info("Self-healed PDF file reference for ID %s -> %s", pdf_entry.id, pdf_entry.file.path)
|
|
113
|
-
file_path = sensitive_path
|
|
114
|
-
except Exception as e:
|
|
115
|
-
logger.error("Failed to self-heal file path for PDF %s: %s", pdf_entry.id, e)
|
|
116
|
-
file_path = sensitive_path
|
|
117
|
-
# If still missing (or anonymized missing), fail
|
|
118
|
-
if not file_path or not os.path.exists(file_path):
|
|
119
|
-
raise Http404("PDF file not found on server.")
|
|
120
|
-
|
|
121
|
-
# Prepare headers
|
|
122
|
-
safe_filename = os.path.basename(getattr(file_field, 'name', None) or f"document_{pdf_id}.pdf")
|
|
123
|
-
if not safe_filename.endswith('.pdf'):
|
|
124
|
-
safe_filename += '.pdf'
|
|
125
|
-
|
|
126
|
-
file_size = os.path.getsize(file_path)
|
|
127
|
-
|
|
128
|
-
# Range support
|
|
129
|
-
if range_header:
|
|
130
|
-
match = _RANGE_RE.match(range_header)
|
|
131
|
-
if match:
|
|
132
|
-
start = int(match.group(1))
|
|
133
|
-
end = int(match.group(2) or file_size - 1)
|
|
134
|
-
|
|
135
|
-
if start < 0 or start >= file_size:
|
|
136
|
-
raise Http404("Invalid range")
|
|
137
|
-
if end >= file_size:
|
|
138
|
-
end = file_size - 1
|
|
139
|
-
|
|
140
|
-
chunk_size = end - start + 1
|
|
141
|
-
try:
|
|
142
|
-
fh = open(file_path, 'rb')
|
|
143
|
-
fh.seek(start)
|
|
144
|
-
resp = StreamingHttpResponse(
|
|
145
|
-
ClosingFileWrapper(fh, blksize=8192),
|
|
146
|
-
status=206,
|
|
147
|
-
content_type="application/pdf",
|
|
148
|
-
)
|
|
149
|
-
resp["Content-Length"] = str(chunk_size)
|
|
150
|
-
resp["Content-Range"] = f"bytes {start}-{end}/{file_size}"
|
|
151
|
-
resp["Accept-Ranges"] = "bytes"
|
|
152
|
-
resp["Content-Disposition"] = f'inline; filename="{safe_filename}"'
|
|
153
|
-
return resp
|
|
154
|
-
except (OSError, IOError) as e:
|
|
155
|
-
logger.error(f"Error opening PDF file for range request: {e}")
|
|
156
|
-
raise Http404("Error accessing PDF file")
|
|
157
|
-
|
|
158
|
-
# Fallback: serve full file
|
|
159
|
-
mime_type, _ = mimetypes.guess_type(file_path)
|
|
160
|
-
try:
|
|
161
|
-
fh = open(file_path, 'rb')
|
|
162
|
-
response = FileResponse(fh, content_type=mime_type or "application/pdf")
|
|
163
|
-
response["Content-Length"] = str(file_size)
|
|
164
|
-
response["Accept-Ranges"] = "bytes"
|
|
165
|
-
response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
|
|
166
|
-
return response
|
|
167
|
-
except (OSError, IOError) as e:
|
|
168
|
-
logger.error(f"Error opening PDF file: {e}")
|
|
169
|
-
raise Http404("Error accessing PDF file")
|
|
170
|
-
|
|
171
|
-
class UpdateSensitiveMetaView(APIView):
|
|
172
|
-
"""
|
|
173
|
-
API endpoint to update patient details in the SensitiveMeta table.
|
|
174
|
-
Handles partial updates (only edited fields) and raw file deletion after validation acceptance.
|
|
175
|
-
"""
|
|
176
|
-
|
|
177
|
-
@transaction.atomic
|
|
178
|
-
def patch(self, request, *args, **kwargs):
|
|
179
|
-
"""
|
|
180
|
-
Updates the provided fields for a specific patient record.
|
|
181
|
-
Only updates fields that are sent in the request.
|
|
182
|
-
Automatically deletes raw PDF files when validation is accepted.
|
|
183
|
-
"""
|
|
184
|
-
sensitive_meta_id = request.data.get("sensitive_meta_id")
|
|
185
|
-
|
|
186
|
-
if not sensitive_meta_id:
|
|
187
|
-
return Response({"error": "sensitive_meta_id is required."}, status=status.HTTP_400_BAD_REQUEST)
|
|
188
|
-
|
|
189
|
-
try:
|
|
190
|
-
sensitive_meta = SensitiveMeta.objects.get(id=sensitive_meta_id)
|
|
191
|
-
except SensitiveMeta.DoesNotExist:
|
|
192
|
-
return Response({"error": "Patient record not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
193
|
-
|
|
194
|
-
is_accepting_validation = request.data.get("is_verified", False)
|
|
195
|
-
delete_raw_files = request.data.get("delete_raw_files", False)
|
|
196
|
-
if is_accepting_validation:
|
|
197
|
-
delete_raw_files = True
|
|
198
|
-
logger.info(f"Validation accepted for PDF SensitiveMeta {sensitive_meta_id}, marking raw files for deletion")
|
|
199
|
-
|
|
200
|
-
serializer = SensitiveMetaUpdateSerializer(sensitive_meta, data=request.data, partial=True)
|
|
201
|
-
|
|
202
|
-
if serializer.is_valid():
|
|
203
|
-
updated_sm = serializer.save()
|
|
204
|
-
if delete_raw_files and updated_sm.is_verified:
|
|
205
|
-
try:
|
|
206
|
-
pdf_file = RawPdfFile.objects.filter(sensitive_meta=updated_sm).first()
|
|
207
|
-
if pdf_file:
|
|
208
|
-
self._schedule_raw_file_deletion(pdf_file)
|
|
209
|
-
logger.info(f"Scheduled raw file deletion for PDF {pdf_file.id}")
|
|
210
|
-
else:
|
|
211
|
-
logger.warning(f"No PDF file found for SensitiveMeta {sensitive_meta_id}")
|
|
212
|
-
except Exception as e:
|
|
213
|
-
logger.error(f"Error scheduling raw file deletion for PDF SensitiveMeta {sensitive_meta_id}: {e}")
|
|
214
|
-
return Response({"message": "Patient information updated successfully.", "updated_data": serializer.data}, status=status.HTTP_200_OK)
|
|
215
|
-
|
|
216
|
-
return Response({"error": "Invalid data.", "details": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
|
|
217
|
-
|
|
218
|
-
def _schedule_raw_file_deletion(self, pdf_file):
|
|
219
|
-
"""
|
|
220
|
-
Schedule deletion of raw PDF file after validation acceptance.
|
|
221
|
-
Deletes the original (sensitive) file but keeps anonymized_file for frontend.
|
|
222
|
-
"""
|
|
223
|
-
try:
|
|
224
|
-
def cleanup_raw_files():
|
|
225
|
-
try:
|
|
226
|
-
if pdf_file.file and getattr(pdf_file.file, 'path', None) and os.path.exists(pdf_file.file.path):
|
|
227
|
-
logger.info(f"Deleting original (sensitive) PDF file: {pdf_file.file.path}")
|
|
228
|
-
os.remove(pdf_file.file.path)
|
|
229
|
-
pdf_file.file = None
|
|
230
|
-
pdf_file.save(update_fields=['file'])
|
|
231
|
-
logger.info(f"Successfully deleted original file for PDF {pdf_file.id}")
|
|
232
|
-
else:
|
|
233
|
-
logger.info(f"Original file already deleted or not found for PDF {pdf_file.id}")
|
|
234
|
-
except Exception as e:
|
|
235
|
-
logger.error(f"Error during raw file cleanup for PDF {pdf_file.id}: {e}")
|
|
236
|
-
transaction.on_commit(cleanup_raw_files)
|
|
237
|
-
except Exception as e:
|
|
238
|
-
logger.error(f"Error scheduling raw file deletion for PDF {pdf_file.id}: {e}")
|
|
239
|
-
raise
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import logging
|
|
3
|
-
from django.http import FileResponse, StreamingHttpResponse, Http404
|
|
4
|
-
from rest_framework.views import APIView
|
|
5
|
-
from ...utils.permissions import EnvironmentAwarePermission
|
|
6
|
-
from endoreg_db.models import RawPdfFile
|
|
7
|
-
import os
|
|
8
|
-
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger(__name__)
|
|
11
|
-
_RANGE_RE = re.compile(r"bytes=(\d+)-(\d*)")
|
|
12
|
-
|
|
13
|
-
class ClosingFileWrapper:
|
|
14
|
-
"""Custom file wrapper that ensures file is closed after streaming"""
|
|
15
|
-
def __init__(self, file_handle, blksize=8192):
|
|
16
|
-
self.file_handle = file_handle
|
|
17
|
-
self.blksize = blksize
|
|
18
|
-
|
|
19
|
-
def __iter__(self):
|
|
20
|
-
return self
|
|
21
|
-
|
|
22
|
-
def __next__(self):
|
|
23
|
-
data = self.file_handle.read(self.blksize)
|
|
24
|
-
if not data:
|
|
25
|
-
self.file_handle.close()
|
|
26
|
-
raise StopIteration
|
|
27
|
-
return data
|
|
28
|
-
|
|
29
|
-
def close(self):
|
|
30
|
-
if hasattr(self.file_handle, 'close'):
|
|
31
|
-
self.file_handle.close()
|
|
32
|
-
|
|
33
|
-
class PDFStreamView(APIView):
|
|
34
|
-
"""
|
|
35
|
-
Streams a PDF file with correct HTTP range support and proper file handle management.
|
|
36
|
-
"""
|
|
37
|
-
permission_classes = [EnvironmentAwarePermission]
|
|
38
|
-
|
|
39
|
-
@xframe_options_sameorigin
|
|
40
|
-
def get(self, request, pdf_id: int, *args, **kwargs):
|
|
41
|
-
try:
|
|
42
|
-
pdf_obj = RawPdfFile.objects.filter(pk=pdf_id).first()
|
|
43
|
-
if not pdf_obj or not pdf_obj.file:
|
|
44
|
-
logger.warning(f"PDF not found: ID {pdf_id}")
|
|
45
|
-
raise Http404("PDF not found")
|
|
46
|
-
|
|
47
|
-
# Check if file exists on filesystem
|
|
48
|
-
try:
|
|
49
|
-
file_path = pdf_obj.file.path
|
|
50
|
-
if not os.path.exists(file_path):
|
|
51
|
-
logger.error(f"PDF file does not exist on filesystem: {file_path}")
|
|
52
|
-
raise Http404("PDF file not found on filesystem")
|
|
53
|
-
|
|
54
|
-
file_size = os.path.getsize(file_path)
|
|
55
|
-
except (OSError, IOError, AttributeError) as e:
|
|
56
|
-
logger.error(f"Error accessing PDF file {pdf_id}: {e}")
|
|
57
|
-
raise Http404("PDF file not accessible")
|
|
58
|
-
|
|
59
|
-
# Generate safe filename
|
|
60
|
-
safe_filename = os.path.basename(pdf_obj.file.name) if pdf_obj.file.name else f"document_{pdf_id}.pdf"
|
|
61
|
-
if not safe_filename.endswith('.pdf'):
|
|
62
|
-
safe_filename += '.pdf'
|
|
63
|
-
|
|
64
|
-
# Handle Range requests
|
|
65
|
-
range_header = request.headers.get("Range")
|
|
66
|
-
if range_header:
|
|
67
|
-
logger.debug(f"Range request for PDF {pdf_id}: {range_header}")
|
|
68
|
-
match = _RANGE_RE.match(range_header)
|
|
69
|
-
if match:
|
|
70
|
-
start = int(match.group(1))
|
|
71
|
-
end = int(match.group(2) or file_size - 1)
|
|
72
|
-
|
|
73
|
-
# Validate range
|
|
74
|
-
if start >= file_size or start < 0:
|
|
75
|
-
logger.warning(f"Invalid range start {start} for file size {file_size}")
|
|
76
|
-
raise Http404("Invalid range")
|
|
77
|
-
|
|
78
|
-
if end >= file_size:
|
|
79
|
-
end = file_size - 1
|
|
80
|
-
|
|
81
|
-
chunk_size = end - start + 1
|
|
82
|
-
|
|
83
|
-
try:
|
|
84
|
-
file_handle = open(file_path, "rb")
|
|
85
|
-
file_handle.seek(start)
|
|
86
|
-
|
|
87
|
-
logger.debug(f"Serving PDF {pdf_id} range {start}-{end}/{file_size}")
|
|
88
|
-
|
|
89
|
-
response = StreamingHttpResponse(
|
|
90
|
-
ClosingFileWrapper(file_handle, blksize=8192),
|
|
91
|
-
status=206,
|
|
92
|
-
content_type="application/pdf",
|
|
93
|
-
)
|
|
94
|
-
response["Content-Length"] = str(chunk_size)
|
|
95
|
-
response["Content-Range"] = f"bytes {start}-{end}/{file_size}"
|
|
96
|
-
response["Accept-Ranges"] = "bytes"
|
|
97
|
-
response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
|
|
98
|
-
|
|
99
|
-
return response
|
|
100
|
-
except (OSError, IOError) as e:
|
|
101
|
-
logger.error(f"Error opening PDF file for range request: {e}")
|
|
102
|
-
raise Http404("Error accessing PDF file")
|
|
103
|
-
else:
|
|
104
|
-
logger.warning(f"Invalid Range header format: {range_header}")
|
|
105
|
-
|
|
106
|
-
# Serve entire file using FileResponse (automatically handles file closing)
|
|
107
|
-
logger.debug(f"Serving full PDF {pdf_id} ({file_size} bytes)")
|
|
108
|
-
|
|
109
|
-
try:
|
|
110
|
-
file_handle = open(file_path, "rb")
|
|
111
|
-
response = FileResponse(
|
|
112
|
-
file_handle,
|
|
113
|
-
content_type="application/pdf"
|
|
114
|
-
)
|
|
115
|
-
response["Content-Length"] = str(file_size)
|
|
116
|
-
response["Accept-Ranges"] = "bytes"
|
|
117
|
-
response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
|
|
118
|
-
|
|
119
|
-
# FileResponse will take ownership of file_handle and close it after response
|
|
120
|
-
return response
|
|
121
|
-
except (OSError, IOError) as e:
|
|
122
|
-
logger.error(f"Error opening PDF file: {e}")
|
|
123
|
-
raise Http404("Error accessing PDF file")
|
|
124
|
-
|
|
125
|
-
except Exception as e:
|
|
126
|
-
logger.error(f"Unexpected error streaming PDF {pdf_id}: {e}", exc_info=True)
|
|
127
|
-
raise Http404("Error streaming PDF")
|