endoreg-db 0.8.4.4__py3-none-any.whl → 0.8.8.0__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 (372) 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 +8 -31
  10. endoreg_db/data/_examples/disease.yaml +55 -0
  11. endoreg_db/data/_examples/disease_classification.yaml +13 -0
  12. endoreg_db/data/_examples/disease_classification_choice.yaml +62 -0
  13. endoreg_db/data/_examples/event.yaml +64 -0
  14. endoreg_db/data/_examples/examination.yaml +72 -0
  15. endoreg_db/data/_examples/finding/anatomy_colon.yaml +128 -0
  16. endoreg_db/data/_examples/finding/colonoscopy.yaml +40 -0
  17. endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +56 -0
  18. endoreg_db/data/_examples/finding/complication.yaml +16 -0
  19. endoreg_db/data/_examples/finding/data.yaml +105 -0
  20. endoreg_db/data/_examples/finding/examination_setting.yaml +16 -0
  21. endoreg_db/data/_examples/finding/medication_related.yaml +18 -0
  22. endoreg_db/data/_examples/finding/outcome.yaml +12 -0
  23. endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +68 -0
  24. endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +22 -0
  25. endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +25 -0
  26. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
  27. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
  28. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +68 -0
  29. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
  30. endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +80 -0
  31. endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +21 -0
  32. endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +20 -0
  33. endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +26 -0
  34. endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +22 -0
  35. endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +53 -0
  36. endoreg_db/data/_examples/finding_classification/complication_generic.yaml +25 -0
  37. endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +40 -0
  38. endoreg_db/data/_examples/finding_classification/histology_colo.yaml +51 -0
  39. endoreg_db/data/_examples/finding_classification/intervention_required.yaml +26 -0
  40. endoreg_db/data/_examples/finding_classification/medication_related.yaml +23 -0
  41. endoreg_db/data/_examples/finding_classification/visualized.yaml +33 -0
  42. endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +78 -0
  43. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
  44. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
  45. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
  46. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +15 -0
  47. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +17 -0
  48. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_paris.yaml +57 -0
  49. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
  50. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +14 -0
  51. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
  52. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_location.yaml +229 -0
  53. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
  54. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +82 -0
  55. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
  56. endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +15 -0
  57. endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
  58. endoreg_db/data/_examples/finding_classification_choice/histology.yaml +24 -0
  59. endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +20 -0
  60. endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +19 -0
  61. endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +11 -0
  62. endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +48 -0
  63. endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +43 -0
  64. endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
  65. endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +128 -0
  66. endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +32 -0
  67. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +9 -0
  68. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +36 -0
  69. endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +15 -0
  70. endoreg_db/data/_examples/finding_type/data.yaml +43 -0
  71. endoreg_db/data/_examples/requirement/age.yaml +26 -0
  72. endoreg_db/data/_examples/requirement/colonoscopy_baseline_austria.yaml +45 -0
  73. endoreg_db/data/_examples/requirement/disease_cardiovascular.yaml +79 -0
  74. endoreg_db/data/_examples/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
  75. endoreg_db/data/_examples/requirement/disease_hepatology.yaml +12 -0
  76. endoreg_db/data/_examples/requirement/disease_misc.yaml +12 -0
  77. endoreg_db/data/_examples/requirement/disease_renal.yaml +96 -0
  78. endoreg_db/data/_examples/requirement/endoscopy_bleeding_risk.yaml +59 -0
  79. endoreg_db/data/_examples/requirement/event_cardiology.yaml +251 -0
  80. endoreg_db/data/_examples/requirement/event_requirements.yaml +145 -0
  81. endoreg_db/data/_examples/requirement/finding_colon_polyp.yaml +50 -0
  82. endoreg_db/data/_examples/requirement/gender.yaml +25 -0
  83. endoreg_db/data/_examples/requirement/lab_value.yaml +441 -0
  84. endoreg_db/data/_examples/requirement/medication.yaml +93 -0
  85. endoreg_db/data/_examples/requirement_operator/age.yaml +13 -0
  86. endoreg_db/data/_examples/requirement_operator/lab_operators.yaml +129 -0
  87. endoreg_db/data/_examples/requirement_operator/model_operators.yaml +96 -0
  88. endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +48 -0
  89. endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +57 -0
  90. endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
  91. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +4 -3
  92. endoreg_db/data/event_classification/data.yaml +4 -0
  93. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  94. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +43 -70
  95. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +22 -52
  96. endoreg_db/data/finding_classification/colonoscopy_location.yaml +31 -62
  97. endoreg_db/data/finding_classification/histology_colo.yaml +28 -36
  98. endoreg_db/data/requirement/colon_polyp_intervention.yaml +49 -0
  99. endoreg_db/data/requirement/coloreg_colon_polyp.yaml +49 -0
  100. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +31 -12
  101. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  102. endoreg_db/data/requirement_set/02_endoscopy_bleeding_risk.yaml +46 -0
  103. endoreg_db/data/requirement_set/90_coloreg.yaml +178 -0
  104. endoreg_db/data/requirement_set/_old_ +109 -0
  105. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  106. endoreg_db/data/setup_config.yaml +4 -4
  107. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  108. endoreg_db/exceptions.py +5 -2
  109. endoreg_db/helpers/data_loader.py +1 -1
  110. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  111. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  112. endoreg_db/management/commands/import_video.py +9 -10
  113. endoreg_db/management/commands/import_video_with_classification.py +1 -1
  114. endoreg_db/management/commands/init_default_ai_model.py +1 -1
  115. endoreg_db/management/commands/list_routes.py +18 -0
  116. endoreg_db/management/commands/load_ai_model_data.py +2 -1
  117. endoreg_db/management/commands/load_center_data.py +12 -12
  118. endoreg_db/management/commands/load_requirement_data.py +60 -31
  119. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  120. endoreg_db/management/commands/setup_endoreg_db.py +14 -10
  121. endoreg_db/management/commands/storage_management.py +271 -203
  122. endoreg_db/migrations/0001_initial.py +1799 -1300
  123. endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
  124. endoreg_db/migrations/_old/0001_initial.py +1857 -0
  125. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
  126. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
  127. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
  128. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
  129. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
  130. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
  131. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
  132. endoreg_db/models/__init__.py +78 -123
  133. endoreg_db/models/administration/__init__.py +21 -42
  134. endoreg_db/models/administration/ai/active_model.py +2 -2
  135. endoreg_db/models/administration/ai/ai_model.py +7 -6
  136. endoreg_db/models/administration/case/__init__.py +1 -15
  137. endoreg_db/models/administration/case/case.py +3 -3
  138. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  139. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  140. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  141. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  142. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  143. endoreg_db/models/administration/center/center.py +33 -19
  144. endoreg_db/models/administration/center/center_product.py +12 -9
  145. endoreg_db/models/administration/center/center_resource.py +25 -19
  146. endoreg_db/models/administration/center/center_shift.py +21 -17
  147. endoreg_db/models/administration/center/center_waste.py +16 -8
  148. endoreg_db/models/administration/person/__init__.py +2 -0
  149. endoreg_db/models/administration/person/employee/employee.py +10 -5
  150. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  151. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  152. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  153. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  154. endoreg_db/models/administration/person/patient/patient.py +103 -100
  155. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  156. endoreg_db/models/administration/person/person.py +4 -0
  157. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  158. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  159. endoreg_db/models/administration/product/product.py +20 -15
  160. endoreg_db/models/administration/product/product_material.py +17 -18
  161. endoreg_db/models/administration/product/product_weight.py +12 -8
  162. endoreg_db/models/administration/product/reference_product.py +23 -55
  163. endoreg_db/models/administration/qualification/qualification.py +7 -3
  164. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  165. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  166. endoreg_db/models/administration/shift/shift.py +16 -12
  167. endoreg_db/models/administration/shift/shift_type.py +23 -31
  168. endoreg_db/models/label/__init__.py +7 -8
  169. endoreg_db/models/label/annotation/image_classification.py +10 -9
  170. endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
  171. endoreg_db/models/label/label.py +15 -15
  172. endoreg_db/models/label/label_set.py +19 -6
  173. endoreg_db/models/label/label_type.py +1 -1
  174. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  175. endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
  176. endoreg_db/models/label/video_segmentation_label.py +4 -0
  177. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  178. endoreg_db/models/media/frame/frame.py +22 -22
  179. endoreg_db/models/media/pdf/raw_pdf.py +249 -177
  180. endoreg_db/models/media/pdf/report_file.py +25 -29
  181. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
  182. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  183. endoreg_db/models/media/video/__init__.py +1 -0
  184. endoreg_db/models/media/video/create_from_file.py +48 -56
  185. endoreg_db/models/media/video/pipe_1.py +30 -33
  186. endoreg_db/models/media/video/pipe_2.py +8 -9
  187. endoreg_db/models/media/video/video_file.py +359 -204
  188. endoreg_db/models/media/video/video_file_ai.py +288 -74
  189. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  190. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  191. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  192. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  193. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  194. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  195. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  196. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  197. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  198. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  199. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  200. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  201. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  202. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  203. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  204. endoreg_db/models/media/video/video_file_io.py +109 -62
  205. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  206. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  207. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  208. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  209. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  210. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  211. endoreg_db/models/media/video/video_file_segments.py +24 -17
  212. endoreg_db/models/media/video/video_metadata.py +19 -35
  213. endoreg_db/models/media/video/video_processing.py +96 -95
  214. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  215. endoreg_db/models/medical/disease.py +22 -16
  216. endoreg_db/models/medical/event.py +31 -18
  217. endoreg_db/models/medical/examination/__init__.py +13 -6
  218. endoreg_db/models/medical/examination/examination.py +17 -18
  219. endoreg_db/models/medical/examination/examination_indication.py +26 -25
  220. endoreg_db/models/medical/examination/examination_time.py +16 -6
  221. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  222. endoreg_db/models/medical/examination/examination_type.py +3 -4
  223. endoreg_db/models/medical/finding/finding.py +38 -39
  224. endoreg_db/models/medical/finding/finding_classification.py +37 -48
  225. endoreg_db/models/medical/finding/finding_intervention.py +27 -22
  226. endoreg_db/models/medical/finding/finding_type.py +13 -12
  227. endoreg_db/models/medical/hardware/endoscope.py +20 -26
  228. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  229. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  230. endoreg_db/models/medical/medication/medication.py +22 -10
  231. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  232. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  233. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  234. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  235. endoreg_db/models/medical/organ/__init__.py +15 -12
  236. endoreg_db/models/medical/patient/medication_examples.py +1 -5
  237. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  238. endoreg_db/models/medical/patient/patient_event.py +19 -22
  239. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  240. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  241. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  242. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  243. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  244. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  245. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  246. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  247. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  248. endoreg_db/models/medical/risk/risk.py +7 -6
  249. endoreg_db/models/medical/risk/risk_type.py +8 -5
  250. endoreg_db/models/metadata/model_meta.py +60 -29
  251. endoreg_db/models/metadata/model_meta_logic.py +139 -18
  252. endoreg_db/models/metadata/pdf_meta.py +19 -24
  253. endoreg_db/models/metadata/sensitive_meta.py +102 -85
  254. endoreg_db/models/metadata/sensitive_meta_logic.py +383 -43
  255. endoreg_db/models/metadata/video_meta.py +51 -31
  256. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  257. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  258. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  259. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  260. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  261. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  262. endoreg_db/models/other/emission/emission_factor.py +18 -8
  263. endoreg_db/models/other/gender.py +10 -5
  264. endoreg_db/models/other/information_source.py +25 -25
  265. endoreg_db/models/other/material.py +9 -5
  266. endoreg_db/models/other/resource.py +6 -4
  267. endoreg_db/models/other/tag.py +10 -5
  268. endoreg_db/models/other/transport_route.py +13 -8
  269. endoreg_db/models/other/unit.py +10 -6
  270. endoreg_db/models/other/waste.py +6 -5
  271. endoreg_db/models/requirement/requirement.py +580 -272
  272. endoreg_db/models/requirement/requirement_error.py +85 -0
  273. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  274. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  275. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  276. endoreg_db/models/requirement/requirement_operator.py +36 -33
  277. endoreg_db/models/requirement/requirement_set.py +74 -57
  278. endoreg_db/models/state/__init__.py +4 -4
  279. endoreg_db/models/state/abstract.py +2 -2
  280. endoreg_db/models/state/anonymization.py +12 -0
  281. endoreg_db/models/state/audit_ledger.py +46 -47
  282. endoreg_db/models/state/label_video_segment.py +9 -0
  283. endoreg_db/models/state/raw_pdf.py +40 -46
  284. endoreg_db/models/state/sensitive_meta.py +6 -2
  285. endoreg_db/models/state/video.py +58 -53
  286. endoreg_db/models/upload_job.py +32 -55
  287. endoreg_db/models/utils.py +1 -2
  288. endoreg_db/root_urls.py +21 -2
  289. endoreg_db/serializers/__init__.py +26 -57
  290. endoreg_db/serializers/anonymization.py +18 -10
  291. endoreg_db/serializers/meta/report_meta.py +1 -1
  292. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  293. endoreg_db/serializers/misc/__init__.py +1 -1
  294. endoreg_db/serializers/misc/file_overview.py +33 -91
  295. endoreg_db/serializers/misc/{vop_patient_data.py → sensitive_patient_data.py} +1 -1
  296. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  297. endoreg_db/serializers/video/segmentation.py +2 -1
  298. endoreg_db/serializers/video/video_processing_history.py +20 -5
  299. endoreg_db/serializers/video_examination.py +198 -0
  300. endoreg_db/services/anonymization.py +75 -73
  301. endoreg_db/services/lookup_service.py +256 -73
  302. endoreg_db/services/lookup_store.py +174 -30
  303. endoreg_db/services/pdf_import.py +711 -310
  304. endoreg_db/services/storage_aware_video_processor.py +140 -114
  305. endoreg_db/services/video_import.py +266 -117
  306. endoreg_db/urls/__init__.py +27 -27
  307. endoreg_db/urls/label_video_segments.py +2 -0
  308. endoreg_db/urls/media.py +108 -66
  309. endoreg_db/urls/root_urls.py +29 -0
  310. endoreg_db/utils/__init__.py +15 -5
  311. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  312. endoreg_db/utils/case_generator/__init__.py +3 -0
  313. endoreg_db/utils/dataloader.py +88 -16
  314. endoreg_db/utils/defaults/set_default_center.py +32 -0
  315. endoreg_db/utils/names.py +22 -16
  316. endoreg_db/utils/permissions.py +2 -1
  317. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  318. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
  319. endoreg_db/utils/setup_config.py +8 -5
  320. endoreg_db/utils/storage.py +115 -0
  321. endoreg_db/utils/validate_endo_roi.py +8 -2
  322. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  323. endoreg_db/views/__init__.py +5 -12
  324. endoreg_db/views/anonymization/media_management.py +198 -163
  325. endoreg_db/views/anonymization/overview.py +4 -1
  326. endoreg_db/views/anonymization/validate.py +174 -40
  327. endoreg_db/views/media/__init__.py +2 -0
  328. endoreg_db/views/media/pdf_media.py +131 -150
  329. endoreg_db/views/media/sensitive_metadata.py +46 -6
  330. endoreg_db/views/media/video_media.py +89 -82
  331. endoreg_db/views/media/video_segments.py +187 -260
  332. endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
  333. endoreg_db/views/patient/patient.py +5 -4
  334. endoreg_db/views/pdf/__init__.py +5 -8
  335. endoreg_db/views/pdf/pdf_stream.py +186 -0
  336. endoreg_db/views/pdf/pdf_stream_views.py +0 -127
  337. endoreg_db/views/pdf/reimport.py +86 -91
  338. endoreg_db/views/requirement/evaluate.py +188 -187
  339. endoreg_db/views/requirement/lookup.py +186 -288
  340. endoreg_db/views/requirement/requirement_utils.py +89 -0
  341. endoreg_db/views/video/__init__.py +0 -4
  342. endoreg_db/views/video/correction.py +2 -2
  343. endoreg_db/views/video/video_examination_viewset.py +202 -289
  344. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
  345. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +350 -255
  346. endoreg_db/models/administration/permissions/__init__.py +0 -44
  347. endoreg_db/models/media/video/refactor_plan.md +0 -0
  348. endoreg_db/models/media/video/video_file_frames.py +0 -0
  349. endoreg_db/models/metadata/frame_ocr_result.py +0 -0
  350. endoreg_db/models/rule/__init__.py +0 -13
  351. endoreg_db/models/rule/rule.py +0 -27
  352. endoreg_db/models/rule/rule_applicator.py +0 -224
  353. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  354. endoreg_db/models/rule/rule_type.py +0 -20
  355. endoreg_db/models/rule/ruleset.py +0 -17
  356. endoreg_db/serializers/video/video_metadata.py +0 -105
  357. endoreg_db/urls/report.py +0 -48
  358. endoreg_db/urls/video.py +0 -61
  359. endoreg_db/utils/case_generator/case_generator.py +0 -159
  360. endoreg_db/utils/case_generator/utils.py +0 -30
  361. endoreg_db/views/pdf/pdf_media.py +0 -239
  362. endoreg_db/views/report/__init__.py +0 -9
  363. endoreg_db/views/report/report_list.py +0 -112
  364. endoreg_db/views/report/report_with_secure_url.py +0 -28
  365. endoreg_db/views/report/start_examination.py +0 -7
  366. endoreg_db/views/video/video_media.py +0 -158
  367. endoreg_db/views.py +0 -0
  368. /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
  369. /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
  370. /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
  371. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
  372. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -20,69 +20,6 @@ class SensitiveMetaDetailView(APIView):
20
20
  PATCH: Updates SensitiveMeta fields including verification state
21
21
  """
22
22
 
23
- permission_classes = DEBUG_PERMISSIONS # Changed from IsAuthenticated for development
24
-
25
- def get(self, request, sensitive_meta_id=None):
26
- """
27
- Retrieve SensitiveMeta details for display and annotation.
28
-
29
- Supports both URL parameter and query parameter access patterns:
30
- - /api/pdf/sensitivemeta/123/ (URL parameter)
31
- - /api/pdf/sensitivemeta/?id=123 (query parameter - for backward compatibility)
32
- - /api/pdf/sensitivemeta/ (list all - returns empty list instead of 400)
33
-
34
- Returns detailed information suitable for user verification.
35
- """
36
- # Handle both URL parameter and query parameter patterns
37
- if not sensitive_meta_id:
38
- sensitive_meta_id = request.query_params.get('id')
39
-
40
- # If no ID provided, return empty list instead of error
41
- if not sensitive_meta_id:
42
- return Response([], status=status.HTTP_200_OK)
43
-
44
- try:
45
- # Convert to int if it's a string
46
- sensitive_meta_id = int(sensitive_meta_id)
47
-
48
- # Get the SensitiveMeta instance with related data
49
- sensitive_meta = SensitiveMeta.objects.select_related(
50
- 'center',
51
- 'patient_gender',
52
- 'pseudo_patient',
53
- 'pseudo_examination'
54
- ).prefetch_related(
55
- 'examiners',
56
- 'state'
57
- ).get(id=sensitive_meta_id)
58
-
59
- # Serialize for display
60
- serializer = SensitiveMetaDetailSerializer(sensitive_meta)
61
-
62
- # Return direct data to match anonymization store expectations
63
- # Instead of wrapping in "sensitive_meta" key, return data directly
64
- response_data = serializer.data
65
-
66
- logger.info(f"Retrieved SensitiveMeta {sensitive_meta_id} for user {request.user}")
67
- return Response(response_data, status=status.HTTP_200_OK)
68
-
69
- except ValueError:
70
- return Response(
71
- {"error": "Invalid sensitive_meta_id format. Must be an integer."},
72
- status=status.HTTP_400_BAD_REQUEST
73
- )
74
- except SensitiveMeta.DoesNotExist:
75
- return Response(
76
- {"error": f"SensitiveMeta with ID {sensitive_meta_id} not found"},
77
- status=status.HTTP_404_NOT_FOUND
78
- )
79
- except Exception as e:
80
- logger.error(f"Error retrieving SensitiveMeta {sensitive_meta_id}: {e}")
81
- return Response(
82
- {"error": "Internal server error occurred"},
83
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
84
- )
85
-
86
23
  @transaction.atomic
87
24
  def patch(self, request, sensitive_meta_id=None):
88
25
  """
@@ -6,11 +6,11 @@ from rest_framework import viewsets, status, serializers
6
6
  from rest_framework.response import Response
7
7
  from rest_framework.decorators import action
8
8
 
9
-
9
+ from endoreg_db.authz.permissions import PolicyPermission
10
10
  from endoreg_db.models import Patient
11
11
  from endoreg_db.serializers.patient import PatientSerializer
12
12
  from endoreg_db.models.medical.patient.patient_examination import PatientExamination
13
-
13
+ from rest_framework.permissions import IsAuthenticated
14
14
  @staff_member_required # Ensures only staff members can access the page
15
15
  def start_examination(request):
16
16
  return render(request, 'admin/start_examination.html') # Loads the simple HTML page
@@ -21,8 +21,9 @@ class PatientViewSet(viewsets.ModelViewSet):
21
21
  """API endpoint for managing patients."""
22
22
  queryset = Patient.objects.all()
23
23
  serializer_class = PatientSerializer
24
- #permission_classes = [IsAuthenticatedOrReadOnly]
25
-
24
+ permission_classes = [PolicyPermission]
25
+ #permission_classes = [PolicyPermission]
26
+
26
27
  def perform_create(self, serializer):
27
28
  """Erweiterte Validierung beim Erstellen eines Patienten"""
28
29
  try:
@@ -1,11 +1,8 @@
1
- from .pdf_media import (
2
- PDFMediaView,
3
- UpdateSensitiveMetaView,
4
- ClosingFileWrapper
5
- )
1
+ from .reimport import PdfReimportView
2
+ from .pdf_stream import PdfStreamView
3
+
6
4
 
7
5
  __all__ = [
8
- "PDFMediaView",
9
- "UpdateSensitiveMetaView",
10
- "ClosingFileWrapper",
6
+ "PdfReimportView",
7
+ "PdfStreamView",
11
8
  ]
@@ -0,0 +1,186 @@
1
+ import logging
2
+ import os
3
+ import re
4
+
5
+ from django.http import FileResponse, Http404, StreamingHttpResponse
6
+ from django.views.decorators.clickjacking import xframe_options_exempt, xframe_options_sameorigin
7
+ from rest_framework.views import APIView
8
+
9
+ from endoreg_db.models import RawPdfFile
10
+
11
+ from ...utils.permissions import EnvironmentAwarePermission
12
+
13
+ logger = logging.getLogger(__name__)
14
+ _RANGE_RE = re.compile(r"bytes=(\d+)-(\d*)")
15
+
16
+
17
+ class ClosingFileWrapper:
18
+ """Custom file wrapper that ensures file is closed after streaming"""
19
+
20
+ def __init__(self, file_handle, blksize=8192):
21
+ self.file_handle = file_handle
22
+ self.blksize = blksize
23
+
24
+ def __iter__(self):
25
+ return self
26
+
27
+ def __next__(self):
28
+ data = self.file_handle.read(self.blksize)
29
+ if not data:
30
+ self.file_handle.close()
31
+ raise StopIteration
32
+ return data
33
+
34
+ def close(self):
35
+ if hasattr(self.file_handle, "close"):
36
+ self.file_handle.close()
37
+
38
+
39
+ class PdfStreamView(APIView):
40
+ """
41
+ Streams a PDF file with correct HTTP range support and proper file handle management.
42
+
43
+ Supports streaming both raw (original) and processed PDF files.
44
+
45
+ Query Parameters:
46
+ type: 'raw' (default) or 'processed' - Selects which PDF file to stream
47
+
48
+ Examples:
49
+ GET /api/media/pdf/1/?type=raw - Stream original raw PDF
50
+ GET /api/media/pdf/1/?type=processed - Stream processed PDF
51
+ """
52
+
53
+ permission_classes = [EnvironmentAwarePermission]
54
+ @xframe_options_exempt
55
+ def get(self, request, pk: int, *args, **kwargs):
56
+ file_type = "raw" # Initialize for error logging
57
+ try:
58
+ pdf_obj = RawPdfFile.objects.filter(pk=pk).first()
59
+ if not pdf_obj:
60
+ logger.warning(f"PDF not found: ID {pk}")
61
+ raise Http404("PDF not found")
62
+
63
+ # Parse query parameters to determine which file to stream
64
+ file_type = request.query_params.get("type", "raw").lower()
65
+ if file_type not in ["raw", "processed"]:
66
+ logger.warning(f"Invalid file_type '{file_type}', defaulting to 'raw'")
67
+ file_type = "raw"
68
+
69
+ # Determine which file field to use
70
+ if file_type == "raw":
71
+ file_field = pdf_obj.file
72
+ if not file_field:
73
+ logger.warning(f"No raw PDF file available for PDF ID {pk}")
74
+ raise Http404("Raw PDF file not available")
75
+ else: # anonymized
76
+ file_field = pdf_obj.anonymized_file
77
+ if not file_field:
78
+ logger.warning(
79
+ f"No processed PDF file available for PDF ID {pk}"
80
+ )
81
+ raise Http404("Processed PDF file not available")
82
+
83
+ # Check if file exists on filesystem
84
+ try:
85
+ file_path = file_field.path
86
+ if not os.path.exists(file_path):
87
+ logger.error(f"PDF file does not exist on filesystem: {file_path}")
88
+ raise Http404(
89
+ f"{file_type.capitalize()} PDF file not found on filesystem"
90
+ )
91
+
92
+ file_size = os.path.getsize(file_path)
93
+ except (OSError, IOError, AttributeError) as e:
94
+ logger.error(f"Error accessing {file_type} PDF file {pk}: {e}")
95
+ raise Http404(f"{file_type.capitalize()} PDF file not accessible")
96
+
97
+ # Generate safe filename
98
+ base_filename = (
99
+ os.path.basename(file_field.name)
100
+ if file_field.name
101
+ else f"document_{pk}.pdf"
102
+ )
103
+ if not base_filename.endswith(".pdf"):
104
+ base_filename += ".pdf"
105
+
106
+ # Add type indicator to filename for clarity
107
+ if file_type == "processed":
108
+ name_parts = base_filename.rsplit(".", 1)
109
+ safe_filename = f"{name_parts[0]}_processed.{name_parts[1]}"
110
+ else:
111
+ safe_filename = base_filename
112
+
113
+ # Handle Range requests
114
+ range_header = request.headers.get("Range")
115
+ if range_header:
116
+ logger.debug(
117
+ f"Range request for {file_type} PDF {pk}: {range_header}"
118
+ )
119
+ match = _RANGE_RE.match(range_header)
120
+ if match:
121
+ start = int(match.group(1))
122
+ end = int(match.group(2) or file_size - 1)
123
+
124
+ # Validate range
125
+ if start >= file_size or start < 0:
126
+ logger.warning(
127
+ f"Invalid range start {start} for file size {file_size}"
128
+ )
129
+ raise Http404("Invalid range")
130
+
131
+ if end >= file_size:
132
+ end = file_size - 1
133
+
134
+ chunk_size = end - start + 1
135
+
136
+ try:
137
+ file_handle = open(file_path, "rb")
138
+ file_handle.seek(start)
139
+
140
+ logger.debug(
141
+ f"Serving {file_type} PDF {pk} range {start}-{end}/{file_size}"
142
+ )
143
+
144
+ response = StreamingHttpResponse(
145
+ ClosingFileWrapper(file_handle, blksize=8192),
146
+ status=206,
147
+ content_type="application/pdf",
148
+ )
149
+ response["Content-Length"] = str(chunk_size)
150
+ response["Content-Range"] = f"bytes {start}-{end}/{file_size}"
151
+ response["Accept-Ranges"] = "bytes"
152
+ response["Content-Disposition"] = (
153
+ f'inline; filename="{safe_filename}"'
154
+ )
155
+
156
+ return response
157
+ except (OSError, IOError) as e:
158
+ logger.error(
159
+ f"Error opening {file_type} PDF file for range request: {e}"
160
+ )
161
+ raise Http404(f"Error accessing {file_type} PDF file")
162
+ else:
163
+ logger.warning(f"Invalid Range header format: {range_header}")
164
+
165
+ # Serve entire file using FileResponse (automatically handles file closing)
166
+ logger.debug(f"Serving full {file_type} PDF {pk} ({file_size} bytes)")
167
+
168
+ try:
169
+ file_handle = open(file_path, "rb")
170
+ response = FileResponse(file_handle, content_type="application/pdf")
171
+ response["Content-Length"] = str(file_size)
172
+ response["Accept-Ranges"] = "bytes"
173
+ response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
174
+
175
+ # FileResponse will take ownership of file_handle and close it after response
176
+ return response
177
+ except (OSError, IOError) as e:
178
+ logger.error(f"Error opening {file_type} PDF file: {e}")
179
+ raise Http404(f"Error accessing {file_type} PDF file")
180
+
181
+ except Exception as e:
182
+ logger.error(
183
+ f"Unexpected error streaming {file_type if 'file_type' in locals() else 'PDF'} {pk}: {e}",
184
+ exc_info=True,
185
+ )
186
+ raise Http404("Error streaming PDF")
@@ -1,127 +0,0 @@
1
- import re
2
- import logging
3
- from django.http import FileResponse, StreamingHttpResponse, Http404
4
- from rest_framework.views import APIView
5
- from ...utils.permissions import EnvironmentAwarePermission
6
- from endoreg_db.models import RawPdfFile
7
- import os
8
- from django.views.decorators.clickjacking import xframe_options_sameorigin
9
-
10
- logger = logging.getLogger(__name__)
11
- _RANGE_RE = re.compile(r"bytes=(\d+)-(\d*)")
12
-
13
- class ClosingFileWrapper:
14
- """Custom file wrapper that ensures file is closed after streaming"""
15
- def __init__(self, file_handle, blksize=8192):
16
- self.file_handle = file_handle
17
- self.blksize = blksize
18
-
19
- def __iter__(self):
20
- return self
21
-
22
- def __next__(self):
23
- data = self.file_handle.read(self.blksize)
24
- if not data:
25
- self.file_handle.close()
26
- raise StopIteration
27
- return data
28
-
29
- def close(self):
30
- if hasattr(self.file_handle, 'close'):
31
- self.file_handle.close()
32
-
33
- class PDFStreamView(APIView):
34
- """
35
- Streams a PDF file with correct HTTP range support and proper file handle management.
36
- """
37
- permission_classes = [EnvironmentAwarePermission]
38
-
39
- @xframe_options_sameorigin
40
- def get(self, request, pdf_id: int, *args, **kwargs):
41
- try:
42
- pdf_obj = RawPdfFile.objects.filter(pk=pdf_id).first()
43
- if not pdf_obj or not pdf_obj.file:
44
- logger.warning(f"PDF not found: ID {pdf_id}")
45
- raise Http404("PDF not found")
46
-
47
- # Check if file exists on filesystem
48
- try:
49
- file_path = pdf_obj.file.path
50
- if not os.path.exists(file_path):
51
- logger.error(f"PDF file does not exist on filesystem: {file_path}")
52
- raise Http404("PDF file not found on filesystem")
53
-
54
- file_size = os.path.getsize(file_path)
55
- except (OSError, IOError, AttributeError) as e:
56
- logger.error(f"Error accessing PDF file {pdf_id}: {e}")
57
- raise Http404("PDF file not accessible")
58
-
59
- # Generate safe filename
60
- safe_filename = os.path.basename(pdf_obj.file.name) if pdf_obj.file.name else f"document_{pdf_id}.pdf"
61
- if not safe_filename.endswith('.pdf'):
62
- safe_filename += '.pdf'
63
-
64
- # Handle Range requests
65
- range_header = request.headers.get("Range")
66
- if range_header:
67
- logger.debug(f"Range request for PDF {pdf_id}: {range_header}")
68
- match = _RANGE_RE.match(range_header)
69
- if match:
70
- start = int(match.group(1))
71
- end = int(match.group(2) or file_size - 1)
72
-
73
- # Validate range
74
- if start >= file_size or start < 0:
75
- logger.warning(f"Invalid range start {start} for file size {file_size}")
76
- raise Http404("Invalid range")
77
-
78
- if end >= file_size:
79
- end = file_size - 1
80
-
81
- chunk_size = end - start + 1
82
-
83
- try:
84
- file_handle = open(file_path, "rb")
85
- file_handle.seek(start)
86
-
87
- logger.debug(f"Serving PDF {pdf_id} range {start}-{end}/{file_size}")
88
-
89
- response = StreamingHttpResponse(
90
- ClosingFileWrapper(file_handle, blksize=8192),
91
- status=206,
92
- content_type="application/pdf",
93
- )
94
- response["Content-Length"] = str(chunk_size)
95
- response["Content-Range"] = f"bytes {start}-{end}/{file_size}"
96
- response["Accept-Ranges"] = "bytes"
97
- response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
98
-
99
- return response
100
- except (OSError, IOError) as e:
101
- logger.error(f"Error opening PDF file for range request: {e}")
102
- raise Http404("Error accessing PDF file")
103
- else:
104
- logger.warning(f"Invalid Range header format: {range_header}")
105
-
106
- # Serve entire file using FileResponse (automatically handles file closing)
107
- logger.debug(f"Serving full PDF {pdf_id} ({file_size} bytes)")
108
-
109
- try:
110
- file_handle = open(file_path, "rb")
111
- response = FileResponse(
112
- file_handle,
113
- content_type="application/pdf"
114
- )
115
- response["Content-Length"] = str(file_size)
116
- response["Accept-Ranges"] = "bytes"
117
- response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
118
-
119
- # FileResponse will take ownership of file_handle and close it after response
120
- return response
121
- except (OSError, IOError) as e:
122
- logger.error(f"Error opening PDF file: {e}")
123
- raise Http404("Error accessing PDF file")
124
-
125
- except Exception as e:
126
- logger.error(f"Unexpected error streaming PDF {pdf_id}: {e}", exc_info=True)
127
- raise Http404("Error streaming PDF")