endoreg-db 0.8.6.1__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 (360) 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_center_data.py +12 -12
  117. endoreg_db/management/commands/load_requirement_data.py +60 -31
  118. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  119. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  120. endoreg_db/management/commands/storage_management.py +271 -203
  121. endoreg_db/migrations/0001_initial.py +1799 -1300
  122. endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
  123. endoreg_db/migrations/_old/0001_initial.py +1857 -0
  124. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
  125. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
  126. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
  127. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
  128. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
  129. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
  130. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
  131. endoreg_db/models/__init__.py +78 -123
  132. endoreg_db/models/administration/__init__.py +21 -42
  133. endoreg_db/models/administration/ai/active_model.py +2 -2
  134. endoreg_db/models/administration/ai/ai_model.py +7 -6
  135. endoreg_db/models/administration/case/__init__.py +1 -15
  136. endoreg_db/models/administration/case/case.py +3 -3
  137. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  138. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  139. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  140. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  141. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  142. endoreg_db/models/administration/center/center.py +33 -19
  143. endoreg_db/models/administration/center/center_product.py +12 -9
  144. endoreg_db/models/administration/center/center_resource.py +25 -19
  145. endoreg_db/models/administration/center/center_shift.py +21 -17
  146. endoreg_db/models/administration/center/center_waste.py +16 -8
  147. endoreg_db/models/administration/person/__init__.py +2 -0
  148. endoreg_db/models/administration/person/employee/employee.py +10 -5
  149. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  150. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  151. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  152. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  153. endoreg_db/models/administration/person/patient/patient.py +103 -100
  154. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  155. endoreg_db/models/administration/person/person.py +4 -0
  156. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  157. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  158. endoreg_db/models/administration/product/product.py +20 -15
  159. endoreg_db/models/administration/product/product_material.py +17 -18
  160. endoreg_db/models/administration/product/product_weight.py +12 -8
  161. endoreg_db/models/administration/product/reference_product.py +23 -55
  162. endoreg_db/models/administration/qualification/qualification.py +7 -3
  163. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  164. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  165. endoreg_db/models/administration/shift/shift.py +16 -12
  166. endoreg_db/models/administration/shift/shift_type.py +23 -31
  167. endoreg_db/models/label/__init__.py +7 -8
  168. endoreg_db/models/label/annotation/image_classification.py +10 -9
  169. endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
  170. endoreg_db/models/label/label.py +15 -15
  171. endoreg_db/models/label/label_set.py +19 -6
  172. endoreg_db/models/label/label_type.py +1 -1
  173. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  174. endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
  175. endoreg_db/models/label/video_segmentation_label.py +4 -0
  176. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  177. endoreg_db/models/media/frame/frame.py +22 -22
  178. endoreg_db/models/media/pdf/raw_pdf.py +110 -182
  179. endoreg_db/models/media/pdf/report_file.py +25 -29
  180. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
  181. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  182. endoreg_db/models/media/video/__init__.py +1 -0
  183. endoreg_db/models/media/video/create_from_file.py +48 -56
  184. endoreg_db/models/media/video/pipe_2.py +8 -9
  185. endoreg_db/models/media/video/video_file.py +150 -108
  186. endoreg_db/models/media/video/video_file_ai.py +288 -74
  187. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  188. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  189. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  190. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  191. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  192. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  193. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  194. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  195. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  196. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  197. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  198. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  199. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  200. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  201. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  202. endoreg_db/models/media/video/video_file_io.py +109 -62
  203. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  204. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  205. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  206. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  207. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  208. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  209. endoreg_db/models/media/video/video_file_segments.py +24 -17
  210. endoreg_db/models/media/video/video_metadata.py +19 -35
  211. endoreg_db/models/media/video/video_processing.py +96 -95
  212. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  213. endoreg_db/models/medical/disease.py +22 -16
  214. endoreg_db/models/medical/event.py +31 -18
  215. endoreg_db/models/medical/examination/__init__.py +13 -6
  216. endoreg_db/models/medical/examination/examination.py +17 -18
  217. endoreg_db/models/medical/examination/examination_indication.py +26 -25
  218. endoreg_db/models/medical/examination/examination_time.py +16 -6
  219. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  220. endoreg_db/models/medical/examination/examination_type.py +3 -4
  221. endoreg_db/models/medical/finding/finding.py +38 -39
  222. endoreg_db/models/medical/finding/finding_classification.py +37 -48
  223. endoreg_db/models/medical/finding/finding_intervention.py +27 -22
  224. endoreg_db/models/medical/finding/finding_type.py +13 -12
  225. endoreg_db/models/medical/hardware/endoscope.py +20 -26
  226. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  227. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  228. endoreg_db/models/medical/medication/medication.py +22 -10
  229. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  230. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  231. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  232. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  233. endoreg_db/models/medical/organ/__init__.py +15 -12
  234. endoreg_db/models/medical/patient/medication_examples.py +1 -5
  235. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  236. endoreg_db/models/medical/patient/patient_event.py +19 -22
  237. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  238. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  239. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  240. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  241. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  242. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  243. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  244. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  245. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  246. endoreg_db/models/medical/risk/risk.py +7 -6
  247. endoreg_db/models/medical/risk/risk_type.py +8 -5
  248. endoreg_db/models/metadata/model_meta.py +60 -29
  249. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  250. endoreg_db/models/metadata/pdf_meta.py +19 -24
  251. endoreg_db/models/metadata/sensitive_meta.py +102 -85
  252. endoreg_db/models/metadata/sensitive_meta_logic.py +192 -173
  253. endoreg_db/models/metadata/video_meta.py +51 -31
  254. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  255. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  256. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  257. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  258. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  259. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  260. endoreg_db/models/other/emission/emission_factor.py +18 -8
  261. endoreg_db/models/other/gender.py +10 -5
  262. endoreg_db/models/other/information_source.py +25 -25
  263. endoreg_db/models/other/material.py +9 -5
  264. endoreg_db/models/other/resource.py +6 -4
  265. endoreg_db/models/other/tag.py +10 -5
  266. endoreg_db/models/other/transport_route.py +13 -8
  267. endoreg_db/models/other/unit.py +10 -6
  268. endoreg_db/models/other/waste.py +6 -5
  269. endoreg_db/models/requirement/requirement.py +580 -272
  270. endoreg_db/models/requirement/requirement_error.py +85 -0
  271. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  272. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  273. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  274. endoreg_db/models/requirement/requirement_operator.py +36 -33
  275. endoreg_db/models/requirement/requirement_set.py +74 -57
  276. endoreg_db/models/state/__init__.py +4 -4
  277. endoreg_db/models/state/abstract.py +2 -2
  278. endoreg_db/models/state/anonymization.py +12 -0
  279. endoreg_db/models/state/audit_ledger.py +46 -47
  280. endoreg_db/models/state/label_video_segment.py +9 -0
  281. endoreg_db/models/state/raw_pdf.py +40 -46
  282. endoreg_db/models/state/sensitive_meta.py +6 -2
  283. endoreg_db/models/state/video.py +58 -53
  284. endoreg_db/models/upload_job.py +32 -55
  285. endoreg_db/models/utils.py +1 -2
  286. endoreg_db/root_urls.py +21 -2
  287. endoreg_db/serializers/__init__.py +0 -2
  288. endoreg_db/serializers/anonymization.py +18 -10
  289. endoreg_db/serializers/meta/report_meta.py +1 -1
  290. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  291. endoreg_db/serializers/misc/file_overview.py +11 -99
  292. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  293. endoreg_db/serializers/video/segmentation.py +2 -1
  294. endoreg_db/serializers/video/video_processing_history.py +20 -5
  295. endoreg_db/services/anonymization.py +75 -73
  296. endoreg_db/services/lookup_service.py +37 -24
  297. endoreg_db/services/pdf_import.py +166 -68
  298. endoreg_db/services/storage_aware_video_processor.py +140 -114
  299. endoreg_db/services/video_import.py +193 -283
  300. endoreg_db/urls/__init__.py +7 -20
  301. endoreg_db/urls/media.py +108 -67
  302. endoreg_db/urls/root_urls.py +29 -0
  303. endoreg_db/utils/__init__.py +15 -5
  304. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  305. endoreg_db/utils/case_generator/__init__.py +3 -0
  306. endoreg_db/utils/dataloader.py +88 -16
  307. endoreg_db/utils/defaults/set_default_center.py +32 -0
  308. endoreg_db/utils/names.py +22 -16
  309. endoreg_db/utils/permissions.py +2 -1
  310. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  311. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
  312. endoreg_db/utils/setup_config.py +8 -5
  313. endoreg_db/utils/storage.py +115 -0
  314. endoreg_db/utils/validate_endo_roi.py +8 -2
  315. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  316. endoreg_db/views/__init__.py +0 -10
  317. endoreg_db/views/anonymization/media_management.py +198 -163
  318. endoreg_db/views/anonymization/overview.py +4 -1
  319. endoreg_db/views/anonymization/validate.py +174 -40
  320. endoreg_db/views/media/__init__.py +2 -0
  321. endoreg_db/views/media/pdf_media.py +131 -152
  322. endoreg_db/views/media/sensitive_metadata.py +46 -6
  323. endoreg_db/views/media/video_media.py +89 -82
  324. endoreg_db/views/media/video_segments.py +2 -3
  325. endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
  326. endoreg_db/views/patient/patient.py +5 -4
  327. endoreg_db/views/pdf/pdf_stream.py +20 -21
  328. endoreg_db/views/pdf/reimport.py +11 -32
  329. endoreg_db/views/requirement/evaluate.py +188 -187
  330. endoreg_db/views/requirement/lookup.py +17 -3
  331. endoreg_db/views/requirement/requirement_utils.py +89 -0
  332. endoreg_db/views/video/__init__.py +0 -2
  333. endoreg_db/views/video/correction.py +2 -2
  334. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
  335. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +341 -245
  336. endoreg_db/models/administration/permissions/__init__.py +0 -44
  337. endoreg_db/models/media/video/video_file_frames.py +0 -0
  338. endoreg_db/models/metadata/frame_ocr_result.py +0 -0
  339. endoreg_db/models/rule/__init__.py +0 -13
  340. endoreg_db/models/rule/rule.py +0 -27
  341. endoreg_db/models/rule/rule_applicator.py +0 -224
  342. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  343. endoreg_db/models/rule/rule_type.py +0 -20
  344. endoreg_db/models/rule/ruleset.py +0 -17
  345. endoreg_db/serializers/video/video_metadata.py +0 -105
  346. endoreg_db/urls/report.py +0 -48
  347. endoreg_db/urls/video.py +0 -61
  348. endoreg_db/utils/case_generator/case_generator.py +0 -159
  349. endoreg_db/utils/case_generator/utils.py +0 -30
  350. endoreg_db/views/report/__init__.py +0 -9
  351. endoreg_db/views/report/report_list.py +0 -112
  352. endoreg_db/views/report/report_with_secure_url.py +0 -28
  353. endoreg_db/views/report/start_examination.py +0 -7
  354. endoreg_db/views.py +0 -0
  355. /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
  356. /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
  357. /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
  358. /endoreg_db/{models/media/video/refactor_plan.md → views/pdf/pdf_stream_views.py} +0 -0
  359. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
  360. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -8,16 +8,20 @@ This complements VideoStreamView which handles the actual video streaming.
8
8
  """
9
9
 
10
10
  import logging
11
+
12
+ from django.db.models import Q
11
13
  from django.http import Http404
12
14
  from rest_framework import status
13
15
  from rest_framework.response import Response
14
16
  from rest_framework.views import APIView
15
- from django.db.models import Q
16
17
 
17
18
  from endoreg_db.models import VideoFile
18
- from endoreg_db.serializers.video.video_file_list import VideoFileListSerializer
19
19
  from endoreg_db.serializers.video.video_file_detail import VideoDetailSerializer
20
+ from endoreg_db.serializers.video.video_file_list import VideoFileListSerializer
20
21
  from endoreg_db.utils.permissions import EnvironmentAwarePermission
22
+ #for keycloak
23
+ from rest_framework.permissions import IsAuthenticated
24
+ from endoreg_db.authz.permissions import PolicyPermission
21
25
 
22
26
  logger = logging.getLogger(__name__)
23
27
 
@@ -25,23 +29,23 @@ logger = logging.getLogger(__name__)
25
29
  class VideoMediaView(APIView):
26
30
  """
27
31
  Video Media Management API for CRUD operations on video files.
28
-
32
+
29
33
  Endpoints:
30
34
  - GET /api/media/videos/ - List all videos with filtering
31
35
  - GET /api/media/videos/{id}/ - Get video details
32
36
  - PATCH /api/media/videos/{id}/ - Update video metadata (future)
33
- - DELETE /api/media/videos/{id}/ - Delete video
34
-
37
+ - DELETE /api/media/videos/{id}/ - Delete video
38
+
35
39
  Query Parameters:
36
40
  - status: Filter by processing status (not_started, processing, done, failed, validated)
37
41
  - search: Search in filename
38
42
  - limit: Limit results (default: 50)
39
43
  - offset: Pagination offset
40
-
44
+
41
45
  Examples:
42
46
  - GET /api/media/videos/?status=done&search=exam
43
47
  - GET /api/media/videos/123/
44
-
48
+
45
49
  Phase 1.2 Implementation:
46
50
  - List and detail views implemented
47
51
  - Filtering and search functionality
@@ -49,19 +53,22 @@ class VideoMediaView(APIView):
49
53
  - Error handling with proper HTTP status codes
50
54
  - Integration with existing serializers
51
55
  """
52
- permission_classes = [EnvironmentAwarePermission]
56
+
57
+ #permission_classes = [EnvironmentAwarePermission]
58
+ #permission_classes = [EnvironmentAwarePermission]
59
+ permission_classes = [IsAuthenticated, PolicyPermission]
53
60
 
54
61
  def get(self, request, pk=None):
55
62
  """
56
63
  Handle GET requests for video listing or detail retrieval.
57
-
64
+
58
65
  Args:
59
66
  request: HTTP request object
60
67
  pk: Optional video ID for detail view
61
-
68
+
62
69
  Returns:
63
70
  Response: JSON response with video data or list
64
-
71
+
65
72
  Raises:
66
73
  Http404: If specific video not found
67
74
  """
@@ -75,13 +82,13 @@ class VideoMediaView(APIView):
75
82
  def _get_video_detail(self, pk):
76
83
  """
77
84
  Get detailed information for a specific video.
78
-
85
+
79
86
  Args:
80
87
  pk: Video primary key
81
-
88
+
82
89
  Returns:
83
90
  Response: JSON response with video details
84
-
91
+
85
92
  Raises:
86
93
  Http404: If video not found
87
94
  """
@@ -91,137 +98,137 @@ class VideoMediaView(APIView):
91
98
  video_id_int = int(pk)
92
99
  except (ValueError, TypeError):
93
100
  raise Http404("Invalid video ID format")
94
-
101
+
95
102
  # Fetch video with related data
96
- video = VideoFile.objects.select_related(
97
- 'state', 'sensitive_meta'
98
- ).get(pk=video_id_int)
99
-
103
+ video = VideoFile.objects.select_related("state", "sensitive_meta").get(
104
+ pk=video_id_int
105
+ )
106
+
100
107
  # Serialize with request context for URL generation
101
- serializer = VideoDetailSerializer(video, context={'request': self.request})
102
-
108
+ serializer = VideoDetailSerializer(video, context={"request": self.request})
109
+
103
110
  return Response(serializer.data)
104
-
111
+
105
112
  except VideoFile.DoesNotExist:
106
113
  raise Http404(f"Video with ID {pk} not found")
107
-
114
+
108
115
  except Exception as e:
109
116
  logger.error(f"Unexpected error in video detail view for ID {pk}: {str(e)}")
110
117
  return Response(
111
118
  {"error": "Failed to retrieve video details"},
112
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
119
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR,
113
120
  )
114
121
 
115
122
  def _list_videos(self, request):
116
123
  """
117
124
  List videos with filtering, search, and pagination.
118
-
125
+
119
126
  Args:
120
127
  request: HTTP request with query parameters
121
-
128
+
122
129
  Returns:
123
130
  Response: JSON response with paginated video list
124
131
  """
125
132
  try:
126
133
  # Start with all videos
127
- queryset = VideoFile.objects.select_related('state', 'sensitive_meta').all()
128
-
134
+ queryset = VideoFile.objects.select_related("state", "sensitive_meta").all()
135
+
129
136
  # Apply filters
130
137
  queryset = self._apply_filters(queryset, request.query_params)
131
-
138
+
132
139
  # Apply search
133
- search = request.query_params.get('search', '').strip()
140
+ search = request.query_params.get("search", "").strip()
134
141
  if search:
135
- queryset = queryset.filter(
136
- Q(original_file_name__icontains=search)
137
- )
138
-
142
+ queryset = queryset.filter(Q(original_file_name__icontains=search))
143
+
139
144
  # Order by upload date (newest first)
140
- queryset = queryset.order_by('-uploaded_at')
141
-
145
+ queryset = queryset.order_by("-uploaded_at")
146
+
142
147
  # Apply pagination
143
- limit = min(int(request.query_params.get('limit', 50)), 100)
144
- offset = int(request.query_params.get('offset', 0))
145
-
148
+ limit = min(int(request.query_params.get("limit", 50)), 100)
149
+ offset = int(request.query_params.get("offset", 0))
150
+
146
151
  total_count = queryset.count()
147
- videos = queryset[offset:offset + limit]
148
-
152
+ videos = queryset[offset : offset + limit]
153
+
149
154
  # Serialize
150
155
  serializer = VideoFileListSerializer(videos, many=True)
151
-
152
- return Response({
153
- "count": total_count,
154
- "next": self._get_next_url(request, offset, limit, total_count),
155
- "previous": self._get_previous_url(request, offset, limit),
156
- "results": serializer.data
157
- })
158
-
156
+
157
+ return Response(
158
+ {
159
+ "count": total_count,
160
+ "next": self._get_next_url(request, offset, limit, total_count),
161
+ "previous": self._get_previous_url(request, offset, limit),
162
+ "results": serializer.data,
163
+ }
164
+ )
165
+
159
166
  except ValueError as e:
160
167
  return Response(
161
168
  {"error": f"Invalid query parameter: {str(e)}"},
162
- status=status.HTTP_400_BAD_REQUEST
169
+ status=status.HTTP_400_BAD_REQUEST,
163
170
  )
164
-
171
+
165
172
  except Exception as e:
166
173
  logger.error(f"Unexpected error in video list view: {str(e)}")
167
174
  return Response(
168
175
  {"error": "Failed to retrieve video list"},
169
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
176
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR,
170
177
  )
171
178
 
172
179
  def _apply_filters(self, queryset, query_params):
173
180
  """
174
181
  Apply status and other filters to video queryset.
175
-
182
+
176
183
  Args:
177
184
  queryset: Base queryset to filter
178
185
  query_params: Request query parameters
179
-
186
+
180
187
  Returns:
181
188
  QuerySet: Filtered queryset
182
189
  """
183
- status_filter = query_params.get('status', '').strip().lower()
184
-
190
+ status_filter = query_params.get("status", "").strip().lower()
191
+
185
192
  if status_filter:
186
- if status_filter == 'not_started':
193
+ if status_filter == "not_started":
187
194
  # Videos without state or with not_started status
188
195
  queryset = queryset.filter(
189
- Q(state__isnull=True) |
190
- Q(state__frames_extracted=False, state__sensitive_meta_processed=False)
196
+ Q(state__isnull=True)
197
+ | Q(
198
+ state__frames_extracted=False,
199
+ state__sensitive_meta_processed=False,
200
+ )
191
201
  )
192
- elif status_filter == 'processing':
202
+ elif status_filter == "processing":
193
203
  # Videos in any processing state
194
204
  queryset = queryset.filter(
195
- state__frames_extracted=True,
196
- state__sensitive_meta_processed=False
205
+ state__frames_extracted=True, state__sensitive_meta_processed=False
197
206
  )
198
- elif status_filter == 'done':
207
+ elif status_filter == "done_processing_anonymization":
199
208
  # Videos with anonymization complete but not validated
200
209
  queryset = queryset.filter(
201
- state__anonymized=True,
202
- sensitive_meta__is_verified=False
210
+ state__anonymized=True, sensitive_meta__is_verified=False
203
211
  )
204
- elif status_filter == 'validated':
212
+ elif status_filter == "validated":
205
213
  # Videos with human validation complete
206
214
  queryset = queryset.filter(
207
- state__anonymized=True,
208
- sensitive_meta__is_verified=True
215
+ state__anonymized=True, sensitive_meta__is_verified=True
209
216
  )
210
- elif status_filter == 'failed':
217
+ elif status_filter == "failed":
211
218
  # Failed videos (this might need adjustment based on actual failure tracking)
212
219
  queryset = queryset.filter(
213
220
  state__isnull=False,
214
221
  state__frames_extracted=False,
215
- state__sensitive_meta_processed=False
222
+ state__sensitive_meta_processed=False,
216
223
  )
217
-
224
+
218
225
  return queryset
219
226
 
220
227
  def _get_next_url(self, request, offset, limit, total_count):
221
228
  """Generate next page URL for pagination."""
222
229
  if offset + limit >= total_count:
223
230
  return None
224
-
231
+
225
232
  next_offset = offset + limit
226
233
  return self._build_paginated_url(request, next_offset, limit)
227
234
 
@@ -229,16 +236,16 @@ class VideoMediaView(APIView):
229
236
  """Generate previous page URL for pagination."""
230
237
  if offset <= 0:
231
238
  return None
232
-
239
+
233
240
  prev_offset = max(0, offset - limit)
234
241
  return self._build_paginated_url(request, prev_offset, limit)
235
242
 
236
243
  def _build_paginated_url(self, request, offset, limit):
237
244
  """Build URL with pagination parameters."""
238
245
  params = request.query_params.copy()
239
- params['offset'] = offset
240
- params['limit'] = limit
241
-
246
+ params["offset"] = offset
247
+ params["limit"] = limit
248
+
242
249
  base_url = request.build_absolute_uri(request.path)
243
250
  if params:
244
251
  return f"{base_url}?{params.urlencode()}"
@@ -248,25 +255,25 @@ class VideoMediaView(APIView):
248
255
  def patch(self, request, pk):
249
256
  """
250
257
  Update video metadata (Phase 1.2+ future enhancement).
251
-
258
+
252
259
  Currently returns 501 Not Implemented.
253
260
  """
254
261
  return Response(
255
262
  {"error": "Video metadata updates not yet implemented"},
256
- status=status.HTTP_501_NOT_IMPLEMENTED
263
+ status=status.HTTP_501_NOT_IMPLEMENTED,
257
264
  )
258
265
 
259
266
  def delete(self, request, pk):
260
267
  """
261
268
  Delete video file (Phase 1.2+ future enhancement).
262
-
269
+
263
270
  Currently returns 501 Not Implemented.
264
271
  Use /api/media-management/force-remove/{id}/ instead.
265
272
  """
266
273
  return Response(
267
274
  {
268
- "error": "Video deletion not yet implemented",
269
- "alternative": f"Use DELETE /api/media-management/force-remove/{pk}/ instead"
275
+ "error": "Video deletion not yet implemented",
276
+ "alternative": f"Use DELETE /api/media-management/force-remove/{pk}/ instead",
270
277
  },
271
- status=status.HTTP_501_NOT_IMPLEMENTED
278
+ status=status.HTTP_501_NOT_IMPLEMENTED,
272
279
  )
@@ -288,8 +288,6 @@ def video_segment_validate(request, pk: int, segment_id: int):
288
288
  # Update state
289
289
  with transaction.atomic():
290
290
  segment.state.is_validated = is_validated
291
- if notes and hasattr(segment.state, "validation_notes"):
292
- segment.state.validation_notes = notes
293
291
  segment.state.save()
294
292
 
295
293
  logger.info(f"Validated segment {segment_id} in video {pk}: {is_validated}")
@@ -510,7 +508,8 @@ def video_segments_validation_status(request, pk: int):
510
508
  failed_count += 1
511
509
 
512
510
  logger.info(f"Completed validation for {updated_count} segments in video {pk}")
513
-
511
+ logger.info(f"Removing Outside Segments")
512
+ video_file.label_video_segments.filter(video_file=video, label="outside", state__is_validated=False).delete()
514
513
  return Response(
515
514
  {
516
515
  "message": f"Video segment validation completed for video {pk}",
@@ -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:
@@ -3,7 +3,7 @@ import os
3
3
  import re
4
4
 
5
5
  from django.http import FileResponse, Http404, StreamingHttpResponse
6
- from django.views.decorators.clickjacking import xframe_options_sameorigin
6
+ from django.views.decorators.clickjacking import xframe_options_exempt, xframe_options_sameorigin
7
7
  from rest_framework.views import APIView
8
8
 
9
9
  from endoreg_db.models import RawPdfFile
@@ -40,30 +40,29 @@ class PdfStreamView(APIView):
40
40
  """
41
41
  Streams a PDF file with correct HTTP range support and proper file handle management.
42
42
 
43
- Supports streaming both raw (original) and anonymized PDF files.
43
+ Supports streaming both raw (original) and processed PDF files.
44
44
 
45
45
  Query Parameters:
46
- type: 'raw' (default) or 'anonymized' - Selects which PDF file to stream
46
+ type: 'raw' (default) or 'processed' - Selects which PDF file to stream
47
47
 
48
48
  Examples:
49
49
  GET /api/media/pdf/1/?type=raw - Stream original raw PDF
50
- GET /api/media/pdf/1/?type=anonymized - Stream anonymized PDF
50
+ GET /api/media/pdf/1/?type=processed - Stream processed PDF
51
51
  """
52
52
 
53
53
  permission_classes = [EnvironmentAwarePermission]
54
-
55
- @xframe_options_sameorigin
56
- def get(self, request, pdf_id: int, *args, **kwargs):
54
+ @xframe_options_exempt
55
+ def get(self, request, pk: int, *args, **kwargs):
57
56
  file_type = "raw" # Initialize for error logging
58
57
  try:
59
- pdf_obj = RawPdfFile.objects.filter(pk=pdf_id).first()
58
+ pdf_obj = RawPdfFile.objects.filter(pk=pk).first()
60
59
  if not pdf_obj:
61
- logger.warning(f"PDF not found: ID {pdf_id}")
60
+ logger.warning(f"PDF not found: ID {pk}")
62
61
  raise Http404("PDF not found")
63
62
 
64
63
  # Parse query parameters to determine which file to stream
65
64
  file_type = request.query_params.get("type", "raw").lower()
66
- if file_type not in ["raw", "anonymized"]:
65
+ if file_type not in ["raw", "processed"]:
67
66
  logger.warning(f"Invalid file_type '{file_type}', defaulting to 'raw'")
68
67
  file_type = "raw"
69
68
 
@@ -71,15 +70,15 @@ class PdfStreamView(APIView):
71
70
  if file_type == "raw":
72
71
  file_field = pdf_obj.file
73
72
  if not file_field:
74
- logger.warning(f"No raw PDF file available for PDF ID {pdf_id}")
73
+ logger.warning(f"No raw PDF file available for PDF ID {pk}")
75
74
  raise Http404("Raw PDF file not available")
76
75
  else: # anonymized
77
76
  file_field = pdf_obj.anonymized_file
78
77
  if not file_field:
79
78
  logger.warning(
80
- f"No anonymized PDF file available for PDF ID {pdf_id}"
79
+ f"No processed PDF file available for PDF ID {pk}"
81
80
  )
82
- raise Http404("Anonymized PDF file not available")
81
+ raise Http404("Processed PDF file not available")
83
82
 
84
83
  # Check if file exists on filesystem
85
84
  try:
@@ -92,22 +91,22 @@ class PdfStreamView(APIView):
92
91
 
93
92
  file_size = os.path.getsize(file_path)
94
93
  except (OSError, IOError, AttributeError) as e:
95
- logger.error(f"Error accessing {file_type} PDF file {pdf_id}: {e}")
94
+ logger.error(f"Error accessing {file_type} PDF file {pk}: {e}")
96
95
  raise Http404(f"{file_type.capitalize()} PDF file not accessible")
97
96
 
98
97
  # Generate safe filename
99
98
  base_filename = (
100
99
  os.path.basename(file_field.name)
101
100
  if file_field.name
102
- else f"document_{pdf_id}.pdf"
101
+ else f"document_{pk}.pdf"
103
102
  )
104
103
  if not base_filename.endswith(".pdf"):
105
104
  base_filename += ".pdf"
106
105
 
107
106
  # Add type indicator to filename for clarity
108
- if file_type == "anonymized":
107
+ if file_type == "processed":
109
108
  name_parts = base_filename.rsplit(".", 1)
110
- safe_filename = f"{name_parts[0]}_anonymized.{name_parts[1]}"
109
+ safe_filename = f"{name_parts[0]}_processed.{name_parts[1]}"
111
110
  else:
112
111
  safe_filename = base_filename
113
112
 
@@ -115,7 +114,7 @@ class PdfStreamView(APIView):
115
114
  range_header = request.headers.get("Range")
116
115
  if range_header:
117
116
  logger.debug(
118
- f"Range request for {file_type} PDF {pdf_id}: {range_header}"
117
+ f"Range request for {file_type} PDF {pk}: {range_header}"
119
118
  )
120
119
  match = _RANGE_RE.match(range_header)
121
120
  if match:
@@ -139,7 +138,7 @@ class PdfStreamView(APIView):
139
138
  file_handle.seek(start)
140
139
 
141
140
  logger.debug(
142
- f"Serving {file_type} PDF {pdf_id} range {start}-{end}/{file_size}"
141
+ f"Serving {file_type} PDF {pk} range {start}-{end}/{file_size}"
143
142
  )
144
143
 
145
144
  response = StreamingHttpResponse(
@@ -164,7 +163,7 @@ class PdfStreamView(APIView):
164
163
  logger.warning(f"Invalid Range header format: {range_header}")
165
164
 
166
165
  # Serve entire file using FileResponse (automatically handles file closing)
167
- logger.debug(f"Serving full {file_type} PDF {pdf_id} ({file_size} bytes)")
166
+ logger.debug(f"Serving full {file_type} PDF {pk} ({file_size} bytes)")
168
167
 
169
168
  try:
170
169
  file_handle = open(file_path, "rb")
@@ -181,7 +180,7 @@ class PdfStreamView(APIView):
181
180
 
182
181
  except Exception as e:
183
182
  logger.error(
184
- f"Unexpected error streaming {file_type if 'file_type' in locals() else 'PDF'} {pdf_id}: {e}",
183
+ f"Unexpected error streaming {file_type if 'file_type' in locals() else 'PDF'} {pk}: {e}",
185
184
  exc_info=True,
186
185
  )
187
186
  raise Http404("Error streaming PDF")