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.

Files changed (503) hide show
  1. endoreg_db/authz/auth.py +74 -0
  2. endoreg_db/authz/backends.py +168 -0
  3. endoreg_db/authz/management/commands/list_routes.py +18 -0
  4. endoreg_db/authz/middleware.py +83 -0
  5. endoreg_db/authz/permissions.py +127 -0
  6. endoreg_db/authz/policy.py +218 -0
  7. endoreg_db/authz/views_auth.py +66 -0
  8. endoreg_db/config/env.py +13 -8
  9. endoreg_db/data/__init__.py +2 -11
  10. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
  11. endoreg_db/data/event_classification/data.yaml +4 -0
  12. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  13. endoreg_db/data/examination/examinations/data.yaml +114 -14
  14. endoreg_db/data/examination/time-type/data.yaml +0 -3
  15. endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
  16. endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
  17. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
  18. endoreg_db/data/finding/00_generic.yaml +35 -0
  19. endoreg_db/data/finding/00_generic_complication.yaml +9 -0
  20. endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
  21. endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
  22. endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
  23. endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
  24. endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
  25. endoreg_db/data/finding_classification/00_generic.yaml +44 -0
  26. endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
  27. endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
  28. endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
  29. endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
  30. endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
  31. endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
  32. endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
  33. endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
  34. endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
  35. endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
  36. endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
  37. endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
  38. endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
  39. endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
  40. endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
  41. endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
  42. endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
  43. endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
  44. endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
  45. endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
  46. endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
  47. endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
  48. endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
  49. endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
  50. endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
  51. endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
  52. endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
  53. endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
  54. endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
  55. endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
  56. endoreg_db/data/finding_type/data.yaml +8 -12
  57. endoreg_db/data/requirement/01_patient_data.yaml +93 -0
  58. endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
  59. endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
  60. endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
  61. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
  62. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  63. endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
  64. endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
  65. endoreg_db/data/requirement_set/_old_ +109 -0
  66. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  67. endoreg_db/data/setup_config.yaml +4 -4
  68. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  69. endoreg_db/exceptions.py +4 -2
  70. endoreg_db/forms/examination_form.py +1 -1
  71. endoreg_db/helpers/data_loader.py +125 -53
  72. endoreg_db/helpers/default_objects.py +116 -81
  73. endoreg_db/import_files/__init__.py +27 -0
  74. endoreg_db/import_files/context/__init__.py +7 -0
  75. endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
  76. endoreg_db/import_files/context/ensure_center.py +17 -0
  77. endoreg_db/import_files/context/file_lock.py +66 -0
  78. endoreg_db/import_files/context/import_context.py +43 -0
  79. endoreg_db/import_files/context/validate_directories.py +56 -0
  80. endoreg_db/import_files/file_storage/__init__.py +15 -0
  81. endoreg_db/import_files/file_storage/create_report_file.py +76 -0
  82. endoreg_db/import_files/file_storage/create_video_file.py +75 -0
  83. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
  84. endoreg_db/import_files/file_storage/state_management.py +400 -0
  85. endoreg_db/import_files/file_storage/storage.py +36 -0
  86. endoreg_db/import_files/import_service.md +26 -0
  87. endoreg_db/import_files/processing/__init__.py +11 -0
  88. endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
  89. endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
  90. endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
  91. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
  92. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  93. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  94. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
  95. endoreg_db/import_files/report_import_service.py +141 -0
  96. endoreg_db/import_files/video_import_service.py +150 -0
  97. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  98. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  99. endoreg_db/management/commands/import_report.py +130 -65
  100. endoreg_db/management/commands/import_video.py +9 -10
  101. endoreg_db/management/commands/import_video_with_classification.py +2 -2
  102. endoreg_db/management/commands/list_routes.py +18 -0
  103. endoreg_db/management/commands/load_ai_model_data.py +5 -5
  104. endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
  105. endoreg_db/management/commands/load_base_db_data.py +5 -134
  106. endoreg_db/management/commands/load_center_data.py +12 -12
  107. endoreg_db/management/commands/load_contraindication_data.py +14 -16
  108. endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
  109. endoreg_db/management/commands/load_disease_classification_data.py +15 -18
  110. endoreg_db/management/commands/load_disease_data.py +25 -28
  111. endoreg_db/management/commands/load_endoscope_data.py +20 -27
  112. endoreg_db/management/commands/load_event_data.py +14 -16
  113. endoreg_db/management/commands/load_examination_data.py +31 -44
  114. endoreg_db/management/commands/load_examination_indication_data.py +20 -21
  115. endoreg_db/management/commands/load_finding_data.py +52 -80
  116. endoreg_db/management/commands/load_information_source.py +21 -23
  117. endoreg_db/management/commands/load_lab_value_data.py +17 -26
  118. endoreg_db/management/commands/load_medication_data.py +13 -12
  119. endoreg_db/management/commands/load_organ_data.py +15 -19
  120. endoreg_db/management/commands/load_pdf_type_data.py +19 -18
  121. endoreg_db/management/commands/load_profession_data.py +14 -17
  122. endoreg_db/management/commands/load_qualification_data.py +20 -23
  123. endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
  124. endoreg_db/management/commands/load_requirement_data.py +62 -39
  125. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  126. endoreg_db/management/commands/load_risk_data.py +7 -6
  127. endoreg_db/management/commands/load_shift_data.py +20 -23
  128. endoreg_db/management/commands/load_tag_data.py +8 -11
  129. endoreg_db/management/commands/load_unit_data.py +17 -19
  130. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  131. endoreg_db/management/commands/start_filewatcher.py +46 -37
  132. endoreg_db/management/commands/storage_management.py +271 -203
  133. endoreg_db/management/commands/validate_video_files.py +1 -5
  134. endoreg_db/migrations/0001_initial.py +297 -250
  135. endoreg_db/models/__init__.py +78 -123
  136. endoreg_db/models/administration/__init__.py +21 -42
  137. endoreg_db/models/administration/ai/active_model.py +2 -2
  138. endoreg_db/models/administration/ai/ai_model.py +7 -6
  139. endoreg_db/models/administration/case/__init__.py +1 -15
  140. endoreg_db/models/administration/case/case.py +3 -3
  141. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  142. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  143. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  144. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  145. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  146. endoreg_db/models/administration/center/center.py +33 -19
  147. endoreg_db/models/administration/center/center_product.py +12 -9
  148. endoreg_db/models/administration/center/center_resource.py +25 -19
  149. endoreg_db/models/administration/center/center_shift.py +21 -17
  150. endoreg_db/models/administration/center/center_waste.py +16 -8
  151. endoreg_db/models/administration/person/__init__.py +2 -0
  152. endoreg_db/models/administration/person/employee/employee.py +10 -5
  153. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  154. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  155. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  156. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  157. endoreg_db/models/administration/person/patient/patient.py +129 -100
  158. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  159. endoreg_db/models/administration/person/person.py +4 -0
  160. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  161. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  162. endoreg_db/models/administration/product/product.py +20 -15
  163. endoreg_db/models/administration/product/product_material.py +17 -18
  164. endoreg_db/models/administration/product/product_weight.py +12 -8
  165. endoreg_db/models/administration/product/reference_product.py +23 -55
  166. endoreg_db/models/administration/qualification/qualification.py +7 -3
  167. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  168. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  169. endoreg_db/models/administration/shift/shift.py +16 -12
  170. endoreg_db/models/administration/shift/shift_type.py +23 -31
  171. endoreg_db/models/label/__init__.py +8 -9
  172. endoreg_db/models/label/annotation/image_classification.py +10 -9
  173. endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
  174. endoreg_db/models/label/label.py +15 -15
  175. endoreg_db/models/label/label_set.py +19 -6
  176. endoreg_db/models/label/label_type.py +1 -1
  177. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  178. endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
  179. endoreg_db/models/label/video_segmentation_label.py +4 -0
  180. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  181. endoreg_db/models/media/frame/frame.py +22 -22
  182. endoreg_db/models/media/pdf/raw_pdf.py +194 -194
  183. endoreg_db/models/media/pdf/report_file.py +25 -29
  184. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
  185. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  186. endoreg_db/models/media/processing_history/__init__.py +5 -0
  187. endoreg_db/models/media/processing_history/processing_history.py +96 -0
  188. endoreg_db/models/media/video/__init__.py +1 -0
  189. endoreg_db/models/media/video/create_from_file.py +139 -77
  190. endoreg_db/models/media/video/pipe_2.py +8 -9
  191. endoreg_db/models/media/video/video_file.py +174 -112
  192. endoreg_db/models/media/video/video_file_ai.py +288 -74
  193. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  194. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  195. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  196. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  197. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  198. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  199. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  200. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  201. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  202. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  203. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  204. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  205. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  206. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  207. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  208. endoreg_db/models/media/video/video_file_io.py +113 -61
  209. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  210. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  211. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  212. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  213. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  214. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  215. endoreg_db/models/media/video/video_file_segments.py +24 -17
  216. endoreg_db/models/media/video/video_metadata.py +19 -35
  217. endoreg_db/models/media/video/video_processing.py +96 -95
  218. endoreg_db/models/medical/contraindication/README.md +1 -0
  219. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  220. endoreg_db/models/medical/disease.py +22 -16
  221. endoreg_db/models/medical/event.py +31 -18
  222. endoreg_db/models/medical/examination/__init__.py +13 -6
  223. endoreg_db/models/medical/examination/examination.py +39 -20
  224. endoreg_db/models/medical/examination/examination_indication.py +30 -95
  225. endoreg_db/models/medical/examination/examination_time.py +23 -8
  226. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  227. endoreg_db/models/medical/examination/examination_type.py +3 -4
  228. endoreg_db/models/medical/finding/finding.py +32 -40
  229. endoreg_db/models/medical/finding/finding_classification.py +42 -72
  230. endoreg_db/models/medical/finding/finding_intervention.py +25 -22
  231. endoreg_db/models/medical/finding/finding_type.py +13 -12
  232. endoreg_db/models/medical/hardware/endoscope.py +26 -26
  233. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  234. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  235. endoreg_db/models/medical/medication/medication.py +22 -10
  236. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  237. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  238. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  239. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  240. endoreg_db/models/medical/organ/__init__.py +15 -12
  241. endoreg_db/models/medical/patient/medication_examples.py +6 -6
  242. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  243. endoreg_db/models/medical/patient/patient_event.py +19 -22
  244. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  245. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  246. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  247. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  248. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  249. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  250. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  251. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  252. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  253. endoreg_db/models/medical/risk/risk.py +7 -6
  254. endoreg_db/models/medical/risk/risk_type.py +8 -5
  255. endoreg_db/models/metadata/model_meta.py +60 -29
  256. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  257. endoreg_db/models/metadata/pdf_meta.py +31 -24
  258. endoreg_db/models/metadata/sensitive_meta.py +105 -85
  259. endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
  260. endoreg_db/models/metadata/video_meta.py +51 -31
  261. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  262. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  263. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  264. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  265. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  266. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  267. endoreg_db/models/other/emission/emission_factor.py +18 -8
  268. endoreg_db/models/other/gender.py +10 -5
  269. endoreg_db/models/other/information_source.py +50 -29
  270. endoreg_db/models/other/material.py +9 -5
  271. endoreg_db/models/other/resource.py +6 -4
  272. endoreg_db/models/other/tag.py +10 -5
  273. endoreg_db/models/other/transport_route.py +13 -8
  274. endoreg_db/models/other/unit.py +10 -6
  275. endoreg_db/models/other/waste.py +6 -5
  276. endoreg_db/models/report/report.py +6 -0
  277. endoreg_db/models/requirement/requirement.py +329 -361
  278. endoreg_db/models/requirement/requirement_error.py +85 -0
  279. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  280. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  281. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  282. endoreg_db/models/requirement/requirement_operator.py +103 -112
  283. endoreg_db/models/requirement/requirement_set.py +74 -57
  284. endoreg_db/models/state/__init__.py +4 -4
  285. endoreg_db/models/state/abstract.py +2 -2
  286. endoreg_db/models/state/anonymization.py +12 -0
  287. endoreg_db/models/state/audit_ledger.py +49 -51
  288. endoreg_db/models/state/label_video_segment.py +9 -0
  289. endoreg_db/models/state/raw_pdf.py +101 -68
  290. endoreg_db/models/state/sensitive_meta.py +6 -2
  291. endoreg_db/models/state/video.py +110 -90
  292. endoreg_db/models/upload_job.py +35 -34
  293. endoreg_db/models/utils.py +28 -25
  294. endoreg_db/queries/__init__.py +3 -1
  295. endoreg_db/root_urls.py +21 -2
  296. endoreg_db/schemas/examination_evaluation.py +1 -1
  297. endoreg_db/serializers/__init__.py +2 -10
  298. endoreg_db/serializers/anonymization.py +18 -10
  299. endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
  300. endoreg_db/serializers/meta/__init__.py +1 -6
  301. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  302. endoreg_db/serializers/misc/file_overview.py +11 -99
  303. endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
  304. endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
  305. endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
  306. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  307. endoreg_db/serializers/video/segmentation.py +2 -1
  308. endoreg_db/serializers/video/video_file_list.py +65 -34
  309. endoreg_db/serializers/video/video_processing_history.py +20 -5
  310. endoreg_db/services/__old/pdf_import.py +1487 -0
  311. endoreg_db/services/__old/video_import.py +1306 -0
  312. endoreg_db/services/anonymization.py +128 -89
  313. endoreg_db/services/lookup_service.py +65 -52
  314. endoreg_db/services/lookup_store.py +2 -2
  315. endoreg_db/services/pdf_import.py +0 -1382
  316. endoreg_db/services/report_import.py +10 -0
  317. endoreg_db/services/video_import.py +6 -1255
  318. endoreg_db/tasks/upload_tasks.py +79 -70
  319. endoreg_db/tasks/video_ingest.py +8 -4
  320. endoreg_db/urls/__init__.py +5 -32
  321. endoreg_db/urls/ai.py +32 -0
  322. endoreg_db/urls/media.py +121 -83
  323. endoreg_db/urls/root_urls.py +29 -0
  324. endoreg_db/utils/__init__.py +15 -5
  325. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  326. endoreg_db/utils/case_generator/__init__.py +3 -0
  327. endoreg_db/utils/dataloader.py +142 -40
  328. endoreg_db/utils/defaults/set_default_center.py +32 -0
  329. endoreg_db/utils/names.py +22 -16
  330. endoreg_db/utils/paths.py +110 -46
  331. endoreg_db/utils/permissions.py +2 -1
  332. endoreg_db/utils/pipelines/Readme.md +1 -1
  333. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  334. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
  335. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
  336. endoreg_db/utils/setup_config.py +8 -5
  337. endoreg_db/utils/storage.py +115 -0
  338. endoreg_db/utils/validate_endo_roi.py +8 -2
  339. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  340. endoreg_db/views/__init__.py +85 -183
  341. endoreg_db/views/ai/__init__.py +8 -0
  342. endoreg_db/views/ai/label.py +155 -0
  343. endoreg_db/views/anonymization/media_management.py +202 -166
  344. endoreg_db/views/anonymization/overview.py +99 -67
  345. endoreg_db/views/anonymization/validate.py +182 -44
  346. endoreg_db/views/media/__init__.py +7 -20
  347. endoreg_db/views/media/pdf_media.py +197 -174
  348. endoreg_db/views/media/sensitive_metadata.py +193 -138
  349. endoreg_db/views/media/video_media.py +89 -82
  350. endoreg_db/views/meta/__init__.py +0 -8
  351. endoreg_db/views/misc/__init__.py +1 -7
  352. endoreg_db/views/misc/upload_views.py +94 -93
  353. endoreg_db/views/patient/patient.py +5 -4
  354. endoreg_db/views/report/__init__.py +5 -7
  355. endoreg_db/views/{pdf → report}/reimport.py +22 -22
  356. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
  357. endoreg_db/views/requirement/evaluate.py +188 -187
  358. endoreg_db/views/requirement/lookup.py +17 -3
  359. endoreg_db/views/requirement/lookup_store.py +22 -90
  360. endoreg_db/views/requirement/requirement_utils.py +89 -0
  361. endoreg_db/views/video/__init__.py +23 -24
  362. endoreg_db/views/video/correction.py +201 -172
  363. endoreg_db/views/video/reimport.py +1 -1
  364. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
  365. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  366. endoreg_db/views/video/video_stream.py +7 -8
  367. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
  368. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
  369. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
  370. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  371. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  372. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  373. endoreg_db/data/finding/complication.yaml +0 -16
  374. endoreg_db/data/finding/data.yaml +0 -105
  375. endoreg_db/data/finding/examination_setting.yaml +0 -16
  376. endoreg_db/data/finding/medication_related.yaml +0 -18
  377. endoreg_db/data/finding/outcome.yaml +0 -12
  378. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
  379. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  380. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  381. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  382. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  383. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  384. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  385. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
  386. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  387. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  388. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  389. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  390. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  391. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  392. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  393. endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
  394. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  395. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  396. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  397. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  398. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  399. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  400. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  401. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  402. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  403. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  404. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  405. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  406. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  407. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  408. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  409. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  410. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  411. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  412. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  413. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  414. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  415. endoreg_db/data/requirement/age.yaml +0 -26
  416. endoreg_db/data/requirement/gender.yaml +0 -25
  417. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  418. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  419. endoreg_db/management/commands/validate_video.py +0 -204
  420. endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
  421. endoreg_db/migrations/0003_add_center_display_name.py +0 -30
  422. endoreg_db/models/administration/permissions/__init__.py +0 -44
  423. endoreg_db/models/rule/__init__.py +0 -13
  424. endoreg_db/models/rule/rule.py +0 -27
  425. endoreg_db/models/rule/rule_applicator.py +0 -224
  426. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  427. endoreg_db/models/rule/rule_type.py +0 -20
  428. endoreg_db/models/rule/ruleset.py +0 -17
  429. endoreg_db/renames.yml +0 -8
  430. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  431. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  432. endoreg_db/serializers/_old/video.py +0 -71
  433. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  434. endoreg_db/serializers/meta/report_meta.py +0 -53
  435. endoreg_db/serializers/report/__init__.py +0 -9
  436. endoreg_db/serializers/report/mixins.py +0 -45
  437. endoreg_db/serializers/report/report.py +0 -105
  438. endoreg_db/serializers/report/report_list.py +0 -22
  439. endoreg_db/serializers/report/secure_file_url.py +0 -26
  440. endoreg_db/serializers/video/video_metadata.py +0 -105
  441. endoreg_db/services/requirements_object.py +0 -147
  442. endoreg_db/services/storage_aware_video_processor.py +0 -344
  443. endoreg_db/urls/files.py +0 -6
  444. endoreg_db/urls/label_video_segment_validate.py +0 -33
  445. endoreg_db/urls/label_video_segments.py +0 -46
  446. endoreg_db/urls/report.py +0 -48
  447. endoreg_db/urls/video.py +0 -61
  448. endoreg_db/utils/case_generator/case_generator.py +0 -159
  449. endoreg_db/utils/case_generator/utils.py +0 -30
  450. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
  451. endoreg_db/views/label/__init__.py +0 -5
  452. endoreg_db/views/label/label.py +0 -15
  453. endoreg_db/views/label_video_segment/__init__.py +0 -16
  454. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  455. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  456. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  457. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  458. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  459. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  460. endoreg_db/views/label_video_segment/validate.py +0 -226
  461. endoreg_db/views/media/segments.py +0 -71
  462. endoreg_db/views/meta/available_files_list.py +0 -146
  463. endoreg_db/views/meta/report_meta.py +0 -53
  464. endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
  465. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  466. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  467. endoreg_db/views/misc/secure_url_validate.py +0 -79
  468. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  469. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  470. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  471. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  472. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  473. endoreg_db/views/pdf/__init__.py +0 -8
  474. endoreg_db/views/report/report_list.py +0 -112
  475. endoreg_db/views/report/report_with_secure_url.py +0 -28
  476. endoreg_db/views/report/start_examination.py +0 -7
  477. endoreg_db/views/video/segmentation.py +0 -274
  478. endoreg_db/views/video/task_status.py +0 -49
  479. endoreg_db/views/video/timeline.py +0 -46
  480. endoreg_db/views/video/video_analyze.py +0 -52
  481. endoreg_db/views.py +0 -0
  482. /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
  483. /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
  484. /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
  485. /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
  486. /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
  487. /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
  488. /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
  489. /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
  490. /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
  491. /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
  492. /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
  493. /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
  494. /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
  495. /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
  496. /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
  497. /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
  498. /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
  499. /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
  500. /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
  501. /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
  502. /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
  503. {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 endoreg_db.models import VideoFile, RawPdfFile
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
- from django.http import JsonResponse
14
- import logging
22
+
15
23
  logger = logging.getLogger(__name__)
16
- PERMS = DEBUG_PERMISSIONS # shorten
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 + PDF) ordered by newest upload first.
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("id", "original_file_name", "raw_file", "uploaded_at", "state", "sensitive_meta")
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
- RawPdfFile.objects
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(file_id, file_type)
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 = {"processing_anonymization", "extracting_frames", "predicting_segments"}
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
- "file_id": file_id,
91
- "file_type": file_type,
92
- "anonymizationStatus": status_val,
93
- "processing_locked": processing_locked_derived,
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({"detail": "Failed to start anonymization"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
128
-
129
- return Response({
130
- "detail": f"Anonymization started for {kind} file",
131
- "file_id": file_id,
132
- "file_type": kind,
133
- "processing_locked": True
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(['GET', 'POST', 'PUT'])
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('sensitive_meta').get(id=file_id)
147
- serializer = VoPPatientDataSerializer(video_file, context={'request': request})
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('sensitive_meta').get(id=file_id)
154
- serializer = VoPPatientDataSerializer(pdf_file, context={'request': request})
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({'status': 'error', 'message': str(e)}, status=500)
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(['GET'])
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(['DELETE'])
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('type', None)
222
+ file_type = request.query_params.get("type", None)
194
223
  cleared_count = PollingCoordinator.clear_all_locks(file_type)
195
-
196
- return Response({
197
- "detail": "Processing locks cleared",
198
- "cleared_count": cleared_count,
199
- "file_type_filter": file_type
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
- @api_view(['GET'])
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 PDF versucht
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
- # Try Video first (unless explicitly requesting PDF)
50
- if file_type in (None, "video"):
51
- video = VideoFile.objects.select_related("center").filter(pk=file_id).first()
52
- if video is not None:
53
- prepared_payload = self._prepare_payload(payload, video)
54
- try:
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
- if not ok:
64
- return Response({"error": "Video validation failed."}, status=status.HTTP_400_BAD_REQUEST)
65
-
66
- return Response({"message": "Video validated."}, status=status.HTTP_200_OK)
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
- # Then PDF (unless explicitly requesting Video)
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": "PDF validation encountered an unexpected error."},
82
- status=status.HTTP_500_INTERNAL_SERVER_ERROR,
117
+ {"error": f"Video {file_id} not found."},
118
+ status=status.HTTP_404_NOT_FOUND,
83
119
  )
84
120
 
85
- if not ok:
86
- return Response({"error": "PDF validation failed."}, status=status.HTTP_400_BAD_REQUEST)
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
- return Response({"message": "PDF validated."}, status=status.HTTP_200_OK)
183
+ return Response(
184
+ {"message": "report validated."},
185
+ status=status.HTTP_200_OK,
186
+ )
89
187
 
90
- if file_type == "pdf":
91
- return Response({"error": f"PDF {file_id} not found."}, status=status.HTTP_404_NOT_FOUND)
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({"error": f"Item {file_id} not found as video or pdf."}, status=status.HTTP_404_NOT_FOUND)
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
- """Return a fresh payload tailored for the given file object."""
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
- prepared = dict(base_payload)
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
- return prepared
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 ..pdf.reimport import PdfReimportView
7
- from .segments import video_segments_by_pk
8
- from .video_segments import (
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
- 'PdfReimportView',
31
- 'video_segments_by_pk',
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
  ]