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
@@ -53,13 +53,9 @@ class PdfReimportView(APIView):
53
53
  raw_file_path = pdf.get_raw_file_path()
54
54
 
55
55
  if not raw_file_path or not raw_file_path.exists():
56
- logger.error(
57
- f"Raw PDF file not found for hash {pdf.pdf_hash}: {raw_file_path}"
58
- )
56
+ logger.error(f"Raw PDF file not found for hash {pdf.pdf_hash}: {raw_file_path}")
59
57
  return Response(
60
- {
61
- "error": f"Raw PDF file not found for PDF {pdf.pdf_hash}. Please upload the original file again."
62
- },
58
+ {"error": f"Raw PDF file not found for PDF {pdf.pdf_hash}. Please upload the original file again."},
63
59
  status=status.HTTP_404_NOT_FOUND,
64
60
  )
65
61
 
@@ -79,10 +75,8 @@ class PdfReimportView(APIView):
79
75
  old_meta_id = None
80
76
  if pdf.sensitive_meta:
81
77
  old_meta_id = pdf.sensitive_meta.pk
82
- logger.info(
83
- f"Clearing existing SensitiveMeta {old_meta_id} for PDF {pdf.pdf_hash}"
84
- )
85
- pdf.sensitive_meta = None # type: ignore
78
+ logger.info(f"Clearing existing SensitiveMeta {old_meta_id} for PDF {pdf.pdf_hash}")
79
+ pdf.sensitive_meta = None
86
80
  pdf.save(update_fields=["sensitive_meta"])
87
81
 
88
82
  # Delete the old SensitiveMeta record
@@ -90,15 +84,11 @@ class PdfReimportView(APIView):
90
84
  SensitiveMeta.objects.filter(pk=old_meta_id).delete()
91
85
  logger.info(f"Deleted old SensitiveMeta {old_meta_id}")
92
86
  except Exception as e:
93
- logger.warning(
94
- f"Could not delete old SensitiveMeta {old_meta_id}: {e}"
95
- )
87
+ logger.warning(f"Could not delete old SensitiveMeta {old_meta_id}: {e}")
96
88
 
97
89
  # Use PdfImportService for reprocessing
98
90
  try:
99
- logger.info(
100
- f"Starting reprocessing using PdfImportService for {pdf.pdf_hash}"
101
- )
91
+ logger.info(f"Starting reprocessing using PdfImportService for {pdf.pdf_hash}")
102
92
  self.pdf_service.import_and_anonymize(
103
93
  file_path=raw_file_path,
104
94
  center_name=pdf.center.name,
@@ -106,9 +96,7 @@ class PdfReimportView(APIView):
106
96
  retry=True, # Mark as retry attempt
107
97
  )
108
98
 
109
- logger.info(
110
- f"PdfImportService reprocessing completed for {pdf.pdf_hash}"
111
- )
99
+ logger.info(f"PdfImportService reprocessing completed for {pdf.pdf_hash}")
112
100
 
113
101
  # Refresh to get updated state
114
102
  pdf.refresh_from_db()
@@ -119,9 +107,7 @@ class PdfReimportView(APIView):
119
107
  "pdf_id": pdf_id,
120
108
  "pdf_hash": str(pdf.pdf_hash),
121
109
  "sensitive_meta_created": pdf.sensitive_meta is not None,
122
- "sensitive_meta_id": pdf.sensitive_meta.pk
123
- if pdf.sensitive_meta
124
- else None,
110
+ "sensitive_meta_id": pdf.sensitive_meta.pk if pdf.sensitive_meta else None,
125
111
  "text_extracted": bool(pdf.text),
126
112
  "anonymized": pdf.anonymized,
127
113
  "status": "done",
@@ -130,9 +116,7 @@ class PdfReimportView(APIView):
130
116
  )
131
117
 
132
118
  except Exception as e:
133
- logger.exception(
134
- f"PdfImportService reprocessing failed for PDF {pdf.pdf_hash}: {e}"
135
- )
119
+ logger.exception(f"PdfImportService reprocessing failed for PDF {pdf.pdf_hash}: {e}")
136
120
  return Response(
137
121
  {
138
122
  "error": f"Reprocessing failed: {str(e)}",
@@ -144,16 +128,11 @@ class PdfReimportView(APIView):
144
128
  )
145
129
 
146
130
  except Exception as e:
147
- logger.error(
148
- f"Failed to re-import PDF {pdf.pdf_hash}: {str(e)}", exc_info=True
149
- )
131
+ logger.error(f"Failed to re-import PDF {pdf.pdf_hash}: {str(e)}", exc_info=True)
150
132
 
151
133
  # Handle specific error types
152
134
  error_msg = str(e)
153
- if any(
154
- phrase in error_msg.lower()
155
- for phrase in ["insufficient storage", "no space left", "disk full"]
156
- ):
135
+ if any(phrase in error_msg.lower() for phrase in ["insufficient storage", "no space left", "disk full"]):
157
136
  # Storage error - return specific error message
158
137
  return Response(
159
138
  {
@@ -1,52 +1,31 @@
1
1
  from endoreg_db.models.requirement.requirement import Requirement
2
+ from endoreg_db.views.requirement.requirement_utils import safe_evaluate_requirement
2
3
  from endoreg_db.models.requirement.requirement_set import RequirementSet
4
+ from endoreg_db.models.requirement.requirement_evaluation.evaluate_with_dependencies import (
5
+ evaluate_requirement_sets_with_dependencies,
6
+ RequirementStatus, # if you export it there, otherwise re-declare in view
7
+ )
3
8
  from endoreg_db.models.medical.patient.patient_examination import PatientExamination
4
-
5
-
6
9
  from rest_framework import status
7
10
  from rest_framework.decorators import api_view
8
11
  from rest_framework.response import Response
12
+ import json
9
13
  import logging
10
14
 
11
15
  logger = logging.getLogger(__name__)
12
- @api_view(['POST'])
16
+
17
+
18
+ @api_view(["POST"])
13
19
  def evaluate_requirements(request):
14
20
  """
15
- Evaluate requirements and always return 200 with structured results.
16
- Payload:
17
- {
18
- "requirement_set_ids": [<int>, ...], // optional; evaluates all if omitted
19
- "patient_examination_id": <int> // required
20
- }
21
-
22
- Response (HTTP 200 always):
23
- {
24
- "ok": <bool>, // false if any errors occurred
25
- "errors": [<str>, ...], // high-level problems (e.g. invalid input, missing PE)
26
- "meta": {
27
- "patientExaminationId": <int|null>,
28
- "setsEvaluated": <int>,
29
- "requirementsEvaluated": <int>,
30
- "status": "ok" | "partial" | "failed"
31
- },
32
- "results": [
33
- {
34
- "requirement_set_id": <int>,
35
- "requirement_set_name": <str>,
36
- "requirement_name": <str>,
37
- "met": <bool>,
38
- "details": <str>, // always a string for UI display
39
- "error": <str|null> // per-item error if evaluation failed
40
- }
41
- ]
42
- }
21
+ Evaluate requirements (all selected sets) and always return 200 with structured results.
43
22
  """
44
23
  payload = request.data or {}
45
24
  req_set_ids = payload.get("requirement_set_ids")
46
25
  pe_id = payload.get("patient_examination_id")
47
26
 
48
- results = []
49
- errors = []
27
+ results: list[dict] = []
28
+ errors: list[str] = []
50
29
  sets_evaluated = 0
51
30
  requirements_evaluated = 0
52
31
 
@@ -55,53 +34,63 @@ def evaluate_requirements(request):
55
34
  msg = "patient_examination_id is required"
56
35
  errors.append(msg)
57
36
  logger.warning("evaluate_requirements: %s; payload=%s", msg, payload)
58
- return Response({
59
- "ok": False,
60
- "errors": errors,
61
- "meta": {
62
- "patientExaminationId": None,
63
- "setsEvaluated": 0,
64
- "requirementsEvaluated": 0,
65
- "status": "failed",
37
+ return Response(
38
+ {
39
+ "ok": False,
40
+ "errors": errors,
41
+ "meta": {
42
+ "patientExaminationId": None,
43
+ "setsEvaluated": 0,
44
+ "requirementsEvaluated": 0,
45
+ "status": "failed",
46
+ },
47
+ "results": [],
66
48
  },
67
- "results": []
68
- }, status=status.HTTP_200_OK)
49
+ status=status.HTTP_200_OK,
50
+ )
69
51
 
70
52
  # ---- fetch PatientExamination
71
53
  try:
72
- pe = (PatientExamination.objects
73
- .select_related("patient")
74
- .get(id=pe_id))
54
+ pe = (
55
+ PatientExamination.objects.select_related("patient")
56
+ .get(id=pe_id)
57
+ )
75
58
  except PatientExamination.DoesNotExist:
76
59
  msg = f"PatientExamination with id {pe_id} does not exist"
77
60
  errors.append(msg)
78
61
  logger.warning("evaluate_requirements: %s", msg)
79
- return Response({
80
- "ok": False,
81
- "errors": errors,
82
- "meta": {
83
- "patientExaminationId": pe_id,
84
- "setsEvaluated": 0,
85
- "requirementsEvaluated": 0,
86
- "status": "failed",
62
+ return Response(
63
+ {
64
+ "ok": False,
65
+ "errors": errors,
66
+ "meta": {
67
+ "patientExaminationId": pe_id,
68
+ "setsEvaluated": 0,
69
+ "requirementsEvaluated": 0,
70
+ "status": "failed",
71
+ },
72
+ "results": [],
87
73
  },
88
- "results": []
89
- }, status=status.HTTP_200_OK)
74
+ status=status.HTTP_200_OK,
75
+ )
90
76
  except Exception as e:
91
77
  msg = f"Unexpected error retrieving PatientExamination {pe_id}: {e}"
92
78
  errors.append(msg)
93
79
  logger.exception("evaluate_requirements: %s", msg)
94
- return Response({
95
- "ok": False,
96
- "errors": errors,
97
- "meta": {
98
- "patientExaminationId": pe_id,
99
- "setsEvaluated": 0,
100
- "requirementsEvaluated": 0,
101
- "status": "failed",
80
+ return Response(
81
+ {
82
+ "ok": False,
83
+ "errors": errors,
84
+ "meta": {
85
+ "patientExaminationId": pe_id,
86
+ "setsEvaluated": 0,
87
+ "requirementsEvaluated": 0,
88
+ "status": "failed",
89
+ },
90
+ "results": [],
102
91
  },
103
- "results": []
104
- }, status=status.HTTP_200_OK)
92
+ status=status.HTTP_200_OK,
93
+ )
105
94
 
106
95
  # ---- determine requirement sets
107
96
  try:
@@ -120,75 +109,152 @@ def evaluate_requirements(request):
120
109
  msg = f"Error loading RequirementSets: {e}"
121
110
  errors.append(msg)
122
111
  logger.exception("evaluate_requirements: %s", msg)
123
- return Response({
124
- "ok": False,
112
+ return Response(
113
+ {
114
+ "ok": False,
115
+ "errors": errors,
116
+ "meta": {
117
+ "patientExaminationId": pe_id,
118
+ "setsEvaluated": 0,
119
+ "requirementsEvaluated": 0,
120
+ "status": "failed",
121
+ },
122
+ "results": [],
123
+ },
124
+ status=status.HTTP_200_OK,
125
+ )
126
+
127
+ # nothing to evaluate → still return 200
128
+ if not requirement_sets:
129
+ response_payload = {
130
+ "ok": len(errors) == 0,
125
131
  "errors": errors,
126
132
  "meta": {
127
133
  "patientExaminationId": pe_id,
128
134
  "setsEvaluated": 0,
129
135
  "requirementsEvaluated": 0,
130
- "status": "failed",
136
+ "status": "failed" if errors else "ok",
131
137
  },
132
- "results": []
133
- }, status=status.HTTP_200_OK)
138
+ "results": [],
139
+ }
140
+ return Response(response_payload, status=status.HTTP_200_OK)
141
+
142
+ # mapping from IDs to objects for later lookup
143
+ sets_by_id: dict[int, RequirementSet] = {s.id: s for s in requirement_sets}
144
+
145
+ # ---- main evaluation with set dependencies
146
+ try:
147
+ # returns: { set_id: { req_id: (status, details) } }
148
+ set_results = evaluate_requirement_sets_with_dependencies(
149
+ requirement_sets,
150
+ pe.patient,
151
+ mode="strict",
152
+ )
153
+
154
+ for set_id, req_dict in set_results.items():
155
+ req_set = sets_by_id.get(set_id)
156
+ set_name = getattr(
157
+ req_set, "name", str(set_id)
158
+ ) if req_set is not None else str(set_id)
134
159
 
135
- # ---- evaluate
136
- for req_set in requirement_sets:
137
- for req in req_set.requirements.all():
138
- # (optionally) reload Requirement to ensure fresh instance as in your original code
139
- try:
140
- requirement_obj = Requirement.objects.get(name=req.name)
141
- except Exception:
142
- # fall back to the prefetched instance
143
- requirement_obj = req
160
+ for req_id, (status_value, details) in req_dict.items():
161
+ try:
162
+ requirement_obj = Requirement.objects.get(id=req_id)
163
+ req_name = getattr(requirement_obj, "name", f"#{req_id}")
164
+ except Requirement.DoesNotExist:
165
+ requirement_obj = None
166
+ req_name = f"#{req_id}"
144
167
 
145
- try:
146
- met, details = requirement_obj.evaluate_with_details(pe.patient, mode="strict")
147
- # normalize details to a string for the frontend
168
+ # map RequirementStatus → met + error
169
+ if status_value == "PASSED":
170
+ met = True
171
+ error_str = None
172
+ elif status_value in ("FAILED", "BLOCKED"):
173
+ met = False
174
+ error_str = None
175
+ else: # "ERROR"
176
+ met = False
177
+ error_str = "Technischer Fehler bei der Auswertung"
178
+
179
+ # normalize details to string
148
180
  if isinstance(details, str):
149
181
  details_str = details
150
182
  else:
151
183
  try:
152
- details_str = json.dumps(details, ensure_ascii=False, default=str)
184
+ details_str = json.dumps(
185
+ details, ensure_ascii=False, default=str
186
+ )
153
187
  except Exception:
154
188
  details_str = str(details)
155
189
 
156
- results.append({
157
- "requirement_set_id": getattr(req_set, "id", None),
158
- "requirement_set_name": getattr(req_set, "name", str(getattr(req_set, "id", ""))),
159
- "requirement_name": getattr(requirement_obj, "name", "unknown"),
160
- "met": bool(met),
161
- "details": details_str if details_str else ("Voraussetzung erfüllt" if met else "Voraussetzung nicht erfüllt"),
162
- "error": None
163
- })
164
- except (TypeError, ValueError) as e:
165
- msg = f"Fehler bei der Bewertung der Voraussetzung: {e}"
166
- logger.warning("evaluate_requirements: requirement '%s' error: %s",
167
- getattr(requirement_obj, "name", "unknown"), e)
168
- results.append({
169
- "requirement_set_id": getattr(req_set, "id", None),
170
- "requirement_set_name": getattr(req_set, "name", str(getattr(req_set, "id", ""))),
171
- "requirement_name": getattr(requirement_obj, "name", "unknown"),
172
- "met": False,
173
- "details": msg,
174
- "error": f"{e.__class__.__name__}: {e}"
175
- })
176
- errors.append(msg)
177
- except Exception as e:
178
- msg = f"Unerwarteter Fehler bei der Bewertung: {e}"
179
- logger.exception("evaluate_requirements: requirement '%s' unexpected error",
180
- getattr(requirement_obj, "name", "unknown"))
181
- results.append({
182
- "requirement_set_id": getattr(req_set, "id", None),
183
- "requirement_set_name": getattr(req_set, "name", str(getattr(req_set, "id", ""))),
184
- "requirement_name": getattr(requirement_obj, "name", "unknown"),
185
- "met": False,
186
- "details": msg,
187
- "error": f"{e.__class__.__name__}: {e}"
188
- })
189
- errors.append(msg)
190
+ # default fallback text if details are empty
191
+ if not details_str:
192
+ details_str = (
193
+ "Voraussetzung erfüllt"
194
+ if met
195
+ else "Voraussetzung nicht erfüllt"
196
+ )
197
+
198
+ if status_value == "ERROR":
199
+ # add a high-level error for meta if there was an internal error
200
+ msg = (
201
+ f"Technischer Fehler bei der Auswertung von "
202
+ f"Voraussetzung '{req_name}' in Set '{set_name}'."
203
+ )
204
+ errors.append(msg)
205
+
206
+ results.append(
207
+ {
208
+ "requirement_set_id": set_id,
209
+ "requirement_set_name": set_name,
210
+ "requirement_name": req_name,
211
+ "met": bool(met),
212
+ "details": details_str,
213
+ "error": error_str,
214
+ "status": status_value,
215
+ }
216
+ )
217
+ requirements_evaluated += 1
218
+
219
+ except Exception as e:
220
+ # hard failure of the orchestrator → log and fall back to per-requirement evaluation
221
+ msg = f"Unerwarteter Fehler bei der gruppenbasierten Bewertung: {e}"
222
+ errors.append(msg)
223
+ logger.exception("evaluate_requirements: %s", msg)
224
+
225
+ for req_set in requirement_sets:
226
+ for req in req_set.requirements.all():
227
+ met, details, error = safe_evaluate_requirement(
228
+ req, pe.patient, mode="strict"
229
+ )
230
+ # normalize details to string
231
+ if not isinstance(details, str):
232
+ try:
233
+ details = json.dumps(details, ensure_ascii=False, default=str)
234
+ except Exception:
235
+ details = str(details)
236
+
237
+ if not details:
238
+ details = (
239
+ "Voraussetzung erfüllt"
240
+ if met
241
+ else "Voraussetzung nicht erfüllt"
242
+ )
190
243
 
191
- requirements_evaluated += 1
244
+ results.append(
245
+ {
246
+ "requirement_set_id": req_set.id,
247
+ "requirement_set_name": getattr(
248
+ req_set, "name", str(req_set.id)
249
+ ),
250
+ "requirement_name": getattr(req, "name", "unknown"),
251
+ "met": bool(met),
252
+ "details": details,
253
+ "error": error,
254
+ "status": "PASSED" if met else "FAILED",
255
+ }
256
+ )
257
+ requirements_evaluated += 1
192
258
 
193
259
  # ---- response meta & status summary
194
260
  any_errors = len(errors) > 0
@@ -201,79 +267,14 @@ def evaluate_requirements(request):
201
267
 
202
268
  response_payload = {
203
269
  "ok": not any_errors,
204
- "errors": errors, # frontend can render these in a toast / banner
270
+ "errors": errors,
205
271
  "meta": {
206
272
  "patientExaminationId": pe_id,
207
273
  "setsEvaluated": sets_evaluated,
208
274
  "requirementsEvaluated": requirements_evaluated,
209
- "status": status_label
275
+ "status": status_label,
210
276
  },
211
- "results": results
277
+ "results": results,
212
278
  }
213
279
 
214
280
  return Response(response_payload, status=status.HTTP_200_OK)
215
-
216
-
217
- def evaluate_requirement_set(request) -> Response:
218
- """
219
- Evaluate a specific RequirementSet based on provided RequirementLinks data.
220
-
221
- Expects a JSON payload with the following structure:
222
- {
223
- "requirement_set_ids": [<requirement_set_ids>],
224
- "patient_examination_id": <patient_examination_id>
225
- }
226
-
227
- Returns a JSON response with the evaluation results for the specified RequirementSet:
228
- {
229
- "results": [
230
- {
231
- "requirement_name": <requirement_name>,
232
- "met": <true/false>,
233
- "details": <additional_details>
234
- },
235
- ...
236
- ]
237
- }
238
- """
239
- try:
240
- data = request.data
241
- requirement_set_ids = data.get("requirement_set_ids", None)
242
- patient_examination_id = data.get("patient_examination_id")
243
-
244
- if not requirement_set_ids:
245
- return Response({"error": "requirement_set_ids is required"}, status=status.HTTP_400_BAD_REQUEST)
246
-
247
- if not patient_examination_id:
248
- return Response({"error": "patient_examination_id is required"}, status=status.HTTP_400_BAD_REQUEST)
249
-
250
- # Get the patient examination
251
- try:
252
- patient_examination = PatientExamination.objects.get(id=patient_examination_id)
253
- except PatientExamination.DoesNotExist:
254
- return Response({"error": f"PatientExamination with id {patient_examination_id} does not exist"}, status=status.HTTP_404_NOT_FOUND)
255
-
256
- results = []
257
-
258
- # Construct RequirementLinks from the provided data
259
- for requirement_set_id in requirement_set_ids:
260
- # Fetch the specified RequirementSet
261
- try:
262
- req_set = RequirementSet.objects.get(id=requirement_set_id)
263
- except RequirementSet.DoesNotExist:
264
- return Response({"error": f"RequirementSet with id {requirement_set_id} does not exist"}, status=status.HTTP_404_NOT_FOUND)
265
-
266
- for requirement in req_set.requirements.all():
267
- met, details = requirement.evaluate(patient_examination.patient, mode="strict")
268
- results.append({
269
- "requirement_name": requirement.name,
270
- "met": met,
271
- "details": details
272
- })
273
-
274
- return Response({
275
- "results": results
276
- }, status=status.HTTP_200_OK)
277
-
278
- except Exception as e:
279
- return Response({"results": str(e), details: "Fehler bei der Bewertung der Voraussetzung"}, status=status.HTTP_400_BAD_REQUEST)
@@ -13,6 +13,7 @@ from rest_framework.response import Response
13
13
  from endoreg_db.services import lookup_service as ls
14
14
  from endoreg_db.services.lookup_store import DEFAULT_TTL_SECONDS, LookupStore
15
15
  from endoreg_db.utils.permissions import EnvironmentAwarePermission
16
+ from endoreg_db.models.other.tag import Tag
16
17
 
17
18
  ORIGIN_MAP_PREFIX = "lookup:origin:"
18
19
  ISSUED_MAP_PREFIX = "lookup:issued_for_internal:"
@@ -53,6 +54,8 @@ class LookupViewSet(viewsets.ViewSet):
53
54
  "selectedRequirementSetIds",
54
55
  "selectedChoices",
55
56
  }
57
+
58
+ user_tags = Tag
56
59
 
57
60
  @action(detail=False, methods=["post"])
58
61
  def init(self, request):
@@ -131,7 +134,10 @@ class LookupViewSet(viewsets.ViewSet):
131
134
 
132
135
  except Exception:
133
136
  pass
134
-
137
+
138
+ user_tags = request.data.get("user_tags", None)
139
+ if user_tags and not isinstance(user_tags, list):
140
+ user_tags = [user_tags]
135
141
  # Fallback to query params
136
142
  if raw_pe is None:
137
143
  raw_pe = request.query_params.get("patient_examination_id")
@@ -167,7 +173,11 @@ class LookupViewSet(viewsets.ViewSet):
167
173
 
168
174
  try:
169
175
  # Create internal session via service (may seed its own token/cache)
170
- internal_token = ls.create_lookup_token_for_pe(pe_id)
176
+ service_kwargs = {}
177
+ if user_tags:
178
+ service_kwargs["user_tags"] = user_tags
179
+
180
+ internal_token = ls.create_lookup_token_for_pe(pe_id, **service_kwargs)
171
181
  internal_data = LookupStore(token=internal_token).get_all()
172
182
 
173
183
  issued_key = f"{ISSUED_MAP_PREFIX}{internal_token}"
@@ -254,7 +264,11 @@ class LookupViewSet(viewsets.ViewSet):
254
264
  status=status.HTTP_404_NOT_FOUND,
255
265
  )
256
266
 
257
- return Response(new_data, status=status.HTTP_200_OK)
267
+ # Hydrate the original token with recovered data and refresh origin TTL
268
+ store.set_many(new_data)
269
+ cache.set(f"{ORIGIN_MAP_PREFIX}{pk}", pe_id, DEFAULT_TTL_SECONDS)
270
+ return Response(store.get_all(), status=status.HTTP_200_OK)
271
+
258
272
 
259
273
  except Exception:
260
274
  pass