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,18 +1,19 @@
1
1
  # endoreg_db/views/media_management.py
2
2
 
3
3
  import logging
4
- from typing import Dict, Any
4
+ from datetime import timedelta
5
+ from typing import Any, Dict
6
+
5
7
  from django.db import transaction
6
8
  from django.db.models import Q
9
+ from django.utils import timezone
7
10
  from numpy import delete
8
11
  from rest_framework import status
9
12
  from rest_framework.decorators import api_view, permission_classes
10
13
  from rest_framework.response import Response
11
14
  from rest_framework.views import APIView
12
- from django.utils import timezone
13
- from datetime import timedelta
14
15
 
15
- from endoreg_db.models import VideoFile, RawPdfFile, VideoState
16
+ from endoreg_db.models import RawPdfFile, VideoFile, VideoState
16
17
  from endoreg_db.utils.permissions import DEBUG_PERMISSIONS
17
18
 
18
19
  logger = logging.getLogger(__name__)
@@ -21,10 +22,12 @@ logger = logging.getLogger(__name__)
21
22
  # Media Cleanup and Management API
22
23
  # ---------------------------------------------------------------------------
23
24
 
25
+
24
26
  class MediaManagementView(APIView):
25
27
  """
26
28
  Comprehensive Media Management API for cleanup and maintenance operations
27
29
  """
30
+
28
31
  permission_classes = DEBUG_PERMISSIONS
29
32
 
30
33
  def get(self, request):
@@ -38,8 +41,8 @@ class MediaManagementView(APIView):
38
41
  except Exception as e:
39
42
  logger.error(f"Error getting media status overview: {e}")
40
43
  return Response(
41
- {"error": "Failed to get status overview"},
42
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
44
+ {"error": "Failed to get status overview"},
45
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR,
43
46
  )
44
47
 
45
48
  def delete(self, request):
@@ -47,10 +50,10 @@ class MediaManagementView(APIView):
47
50
  DELETE /api/media-management/cleanup/
48
51
  Cleanup unfinished, failed, or stale media processing entries
49
52
  """
50
- cleanup_type = request.query_params.get('type', 'unfinished')
51
- force = request.query_params.get('force', 'false').lower() == 'true'
52
- media_type = request.query_params.get('file_type', 'all')
53
- file_id = request.query_params.get('file_id', None)
53
+ cleanup_type = request.query_params.get("type", "unfinished")
54
+ force = request.query_params.get("force", "false").lower() == "true"
55
+ media_type = request.query_params.get("file_type", "all")
56
+ file_id = request.query_params.get("file_id", None)
54
57
 
55
58
  try:
56
59
  result = self._perform_cleanup(cleanup_type, force, media_type, file_id)
@@ -59,40 +62,40 @@ class MediaManagementView(APIView):
59
62
  except Exception as e:
60
63
  logger.error(f"Error during media cleanup: {e}")
61
64
  return Response(
62
- {"error": "Cleanup operation failed"},
63
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
65
+ {"error": "Cleanup operation failed"},
66
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR,
64
67
  )
65
68
 
66
69
  def _get_status_overview(self) -> Dict[str, Any]:
67
70
  """Get comprehensive status overview"""
68
71
  video_stats = self._get_video_stats()
69
72
  pdf_stats = self._get_pdf_stats()
70
-
73
+
71
74
  # Stale processing detection (older than 2 hours)
72
75
  stale_threshold = timezone.now() - timedelta(hours=2)
73
76
  # Use VideoState boolean fields instead of non-existent name field
74
77
  stale_videos = VideoFile.objects.filter(
75
78
  uploaded_at__lt=stale_threshold,
76
79
  state__frames_extracted=True,
77
- state__sensitive_meta_processed=False
80
+ state__sensitive_meta_processed=False,
78
81
  ).count()
79
-
82
+
80
83
  return {
81
84
  "videos": video_stats,
82
85
  "pdfs": pdf_stats,
83
86
  "cleanup_opportunities": {
84
87
  "stale_processing": stale_videos,
85
88
  "failed_videos": video_stats["failed"],
86
- "unfinished_total": video_stats["unfinished"] + pdf_stats["unfinished"]
89
+ "unfinished_total": video_stats["unfinished"] + pdf_stats["unfinished"],
87
90
  },
88
91
  "total_files": video_stats["total"] + pdf_stats["total"],
89
- "timestamp": timezone.now().isoformat()
92
+ "timestamp": timezone.now().isoformat(),
90
93
  }
91
94
 
92
95
  def _get_video_stats(self) -> Dict[str, int]:
93
96
  """Get video file statistics using VideoState boolean fields"""
94
- videos = VideoFile.objects.select_related('state').all()
95
-
97
+ videos = VideoFile.objects.select_related("state").all()
98
+
96
99
  stats = {
97
100
  "total": videos.count(),
98
101
  "not_started": 0,
@@ -100,39 +103,42 @@ class MediaManagementView(APIView):
100
103
  "done": 0,
101
104
  "failed": 0,
102
105
  "validated": 0,
103
- "unfinished": 0
106
+ "unfinished": 0,
104
107
  }
105
-
108
+
106
109
  for video in videos:
107
110
  if not video.state:
108
111
  stats["not_started"] += 1
109
112
  stats["unfinished"] += 1
110
113
  continue
111
-
114
+
112
115
  # Use the anonymization_status property
113
116
  video_status = video.state.anonymization_status
114
-
115
- if video_status.value == 'not_started':
117
+
118
+ if video_status.value == "not_started":
116
119
  stats["not_started"] += 1
117
120
  stats["unfinished"] += 1
118
- elif video_status.value in ['extracting_frames', 'processing_anonymization']:
121
+ elif video_status.value in [
122
+ "extracting_frames",
123
+ "processing_anonymization",
124
+ ]:
119
125
  stats["processing"] += 1
120
126
  stats["unfinished"] += 1
121
- elif video_status.value == 'done':
127
+ elif video_status.value == "done_processing_anonymization":
122
128
  stats["done"] += 1
123
- elif video_status.value == 'failed':
129
+ elif video_status.value == "failed":
124
130
  stats["failed"] += 1
125
131
  stats["unfinished"] += 1
126
- elif video_status.value == 'validated':
132
+ elif video_status.value == "validated":
127
133
  stats["validated"] += 1
128
134
  else:
129
135
  stats["unfinished"] += 1
130
136
  return stats
131
137
 
132
138
  def _get_pdf_stats(self) -> Dict[str, int]:
133
- """Get PDF file statistics"""
139
+ """Get report file statistics"""
134
140
  pdfs = RawPdfFile.objects.all()
135
-
141
+
136
142
  stats = {
137
143
  "total": pdfs.count(),
138
144
  "not_started": 0,
@@ -140,14 +146,18 @@ class MediaManagementView(APIView):
140
146
  "done": 0,
141
147
  "failed": 0,
142
148
  "validated": 0,
143
- "unfinished": 0
149
+ "unfinished": 0,
144
150
  }
145
-
151
+
146
152
  for pdf in pdfs:
147
- # PDF status logic based on anonymized_text presence and validation
153
+ # report status logic based on anonymized_text presence and validation
148
154
  has_anonymized = bool(pdf.anonymized_text and pdf.anonymized_text.strip())
149
- is_validated = getattr(pdf.sensitive_meta, 'is_verified', False) if pdf.sensitive_meta else False
150
-
155
+ is_validated = (
156
+ getattr(pdf.sensitive_meta, "is_verified", False)
157
+ if pdf.sensitive_meta
158
+ else False
159
+ )
160
+
151
161
  if not has_anonymized:
152
162
  stats["not_started"] += 1
153
163
  stats["unfinished"] += 1
@@ -157,22 +167,24 @@ class MediaManagementView(APIView):
157
167
  stats["done"] += 1
158
168
  else:
159
169
  stats["unfinished"] += 1
160
-
170
+
161
171
  return stats
162
172
 
163
- def _perform_cleanup(self, cleanup_type: str, force: bool, media_type: str, file_id: int) -> Dict[str, Any]:
173
+ def _perform_cleanup(
174
+ self, cleanup_type: str, force: bool, media_type: str, file_id: int
175
+ ) -> Dict[str, Any]:
164
176
  """Perform the actual cleanup operations"""
165
-
177
+
166
178
  result = {
167
179
  "cleanup_type": cleanup_type,
168
180
  "force": force,
169
181
  "removed_items": [],
170
- "summary": {}
182
+ "summary": {},
171
183
  }
172
-
173
- if media_type not in ['video', 'pdf', 'all']:
184
+
185
+ if media_type not in ["video", "pdf", "all"]:
174
186
  raise ValueError(f"Unknown media type: {media_type}")
175
-
187
+
176
188
  if file_id is not None:
177
189
  try:
178
190
  file_id = int(file_id)
@@ -181,81 +193,92 @@ class MediaManagementView(APIView):
181
193
 
182
194
  video_file_obj = None
183
195
  pdf_file_obj = None
184
-
185
- if media_type == 'video':
186
- video_file_obj = VideoFile.get_video_by_id(self, video_id=file_id) if file_id else None
187
- elif media_type == 'pdf':
188
- pdf_file_obj = RawPdfFile.get_pdf_by_id(file_id) if file_id else None
189
196
 
197
+ if media_type == "video":
198
+ video_file_obj = (
199
+ VideoFile.get_video_by_pk(pk=file_id) if file_id else None
200
+ )
201
+
202
+ elif media_type == "pdf":
203
+ pdf_file_obj = RawPdfFile.get_pdf_by_pk(pk=file_id) if file_id else None
190
204
 
191
205
  with transaction.atomic():
192
206
  if video_file_obj:
193
207
  video_file_obj.delete()
194
208
  if pdf_file_obj:
195
209
  pdf_file_obj.delete()
196
-
197
- if cleanup_type == 'unfinished':
210
+
211
+ if cleanup_type == "unfinished":
198
212
  result.update(self._cleanup_unfinished_media(force))
199
- elif cleanup_type == 'failed':
213
+ elif cleanup_type == "failed":
200
214
  result.update(self._cleanup_failed_media(force))
201
- elif cleanup_type == 'stale':
215
+ elif cleanup_type == "stale":
202
216
  result.update(self._cleanup_stale_processing(force))
203
- elif cleanup_type == 'all':
217
+ elif cleanup_type == "all":
204
218
  unfinished = self._cleanup_unfinished_media(force)
205
219
  failed = self._cleanup_failed_media(force)
206
220
  stale = self._cleanup_stale_processing(force)
207
-
221
+
208
222
  result["removed_items"] = (
209
- unfinished.get("removed_items", []) +
210
- failed.get("removed_items", []) +
211
- stale.get("removed_items", [])
223
+ unfinished.get("removed_items", [])
224
+ + failed.get("removed_items", [])
225
+ + stale.get("removed_items", [])
212
226
  )
213
227
  result["summary"] = {
214
228
  "unfinished": unfinished.get("summary", {}),
215
229
  "failed": failed.get("summary", {}),
216
- "stale": stale.get("summary", {})
230
+ "stale": stale.get("summary", {}),
217
231
  }
218
232
  else:
219
233
  raise ValueError(f"Unknown cleanup type: {cleanup_type}")
220
-
234
+
221
235
  return result
222
236
 
223
237
  def _cleanup_unfinished_media(self, force: bool) -> Dict[str, Any]:
224
238
  """Remove unfinished media processing entries"""
225
239
  removed_videos = []
226
240
  removed_pdfs = []
227
-
241
+
228
242
  # Find unfinished videos using VideoState boolean fields
229
- unfinished_videos = VideoFile.objects.select_related('state').all()
230
-
243
+ unfinished_videos = VideoFile.objects.select_related("state").all()
244
+
231
245
  for video in unfinished_videos:
232
246
  if not video.state:
233
247
  if force: # Only remove videos without state if force=True
234
- removed_videos.append({
235
- "id": video.id,
236
- "type": "video",
237
- "filename": video.original_file_name,
238
- "status": "no_state",
239
- "uploaded_at": video.uploaded_at.isoformat()
240
- })
248
+ removed_videos.append(
249
+ {
250
+ "id": video.id,
251
+ "type": "video",
252
+ "filename": video.original_file_name,
253
+ "status": "no_state",
254
+ "uploaded_at": video.uploaded_at.isoformat(),
255
+ }
256
+ )
241
257
  video.delete()
242
258
  continue
243
-
259
+
244
260
  video_status = video.state.anonymization_status
245
- is_unfinished = video_status.value in ['not_started', 'extracting_frames', 'processing_anonymization', 'failed']
246
-
261
+ is_unfinished = video_status.value in [
262
+ "not_started",
263
+ "extracting_frames",
264
+ "processing_anonymization",
265
+ "failed",
266
+ ]
267
+
247
268
  # Remove unfinished videos
248
- if is_unfinished and (force or video_status.value != 'not_started'):
249
- removed_videos.append({
250
- "id": video.id,
251
- "type": "video",
252
- "filename": video.original_file_name,
253
- "status": video_status.value,
254
- "uploaded_at": video.uploaded_at.isoformat()
255
- })
269
+ if is_unfinished and (force or video_status.value != "not_started"):
270
+ removed_videos.append(
271
+ {
272
+ "id": video.id,
273
+ "type": "video",
274
+ "filename": video.original_file_name,
275
+ "status": video_status.value,
276
+ "uploaded_at": video.uploaded_at.isoformat(),
277
+ }
278
+ )
256
279
  if force:
257
280
  video.delete()
258
-
281
+
259
282
  # Return the results
260
283
  return {
261
284
  "removed_items": removed_videos + removed_pdfs,
@@ -263,29 +286,31 @@ class MediaManagementView(APIView):
263
286
  "videos_removed": len(removed_videos),
264
287
  "pdfs_removed": len(removed_pdfs),
265
288
  "total_removed": len(removed_videos) + len(removed_pdfs),
266
- "dry_run": not force
267
- }
289
+ "dry_run": not force,
290
+ },
268
291
  }
269
292
 
270
293
  def _cleanup_failed_media(self, force: bool) -> Dict[str, Any]:
271
294
  """Remove failed media processing entries"""
272
295
  removed_items = []
273
-
296
+
274
297
  # Find failed videos using VideoState boolean fields
275
- failed_videos = VideoFile.objects.select_related('state').all()
276
-
298
+ failed_videos = VideoFile.objects.select_related("state").all()
299
+
277
300
  for video in failed_videos:
278
- if video.state and video.state.anonymization_status.value == 'failed':
279
- removed_items.append({
280
- "id": video.id,
281
- "type": "video",
282
- "filename": video.original_file_name,
283
- "status": "failed",
284
- "uploaded_at": video.uploaded_at.isoformat()
285
- })
301
+ if video.state and video.state.anonymization_status.value == "failed":
302
+ removed_items.append(
303
+ {
304
+ "id": video.id,
305
+ "type": "video",
306
+ "filename": video.original_file_name,
307
+ "status": "failed",
308
+ "uploaded_at": video.uploaded_at.isoformat(),
309
+ }
310
+ )
286
311
  if force:
287
312
  video.delete()
288
-
313
+
289
314
  if force:
290
315
  # Count actual deletions
291
316
  videos_deleted = len([v for v in removed_items if v["type"] == "video"])
@@ -294,8 +319,8 @@ class MediaManagementView(APIView):
294
319
  "summary": {
295
320
  "videos_removed": videos_deleted,
296
321
  "total_removed": videos_deleted,
297
- "dry_run": False
298
- }
322
+ "dry_run": False,
323
+ },
299
324
  }
300
325
  else:
301
326
  return {
@@ -303,33 +328,40 @@ class MediaManagementView(APIView):
303
328
  "summary": {
304
329
  "videos_removed": len(removed_items),
305
330
  "total_removed": len(removed_items),
306
- "dry_run": True
307
- }
331
+ "dry_run": True,
332
+ },
308
333
  }
309
334
 
310
335
  def _cleanup_stale_processing(self, force: bool) -> Dict[str, Any]:
311
336
  """Remove stale processing entries (older than 2 hours)"""
312
337
  stale_threshold = timezone.now() - timedelta(hours=2)
313
338
  removed_items = []
314
-
339
+
315
340
  # Find stale videos using VideoState boolean fields
316
341
  stale_videos = VideoFile.objects.filter(
317
342
  uploaded_at__lt=stale_threshold,
318
343
  state__frames_extracted=True,
319
- state__sensitive_meta_processed=False
320
- ).select_related('state')
321
-
344
+ state__sensitive_meta_processed=False,
345
+ ).select_related("state")
346
+
322
347
  for video in stale_videos:
323
- video_status = video.state.anonymization_status if video.state else "no_state"
324
- removed_items.append({
325
- "id": video.id,
326
- "type": "video",
327
- "filename": video.original_file_name,
328
- "status": f"stale_{video_status.value if hasattr(video_status, 'value') else video_status}",
329
- "uploaded_at": video.uploaded_at.isoformat(),
330
- "stale_duration_hours": (timezone.now() - video.uploaded_at).total_seconds() / 3600
331
- })
332
-
348
+ video_status = (
349
+ video.state.anonymization_status if video.state else "no_state"
350
+ )
351
+ removed_items.append(
352
+ {
353
+ "id": video.id,
354
+ "type": "video",
355
+ "filename": video.original_file_name,
356
+ "status": f"stale_{video_status.value if hasattr(video_status, 'value') else video_status}",
357
+ "uploaded_at": video.uploaded_at.isoformat(),
358
+ "stale_duration_hours": (
359
+ timezone.now() - video.uploaded_at
360
+ ).total_seconds()
361
+ / 3600,
362
+ }
363
+ )
364
+
333
365
  if force:
334
366
  videos_deleted = stale_videos.delete()[0]
335
367
  return {
@@ -337,8 +369,8 @@ class MediaManagementView(APIView):
337
369
  "summary": {
338
370
  "stale_videos_removed": videos_deleted,
339
371
  "total_removed": videos_deleted,
340
- "dry_run": False
341
- }
372
+ "dry_run": False,
373
+ },
342
374
  }
343
375
  else:
344
376
  return {
@@ -346,12 +378,12 @@ class MediaManagementView(APIView):
346
378
  "summary": {
347
379
  "stale_videos_removed": len(removed_items),
348
380
  "total_removed": len(removed_items),
349
- "dry_run": True
350
- }
381
+ "dry_run": True,
382
+ },
351
383
  }
352
384
 
353
385
 
354
- @api_view(['DELETE'])
386
+ @api_view(["DELETE"])
355
387
  @permission_classes(DEBUG_PERMISSIONS)
356
388
  def force_remove_media(request, file_id: int):
357
389
  """
@@ -364,43 +396,44 @@ def force_remove_media(request, file_id: int):
364
396
  video = VideoFile.objects.get(id=file_id)
365
397
  filename = video.original_file_name
366
398
  video.delete()
367
-
368
- return Response({
369
- "detail": f"Video file '{filename}' (ID: {file_id}) removed successfully",
370
- "file_type": "video",
371
- "file_id": file_id
372
- })
399
+
400
+ return Response(
401
+ {
402
+ "detail": f"Video file '{filename}' (ID: {file_id}) removed successfully",
403
+ "file_type": "video",
404
+ "file_id": file_id,
405
+ }
406
+ )
373
407
  except VideoFile.DoesNotExist:
374
408
  pass
375
-
409
+
376
410
  # Try to find and delete from RawPdfFile
377
411
  try:
378
412
  pdf = RawPdfFile.objects.get(id=file_id)
379
- filename = getattr(pdf.file, 'name', 'Unknown')
413
+ filename = getattr(pdf.file, "name", "Unknown")
380
414
  pdf.delete()
381
-
382
- return Response({
383
- "detail": f"PDF file '{filename}' (ID: {file_id}) removed successfully",
384
- "file_type": "pdf",
385
- "file_id": file_id
386
- })
415
+
416
+ return Response(
417
+ {
418
+ "detail": f"report file '{filename}' (ID: {file_id}) removed successfully",
419
+ "file_type": "pdf",
420
+ "file_id": file_id,
421
+ }
422
+ )
387
423
  except RawPdfFile.DoesNotExist:
388
424
  pass
389
-
390
- return Response(
391
- {"detail": "File not found"},
392
- status=status.HTTP_404_NOT_FOUND
393
- )
394
-
425
+
426
+ return Response({"detail": "File not found"}, status=status.HTTP_404_NOT_FOUND)
427
+
395
428
  except Exception as e:
396
429
  logger.error(f"Error force removing media {file_id}: {e}")
397
430
  return Response(
398
- {"error": "Force removal failed"},
399
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
431
+ {"error": "Force removal failed"},
432
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR,
400
433
  )
401
434
 
402
435
 
403
- @api_view(['POST'])
436
+ @api_view(["POST"])
404
437
  @permission_classes(DEBUG_PERMISSIONS)
405
438
  def reset_processing_status(request, file_id: int):
406
439
  """
@@ -411,44 +444,47 @@ def reset_processing_status(request, file_id: int):
411
444
  # Try VideoFile first
412
445
  try:
413
446
  video = VideoFile.objects.get(id=file_id)
414
-
447
+
415
448
  # Reset to 'not_started' state
416
- not_started_state, created = VideoState.objects.get_or_create(name='not_started')
449
+ not_started_state, created = VideoState.objects.get_or_create(
450
+ name="not_started"
451
+ )
417
452
  video.state = not_started_state
418
453
  video.save()
419
-
420
- return Response({
421
- "detail": "Video file status reset to 'not_started'",
422
- "file_type": "video",
423
- "file_id": file_id,
424
- "new_status": "not_started"
425
- })
454
+
455
+ return Response(
456
+ {
457
+ "detail": "Video file status reset to 'not_started'",
458
+ "file_type": "video",
459
+ "file_id": file_id,
460
+ "new_status": "not_started",
461
+ }
462
+ )
426
463
  except VideoFile.DoesNotExist:
427
464
  pass
428
-
429
- # PDF files don't have state, but we can clear anonymized_text
465
+
466
+ # report files don't have state, but we can clear anonymized_text
430
467
  try:
431
468
  pdf = RawPdfFile.objects.get(id=file_id)
432
469
  pdf.anonymized_text = ""
433
470
  pdf.save()
434
-
435
- return Response({
436
- "detail": "PDF file processing reset",
437
- "file_type": "pdf",
438
- "file_id": file_id,
439
- "new_status": "not_started"
440
- })
471
+
472
+ return Response(
473
+ {
474
+ "detail": "report file processing reset",
475
+ "file_type": "pdf",
476
+ "file_id": file_id,
477
+ "new_status": "not_started",
478
+ }
479
+ )
441
480
  except RawPdfFile.DoesNotExist:
442
481
  pass
443
-
444
- return Response(
445
- {"detail": "File not found"},
446
- status=status.HTTP_404_NOT_FOUND
447
- )
448
-
482
+
483
+ return Response({"detail": "File not found"}, status=status.HTTP_404_NOT_FOUND)
484
+
449
485
  except Exception as e:
450
486
  logger.error(f"Error resetting status for media {file_id}: {e}")
451
487
  return Response(
452
- {"error": "Status reset failed"},
453
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
488
+ {"error": "Status reset failed"},
489
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR,
454
490
  )