clinicedc 2.0.6__py3-none-any.whl → 2.0.8__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 clinicedc might be problematic. Click here for more details.
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/METADATA +2 -2
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/RECORD +489 -441
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/WHEEL +1 -1
- edc_action_item/action.py +1 -1
- edc_action_item/action_item_notification.py +2 -2
- edc_action_item/auths.py +37 -32
- edc_action_item/create_action_item.py +1 -1
- edc_action_item/decorators.py +1 -1
- edc_action_item/migrations/0001_initial.py +21 -22
- edc_action_item/migrations/0006_auto_20180707_1659.py +4 -4
- edc_action_item/migrations/0008_auto_20180809_0303.py +4 -4
- edc_action_item/migrations/0015_auto_20190114_0250.py +4 -4
- edc_action_item/migrations/0017_auto_20190305_0123.py +11 -30
- edc_action_item/migrations/0030_edcpermissions.py +3 -2
- edc_action_item/migrations/0039_alter_actionitem_auto_created_comment_and_more.py +398 -0
- edc_action_item/migrations/0040_alter_actionitem_report_datetime_and_more.py +34 -0
- edc_action_item/models/action_item.py +9 -4
- edc_action_item/models/action_model_mixin.py +5 -6
- edc_action_item/models/reference.py +2 -2
- edc_action_item/models/signals.py +22 -23
- edc_action_item/post_migrate_signals.py +1 -1
- edc_action_item/send_email.py +0 -85
- edc_action_item/site_action_items.py +5 -9
- edc_action_item/utils.py +3 -3
- edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
- edc_adherence/model_mixins.py +1 -1
- edc_adverse_event/auths.py +55 -51
- edc_adverse_event/migrations/0001_initial.py +5 -4
- edc_adverse_event/migrations/0002_auto_20190802_0059.py +3 -2
- edc_adverse_event/migrations/0008_auto_20220825_0451.py +3 -2
- edc_adverse_event/migrations/0009_auto_20220907_0157.py +3 -2
- edc_adverse_event/migrations/0016_alter_aeactionclassification_device_created_and_more.py +285 -0
- edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +6 -5
- edc_adverse_event/model_mixins/ae_special_interest/aesi_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_susar/ae_susar_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +15 -11
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
- edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +5 -4
- edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +6 -3
- edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +4 -3
- edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +3 -3
- edc_adverse_event/models/signals.py +7 -7
- edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -4
- edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +3 -5
- edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +6 -8
- edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -2
- edc_adverse_event/views/tmg/summary_listboard_view.py +3 -2
- edc_appointment/admin/appointment_admin.py +2 -2
- edc_appointment/admin/list_filters.py +2 -2
- edc_appointment/auths.py +14 -10
- edc_appointment/creators/appointment_creator.py +1 -1
- edc_appointment/creators/appointments_creator.py +1 -1
- edc_appointment/form_validators/appointment_form_validator.py +108 -82
- edc_appointment/migrations/0003_auto_20161127_2226.py +5 -6
- edc_appointment/migrations/0006_auto_20170106_2118.py +5 -5
- edc_appointment/migrations/0018_auto_20190305_0123.py +5 -12
- edc_appointment/migrations/0050_alter_appointment_appt_type_and_more.py +220 -0
- edc_appointment/model_mixins/appointment_fields_model_mixin.py +1 -2
- edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -3
- edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
- edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
- edc_appointment/models/appointment.py +1 -1
- edc_appointment/models/signals.py +44 -35
- edc_appointment/utils.py +19 -24
- edc_appointment/view_utils/appointment_button.py +2 -2
- edc_auth/admin/user_admin.py +1 -1
- edc_auth/auth_objects/__init__.py +2 -20
- edc_auth/auth_objects/default_groups.py +13 -11
- edc_auth/auth_objects/default_roles.py +26 -24
- edc_auth/auth_updater/auth_updater.py +13 -2
- edc_auth/auth_updater/group_updater.py +12 -10
- edc_auth/auth_updater/role_updater.py +2 -2
- edc_auth/constants.py +10 -0
- edc_auth/import_users.py +3 -3
- edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +5 -5
- edc_auth/migrations/0012_auto_20191026_0034.py +3 -2
- edc_auth/migrations/0013_auto_20191026_0055.py +3 -2
- edc_auth/migrations/0025_permissions.py +3 -2
- edc_auth/migrations/0035_alter_edcpermissions_device_created_and_more.py +85 -0
- edc_auth/models/user_profile.py +14 -11
- edc_auth/post_migrate_signals.py +1 -1
- edc_auth/site_auths.py +80 -67
- edc_consent/actions.py +4 -5
- edc_consent/auths.py +18 -12
- edc_consent/migrations/0001_initial.py +3 -2
- edc_consent/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_consent/model_mixins/consent_extension_model_mixin.py +4 -5
- edc_consent/model_mixins/requires_consent_fields_model_mixin.py +2 -2
- edc_consent/utils.py +1 -1
- edc_constants/constants.py +1 -0
- edc_crf/auths.py +5 -0
- edc_crf/migrations/0001_initial.py +3 -2
- edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
- edc_dashboard/auths.py +10 -6
- edc_dashboard/migrations/0001_initial.py +3 -2
- edc_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_dashboard/templatetags/edc_dashboard_extras.py +3 -2
- edc_dashboard/url_config.py +92 -83
- edc_dashboard/url_names.py +4 -4
- edc_dashboard/view_mixins/url_request_context_mixin.py +6 -5
- edc_data_manager/action_items.py +4 -6
- edc_data_manager/admin/actions.py +5 -5
- edc_data_manager/admin/data_query_admin.py +12 -11
- edc_data_manager/auths.py +37 -34
- edc_data_manager/handlers/handlers.py +6 -7
- edc_data_manager/migrations/0001_initial.py +19 -19
- edc_data_manager/migrations/0025_edcpermissions.py +3 -2
- edc_data_manager/migrations/0040_alter_datadictionary_device_created_and_more.py +327 -0
- edc_data_manager/migrations/0041_alter_dataquery_dm_user_and_more.py +164 -0
- edc_data_manager/models/data_query.py +5 -5
- edc_data_manager/models/model_mixins.py +8 -8
- edc_data_manager/rule/query_rule_wrapper.py +7 -7
- edc_data_manager/rule/rule_runner.py +4 -3
- edc_document_status/model_mixins.py +1 -1
- edc_egfr/egfr.py +11 -7
- edc_egfr/model_mixins/egfr_model_mixin.py +3 -7
- edc_export/admin/data_request_admin.py +2 -2
- edc_export/archive_exporter.py +7 -5
- edc_export/auths.py +32 -28
- edc_export/files_archiver.py +3 -2
- edc_export/migrations/0001_initial.py +26 -26
- edc_export/migrations/0004_auto_20190305_0123.py +25 -72
- edc_export/migrations/0013_edcpermissions.py +3 -2
- edc_export/migrations/0022_alter_datarequest_description_and_more.py +611 -0
- edc_export/migrations/0023_alter_datarequesthistory_archive_filename_and_more.py +29 -0
- edc_export/model_exporter/file_history_updater.py +10 -10
- edc_export/model_exporter/model_exporter.py +17 -15
- edc_export/model_exporter/object_history_helpers.py +2 -2
- edc_export/models/data_request_history.py +4 -4
- edc_export/utils.py +10 -15
- edc_facility/auths.py +8 -3
- edc_facility/facility.py +16 -22
- edc_facility/import_holidays.py +13 -13
- edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +8 -7
- edc_facility/migrations/0016_alter_healthfacility_device_created_and_more.py +139 -0
- edc_facility/migrations/0017_alter_healthfacility_gps_and_more.py +54 -0
- edc_facility/model_mixins.py +5 -5
- edc_form_label/custom_label_condition.py +11 -8
- edc_form_label/form_label.py +1 -1
- edc_form_runners/auths.py +11 -6
- edc_form_runners/form_runner.py +3 -5
- edc_form_runners/migrations/0001_initial.py +3 -2
- edc_form_runners/migrations/0005_alter_issue_device_created_and_more.py +49 -0
- edc_form_validators/applicable_field_validator.py +7 -6
- edc_form_validators/base_form_validator.py +8 -9
- edc_form_validators/other_specify_field_validator.py +2 -8
- edc_form_validators/required_field_validator.py +19 -16
- edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -3
- edc_identifier/migrations/0002_auto_20190305_0123.py +3 -6
- edc_identifier/migrations/0006_auto_20161127_2226.py +15 -15
- edc_identifier/migrations/0007_auto_20161204_2227.py +3 -3
- edc_identifier/migrations/0009_auto_20161221_2323.py +3 -5
- edc_identifier/migrations/0010_auto_20170112_0602.py +17 -17
- edc_identifier/migrations/0011_alter_identifiermodel_device_created_and_more.py +79 -0
- edc_identifier/model_mixins.py +1 -1
- edc_identifier/models.py +9 -9
- edc_identifier/research_identifier.py +11 -10
- edc_identifier/simple_identifier.py +9 -5
- edc_identifier/subject_identifier.py +3 -2
- edc_lab/auths.py +26 -23
- edc_lab/lab/aliquot_creator.py +5 -8
- edc_lab/lab/primary_aliquot.py +14 -5
- edc_lab/migrations/0001_initial.py +29 -29
- edc_lab/migrations/0008_auto_20170921_0719.py +3 -3
- edc_lab/migrations/0010_auto_20171127_1541.py +15 -15
- edc_lab/migrations/0012_auto_20180114_1438.py +3 -3
- edc_lab/migrations/0019_auto_20190305_0123.py +43 -127
- edc_lab/migrations/0036_alter_aliquot_comment_alter_aliquot_device_created_and_more.py +1139 -0
- edc_lab/migrations/0037_alter_historicalorder_order_datetime_and_more.py +31 -0
- edc_lab/model_mixins/aliquot/aliquot_identifier_model_mixin.py +2 -2
- edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +2 -2
- edc_lab/model_mixins/panel_model_mixin.py +18 -7
- edc_lab/model_mixins/requisition/crf_with_requisition_model_mixin.py +2 -4
- edc_lab/model_mixins/requisition/requisition_model_mixin.py +13 -16
- edc_lab/model_mixins/requisition/requisition_verify_model_mixin.py +1 -1
- edc_lab/model_mixins/result/result_item_model_mixin.py +4 -4
- edc_lab/model_mixins/shipping/manifest_model_mixin.py +4 -5
- edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -6
- edc_lab/models/aliquot.py +2 -2
- edc_lab/models/box.py +1 -1
- edc_lab/models/box_item.py +6 -7
- edc_lab/models/manifest/manifest.py +3 -3
- edc_lab/models/manifest/manifest_item.py +7 -7
- edc_lab/models/manifest/shipper.py +3 -4
- edc_lab/models/order.py +6 -4
- edc_lab/models/panel.py +4 -4
- edc_lab/models/result.py +2 -2
- edc_lab/models/result_item.py +2 -2
- edc_lab_dashboard/auths.py +16 -11
- edc_lab_dashboard/migrations/0001_initial.py +3 -2
- edc_lab_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_lab_dashboard/views/action_views/receive_view.py +2 -2
- edc_lab_dashboard/views/action_views/verify_box_item_view.py +2 -2
- edc_lab_results/calculate_missing.py +8 -8
- edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +2 -2
- edc_lab_results/get_summary.py +26 -25
- edc_lab_results/model_mixins/blood_result_model_mixin.py +9 -7
- edc_lab_results/model_mixins/fbg_model_mixin.py +3 -3
- edc_lab_results/model_mixins/glucose_model_mixin.py +3 -3
- edc_lab_results/model_mixins/hba1c_model_mixin.py +3 -3
- edc_label/auths.py +6 -1
- edc_label/label_template.py +8 -8
- edc_label/migrations/0001_initial.py +3 -2
- edc_label/migrations/0007_alter_zpllabeltemplates_device_created_and_more.py +49 -0
- edc_list_data/list_model_maker.py +2 -2
- edc_list_data/load_list_data.py +11 -14
- edc_list_data/load_model_data.py +3 -3
- edc_list_data/model_mixins.py +12 -4
- edc_list_data/post_migrate_signals.py +1 -1
- edc_list_data/preload_data.py +4 -4
- edc_list_data/row.py +1 -1
- edc_list_data/site_list_data.py +6 -5
- edc_listboard/migrations/0001_initial.py +3 -2
- edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
- edc_locator/auths.py +18 -13
- edc_locator/migrations/0001_initial.py +7 -7
- edc_locator/migrations/0018_auto_20190305_0123.py +5 -12
- edc_locator/migrations/0040_alter_historicalsubjectlocator_action_identifier_and_more.py +187 -0
- edc_locator/migrations/0041_alter_historicalsubjectlocator_report_datetime_and_more.py +27 -0
- edc_locator/model_mixins/locator_model_mixin.py +2 -2
- edc_locator/model_mixins/subject_contact_fields_mixin.py +1 -1
- edc_locator/modeladmin_mixins.py +5 -4
- edc_ltfu/model_mixins.py +7 -5
- edc_metadata/auths.py +11 -7
- edc_metadata/metadata/metadata.py +1 -1
- edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
- edc_metadata/metadata_rules/decorators.py +1 -1
- edc_metadata/metadata_rules/metadata_rule_evaluator.py +5 -3
- edc_metadata/metadata_rules/rule.py +2 -3
- edc_metadata/metadata_rules/rule_evaluator.py +1 -1
- edc_metadata/migrations/0002_auto_20161127_2226.py +5 -5
- edc_metadata/migrations/0005_auto_20170112_0602.py +5 -5
- edc_metadata/migrations/0011_auto_20190305_0123.py +5 -12
- edc_metadata/migrations/0031_alter_crfmetadata_device_created_and_more.py +120 -0
- edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +7 -4
- edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +5 -2
- edc_metadata/models/crf_metadata.py +5 -5
- edc_metadata/models/crf_metadata_model_mixin.py +4 -5
- edc_metadata/models/requisition_metadata.py +6 -6
- edc_metadata/models/signals.py +10 -11
- edc_metadata/views/refresh_metadata_actions_view.py +3 -3
- edc_model/models/address_mixin.py +6 -6
- edc_model/models/fields/initials_field.py +2 -1
- edc_model/models/historical_records.py +2 -9
- edc_model/models/url_model_mixin.py +2 -2
- edc_model/validators/date.py +7 -8
- edc_model_admin/list_filters/future_date_list_filter.py +3 -3
- edc_model_admin/list_filters/past_date_list_filter.py +3 -3
- edc_model_admin/mixins/model_admin_protect_pii_mixin.py +4 -5
- edc_model_fields/fields/other_charfield.py +2 -2
- edc_navbar/auths.py +18 -13
- edc_navbar/migrations/0004_auto_20220825_0451.py +3 -2
- edc_navbar/migrations/0009_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_notification/auths.py +9 -4
- edc_notification/migrations/0001_initial.py +3 -3
- edc_notification/migrations/0004_auto_20190305_0123.py +3 -6
- edc_notification/migrations/0011_alter_notification_device_created_and_more.py +59 -0
- edc_notification/models/notification.py +1 -1
- edc_notification/notification/graded_event_notification.py +2 -2
- edc_notification/notification/model_notification.py +3 -30
- edc_notification/notification/new_model_notification.py +1 -1
- edc_notification/notification/notification.py +12 -12
- edc_notification/notification/updated_model_notification.py +2 -2
- edc_offstudy/auths.py +12 -7
- edc_offstudy/migrations/0001_initial.py +4 -4
- edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -4
- edc_offstudy/migrations/0005_auto_20190305_0123.py +5 -12
- edc_offstudy/migrations/0023_alter_historicalsubjectoffstudy_action_identifier_and_more.py +188 -0
- edc_offstudy/migrations/0024_alter_historicalsubjectoffstudy_offstudy_datetime_and_more.py +43 -0
- edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -2
- edc_pdutils/df_exporters/csv_exporter.py +33 -37
- edc_pdutils/df_exporters/csv_model_exporter.py +7 -3
- edc_pdutils/migrations/0001_initial.py +8 -8
- edc_pharmacy/admin/prescription/rx_refill_admin.py +4 -3
- edc_pharmacy/admin/reports/stock_availability_admin.py +5 -6
- edc_pharmacy/auths.py +19 -15
- edc_pharmacy/migrations/0001_initial.py +64 -63
- edc_pharmacy/migrations/0015_auto_20220913_2139.py +26 -26
- edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +81 -86
- edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +5 -5
- edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -8
- edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +12 -12
- edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +5 -5
- edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +3 -4
- edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +3 -3
- edc_pharmacy/migrations/0057_scanduplicates.py +3 -3
- edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +13 -15
- edc_pharmacy/migrations/0068_stockout.py +2 -3
- edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -5
- edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +3 -4
- edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -8
- edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +0 -2
- edc_pharmacy/migrations/0089_alter_allocation_allocated_by_and_more.py +3284 -0
- edc_pharmacy/migrations/0090_alter_allocation_allocation_datetime_and_more.py +227 -0
- edc_pharmacy/model_mixins/study_medication_refill_model_mixin.py +2 -2
- edc_pharmacy/models/medication/formulation.py +5 -7
- edc_pharmacy/models/medication/medication.py +3 -3
- edc_pharmacy/models/model_mixins.py +10 -11
- edc_pharmacy/models/prescription/rx.py +13 -12
- edc_pharmacy/models/prescription/rx_refill.py +0 -1
- edc_pharmacy/models/stock/allocation.py +3 -3
- edc_pharmacy/models/stock/confirmation.py +3 -3
- edc_pharmacy/models/stock/confirmation_at_site.py +3 -2
- edc_pharmacy/models/stock/confirmation_at_site_item.py +3 -4
- edc_pharmacy/models/stock/dispense.py +5 -6
- edc_pharmacy/models/stock/dispense_item.py +2 -2
- edc_pharmacy/models/stock/location.py +3 -4
- edc_pharmacy/models/stock/lot.py +6 -7
- edc_pharmacy/models/stock/order.py +1 -1
- edc_pharmacy/models/stock/receive.py +3 -3
- edc_pharmacy/models/stock/receive_item.py +4 -4
- edc_pharmacy/models/stock/repack_request.py +2 -2
- edc_pharmacy/models/stock/stock.py +12 -18
- edc_pharmacy/models/stock/stock_adjustment.py +4 -4
- edc_pharmacy/models/stock/stock_request.py +2 -2
- edc_pharmacy/models/stock/stock_request_item.py +2 -2
- edc_pharmacy/models/stock/stock_transfer.py +3 -3
- edc_pharmacy/models/stock/stock_transfer_item.py +2 -2
- edc_pharmacy/models/stock/storage_bin.py +3 -4
- edc_pharmacy/models/stock/storage_bin_item.py +2 -2
- edc_pharmacy/models/stock/supplier.py +3 -4
- edc_pharmacy/models/storage/box.py +2 -2
- edc_pharmacy/models/storage/items/container_model_mixin.py +3 -4
- edc_pharmacy/models/storage/items/pill_bottle_model_mixin.py +2 -2
- edc_pharmacy/models/storage/items/subject_pill_bottle.py +1 -1
- edc_pharmacy/models/storage/room.py +2 -2
- edc_pharmacy/models/storage/shelf.py +2 -2
- edc_pharmacy/models/storage/utils.py +1 -1
- edc_pharmacy/prescribe/create_prescription.py +3 -3
- edc_pharmacy/utils/allocate_stock.py +2 -3
- edc_pharmacy/utils/confirm_stock.py +3 -4
- edc_pharmacy/utils/confirm_stock_at_site.py +4 -5
- edc_pharmacy/utils/dispense.py +3 -4
- edc_pharmacy/utils/process_repack_request.py +4 -5
- edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
- edc_pharmacy/utils/transfer_stock.py +2 -3
- edc_pharmacy/views/add_to_storage_bin_view.py +2 -2
- edc_pharmacy/views/allocate_to_subject_view.py +2 -2
- edc_pharmacy/views/confirmation_at_site_view.py +6 -9
- edc_pharmacy/views/dispense_view.py +2 -2
- edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
- edc_pharmacy/views/print_labels_view.py +2 -2
- edc_prn/admin_site.py +5 -0
- edc_prn/prn.py +10 -11
- edc_prn/urls.py +11 -0
- edc_protocol/research_protocol_config.py +2 -3
- edc_protocol_incident/action_items.py +4 -4
- edc_protocol_incident/auths.py +27 -20
- edc_protocol_incident/migrations/0001_initial.py +7 -7
- edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +13 -13
- edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +7 -7
- edc_protocol_incident/migrations/0024_alter_actionsrequired_extra_value_and_more.py +625 -0
- edc_protocol_incident/migrations/0025_alter_historicalprotocoldeviationviolation_report_datetime_and_more.py +42 -0
- edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +18 -11
- edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +26 -11
- edc_pylabels/actions.py +3 -5
- edc_pylabels/auths.py +6 -1
- edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +3 -7
- edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +3 -3
- edc_pylabels/migrations/0013_alter_labelconfiguration_device_created_and_more.py +49 -0
- edc_qareports/auths.py +11 -7
- edc_qareports/migrations/0001_initial.py +4 -5
- edc_qareports/migrations/0005_edcpermissions.py +3 -3
- edc_qareports/migrations/0006_qareportlog.py +2 -3
- edc_qareports/migrations/0019_alter_edcpermissions_device_created_and_more.py +102 -0
- edc_qareports/migrations/0020_alter_note_report_datetime_and_more.py +24 -0
- edc_qareports/model_mixins/note_model_mixin.py +7 -4
- edc_qareports/model_mixins/on_study_missing_values_model_mixin.py +4 -4
- edc_qareports/model_mixins/qa_report_model_mixin.py +2 -3
- edc_qareports/models/note.py +4 -4
- edc_qareports/models/qa_reports_log.py +2 -3
- edc_randomization/admin.py +30 -24
- edc_randomization/auths.py +12 -7
- edc_randomization/decorators.py +1 -1
- edc_randomization/migrations/0001_initial.py +3 -2
- edc_randomization/migrations/0002_historicalrandomizationlist.py +3 -2
- edc_randomization/migrations/0009_edcpermissions.py +3 -2
- edc_randomization/migrations/0014_alter_edcpermissions_device_created_and_more.py +141 -0
- edc_randomization/model_mixins.py +9 -9
- edc_randomization/randomizer.py +22 -20
- edc_randomization/utils.py +19 -18
- edc_refusal/auths.py +7 -2
- edc_refusal/migrations/0001_initial.py +4 -4
- edc_refusal/migrations/0002_historicalsubjectrefusal.py +4 -4
- edc_refusal/migrations/0012_alter_historicalsubjectrefusal_comment_and_more.py +122 -0
- edc_refusal/migrations/0013_alter_historicalsubjectrefusal_report_datetime_and_more.py +28 -0
- edc_refusal/model_mixins.py +4 -4
- edc_registration/auths.py +28 -23
- edc_registration/migrations/0002_auto_20161127_2226.py +3 -4
- edc_registration/migrations/0005_auto_20170111_1809.py +4 -2
- edc_registration/migrations/0016_historicalregisteredsubject.py +3 -2
- edc_registration/migrations/0017_auto_20190305_0123.py +5 -12
- edc_registration/migrations/0033_alter_historicalregisteredsubject_additional_key_and_more.py +302 -0
- edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +15 -7
- edc_registration/models/registered_subject.py +28 -27
- edc_reportable/age_evaluator.py +4 -2
- edc_reportable/formula.py +5 -5
- edc_reportable/migrations/0001_initial.py +7 -7
- edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -3
- edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +5 -5
- edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +5 -6
- edc_reportable/migrations/0007_alter_gradingdata_age_phrase_and_more.py +509 -0
- edc_reportable/models/normal_data.py +4 -5
- edc_reportable/models/reference_model_mixins.py +10 -11
- edc_reportable/models/reference_range_collection.py +12 -13
- edc_reportable/post_migrate_signals.py +1 -1
- edc_reportable/utils/convert_units.py +11 -45
- edc_reportable/utils/get_normal_data_or_raise.py +2 -2
- edc_reportable/utils/get_reference_range_collection.py +2 -3
- edc_reportable/utils/load_data.py +4 -4
- edc_reportable/utils/update_grading_data.py +5 -5
- edc_review_dashboard/auths.py +23 -18
- edc_review_dashboard/migrations/0001_initial.py +3 -2
- edc_review_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_screening/age_evaluator.py +6 -6
- edc_screening/auths.py +35 -30
- edc_screening/eligibility.py +1 -1
- edc_screening/gender_evaluator.py +1 -1
- edc_screening/migrations/0001_initial.py +3 -2
- edc_screening/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_screening/model_mixins/eligibility_model_mixin.py +3 -6
- edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
- edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
- edc_screening/screening_eligibility.py +2 -4
- edc_screening/utils.py +9 -9
- edc_search/generate_slug.py +26 -0
- edc_search/model_mixins.py +10 -22
- edc_sites/auths.py +8 -3
- edc_sites/migrations/0007_edcpermissions.py +3 -2
- edc_sites/migrations/0010_alter_edcpermissions_device_created_and_more.py +69 -0
- edc_sites/model_mixins/site_model_mixin.py +2 -2
- edc_sites/site.py +5 -5
- edc_sites/system_checks.py +1 -1
- edc_subject_dashboard/auths.py +27 -22
- edc_subject_dashboard/migrations/0001_initial.py +3 -2
- edc_subject_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_subject_dashboard/requisition_report.py +6 -4
- edc_subject_dashboard/requisition_verifier.py +6 -6
- edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -2
- edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +7 -8
- edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +3 -2
- edc_subject_dashboard/view_utils/timepoint_status_button.py +2 -2
- edc_timepoint/apps.py +0 -21
- edc_timepoint/model_mixins.py +22 -20
- edc_transfer/model_mixins.py +4 -4
- edc_transfer/modeladmin_mixins.py +1 -1
- edc_unblinding/auths.py +9 -4
- edc_unblinding/migrations/0001_initial.py +13 -13
- edc_unblinding/migrations/0014_alter_historicalunblindingrequest_action_identifier_and_more.py +291 -0
- edc_unblinding/migrations/0015_alter_historicalunblindingrequest_report_datetime_and_more.py +45 -0
- edc_unblinding/models/unblinding_request.py +2 -2
- edc_unblinding/models/unblinding_review.py +3 -3
- edc_utils/__init__.py +3 -1
- edc_utils/age.py +10 -16
- edc_utils/show_urls.py +29 -2
- edc_visit_schedule/auths.py +6 -1
- edc_visit_schedule/migrations/0001_initial.py +3 -3
- edc_visit_schedule/migrations/0002_auto_20190305_0123.py +3 -6
- edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +5 -4
- edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +10 -10
- edc_visit_schedule/migrations/0019_alter_historicalonschedule_device_created_and_more.py +229 -0
- edc_visit_schedule/migrations/0020_alter_historicalonschedule_onschedule_datetime_and_more.py +65 -0
- edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +5 -4
- edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +5 -4
- edc_visit_schedule/model_mixins/visit_schedule/visit_code_fields_model_mixin.py +1 -1
- edc_visit_schedule/models/subject_schedule_history.py +6 -6
- edc_visit_schedule/schedule/visit_collection.py +1 -1
- edc_visit_schedule/site_visit_schedules.py +2 -2
- edc_visit_schedule/subject_schedule.py +5 -4
- edc_visit_schedule/view_mixins.py +2 -3
- edc_visit_schedule/visit/visit.py +3 -2
- edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +13 -13
- edc_visit_tracking/migrations/0009_alter_historicalsubjectvisit_comments_and_more.py +450 -0
- edc_visit_tracking/migrations/0010_alter_historicalsubjectvisit_report_datetime_and_more.py +68 -0
- edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -3
- edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/visit_model_mixin/caretaker_fields_mixin.py +2 -3
- edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +1 -1
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +8 -11
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +1 -1
- edc_visit_tracking/models/signals.py +3 -3
- edc_visit_tracking/models/subject_visit.py +1 -1
- edc_vitals/calculators/bmi.py +7 -5
- edc_vitals/utils.py +1 -1
- edc_form_label/models.py +0 -0
- edc_search/constants.py +0 -1
- edc_search/models.py +0 -0
- edc_search/search_slug.py +0 -50
- edc_search/updater.py +0 -30
- edc_search/wsgi.py +0 -7
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/licenses/LICENSE +0 -0
edc_appointment/utils.py
CHANGED
|
@@ -80,7 +80,7 @@ class AppointmentDateWindowPeriodGapError(Exception):
|
|
|
80
80
|
pass
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
class AppointmentAlreadyStarted(Exception):
|
|
83
|
+
class AppointmentAlreadyStarted(Exception): # noqa: N818
|
|
84
84
|
pass
|
|
85
85
|
|
|
86
86
|
|
|
@@ -157,10 +157,9 @@ def raise_on_appt_may_not_be_missed(
|
|
|
157
157
|
|
|
158
158
|
|
|
159
159
|
def get_appointment_form_meta_options() -> dict:
|
|
160
|
-
|
|
160
|
+
return getattr(
|
|
161
161
|
settings, "EDC_APPOINTMENT_FORM_META_OPTIONS", dict(labels={}, help_texts={})
|
|
162
162
|
)
|
|
163
|
-
return options
|
|
164
163
|
|
|
165
164
|
|
|
166
165
|
def get_appt_reason_choices() -> tuple[str, ...]:
|
|
@@ -516,11 +515,11 @@ def raise_on_appt_datetime_not_in_window(
|
|
|
516
515
|
except ScheduledVisitWindowError as e:
|
|
517
516
|
msg = str(e)
|
|
518
517
|
msg.replace("Invalid datetime", "Invalid appointment datetime (S)")
|
|
519
|
-
raise AppointmentWindowError(msg)
|
|
518
|
+
raise AppointmentWindowError(msg) from e
|
|
520
519
|
except UnScheduledVisitWindowError as e:
|
|
521
520
|
msg = str(e)
|
|
522
521
|
msg.replace("Invalid datetime", "Invalid appointment datetime (U)")
|
|
523
|
-
raise AppointmentWindowError(msg)
|
|
522
|
+
raise AppointmentWindowError(msg) from e
|
|
524
523
|
|
|
525
524
|
|
|
526
525
|
def get_window_gap_days(appointment) -> int:
|
|
@@ -623,7 +622,7 @@ def get_appointment_by_datetime(
|
|
|
623
622
|
raise_on_appt_datetime_not_in_window(
|
|
624
623
|
appointment, appt_datetime=suggested_appt_datetime
|
|
625
624
|
)
|
|
626
|
-
except AppointmentWindowError:
|
|
625
|
+
except AppointmentWindowError as e:
|
|
627
626
|
in_gap = appt_datetime_in_gap(appointment, suggested_appt_datetime)
|
|
628
627
|
in_next_window_adjusted = appt_datetime_in_next_window_adjusted_for_gap(
|
|
629
628
|
appointment, suggested_appt_datetime
|
|
@@ -635,7 +634,7 @@ def get_appointment_by_datetime(
|
|
|
635
634
|
raise AppointmentDateWindowPeriodGapError(
|
|
636
635
|
f"Date falls in a `window period gap` between {appointment.visit_code} "
|
|
637
636
|
f"and {appointment.next.visit_code}. Got {dt}."
|
|
638
|
-
)
|
|
637
|
+
) from e
|
|
639
638
|
if (
|
|
640
639
|
in_gap
|
|
641
640
|
and in_next_window_adjusted
|
|
@@ -674,7 +673,7 @@ def reset_appointment(appointment: Appointment, **kwargs):
|
|
|
674
673
|
appt_status=appointment._meta.get_field("appt_status").default,
|
|
675
674
|
appt_timing=appointment._meta.get_field("appt_timing").default,
|
|
676
675
|
appt_type=None,
|
|
677
|
-
appt_type_other=
|
|
676
|
+
appt_type_other="",
|
|
678
677
|
appt_datetime=appointment.timepoint_datetime,
|
|
679
678
|
comment="",
|
|
680
679
|
)
|
|
@@ -705,7 +704,7 @@ def skip_appointment(appointment: Appointment, comment: str | None = None):
|
|
|
705
704
|
appt_status=SKIPPED_APPT,
|
|
706
705
|
appt_timing=NOT_APPLICABLE,
|
|
707
706
|
appt_type=NOT_APPLICABLE,
|
|
708
|
-
comment=comment,
|
|
707
|
+
comment=comment or "",
|
|
709
708
|
)
|
|
710
709
|
|
|
711
710
|
|
|
@@ -722,11 +721,6 @@ def get_unscheduled_appointment_url(appointment: Appointment = None) -> str:
|
|
|
722
721
|
visit_code_sequence=appointment.visit_code_sequence + 1,
|
|
723
722
|
timepoint=appointment.timepoint,
|
|
724
723
|
)
|
|
725
|
-
# if appointment := (
|
|
726
|
-
# appointment.__class__.objects.filter(visit_code_sequence__gt=0, **kwargs)
|
|
727
|
-
# .order_by("visit_code_sequence")
|
|
728
|
-
# .last()
|
|
729
|
-
# ):
|
|
730
724
|
kwargs.update(visit_code_sequence=str(appointment.visit_code_sequence + 1))
|
|
731
725
|
kwargs.update(redirect_url=dashboard_url)
|
|
732
726
|
return reverse(unscheduled_appointment_url_name, kwargs=kwargs)
|
|
@@ -741,19 +735,18 @@ def update_appt_status_for_timepoint(related_visit: RelatedVisitModel) -> None:
|
|
|
741
735
|
):
|
|
742
736
|
related_visit.appointment.appt_status = INCOMPLETE_APPT
|
|
743
737
|
related_visit.appointment.save_base(update_fields=["appt_status"])
|
|
744
|
-
elif related_visit.appointment.appt_status == INCOMPLETE_APPT
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
related_visit.appointment.save_base(update_fields=["appt_status"])
|
|
738
|
+
elif related_visit.appointment.appt_status == INCOMPLETE_APPT and (
|
|
739
|
+
not related_visit.metadata[CRF].filter(entry_status=REQUIRED).exists()
|
|
740
|
+
and not related_visit.metadata[REQUISITION].filter(entry_status=REQUIRED).exists()
|
|
741
|
+
):
|
|
742
|
+
related_visit.appointment.appt_status = COMPLETE_APPT
|
|
743
|
+
related_visit.appointment.save_base(update_fields=["appt_status"])
|
|
751
744
|
|
|
752
745
|
|
|
753
746
|
def refresh_appointments(
|
|
754
|
-
subject_identifier: str = None,
|
|
755
|
-
visit_schedule_name: str = None,
|
|
756
|
-
schedule_name: str = None,
|
|
747
|
+
subject_identifier: str | None = None,
|
|
748
|
+
visit_schedule_name: str | None = None,
|
|
749
|
+
schedule_name: str | None = None,
|
|
757
750
|
request: WSGIRequest | None = None,
|
|
758
751
|
warn_only: bool | None = None,
|
|
759
752
|
) -> tuple[str, str]:
|
|
@@ -839,6 +832,8 @@ def validate_date_is_on_clinic_day(
|
|
|
839
832
|
and calendar.weekday(appt_date.year, appt_date.month, appt_date.day)
|
|
840
833
|
not in clinic_days
|
|
841
834
|
):
|
|
835
|
+
|
|
836
|
+
days_str = [day_abbr[d] for d in clinic_days]
|
|
842
837
|
days_str = []
|
|
843
838
|
for d in clinic_days:
|
|
844
839
|
days_str.append(day_abbr[d])
|
|
@@ -5,9 +5,9 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
from uuid import UUID
|
|
6
6
|
|
|
7
7
|
from django.apps import apps as django_apps
|
|
8
|
+
from django.utils import timezone
|
|
8
9
|
from django.utils.translation import gettext as _
|
|
9
10
|
|
|
10
|
-
from edc_utils import get_utcnow
|
|
11
11
|
from edc_view_utils.dashboard_model_button import DashboardModelButton
|
|
12
12
|
from edc_view_utils.model_button import ADD
|
|
13
13
|
|
|
@@ -51,7 +51,7 @@ class AppointmentButton(DashboardModelButton):
|
|
|
51
51
|
color = super().color
|
|
52
52
|
if (
|
|
53
53
|
self.model_obj
|
|
54
|
-
and self.model_obj.appt_datetime <=
|
|
54
|
+
and self.model_obj.appt_datetime <= timezone.now()
|
|
55
55
|
and not self.model_obj.related_visit
|
|
56
56
|
):
|
|
57
57
|
color = self.colors[ADD]
|
edc_auth/admin/user_admin.py
CHANGED
|
@@ -15,7 +15,7 @@ from .user_profile_admin import UserProfileInline
|
|
|
15
15
|
admin.site.unregister(User)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def send_new_credentials_to_user_action(modeladmin, request, queryset):
|
|
18
|
+
def send_new_credentials_to_user_action(modeladmin, request, queryset):
|
|
19
19
|
if request.user.has_perm("auth.change_user"):
|
|
20
20
|
for obj in queryset:
|
|
21
21
|
send_new_credentials_to_user(user=obj)
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
from ..constants import (
|
|
2
|
-
ACCOUNT_MANAGER,
|
|
3
|
-
ACCOUNT_MANAGER_ROLE,
|
|
4
|
-
ADMINISTRATION,
|
|
5
|
-
AUDITOR,
|
|
6
|
-
AUDITOR_ROLE,
|
|
7
|
-
CELERY_MANAGER,
|
|
8
|
-
CLINIC,
|
|
9
|
-
CLINIC_SUPER,
|
|
10
|
-
CLINICIAN_ROLE,
|
|
11
|
-
CLINICIAN_SUPER_ROLE,
|
|
12
|
-
CUSTOM_ROLE,
|
|
13
|
-
EVERYONE,
|
|
14
|
-
NURSE_ROLE,
|
|
15
|
-
PII,
|
|
16
|
-
PII_VIEW,
|
|
17
|
-
STAFF_ROLE,
|
|
18
|
-
)
|
|
19
1
|
from .codenames import (
|
|
20
2
|
account_manager,
|
|
21
3
|
administration,
|
|
@@ -25,6 +7,6 @@ from .codenames import (
|
|
|
25
7
|
clinic_super,
|
|
26
8
|
everyone,
|
|
27
9
|
)
|
|
28
|
-
from .default_groups import
|
|
10
|
+
from .default_groups import get_default_groups
|
|
29
11
|
from .default_pii_models import default_pii_models
|
|
30
|
-
from .default_roles import
|
|
12
|
+
from .default_roles import get_default_roles
|
|
@@ -11,14 +11,16 @@ from ..constants import (
|
|
|
11
11
|
)
|
|
12
12
|
from .codenames import account_manager, administration, celery_manager, everyone
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
|
|
15
|
+
def get_default_groups():
|
|
16
|
+
return {
|
|
17
|
+
ACCOUNT_MANAGER: account_manager,
|
|
18
|
+
ADMINISTRATION: administration,
|
|
19
|
+
AUDITOR: [],
|
|
20
|
+
CELERY_MANAGER: celery_manager,
|
|
21
|
+
CLINIC: [],
|
|
22
|
+
CLINIC_SUPER: [],
|
|
23
|
+
EVERYONE: everyone,
|
|
24
|
+
PII: [],
|
|
25
|
+
PII_VIEW: [],
|
|
26
|
+
}
|
|
@@ -17,27 +17,29 @@ from ..constants import (
|
|
|
17
17
|
STATISTICIAN,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
20
|
+
|
|
21
|
+
def get_default_roles() -> dict[str, list[str]]:
|
|
22
|
+
"""Format {ROLE_NAME: [GROUP_NAME, GROUP_NAME, ...]"""
|
|
23
|
+
return {
|
|
24
|
+
ACCOUNT_MANAGER_ROLE: [ACCOUNT_MANAGER],
|
|
25
|
+
AUDITOR_ROLE: [
|
|
26
|
+
AUDITOR,
|
|
27
|
+
PII_VIEW,
|
|
28
|
+
],
|
|
29
|
+
CLINICIAN_ROLE: [
|
|
30
|
+
CLINIC,
|
|
31
|
+
PII,
|
|
32
|
+
],
|
|
33
|
+
CLINICIAN_SUPER_ROLE: [
|
|
34
|
+
CLINIC_SUPER,
|
|
35
|
+
CLINIC,
|
|
36
|
+
PII,
|
|
37
|
+
],
|
|
38
|
+
CUSTOM_ROLE: [],
|
|
39
|
+
NURSE_ROLE: [
|
|
40
|
+
CLINIC,
|
|
41
|
+
PII,
|
|
42
|
+
],
|
|
43
|
+
STAFF_ROLE: [ADMINISTRATION, EVERYONE],
|
|
44
|
+
STATISTICIAN: [AUDITOR],
|
|
45
|
+
}
|
|
@@ -9,6 +9,7 @@ from django.contrib.auth import get_user_model
|
|
|
9
9
|
from django.core.exceptions import ObjectDoesNotExist
|
|
10
10
|
from django.core.management.color import color_style
|
|
11
11
|
|
|
12
|
+
from ..constants import POST_UPDATE_FUNCS_KEY, PRE_UPDATE_FUNCS_KEY
|
|
12
13
|
from ..site_auths import site_auths
|
|
13
14
|
from .group_updater import GroupUpdater
|
|
14
15
|
from .role_updater import RoleUpdater
|
|
@@ -17,6 +18,14 @@ style = color_style()
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class AuthUpdater:
|
|
21
|
+
"""A class to update auth.Group, edc_auth.Role, auth.Permissions
|
|
22
|
+
models using the site_auth registry.
|
|
23
|
+
|
|
24
|
+
Called once on application startup. For example::
|
|
25
|
+
|
|
26
|
+
AuthUpdater(verbose=False, warn_only=True)
|
|
27
|
+
"""
|
|
28
|
+
|
|
20
29
|
group_updater_cls = GroupUpdater
|
|
21
30
|
role_updater_cls = RoleUpdater
|
|
22
31
|
|
|
@@ -38,8 +47,10 @@ class AuthUpdater:
|
|
|
38
47
|
)
|
|
39
48
|
groups = groups or site_auths.groups
|
|
40
49
|
pii_models = pii_models or site_auths.pii_models
|
|
41
|
-
post_update_funcs = post_update_funcs or site_auths.post_update_funcs
|
|
42
|
-
|
|
50
|
+
post_update_funcs = post_update_funcs or [f for f in site_auths.post_update_funcs]
|
|
51
|
+
site_auths.registry[POST_UPDATE_FUNCS_KEY] = []
|
|
52
|
+
pre_update_funcs = pre_update_funcs or [f for f in site_auths.pre_update_funcs]
|
|
53
|
+
site_auths.registry[PRE_UPDATE_FUNCS_KEY] = []
|
|
43
54
|
roles = roles or site_auths.roles
|
|
44
55
|
self.apps = apps
|
|
45
56
|
if not self.edc_auth_skip_auth_updater:
|
|
@@ -11,7 +11,7 @@ from django.core.exceptions import (
|
|
|
11
11
|
)
|
|
12
12
|
from django.core.management.color import color_style
|
|
13
13
|
|
|
14
|
-
from ..
|
|
14
|
+
from ..constants import PII, PII_VIEW
|
|
15
15
|
from ..utils import make_view_only_group_permissions
|
|
16
16
|
|
|
17
17
|
style = color_style()
|
|
@@ -27,7 +27,7 @@ class PermissionsCreatorError(ValidationError):
|
|
|
27
27
|
pass
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
class CodenameDoesNotExist(Exception):
|
|
30
|
+
class CodenameDoesNotExist(Exception): # noqa: N818
|
|
31
31
|
pass
|
|
32
32
|
|
|
33
33
|
|
|
@@ -87,7 +87,7 @@ class GroupUpdater:
|
|
|
87
87
|
group = self.group_model_cls.objects.get(name=group_name)
|
|
88
88
|
except ObjectDoesNotExist as e:
|
|
89
89
|
if not create_group:
|
|
90
|
-
raise ObjectDoesNotExist(f"{e} Got {group_name}")
|
|
90
|
+
raise ObjectDoesNotExist(f"{e} Got {group_name}") from e
|
|
91
91
|
group = self.group_model_cls.objects.create(name=group_name)
|
|
92
92
|
else:
|
|
93
93
|
group.permissions.clear()
|
|
@@ -122,7 +122,7 @@ class GroupUpdater:
|
|
|
122
122
|
try:
|
|
123
123
|
app_label, codename = self.get_from_dotted_codename(dotted_codename)
|
|
124
124
|
except PermissionsCodenameError as e:
|
|
125
|
-
warn(str(e))
|
|
125
|
+
warn(str(e), stacklevel=2)
|
|
126
126
|
else:
|
|
127
127
|
# if you add extra codenames you must also add custom
|
|
128
128
|
# codename tuples to the Permissions model before you
|
|
@@ -138,7 +138,7 @@ class GroupUpdater:
|
|
|
138
138
|
except ObjectDoesNotExist as e:
|
|
139
139
|
errmsg = f"{e} Got codename={codename},app_label={app_label}"
|
|
140
140
|
if not self.warn_only:
|
|
141
|
-
raise CodenameDoesNotExist(errmsg)
|
|
141
|
+
raise CodenameDoesNotExist(errmsg) from e
|
|
142
142
|
warn(style.ERROR(errmsg))
|
|
143
143
|
except MultipleObjectsReturned as e:
|
|
144
144
|
if not allow_multiple_objects:
|
|
@@ -166,15 +166,17 @@ class GroupUpdater:
|
|
|
166
166
|
try:
|
|
167
167
|
app_label, _codename = codename.split(".")
|
|
168
168
|
except ValueError as e:
|
|
169
|
-
raise PermissionsCodenameError(
|
|
169
|
+
raise PermissionsCodenameError(
|
|
170
|
+
f"Invalid dotted codename. {e} Got {codename}."
|
|
171
|
+
) from e
|
|
170
172
|
else:
|
|
171
173
|
try:
|
|
172
174
|
self.apps.get_app_config(app_label)
|
|
173
|
-
except LookupError:
|
|
175
|
+
except LookupError as e:
|
|
174
176
|
raise PermissionsCodenameError(
|
|
175
177
|
"Invalid app_label in codename. Expected format "
|
|
176
178
|
f"'<app_label>.<some_codename>'. Got {codename}."
|
|
177
|
-
)
|
|
179
|
+
) from e
|
|
178
180
|
prefix = _codename.split("_")[0]
|
|
179
181
|
if prefix not in self.codename_prefixes:
|
|
180
182
|
raise PermissionsCodenameError(
|
|
@@ -244,7 +246,7 @@ class GroupUpdater:
|
|
|
244
246
|
except ObjectDoesNotExist as e:
|
|
245
247
|
raise CodenameDoesNotExist(
|
|
246
248
|
f"Unable to verify codename. {e} Got '{app_label}.{codename}'"
|
|
247
|
-
)
|
|
249
|
+
) from e
|
|
248
250
|
except MultipleObjectsReturned as e:
|
|
249
251
|
self.delete_and_raise_on_duplicate_codenames(codename, app_label, exception=e)
|
|
250
252
|
return permission
|
|
@@ -267,7 +269,7 @@ class GroupUpdater:
|
|
|
267
269
|
try:
|
|
268
270
|
value, name = codename_tpl
|
|
269
271
|
except ValueError as e:
|
|
270
|
-
raise ValueError(f"{e} Got {codename_tpl}")
|
|
272
|
+
raise ValueError(f"{e} Got {codename_tpl}") from e
|
|
271
273
|
_app_label, codename = value.split(".")
|
|
272
274
|
if app_label and _app_label != app_label:
|
|
273
275
|
raise PermissionsCreatorError(
|
|
@@ -56,11 +56,11 @@ class RoleUpdater:
|
|
|
56
56
|
for group_name in groups:
|
|
57
57
|
try:
|
|
58
58
|
group = self.group_model_cls.objects.get(name=group_name)
|
|
59
|
-
except ObjectDoesNotExist:
|
|
59
|
+
except ObjectDoesNotExist as e:
|
|
60
60
|
raise RoleUpdaterError(
|
|
61
61
|
"Invalid group specified for role. "
|
|
62
62
|
f"`{group_name}` is not a group. See role `{role}`."
|
|
63
|
-
)
|
|
63
|
+
) from e
|
|
64
64
|
# group = self.group_model_cls.objects.create(name=group_name)
|
|
65
65
|
role.groups.add(group)
|
|
66
66
|
index += 1
|
edc_auth/constants.py
CHANGED
|
@@ -19,3 +19,13 @@ CUSTOM_ROLE = "custom"
|
|
|
19
19
|
NURSE_ROLE = "research_nurse"
|
|
20
20
|
STAFF_ROLE = "staff"
|
|
21
21
|
STATISTICIAN = "statistician"
|
|
22
|
+
|
|
23
|
+
# keys for the site_auths registry
|
|
24
|
+
UPDATE_ROLES_KEY = "update_roles"
|
|
25
|
+
UPDATE_GROUPS_KEY = "update_groups"
|
|
26
|
+
PRE_UPDATE_FUNCS_KEY = "pre_update_funcs"
|
|
27
|
+
POST_UPDATE_FUNCS_KEY = "post_update_funcs"
|
|
28
|
+
GROUPS_KEY = "groups"
|
|
29
|
+
ROLES_KEY = "roles"
|
|
30
|
+
PII_MODELS_KEY = "pii_models"
|
|
31
|
+
CUSTOM_PERMISSIONS_TUPLES_KEY = "custom_permissions_tuples"
|
edc_auth/import_users.py
CHANGED
|
@@ -183,9 +183,9 @@ class UserImporter:
|
|
|
183
183
|
self.update_user_sites(site_names or [])
|
|
184
184
|
self.update_user_roles(role_names or [STAFF_ROLE])
|
|
185
185
|
self.user.save()
|
|
186
|
-
self.user.userprofile.job_title = self.job_title
|
|
187
|
-
self.user.userprofile.mobile = self.mobile
|
|
188
|
-
self.user.userprofile.alternate_email = self.alternate_email
|
|
186
|
+
self.user.userprofile.job_title = self.job_title or ""
|
|
187
|
+
self.user.userprofile.mobile = self.mobile or ""
|
|
188
|
+
self.user.userprofile.alternate_email = self.alternate_email or ""
|
|
189
189
|
self.user.userprofile.save()
|
|
190
190
|
|
|
191
191
|
self.site_names = (
|
|
@@ -10,10 +10,10 @@ import django_audit_fields.models.audit_model_mixin
|
|
|
10
10
|
import django_revision.revision_field
|
|
11
11
|
from django.conf import settings
|
|
12
12
|
from django.db import migrations, models
|
|
13
|
+
import django.utils.timezone
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class Migration(migrations.Migration):
|
|
16
|
-
|
|
17
17
|
replaces = [
|
|
18
18
|
("edc_auth", "0001_initial"),
|
|
19
19
|
("edc_auth", "0002_auto_20180803_0515"),
|
|
@@ -78,14 +78,14 @@ class Migration(migrations.Migration):
|
|
|
78
78
|
"created",
|
|
79
79
|
models.DateTimeField(
|
|
80
80
|
blank=True,
|
|
81
|
-
default=
|
|
81
|
+
default=django.utils.timezone.now,
|
|
82
82
|
),
|
|
83
83
|
),
|
|
84
84
|
(
|
|
85
85
|
"modified",
|
|
86
86
|
models.DateTimeField(
|
|
87
87
|
blank=True,
|
|
88
|
-
default=
|
|
88
|
+
default=django.utils.timezone.now,
|
|
89
89
|
),
|
|
90
90
|
),
|
|
91
91
|
(
|
|
@@ -402,14 +402,14 @@ class Migration(migrations.Migration):
|
|
|
402
402
|
"created",
|
|
403
403
|
models.DateTimeField(
|
|
404
404
|
blank=True,
|
|
405
|
-
default=
|
|
405
|
+
default=django.utils.timezone.now,
|
|
406
406
|
),
|
|
407
407
|
),
|
|
408
408
|
(
|
|
409
409
|
"modified",
|
|
410
410
|
models.DateTimeField(
|
|
411
411
|
blank=True,
|
|
412
|
-
default=
|
|
412
|
+
default=django.utils.timezone.now,
|
|
413
413
|
),
|
|
414
414
|
),
|
|
415
415
|
(
|
|
@@ -7,6 +7,7 @@ import django_audit_fields.fields.uuid_auto_field
|
|
|
7
7
|
import django_audit_fields.models.audit_model_mixin
|
|
8
8
|
import django_revision.revision_field
|
|
9
9
|
from django.db import migrations, models
|
|
10
|
+
import django.utils.timezone
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class Migration(migrations.Migration):
|
|
@@ -31,14 +32,14 @@ class Migration(migrations.Migration):
|
|
|
31
32
|
"created",
|
|
32
33
|
models.DateTimeField(
|
|
33
34
|
blank=True,
|
|
34
|
-
default=
|
|
35
|
+
default=django.utils.timezone.now,
|
|
35
36
|
),
|
|
36
37
|
),
|
|
37
38
|
(
|
|
38
39
|
"modified",
|
|
39
40
|
models.DateTimeField(
|
|
40
41
|
blank=True,
|
|
41
|
-
default=
|
|
42
|
+
default=django.utils.timezone.now,
|
|
42
43
|
),
|
|
43
44
|
),
|
|
44
45
|
(
|
|
@@ -7,6 +7,7 @@ import django_audit_fields.fields.uuid_auto_field
|
|
|
7
7
|
import django_audit_fields.models.audit_model_mixin
|
|
8
8
|
import django_revision.revision_field
|
|
9
9
|
from django.db import migrations, models
|
|
10
|
+
import django.utils.timezone
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class Migration(migrations.Migration):
|
|
@@ -34,14 +35,14 @@ class Migration(migrations.Migration):
|
|
|
34
35
|
"created",
|
|
35
36
|
models.DateTimeField(
|
|
36
37
|
blank=True,
|
|
37
|
-
default=
|
|
38
|
+
default=django.utils.timezone.now,
|
|
38
39
|
),
|
|
39
40
|
),
|
|
40
41
|
(
|
|
41
42
|
"modified",
|
|
42
43
|
models.DateTimeField(
|
|
43
44
|
blank=True,
|
|
44
|
-
default=
|
|
45
|
+
default=django.utils.timezone.now,
|
|
45
46
|
),
|
|
46
47
|
),
|
|
47
48
|
(
|
|
@@ -7,6 +7,7 @@ import django_audit_fields.fields.uuid_auto_field
|
|
|
7
7
|
import django_audit_fields.models.audit_model_mixin
|
|
8
8
|
import django_revision.revision_field
|
|
9
9
|
from django.db import migrations, models
|
|
10
|
+
import django.utils.timezone
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class Migration(migrations.Migration):
|
|
@@ -33,14 +34,14 @@ class Migration(migrations.Migration):
|
|
|
33
34
|
"created",
|
|
34
35
|
models.DateTimeField(
|
|
35
36
|
blank=True,
|
|
36
|
-
default=
|
|
37
|
+
default=django.utils.timezone.now,
|
|
37
38
|
),
|
|
38
39
|
),
|
|
39
40
|
(
|
|
40
41
|
"modified",
|
|
41
42
|
models.DateTimeField(
|
|
42
43
|
blank=True,
|
|
43
|
-
default=
|
|
44
|
+
default=django.utils.timezone.now,
|
|
44
45
|
),
|
|
45
46
|
),
|
|
46
47
|
(
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-17 16:53
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("edc_auth", "0034_alter_edcpermissions_revision_alter_role_revision"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name="edcpermissions",
|
|
15
|
+
name="device_created",
|
|
16
|
+
field=models.CharField(
|
|
17
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
migrations.AlterField(
|
|
21
|
+
model_name="edcpermissions",
|
|
22
|
+
name="device_modified",
|
|
23
|
+
field=models.CharField(
|
|
24
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
migrations.AlterField(
|
|
28
|
+
model_name="edcpermissions",
|
|
29
|
+
name="locale_created",
|
|
30
|
+
field=models.CharField(
|
|
31
|
+
blank=True,
|
|
32
|
+
default="",
|
|
33
|
+
help_text="Auto-updated by Modeladmin",
|
|
34
|
+
max_length=10,
|
|
35
|
+
verbose_name="Locale created",
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
migrations.AlterField(
|
|
39
|
+
model_name="edcpermissions",
|
|
40
|
+
name="locale_modified",
|
|
41
|
+
field=models.CharField(
|
|
42
|
+
blank=True,
|
|
43
|
+
default="",
|
|
44
|
+
help_text="Auto-updated by Modeladmin",
|
|
45
|
+
max_length=10,
|
|
46
|
+
verbose_name="Locale modified",
|
|
47
|
+
),
|
|
48
|
+
),
|
|
49
|
+
migrations.AlterField(
|
|
50
|
+
model_name="role",
|
|
51
|
+
name="device_created",
|
|
52
|
+
field=models.CharField(
|
|
53
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
migrations.AlterField(
|
|
57
|
+
model_name="role",
|
|
58
|
+
name="device_modified",
|
|
59
|
+
field=models.CharField(
|
|
60
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
migrations.AlterField(
|
|
64
|
+
model_name="role",
|
|
65
|
+
name="locale_created",
|
|
66
|
+
field=models.CharField(
|
|
67
|
+
blank=True,
|
|
68
|
+
default="",
|
|
69
|
+
help_text="Auto-updated by Modeladmin",
|
|
70
|
+
max_length=10,
|
|
71
|
+
verbose_name="Locale created",
|
|
72
|
+
),
|
|
73
|
+
),
|
|
74
|
+
migrations.AlterField(
|
|
75
|
+
model_name="role",
|
|
76
|
+
name="locale_modified",
|
|
77
|
+
field=models.CharField(
|
|
78
|
+
blank=True,
|
|
79
|
+
default="",
|
|
80
|
+
help_text="Auto-updated by Modeladmin",
|
|
81
|
+
max_length=10,
|
|
82
|
+
verbose_name="Locale modified",
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
]
|