endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__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/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +2 -11
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/examination/examinations/data.yaml +114 -14
- endoreg_db/data/examination/time-type/data.yaml +0 -3
- endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
- endoreg_db/data/finding/00_generic.yaml +35 -0
- endoreg_db/data/finding/00_generic_complication.yaml +9 -0
- endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
- endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
- endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
- endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
- endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
- endoreg_db/data/finding_classification/00_generic.yaml +44 -0
- endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
- endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
- endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
- endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
- endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
- endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
- endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
- endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
- endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
- endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
- endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
- endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
- endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
- endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
- endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
- endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
- endoreg_db/data/finding_type/data.yaml +8 -12
- endoreg_db/data/requirement/01_patient_data.yaml +93 -0
- endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +4 -2
- endoreg_db/forms/examination_form.py +1 -1
- endoreg_db/helpers/data_loader.py +125 -53
- endoreg_db/helpers/default_objects.py +116 -81
- endoreg_db/import_files/__init__.py +27 -0
- endoreg_db/import_files/context/__init__.py +7 -0
- endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
- endoreg_db/import_files/context/ensure_center.py +17 -0
- endoreg_db/import_files/context/file_lock.py +66 -0
- endoreg_db/import_files/context/import_context.py +43 -0
- endoreg_db/import_files/context/validate_directories.py +56 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +76 -0
- endoreg_db/import_files/file_storage/create_video_file.py +75 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
- endoreg_db/import_files/file_storage/state_management.py +400 -0
- endoreg_db/import_files/file_storage/storage.py +36 -0
- endoreg_db/import_files/import_service.md +26 -0
- endoreg_db/import_files/processing/__init__.py +11 -0
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
- endoreg_db/import_files/report_import_service.py +141 -0
- endoreg_db/import_files/video_import_service.py +150 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_report.py +130 -65
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +2 -2
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +5 -5
- endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
- endoreg_db/management/commands/load_base_db_data.py +5 -134
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_contraindication_data.py +14 -16
- endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
- endoreg_db/management/commands/load_disease_classification_data.py +15 -18
- endoreg_db/management/commands/load_disease_data.py +25 -28
- endoreg_db/management/commands/load_endoscope_data.py +20 -27
- endoreg_db/management/commands/load_event_data.py +14 -16
- endoreg_db/management/commands/load_examination_data.py +31 -44
- endoreg_db/management/commands/load_examination_indication_data.py +20 -21
- endoreg_db/management/commands/load_finding_data.py +52 -80
- endoreg_db/management/commands/load_information_source.py +21 -23
- endoreg_db/management/commands/load_lab_value_data.py +17 -26
- endoreg_db/management/commands/load_medication_data.py +13 -12
- endoreg_db/management/commands/load_organ_data.py +15 -19
- endoreg_db/management/commands/load_pdf_type_data.py +19 -18
- endoreg_db/management/commands/load_profession_data.py +14 -17
- endoreg_db/management/commands/load_qualification_data.py +20 -23
- endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
- endoreg_db/management/commands/load_requirement_data.py +62 -39
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +7 -6
- endoreg_db/management/commands/load_shift_data.py +20 -23
- endoreg_db/management/commands/load_tag_data.py +8 -11
- endoreg_db/management/commands/load_unit_data.py +17 -19
- endoreg_db/management/commands/setup_endoreg_db.py +3 -3
- endoreg_db/management/commands/start_filewatcher.py +46 -37
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/management/commands/validate_video_files.py +1 -5
- endoreg_db/migrations/0001_initial.py +297 -250
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +129 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +8 -9
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +194 -194
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/processing_history/__init__.py +5 -0
- endoreg_db/models/media/processing_history/processing_history.py +96 -0
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +139 -77
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +174 -112
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +113 -61
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +39 -20
- endoreg_db/models/medical/examination/examination_indication.py +30 -95
- endoreg_db/models/medical/examination/examination_time.py +23 -8
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +32 -40
- endoreg_db/models/medical/finding/finding_classification.py +42 -72
- endoreg_db/models/medical/finding/finding_intervention.py +25 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +26 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +6 -6
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +125 -18
- endoreg_db/models/metadata/pdf_meta.py +31 -24
- endoreg_db/models/metadata/sensitive_meta.py +105 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +50 -29
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/report/report.py +6 -0
- endoreg_db/models/requirement/requirement.py +329 -361
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +103 -112
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +49 -51
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +101 -68
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +110 -90
- endoreg_db/models/upload_job.py +35 -34
- endoreg_db/models/utils.py +28 -25
- endoreg_db/queries/__init__.py +3 -1
- endoreg_db/root_urls.py +21 -2
- endoreg_db/schemas/examination_evaluation.py +1 -1
- endoreg_db/serializers/__init__.py +2 -10
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
- endoreg_db/serializers/meta/__init__.py +1 -6
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/file_overview.py +11 -99
- endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
- endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
- endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_file_list.py +65 -34
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/services/__old/pdf_import.py +1487 -0
- endoreg_db/services/__old/video_import.py +1306 -0
- endoreg_db/services/anonymization.py +128 -89
- endoreg_db/services/lookup_service.py +65 -52
- endoreg_db/services/lookup_store.py +2 -2
- endoreg_db/services/pdf_import.py +0 -1382
- endoreg_db/services/report_import.py +10 -0
- endoreg_db/services/video_import.py +6 -1255
- endoreg_db/tasks/upload_tasks.py +79 -70
- endoreg_db/tasks/video_ingest.py +8 -4
- endoreg_db/urls/__init__.py +5 -32
- endoreg_db/urls/ai.py +32 -0
- endoreg_db/urls/media.py +121 -83
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +142 -40
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/paths.py +110 -46
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/Readme.md +1 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +85 -183
- endoreg_db/views/ai/__init__.py +8 -0
- endoreg_db/views/ai/label.py +155 -0
- endoreg_db/views/anonymization/media_management.py +202 -166
- endoreg_db/views/anonymization/overview.py +99 -67
- endoreg_db/views/anonymization/validate.py +182 -44
- endoreg_db/views/media/__init__.py +7 -20
- endoreg_db/views/media/pdf_media.py +197 -174
- endoreg_db/views/media/sensitive_metadata.py +193 -138
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/meta/__init__.py +0 -8
- endoreg_db/views/misc/__init__.py +1 -7
- endoreg_db/views/misc/upload_views.py +94 -93
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/report/__init__.py +5 -7
- endoreg_db/views/{pdf → report}/reimport.py +22 -22
- endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +17 -3
- endoreg_db/views/requirement/lookup_store.py +22 -90
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +23 -24
- endoreg_db/views/video/correction.py +201 -172
- endoreg_db/views/video/reimport.py +1 -1
- endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
- endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
- endoreg_db/views/video/video_stream.py +7 -8
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
- endoreg_db/data/finding/anatomy_colon.yaml +0 -128
- endoreg_db/data/finding/colonoscopy.yaml +0 -40
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
- endoreg_db/data/finding/complication.yaml +0 -16
- endoreg_db/data/finding/data.yaml +0 -105
- endoreg_db/data/finding/examination_setting.yaml +0 -16
- endoreg_db/data/finding/medication_related.yaml +0 -18
- endoreg_db/data/finding/outcome.yaml +0 -12
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
- endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
- endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
- endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
- endoreg_db/data/finding_classification/medication_related.yaml +0 -23
- endoreg_db/data/finding_classification/visualized.yaml +0 -33
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
- endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
- endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
- endoreg_db/data/requirement/age.yaml +0 -26
- endoreg_db/data/requirement/gender.yaml +0 -25
- endoreg_db/management/commands/init_default_ai_model.py +0 -112
- endoreg_db/management/commands/reset_celery_schedule.py +0 -9
- endoreg_db/management/commands/validate_video.py +0 -204
- endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
- endoreg_db/migrations/0003_add_center_display_name.py +0 -30
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/renames.yml +0 -8
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
- endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
- endoreg_db/serializers/_old/video.py +0 -71
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
- endoreg_db/serializers/meta/report_meta.py +0 -53
- endoreg_db/serializers/report/__init__.py +0 -9
- endoreg_db/serializers/report/mixins.py +0 -45
- endoreg_db/serializers/report/report.py +0 -105
- endoreg_db/serializers/report/report_list.py +0 -22
- endoreg_db/serializers/report/secure_file_url.py +0 -26
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/services/requirements_object.py +0 -147
- endoreg_db/services/storage_aware_video_processor.py +0 -344
- endoreg_db/urls/files.py +0 -6
- endoreg_db/urls/label_video_segment_validate.py +0 -33
- endoreg_db/urls/label_video_segments.py +0 -46
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
- endoreg_db/views/label/__init__.py +0 -5
- endoreg_db/views/label/label.py +0 -15
- endoreg_db/views/label_video_segment/__init__.py +0 -16
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
- endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
- endoreg_db/views/label_video_segment/validate.py +0 -226
- endoreg_db/views/media/segments.py +0 -71
- endoreg_db/views/meta/available_files_list.py +0 -146
- endoreg_db/views/meta/report_meta.py +0 -53
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
- endoreg_db/views/misc/secure_file_serving_view.py +0 -80
- endoreg_db/views/misc/secure_file_url_view.py +0 -84
- endoreg_db/views/misc/secure_url_validate.py +0 -79
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
- endoreg_db/views/patient_finding_location/__init__.py +0 -5
- endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
- endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
- endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
- endoreg_db/views/pdf/__init__.py +0 -8
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/segmentation.py +0 -274
- endoreg_db/views/video/task_status.py +0 -49
- endoreg_db/views/video/timeline.py +0 -46
- endoreg_db/views/video/video_analyze.py +0 -52
- endoreg_db/views.py +0 -0
- /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
- /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
- /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
- /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
- /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
- /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
- /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
- /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
- /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
- /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
- /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
- /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
- /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
# endoreg_db/api/views/anonymization_overview.py
|
|
2
2
|
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from django.http import JsonResponse
|
|
3
6
|
from rest_framework import status
|
|
4
7
|
from rest_framework.decorators import api_view, permission_classes
|
|
5
|
-
from rest_framework.response import Response
|
|
6
|
-
from endoreg_db.utils.permissions import DEBUG_PERMISSIONS
|
|
7
|
-
from endoreg_db.services.anonymization import AnonymizationService
|
|
8
|
-
from endoreg_db.services.polling_coordinator import PollingCoordinator, ProcessingLockContext
|
|
9
8
|
from rest_framework.generics import ListAPIView
|
|
10
9
|
from rest_framework.pagination import PageNumberPagination
|
|
11
|
-
from
|
|
10
|
+
from rest_framework.response import Response
|
|
11
|
+
|
|
12
|
+
from endoreg_db.authz.permissions import PolicyPermission # import RBAC
|
|
13
|
+
from endoreg_db.models import RawPdfFile, VideoFile
|
|
14
|
+
from endoreg_db.services.anonymization import AnonymizationService
|
|
15
|
+
from endoreg_db.services.polling_coordinator import (
|
|
16
|
+
PollingCoordinator,
|
|
17
|
+
ProcessingLockContext,
|
|
18
|
+
)
|
|
19
|
+
from endoreg_db.utils.permissions import DEBUG_PERMISSIONS
|
|
20
|
+
|
|
12
21
|
from ...serializers import FileOverviewSerializer, VoPPatientDataSerializer
|
|
13
|
-
|
|
14
|
-
import logging
|
|
22
|
+
|
|
15
23
|
logger = logging.getLogger(__name__)
|
|
16
|
-
PERMS = DEBUG_PERMISSIONS
|
|
24
|
+
PERMS = DEBUG_PERMISSIONS # shorten
|
|
25
|
+
|
|
17
26
|
|
|
18
27
|
# ---------- overview ----------------------------------------------------
|
|
19
28
|
class NoPagination(PageNumberPagination):
|
|
@@ -24,10 +33,12 @@ class AnonymizationOverviewView(ListAPIView):
|
|
|
24
33
|
"""
|
|
25
34
|
GET /api/anonymization/items/overview/
|
|
26
35
|
--------------------------------------
|
|
27
|
-
Returns a flat list (Video +
|
|
36
|
+
Returns a flat list (Video + report) ordered by newest upload first.
|
|
28
37
|
"""
|
|
38
|
+
|
|
29
39
|
serializer_class = FileOverviewSerializer
|
|
30
|
-
permission_classes = DEBUG_PERMISSIONS
|
|
40
|
+
# permission_classes = DEBUG_PERMISSIONS
|
|
41
|
+
permission_classes = [PolicyPermission]
|
|
31
42
|
pagination_class = NoPagination
|
|
32
43
|
|
|
33
44
|
def get_queryset(self):
|
|
@@ -36,23 +47,25 @@ class AnonymizationOverviewView(ListAPIView):
|
|
|
36
47
|
"""
|
|
37
48
|
# 1) VideoFile queryset - only fields that exist on VideoFile
|
|
38
49
|
qs_video = (
|
|
39
|
-
VideoFile.objects
|
|
40
|
-
.select_related("state", "sensitive_meta")
|
|
50
|
+
VideoFile.objects.select_related("state", "sensitive_meta")
|
|
41
51
|
.prefetch_related("label_video_segments__state")
|
|
42
|
-
.only(
|
|
52
|
+
.only(
|
|
53
|
+
"id",
|
|
54
|
+
"original_file_name",
|
|
55
|
+
"raw_file",
|
|
56
|
+
"uploaded_at",
|
|
57
|
+
"state",
|
|
58
|
+
"sensitive_meta",
|
|
59
|
+
)
|
|
43
60
|
)
|
|
44
61
|
# 2) RawPdfFile queryset - only fields that exist on RawPdfFile
|
|
45
|
-
qs_pdf = (
|
|
46
|
-
|
|
47
|
-
.select_related("sensitive_meta")
|
|
48
|
-
.only("id", "file", "date_created",
|
|
49
|
-
"text", "anonymized_text",
|
|
50
|
-
"sensitive_meta")
|
|
51
|
-
|
|
62
|
+
qs_pdf = RawPdfFile.objects.select_related("sensitive_meta").only(
|
|
63
|
+
"id", "file", "date_created", "text", "anonymized_text", "sensitive_meta"
|
|
52
64
|
)
|
|
53
65
|
|
|
54
66
|
return list(qs_video) + list(qs_pdf)
|
|
55
|
-
|
|
67
|
+
|
|
68
|
+
|
|
56
69
|
# ---------- status with polling protection ------------------------------
|
|
57
70
|
@api_view(["GET"])
|
|
58
71
|
@permission_classes(PERMS)
|
|
@@ -69,12 +82,14 @@ def anonymization_status(request, file_id: int):
|
|
|
69
82
|
|
|
70
83
|
# Wende Rate-Limiting auf den echten Typ an (nicht auf einen evtl. falschen request-Parameter)
|
|
71
84
|
if not PollingCoordinator.can_check_status(file_id, file_type):
|
|
72
|
-
remaining_seconds = PollingCoordinator.get_remaining_cooldown_seconds(
|
|
85
|
+
remaining_seconds = PollingCoordinator.get_remaining_cooldown_seconds(
|
|
86
|
+
file_id, file_type
|
|
87
|
+
)
|
|
73
88
|
response_data = {
|
|
74
89
|
"detail": "Status check rate limited. Please wait before checking again.",
|
|
75
90
|
"file_id": file_id,
|
|
76
91
|
"cooldown_active": True,
|
|
77
|
-
"retry_after": remaining_seconds
|
|
92
|
+
"retry_after": remaining_seconds,
|
|
78
93
|
}
|
|
79
94
|
response = Response(response_data, status=status.HTTP_429_TOO_MANY_REQUESTS)
|
|
80
95
|
response["Retry-After"] = str(remaining_seconds)
|
|
@@ -83,15 +98,22 @@ def anonymization_status(request, file_id: int):
|
|
|
83
98
|
status_val = info.get("anonymizationStatus") or info.get("status") or "not_started"
|
|
84
99
|
|
|
85
100
|
# processing_locked als Ableitung des Status interpretieren
|
|
86
|
-
processing_statuses = {
|
|
101
|
+
processing_statuses = {
|
|
102
|
+
"processing_anonymization",
|
|
103
|
+
"extracting_frames",
|
|
104
|
+
"predicting_segments",
|
|
105
|
+
}
|
|
87
106
|
processing_locked_derived = status_val in processing_statuses
|
|
88
107
|
|
|
89
|
-
return Response(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
108
|
+
return Response(
|
|
109
|
+
{
|
|
110
|
+
"file_id": file_id,
|
|
111
|
+
"file_type": file_type,
|
|
112
|
+
"anonymizationStatus": status_val,
|
|
113
|
+
"processing_locked": processing_locked_derived,
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
|
|
95
117
|
|
|
96
118
|
# ---------- start with processing lock ----------------------------------
|
|
97
119
|
@api_view(["POST"])
|
|
@@ -104,9 +126,9 @@ def start_anonymization(request, file_id: int):
|
|
|
104
126
|
info = AnonymizationService.get_status(file_id)
|
|
105
127
|
if not info:
|
|
106
128
|
return Response({"detail": "File not found"}, status=status.HTTP_404_NOT_FOUND)
|
|
107
|
-
|
|
129
|
+
|
|
108
130
|
file_type = info["mediaType"]
|
|
109
|
-
|
|
131
|
+
|
|
110
132
|
# Use processing lock context to prevent duplicate processing
|
|
111
133
|
with ProcessingLockContext(file_id, file_type) as lock:
|
|
112
134
|
if not lock.acquired:
|
|
@@ -115,27 +137,32 @@ def start_anonymization(request, file_id: int):
|
|
|
115
137
|
"detail": "File is already being processed by another request",
|
|
116
138
|
"file_id": file_id,
|
|
117
139
|
"file_type": file_type,
|
|
118
|
-
"processing_locked": True
|
|
119
|
-
},
|
|
120
|
-
status=status.HTTP_409_CONFLICT
|
|
140
|
+
"processing_locked": True,
|
|
141
|
+
},
|
|
142
|
+
status=status.HTTP_409_CONFLICT,
|
|
121
143
|
)
|
|
122
|
-
|
|
144
|
+
|
|
123
145
|
# Proceed with starting anonymization
|
|
124
146
|
service = AnonymizationService()
|
|
125
147
|
kind = service.start(file_id)
|
|
126
148
|
if not kind:
|
|
127
|
-
return Response(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
return Response(
|
|
150
|
+
{"detail": "Failed to start anonymization"},
|
|
151
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return Response(
|
|
155
|
+
{
|
|
156
|
+
"detail": f"Anonymization started for {kind} file",
|
|
157
|
+
"file_id": file_id,
|
|
158
|
+
"file_type": kind,
|
|
159
|
+
"processing_locked": True,
|
|
160
|
+
}
|
|
161
|
+
)
|
|
135
162
|
|
|
136
163
|
|
|
137
164
|
# ---------- current with coordination ------------------------------------
|
|
138
|
-
@api_view([
|
|
165
|
+
@api_view(["GET", "POST", "PUT"])
|
|
139
166
|
@permission_classes(DEBUG_PERMISSIONS)
|
|
140
167
|
def anonymization_current(request, file_id):
|
|
141
168
|
"""
|
|
@@ -143,15 +170,15 @@ def anonymization_current(request, file_id):
|
|
|
143
170
|
"""
|
|
144
171
|
# Try to find the file in VideoFile first
|
|
145
172
|
try:
|
|
146
|
-
video_file = VideoFile.objects.select_related(
|
|
147
|
-
serializer = VoPPatientDataSerializer(video_file, context={
|
|
173
|
+
video_file = VideoFile.objects.select_related("sensitive_meta").get(id=file_id)
|
|
174
|
+
serializer = VoPPatientDataSerializer(video_file, context={"request": request})
|
|
148
175
|
return Response(serializer.data)
|
|
149
176
|
except VideoFile.DoesNotExist:
|
|
150
177
|
pass
|
|
151
178
|
# Try to find the file in RawPdfFile
|
|
152
179
|
try:
|
|
153
|
-
pdf_file = RawPdfFile.objects.select_related(
|
|
154
|
-
serializer = VoPPatientDataSerializer(pdf_file, context={
|
|
180
|
+
pdf_file = RawPdfFile.objects.select_related("sensitive_meta").get(id=file_id)
|
|
181
|
+
serializer = VoPPatientDataSerializer(pdf_file, context={"request": request})
|
|
155
182
|
return Response(serializer.data)
|
|
156
183
|
|
|
157
184
|
except RawPdfFile.DoesNotExist:
|
|
@@ -159,12 +186,13 @@ def anonymization_current(request, file_id):
|
|
|
159
186
|
|
|
160
187
|
except (ValueError, TypeError, AttributeError) as e:
|
|
161
188
|
logger.error(f"Error in set_current_for_validation: {e}")
|
|
162
|
-
return JsonResponse({
|
|
189
|
+
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
|
190
|
+
|
|
191
|
+
return JsonResponse({"status": "error", "message": "File not found"}, status=404)
|
|
163
192
|
|
|
164
|
-
return JsonResponse({'status': 'error', 'message': 'File not found'}, status=404)
|
|
165
193
|
|
|
166
194
|
# ---------- polling coordinator info ------------------------------------
|
|
167
|
-
@api_view([
|
|
195
|
+
@api_view(["GET"])
|
|
168
196
|
@permission_classes(DEBUG_PERMISSIONS)
|
|
169
197
|
def polling_coordinator_info(request):
|
|
170
198
|
"""
|
|
@@ -177,12 +205,13 @@ def polling_coordinator_info(request):
|
|
|
177
205
|
except Exception as e:
|
|
178
206
|
logger.error(f"Error getting polling coordinator info: {e}")
|
|
179
207
|
return Response(
|
|
180
|
-
{"error": "Failed to get coordinator info"},
|
|
181
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
208
|
+
{"error": "Failed to get coordinator info"},
|
|
209
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
182
210
|
)
|
|
183
211
|
|
|
212
|
+
|
|
184
213
|
# ---------- emergency lock management -----------------------------------
|
|
185
|
-
@api_view([
|
|
214
|
+
@api_view(["DELETE"])
|
|
186
215
|
@permission_classes(DEBUG_PERMISSIONS)
|
|
187
216
|
def clear_processing_locks(request):
|
|
188
217
|
"""
|
|
@@ -190,22 +219,25 @@ def clear_processing_locks(request):
|
|
|
190
219
|
Emergency endpoint to clear all processing locks
|
|
191
220
|
"""
|
|
192
221
|
try:
|
|
193
|
-
file_type = request.query_params.get(
|
|
222
|
+
file_type = request.query_params.get("type", None)
|
|
194
223
|
cleared_count = PollingCoordinator.clear_all_locks(file_type)
|
|
195
|
-
|
|
196
|
-
return Response(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
224
|
+
|
|
225
|
+
return Response(
|
|
226
|
+
{
|
|
227
|
+
"detail": "Processing locks cleared",
|
|
228
|
+
"cleared_count": cleared_count,
|
|
229
|
+
"file_type_filter": file_type,
|
|
230
|
+
}
|
|
231
|
+
)
|
|
201
232
|
except Exception as e:
|
|
202
233
|
logger.error(f"Error clearing processing locks: {e}")
|
|
203
234
|
return Response(
|
|
204
|
-
{"error": "Failed to clear locks"},
|
|
205
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
235
|
+
{"error": "Failed to clear locks"},
|
|
236
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
206
237
|
)
|
|
207
|
-
|
|
208
|
-
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@api_view(["GET"])
|
|
209
241
|
@permission_classes(DEBUG_PERMISSIONS)
|
|
210
242
|
def has_raw_video_file(request, file_id):
|
|
211
243
|
"""
|
|
@@ -213,4 +245,4 @@ def has_raw_video_file(request, file_id):
|
|
|
213
245
|
Check if a raw video file exists for the given file ID
|
|
214
246
|
"""
|
|
215
247
|
exists = VideoFile.objects.filter(id=file_id, raw_file__isnull=False).exists()
|
|
216
|
-
return Response({"file_id": file_id, "has_raw_file": exists})
|
|
248
|
+
return Response({"file_id": file_id, "has_raw_file": exists})
|
|
@@ -7,30 +7,37 @@ from rest_framework.response import Response
|
|
|
7
7
|
from rest_framework.views import APIView
|
|
8
8
|
|
|
9
9
|
from endoreg_db.models import RawPdfFile, VideoFile
|
|
10
|
+
from endoreg_db.models.metadata import SensitiveMeta
|
|
10
11
|
from endoreg_db.serializers.anonymization import SensitiveMetaValidateSerializer
|
|
11
12
|
|
|
12
|
-
|
|
13
13
|
logger = logging.getLogger(__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class AnonymizationValidateView(APIView):
|
|
17
17
|
"""
|
|
18
18
|
POST /api/anonymization/<int:file_id>/validate/
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
Validiert und aktualisiert SensitiveMeta-Felder für Videos oder PDFs.
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
DATA HERE IS COMING FROM THE ANONYIZATION VALIDATION COMPONENT
|
|
23
|
+
|
|
22
24
|
Body (Datumsfelder bevorzugt in deutschem Format DD.MM.YYYY; ISO YYYY-MM-DD ebenfalls akzeptiert):
|
|
23
25
|
{
|
|
24
26
|
"patient_first_name": "Max",
|
|
25
27
|
"patient_last_name": "Mustermann",
|
|
26
28
|
"patient_dob": "21.03.1994", // DD.MM.YYYY bevorzugt
|
|
29
|
+
"patient_gender": "male"
|
|
27
30
|
"examination_date": "15.02.2024", // DD.MM.YYYY bevorzugt
|
|
31
|
+
|
|
28
32
|
"casenumber": "12345",
|
|
29
33
|
"anonymized_text": "...", // nur für PDFs; Videos ignorieren
|
|
30
34
|
"is_verified": true // optional; default true
|
|
31
|
-
"file_type": "video" // optional; "video" oder "pdf"; wenn nicht angegeben, wird zuerst Video, dann
|
|
35
|
+
"file_type": "video" // optional; "video" oder "pdf"; wenn nicht angegeben, wird zuerst Video, dann report versucht
|
|
36
|
+
"center_name": editedPatient.value.centerName || '',
|
|
37
|
+
"external_id": editedPatient.value.externalId || '',
|
|
38
|
+
"external_id_origin":editedPatient.value.externalIdOrigin || '',
|
|
32
39
|
}
|
|
33
|
-
|
|
40
|
+
|
|
34
41
|
Rückwärtskompatibilität: ISO-Format (YYYY-MM-DD) wird ebenfalls akzeptiert.
|
|
35
42
|
"""
|
|
36
43
|
|
|
@@ -41,67 +48,198 @@ class AnonymizationValidateView(APIView):
|
|
|
41
48
|
serializer.is_valid(raise_exception=True)
|
|
42
49
|
validated_data = cast(Dict[str, Any], serializer.validated_data)
|
|
43
50
|
payload: Dict[str, Any] = dict(validated_data)
|
|
51
|
+
|
|
52
|
+
# Default ist_verified = True
|
|
44
53
|
if "is_verified" not in payload:
|
|
45
54
|
payload["is_verified"] = True
|
|
46
55
|
|
|
47
56
|
file_type = payload.get("file_type")
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
ok = video.validate_metadata_annotation(prepared_payload)
|
|
56
|
-
except Exception: # pragma: no cover - defensive safety net
|
|
57
|
-
logger.exception("Video validation crashed for id=%s", file_id)
|
|
58
|
-
return Response(
|
|
59
|
-
{"error": "Video validation encountered an unexpected error."},
|
|
60
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
58
|
+
with transaction.atomic():
|
|
59
|
+
# Try Video first (unless explicitly requesting report)
|
|
60
|
+
if file_type in (None, "video"):
|
|
61
|
+
video = (
|
|
62
|
+
VideoFile.objects.select_related(
|
|
63
|
+
"center", "sensitive_meta", "state"
|
|
61
64
|
)
|
|
65
|
+
.filter(pk=file_id)
|
|
66
|
+
.first()
|
|
67
|
+
)
|
|
68
|
+
if video is not None:
|
|
69
|
+
prepared_payload = self._prepare_payload(payload, video)
|
|
70
|
+
try:
|
|
71
|
+
ok = video.validate_metadata_annotation(prepared_payload)
|
|
72
|
+
except Exception: # pragma: no cover - defensive safety net
|
|
73
|
+
logger.exception("Video validation crashed for id=%s", file_id)
|
|
74
|
+
return Response(
|
|
75
|
+
{
|
|
76
|
+
"error": "Video validation encountered an unexpected error."
|
|
77
|
+
},
|
|
78
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if not ok:
|
|
82
|
+
return Response(
|
|
83
|
+
{"error": "Video validation failed."},
|
|
84
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# this is here for tests!
|
|
88
|
+
if video.sensitive_meta is None:
|
|
89
|
+
sm = SensitiveMeta.objects.create(center=video.center)
|
|
90
|
+
video.sensitive_meta = sm
|
|
91
|
+
|
|
92
|
+
video.save(update_fields=["sensitive_meta"])
|
|
93
|
+
video.sensitive_meta.get_or_create_state()
|
|
94
|
+
if video.sensitive_meta.state is not None:
|
|
95
|
+
video.sensitive_meta.state.refresh_from_db()
|
|
96
|
+
video.sensitive_meta.state.mark_dob_verified()
|
|
97
|
+
video.sensitive_meta.state.mark_names_verified()
|
|
98
|
+
video.sensitive_meta.create_anonymized_record()
|
|
99
|
+
else:
|
|
100
|
+
return Response(
|
|
101
|
+
{"message": "Video not validated, failed to create State."},
|
|
102
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if video.state is not None:
|
|
106
|
+
video.state.state.anonymization_status.mark_anonymized()
|
|
107
|
+
video.state.save(update_fields=["anonymized"])
|
|
108
|
+
video.sensitive_meta.state.save()
|
|
62
109
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if file_type == "video":
|
|
69
|
-
return Response({"error": f"Video {file_id} not found."}, status=status.HTTP_404_NOT_FOUND)
|
|
110
|
+
return Response(
|
|
111
|
+
{"message": "Video validated."},
|
|
112
|
+
status=status.HTTP_200_OK,
|
|
113
|
+
)
|
|
70
114
|
|
|
71
|
-
|
|
72
|
-
if file_type in (None, "pdf"):
|
|
73
|
-
pdf = RawPdfFile.objects.select_related("center").filter(pk=file_id).first()
|
|
74
|
-
if pdf is not None:
|
|
75
|
-
prepared_payload = self._prepare_payload(payload, pdf)
|
|
76
|
-
try:
|
|
77
|
-
ok = pdf.validate_metadata_annotation(prepared_payload)
|
|
78
|
-
except Exception: # pragma: no cover - defensive safety net
|
|
79
|
-
logger.exception("PDF validation crashed for id=%s", file_id)
|
|
115
|
+
if file_type == "video":
|
|
80
116
|
return Response(
|
|
81
|
-
{"error": "
|
|
82
|
-
status=status.
|
|
117
|
+
{"error": f"Video {file_id} not found."},
|
|
118
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
83
119
|
)
|
|
84
120
|
|
|
85
|
-
|
|
86
|
-
|
|
121
|
+
# Then report (unless explicitly requesting Video)
|
|
122
|
+
if file_type in (None, "pdf"):
|
|
123
|
+
pdf = (
|
|
124
|
+
RawPdfFile.objects.select_related(
|
|
125
|
+
"center", "sensitive_meta", "state"
|
|
126
|
+
)
|
|
127
|
+
.filter(pk=file_id)
|
|
128
|
+
.first()
|
|
129
|
+
)
|
|
130
|
+
if pdf is not None:
|
|
131
|
+
prepared_payload = self._prepare_payload(payload, pdf)
|
|
132
|
+
try:
|
|
133
|
+
ok = pdf.validate_metadata_annotation(prepared_payload)
|
|
134
|
+
except Exception: # pragma: no cover - defensive safety net
|
|
135
|
+
logger.exception("report validation crashed for id=%s", file_id)
|
|
136
|
+
return Response(
|
|
137
|
+
{
|
|
138
|
+
"error": "report validation encountered an unexpected error."
|
|
139
|
+
},
|
|
140
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# sanity logging – but don't break flow
|
|
144
|
+
try:
|
|
145
|
+
assert pdf.sensitive_meta is not None
|
|
146
|
+
assert pdf.sensitive_meta.state is not None
|
|
147
|
+
except AssertionError as e:
|
|
148
|
+
logger.error("%s", e)
|
|
149
|
+
|
|
150
|
+
if not ok:
|
|
151
|
+
return Response(
|
|
152
|
+
{"error": "report validation failed."},
|
|
153
|
+
status=status.HTTP_400_BAD_REQUEST,
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
# this is here for tests!
|
|
157
|
+
if pdf.sensitive_meta is None:
|
|
158
|
+
sm = SensitiveMeta.objects.create(center=pdf.center)
|
|
159
|
+
pdf.sensitive_meta = sm
|
|
160
|
+
|
|
161
|
+
pdf.save(update_fields=["sensitive_meta"])
|
|
162
|
+
pdf.sensitive_meta.get_or_create_state()
|
|
163
|
+
if (
|
|
164
|
+
pdf.sensitive_meta
|
|
165
|
+
and pdf.sensitive_meta.state
|
|
166
|
+
and pdf.state
|
|
167
|
+
):
|
|
168
|
+
pdf.sensitive_meta.state.refresh_from_db()
|
|
169
|
+
pdf.sensitive_meta.state.mark_dob_verified()
|
|
170
|
+
pdf.sensitive_meta.state.mark_names_verified()
|
|
171
|
+
pdf.sensitive_meta.create_anonymized_record()
|
|
172
|
+
pdf.state.state.anonymization_status.mark_anonymized()
|
|
173
|
+
pdf.state.save(update_fields=["anonymized"])
|
|
174
|
+
pdf.sensitive_meta.state.save()
|
|
175
|
+
else:
|
|
176
|
+
return Response(
|
|
177
|
+
{
|
|
178
|
+
"message": "report not validated, failed to create State."
|
|
179
|
+
},
|
|
180
|
+
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
181
|
+
)
|
|
87
182
|
|
|
88
|
-
|
|
183
|
+
return Response(
|
|
184
|
+
{"message": "report validated."},
|
|
185
|
+
status=status.HTTP_200_OK,
|
|
186
|
+
)
|
|
89
187
|
|
|
90
|
-
|
|
91
|
-
|
|
188
|
+
if file_type == "pdf":
|
|
189
|
+
return Response(
|
|
190
|
+
{"error": f"report {file_id} not found."},
|
|
191
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
192
|
+
)
|
|
92
193
|
|
|
93
|
-
return Response(
|
|
194
|
+
return Response(
|
|
195
|
+
{"error": f"Item {file_id} not found as video or pdf."},
|
|
196
|
+
status=status.HTTP_404_NOT_FOUND,
|
|
197
|
+
)
|
|
94
198
|
|
|
95
199
|
@staticmethod
|
|
96
200
|
def _prepare_payload(base_payload: Dict[str, Any], file_obj: Any) -> Dict[str, Any]:
|
|
97
|
-
"""
|
|
201
|
+
"""
|
|
202
|
+
Return a fresh payload tailored for the given file object.
|
|
203
|
+
|
|
204
|
+
- Strips `file_type` before forwarding to validators.
|
|
205
|
+
- Injects `center_name` from the file's center if not already present.
|
|
206
|
+
- Normalizes `patient_gender` if present, but does NOT require it.
|
|
207
|
+
"""
|
|
208
|
+
prepared: Dict[str, Any] = dict(base_payload)
|
|
98
209
|
|
|
99
|
-
|
|
210
|
+
# never send file_type to validators
|
|
100
211
|
prepared.pop("file_type", None)
|
|
101
212
|
|
|
213
|
+
# center_name from file.center if not already set
|
|
102
214
|
center = getattr(file_obj, "center", None)
|
|
103
215
|
center_name = getattr(center, "name", None)
|
|
104
216
|
if center_name and not prepared.get("center_name"):
|
|
105
217
|
prepared["center_name"] = center_name
|
|
106
218
|
|
|
107
|
-
|
|
219
|
+
# Gender normalization: optional, robust against missing or unknown values
|
|
220
|
+
raw_gender = base_payload.get("patient_gender", None)
|
|
221
|
+
if raw_gender is None:
|
|
222
|
+
# nothing provided → don't touch gender
|
|
223
|
+
return prepared
|
|
224
|
+
|
|
225
|
+
gender = str(raw_gender).strip().lower()
|
|
226
|
+
|
|
227
|
+
# empty string behaves as "not set" – don't override anything
|
|
228
|
+
if gender == "":
|
|
229
|
+
return prepared
|
|
230
|
+
|
|
231
|
+
male_values = {"m", "male", "männlich"}
|
|
232
|
+
female_values = {"w", "f", "female", "weiblich"}
|
|
233
|
+
|
|
234
|
+
if gender in male_values:
|
|
235
|
+
prepared["patient_gender"] = "male"
|
|
236
|
+
elif gender in female_values:
|
|
237
|
+
prepared["patient_gender"] = "female"
|
|
238
|
+
else:
|
|
239
|
+
# keep existing semantics: unknown values default to "male"
|
|
240
|
+
logger.warning(
|
|
241
|
+
"Unsupported patient_gender value %r; defaulting to 'male'", raw_gender
|
|
242
|
+
)
|
|
243
|
+
prepared["patient_gender"] = "male"
|
|
244
|
+
|
|
245
|
+
return prepared
|
|
@@ -3,18 +3,11 @@
|
|
|
3
3
|
from .video_media import VideoMediaView
|
|
4
4
|
from .pdf_media import PdfMediaView
|
|
5
5
|
from ..video.reimport import VideoReimportView
|
|
6
|
-
from ..
|
|
7
|
-
from .
|
|
8
|
-
|
|
9
|
-
video_segments_collection,
|
|
10
|
-
video_segments_by_video,
|
|
11
|
-
video_segment_detail,
|
|
12
|
-
video_segments_stats,
|
|
13
|
-
video_segment_validate,
|
|
14
|
-
video_segments_validate_bulk,
|
|
15
|
-
video_segments_validation_status,
|
|
16
|
-
)
|
|
6
|
+
from ..report.reimport import ReportReimportView
|
|
7
|
+
from ..ai.label import label_list
|
|
8
|
+
|
|
17
9
|
from .sensitive_metadata import (
|
|
10
|
+
get_sensitive_metadata_pk,
|
|
18
11
|
video_sensitive_metadata,
|
|
19
12
|
video_sensitive_metadata_verify,
|
|
20
13
|
pdf_sensitive_metadata,
|
|
@@ -27,19 +20,13 @@ __all__ = [
|
|
|
27
20
|
'VideoMediaView',
|
|
28
21
|
'PdfMediaView',
|
|
29
22
|
'VideoReimportView',
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'video_segments_collection',
|
|
33
|
-
'video_segments_by_video',
|
|
34
|
-
'video_segment_detail',
|
|
35
|
-
'video_segments_stats',
|
|
36
|
-
'video_segment_validate',
|
|
37
|
-
'video_segments_validate_bulk',
|
|
38
|
-
'video_segments_validation_status',
|
|
23
|
+
'ReportReimportView',
|
|
24
|
+
'get_sensitive_metadata_pk',
|
|
39
25
|
'video_sensitive_metadata',
|
|
40
26
|
'video_sensitive_metadata_verify',
|
|
41
27
|
'pdf_sensitive_metadata',
|
|
42
28
|
'pdf_sensitive_metadata_verify',
|
|
43
29
|
'sensitive_metadata_list',
|
|
44
30
|
'pdf_sensitive_metadata_list',
|
|
31
|
+
'label_list',
|
|
45
32
|
]
|