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_auth/models/user_profile.py
CHANGED
|
@@ -11,7 +11,7 @@ from edc_export.choices import EXPORT_FORMATS
|
|
|
11
11
|
from edc_export.constants import CSV
|
|
12
12
|
from edc_notification.model_mixins import NotificationUserProfileModelMixin
|
|
13
13
|
|
|
14
|
-
from ..
|
|
14
|
+
from ..constants import CUSTOM_ROLE, STAFF_ROLE
|
|
15
15
|
from .role import Role
|
|
16
16
|
|
|
17
17
|
|
|
@@ -32,21 +32,21 @@ class UserProfile(NotificationUserProfileModelMixin, models.Model):
|
|
|
32
32
|
|
|
33
33
|
sites = models.ManyToManyField(Site, blank=True)
|
|
34
34
|
|
|
35
|
-
job_title = models.CharField(max_length=100,
|
|
35
|
+
job_title = models.CharField(max_length=100, default="", blank=True)
|
|
36
36
|
|
|
37
|
-
alternate_email = models.EmailField(_("Alternate email address"), blank=True,
|
|
37
|
+
alternate_email = models.EmailField(_("Alternate email address"), blank=True, default="")
|
|
38
38
|
|
|
39
39
|
mobile = models.CharField(
|
|
40
40
|
max_length=25,
|
|
41
41
|
validators=[RegexValidator(regex=r"^\+\d+")],
|
|
42
|
-
|
|
42
|
+
default="",
|
|
43
43
|
blank=True,
|
|
44
44
|
help_text="e.g. +1234567890",
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
clinic_label_printer = models.CharField(
|
|
48
48
|
max_length=100,
|
|
49
|
-
|
|
49
|
+
default="",
|
|
50
50
|
blank=True,
|
|
51
51
|
help_text=format_html(
|
|
52
52
|
'Change in <a href="{href}">{label}</a>',
|
|
@@ -57,7 +57,7 @@ class UserProfile(NotificationUserProfileModelMixin, models.Model):
|
|
|
57
57
|
|
|
58
58
|
lab_label_printer = models.CharField(
|
|
59
59
|
max_length=100,
|
|
60
|
-
|
|
60
|
+
default="",
|
|
61
61
|
blank=True,
|
|
62
62
|
help_text=format_html(
|
|
63
63
|
'Change in <a href="{href}">{label}</a>',
|
|
@@ -68,7 +68,7 @@ class UserProfile(NotificationUserProfileModelMixin, models.Model):
|
|
|
68
68
|
|
|
69
69
|
print_server = models.CharField(
|
|
70
70
|
max_length=100,
|
|
71
|
-
|
|
71
|
+
default="",
|
|
72
72
|
blank=True,
|
|
73
73
|
help_text=format_html(
|
|
74
74
|
'Change in <a href="{href}">{label}</a>',
|
|
@@ -82,7 +82,6 @@ class UserProfile(NotificationUserProfileModelMixin, models.Model):
|
|
|
82
82
|
max_length=25,
|
|
83
83
|
choices=EXPORT_FORMATS,
|
|
84
84
|
default=CSV,
|
|
85
|
-
null=True,
|
|
86
85
|
blank=True,
|
|
87
86
|
help_text="Note: requires export permissions",
|
|
88
87
|
)
|
|
@@ -101,9 +100,13 @@ class UserProfile(NotificationUserProfileModelMixin, models.Model):
|
|
|
101
100
|
group_names = [group.name for group in self.user.groups.all()]
|
|
102
101
|
add_group_names = []
|
|
103
102
|
for role in self.roles.all():
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
add_group_names.extend(
|
|
104
|
+
[
|
|
105
|
+
group.name
|
|
106
|
+
for group in role.groups.all()
|
|
107
|
+
if group.name not in group_names
|
|
108
|
+
]
|
|
109
|
+
)
|
|
107
110
|
add_group_names = list(set(add_group_names))
|
|
108
111
|
for name in add_group_names:
|
|
109
112
|
self.user.groups.add(Group.objects.get(name=name))
|
edc_auth/post_migrate_signals.py
CHANGED
|
@@ -6,7 +6,7 @@ from django.core.management.color import color_style
|
|
|
6
6
|
style = color_style()
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def post_migrate_user_groups_and_roles(sender=None, **kwargs):
|
|
9
|
+
def post_migrate_user_groups_and_roles(sender=None, **kwargs):
|
|
10
10
|
"""Update Groups, Role model with EDC defaults."""
|
|
11
11
|
|
|
12
12
|
from .auth_updater import AuthUpdater
|
edc_auth/site_auths.py
CHANGED
|
@@ -9,30 +9,40 @@ from django.apps import apps as django_apps
|
|
|
9
9
|
from django.conf import settings
|
|
10
10
|
from django.utils.module_loading import import_module, module_has_submodule
|
|
11
11
|
|
|
12
|
-
from .auth_objects import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
from .auth_objects import default_pii_models, get_default_groups, get_default_roles
|
|
13
|
+
from .constants import (
|
|
14
|
+
CUSTOM_PERMISSIONS_TUPLES_KEY,
|
|
15
|
+
GROUPS_KEY,
|
|
16
|
+
PII_MODELS_KEY,
|
|
17
|
+
POST_UPDATE_FUNCS_KEY,
|
|
18
|
+
PRE_UPDATE_FUNCS_KEY,
|
|
19
|
+
ROLES_KEY,
|
|
20
|
+
UPDATE_GROUPS_KEY,
|
|
21
|
+
UPDATE_ROLES_KEY,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AlreadyRegistered(Exception): # noqa: N818
|
|
16
26
|
pass
|
|
17
27
|
|
|
18
28
|
|
|
19
|
-
class InvalidGroup(Exception):
|
|
29
|
+
class InvalidGroup(Exception): # noqa: N818
|
|
20
30
|
pass
|
|
21
31
|
|
|
22
32
|
|
|
23
|
-
class InvalidRole(Exception):
|
|
33
|
+
class InvalidRole(Exception): # noqa: N818
|
|
24
34
|
pass
|
|
25
35
|
|
|
26
36
|
|
|
27
|
-
class RoleAlreadyExists(Exception):
|
|
37
|
+
class RoleAlreadyExists(Exception): # noqa: N818
|
|
28
38
|
pass
|
|
29
39
|
|
|
30
40
|
|
|
31
|
-
class GroupAlreadyExists(Exception):
|
|
41
|
+
class GroupAlreadyExists(Exception): # noqa: N818
|
|
32
42
|
pass
|
|
33
43
|
|
|
34
44
|
|
|
35
|
-
class PiiModelAlreadyExists(Exception):
|
|
45
|
+
class PiiModelAlreadyExists(Exception): # noqa: N818
|
|
36
46
|
pass
|
|
37
47
|
|
|
38
48
|
|
|
@@ -96,39 +106,39 @@ class SiteAuths:
|
|
|
96
106
|
|
|
97
107
|
def initialize(self):
|
|
98
108
|
self.registry = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
GROUPS_KEY: get_default_groups(),
|
|
110
|
+
ROLES_KEY: get_default_roles(),
|
|
111
|
+
UPDATE_GROUPS_KEY: {},
|
|
112
|
+
UPDATE_ROLES_KEY: {},
|
|
113
|
+
CUSTOM_PERMISSIONS_TUPLES_KEY: {},
|
|
114
|
+
PRE_UPDATE_FUNCS_KEY: [],
|
|
115
|
+
POST_UPDATE_FUNCS_KEY: [],
|
|
116
|
+
PII_MODELS_KEY: default_pii_models,
|
|
107
117
|
}
|
|
108
118
|
|
|
109
119
|
def clear(self):
|
|
110
120
|
self.registry = {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
GROUPS_KEY: {},
|
|
122
|
+
ROLES_KEY: {},
|
|
123
|
+
UPDATE_GROUPS_KEY: {},
|
|
124
|
+
UPDATE_ROLES_KEY: {},
|
|
125
|
+
CUSTOM_PERMISSIONS_TUPLES_KEY: {},
|
|
126
|
+
PRE_UPDATE_FUNCS_KEY: [],
|
|
127
|
+
POST_UPDATE_FUNCS_KEY: [],
|
|
128
|
+
PII_MODELS_KEY: [],
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
def clear_values(self):
|
|
122
132
|
registry = deepcopy(self.registry)
|
|
123
133
|
self.registry = {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
GROUPS_KEY: {k: [] for k in registry.get(GROUPS_KEY)},
|
|
135
|
+
ROLES_KEY: {k: [] for k in self.registry.get(ROLES_KEY)},
|
|
136
|
+
UPDATE_GROUPS_KEY: {},
|
|
137
|
+
UPDATE_ROLES_KEY: {},
|
|
138
|
+
CUSTOM_PERMISSIONS_TUPLES_KEY: {},
|
|
139
|
+
PRE_UPDATE_FUNCS_KEY: [],
|
|
140
|
+
POST_UPDATE_FUNCS_KEY: [],
|
|
141
|
+
PII_MODELS_KEY: [],
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
@property
|
|
@@ -136,15 +146,15 @@ class SiteAuths:
|
|
|
136
146
|
return getattr(settings, "EDC_AUTH_SKIP_SITE_AUTHS", False)
|
|
137
147
|
|
|
138
148
|
def add_pre_update_func(self, func):
|
|
139
|
-
self.registry[
|
|
149
|
+
self.registry[PRE_UPDATE_FUNCS_KEY].append(func)
|
|
140
150
|
|
|
141
151
|
def add_post_update_func(self, app_label: str, func: Callable):
|
|
142
|
-
self.registry[
|
|
152
|
+
self.registry[POST_UPDATE_FUNCS_KEY].append((app_label, func))
|
|
143
153
|
|
|
144
154
|
def add_pii_model(self, model_name):
|
|
145
|
-
if model_name in self.registry[
|
|
155
|
+
if model_name in self.registry[PII_MODELS_KEY]:
|
|
146
156
|
raise PiiModelAlreadyExists(f"PII model already exists. Got {model_name}")
|
|
147
|
-
self.registry[
|
|
157
|
+
self.registry[PII_MODELS_KEY].append(model_name)
|
|
148
158
|
|
|
149
159
|
def add_groups(self, data: dict):
|
|
150
160
|
for name, codenames in data.items():
|
|
@@ -162,7 +172,7 @@ class SiteAuths:
|
|
|
162
172
|
convert_to_export=None,
|
|
163
173
|
no_delete=None,
|
|
164
174
|
):
|
|
165
|
-
if name in self.registry[
|
|
175
|
+
if name in self.registry[GROUPS_KEY]:
|
|
166
176
|
raise GroupAlreadyExists(f"Group name already exists. Got {name}.")
|
|
167
177
|
if no_delete:
|
|
168
178
|
codenames_or_func = self.remove_delete_codenames(codenames_or_func)
|
|
@@ -170,18 +180,18 @@ class SiteAuths:
|
|
|
170
180
|
codenames_or_func = self.get_view_only_codenames(codenames_or_func)
|
|
171
181
|
if convert_to_export:
|
|
172
182
|
codenames_or_func = self.convert_to_export_codenames(codenames_or_func)
|
|
173
|
-
self.registry[
|
|
183
|
+
self.registry[GROUPS_KEY].update({name: codenames_or_func})
|
|
174
184
|
|
|
175
185
|
def add_role(self, *group_names, name=None):
|
|
176
|
-
if name in self.registry[
|
|
186
|
+
if name in self.registry[ROLES_KEY]:
|
|
177
187
|
raise RoleAlreadyExists(f"Role name already exists. Got {name}.")
|
|
178
188
|
group_names = list(set(group_names))
|
|
179
|
-
self.registry[
|
|
189
|
+
self.registry[ROLES_KEY].update({name: group_names})
|
|
180
190
|
|
|
181
191
|
def update_group(
|
|
182
192
|
self, *codenames_or_func, name=None, key=None, view_only=None, no_delete=None
|
|
183
193
|
) -> None:
|
|
184
|
-
key = key or
|
|
194
|
+
key = key or UPDATE_GROUPS_KEY
|
|
185
195
|
if no_delete:
|
|
186
196
|
codenames_or_func = self.remove_delete_codenames(codenames_or_func)
|
|
187
197
|
if view_only:
|
|
@@ -191,30 +201,30 @@ class SiteAuths:
|
|
|
191
201
|
try:
|
|
192
202
|
existing_codenames = list(set(existing_codenames))
|
|
193
203
|
except TypeError as e:
|
|
194
|
-
raise TypeError(f"{e}. Got {name}")
|
|
204
|
+
raise TypeError(f"{e}. Got {name}") from e
|
|
195
205
|
existing_codenames.extend(codenames_or_func)
|
|
196
206
|
existing_codenames = list(set(existing_codenames))
|
|
197
207
|
self.registry[key].update({name: existing_codenames})
|
|
198
208
|
|
|
199
209
|
def update_role(self, *group_names, name=None, key=None) -> None:
|
|
200
|
-
key = key or
|
|
210
|
+
key = key or UPDATE_ROLES_KEY
|
|
201
211
|
group_names = list(set(group_names))
|
|
202
|
-
existing_group_names =
|
|
203
|
-
|
|
212
|
+
existing_group_names = [
|
|
213
|
+
name for name in self.registry[key].get(name) or [] if name not in group_names
|
|
214
|
+
]
|
|
204
215
|
existing_group_names.extend(group_names)
|
|
205
|
-
existing_group_names = list(set(existing_group_names))
|
|
206
216
|
self.registry[key].update({name: existing_group_names})
|
|
207
217
|
|
|
208
218
|
def add_custom_permissions_tuples(
|
|
209
219
|
self, model: str, codename_tuples: tuple[tuple[str, str], ...]
|
|
210
220
|
):
|
|
211
221
|
try:
|
|
212
|
-
self.registry[
|
|
222
|
+
self.registry[CUSTOM_PERMISSIONS_TUPLES_KEY][model]
|
|
213
223
|
except KeyError:
|
|
214
|
-
self.registry[
|
|
224
|
+
self.registry[CUSTOM_PERMISSIONS_TUPLES_KEY].update({model: []})
|
|
215
225
|
for codename_tuple in codename_tuples:
|
|
216
|
-
if codename_tuple not in self.registry[
|
|
217
|
-
self.registry[
|
|
226
|
+
if codename_tuple not in self.registry[CUSTOM_PERMISSIONS_TUPLES_KEY][model]:
|
|
227
|
+
self.registry[CUSTOM_PERMISSIONS_TUPLES_KEY][model].append(codename_tuple)
|
|
218
228
|
|
|
219
229
|
@staticmethod
|
|
220
230
|
def get_view_only_codenames(codenames):
|
|
@@ -225,7 +235,8 @@ class SiteAuths:
|
|
|
225
235
|
Does not remove `edc_navbar`, 'nav_' or `edc_dashboard`
|
|
226
236
|
codenames.
|
|
227
237
|
"""
|
|
228
|
-
callables = [lambda: view_only_wrapper(c) for c in codenames if callable(c)]
|
|
238
|
+
# callables = [lambda: view_only_wrapper(c) for c in codenames if callable(c)]
|
|
239
|
+
callables = [lambda c=c: view_only_wrapper(c) for c in codenames if callable(c)]
|
|
229
240
|
view_only_codenames = [
|
|
230
241
|
codename
|
|
231
242
|
for codename in codenames
|
|
@@ -263,27 +274,27 @@ class SiteAuths:
|
|
|
263
274
|
|
|
264
275
|
@property
|
|
265
276
|
def roles(self):
|
|
266
|
-
return self.registry[
|
|
277
|
+
return self.registry[ROLES_KEY]
|
|
267
278
|
|
|
268
279
|
@property
|
|
269
280
|
def groups(self):
|
|
270
|
-
return self.registry[
|
|
281
|
+
return self.registry[GROUPS_KEY]
|
|
271
282
|
|
|
272
283
|
@property
|
|
273
284
|
def pii_models(self):
|
|
274
|
-
return self.registry[
|
|
285
|
+
return self.registry[PII_MODELS_KEY]
|
|
275
286
|
|
|
276
287
|
@property
|
|
277
288
|
def pre_update_funcs(self):
|
|
278
|
-
return self.registry[
|
|
289
|
+
return self.registry[PRE_UPDATE_FUNCS_KEY]
|
|
279
290
|
|
|
280
291
|
@property
|
|
281
292
|
def post_update_funcs(self) -> tuple[str, Callable]:
|
|
282
|
-
return self.registry[
|
|
293
|
+
return self.registry[POST_UPDATE_FUNCS_KEY]
|
|
283
294
|
|
|
284
295
|
@property
|
|
285
296
|
def custom_permissions_tuples(self):
|
|
286
|
-
return self.registry[
|
|
297
|
+
return self.registry[CUSTOM_PERMISSIONS_TUPLES_KEY]
|
|
287
298
|
|
|
288
299
|
def verify_and_populate(
|
|
289
300
|
self, app_name: str | None = None, warn_only: bool | None = None
|
|
@@ -294,28 +305,30 @@ class SiteAuths:
|
|
|
294
305
|
* Updates data from `update_groups` -> `groups`
|
|
295
306
|
* Updates data from `update_roles` -> `roles`
|
|
296
307
|
"""
|
|
297
|
-
for name, codenames in self.registry[
|
|
298
|
-
if name not in self.registry[
|
|
308
|
+
for name, codenames in self.registry[UPDATE_GROUPS_KEY].items():
|
|
309
|
+
if name not in self.registry[GROUPS_KEY]:
|
|
299
310
|
msg = (
|
|
300
311
|
f"Cannot update group. Group name does not exist. See app={app_name}"
|
|
301
312
|
f"update_groups['groups']={codenames}. Got {name}"
|
|
302
313
|
)
|
|
303
314
|
if warn_only:
|
|
304
|
-
warn(msg)
|
|
315
|
+
warn(msg, stacklevel=2)
|
|
305
316
|
else:
|
|
306
317
|
raise InvalidGroup(msg)
|
|
307
|
-
self.update_group(*codenames, name=name, key=
|
|
308
|
-
|
|
309
|
-
|
|
318
|
+
self.update_group(*codenames, name=name, key=GROUPS_KEY)
|
|
319
|
+
self.registry[UPDATE_GROUPS_KEY] = {}
|
|
320
|
+
for name, group_names in self.registry[UPDATE_ROLES_KEY].items():
|
|
321
|
+
if name not in self.registry[ROLES_KEY]:
|
|
310
322
|
msg = (
|
|
311
323
|
f"Cannot update role. Role name does not exist. See app={app_name}. "
|
|
312
324
|
f"update_roles['groups']={group_names}. Got {name}"
|
|
313
325
|
)
|
|
314
326
|
if warn_only:
|
|
315
|
-
warn(msg)
|
|
327
|
+
warn(msg, stacklevel=2)
|
|
316
328
|
else:
|
|
317
329
|
raise InvalidRole(msg)
|
|
318
|
-
self.update_role(*group_names, name=name, key=
|
|
330
|
+
self.update_role(*group_names, name=name, key=ROLES_KEY)
|
|
331
|
+
self.registry[UPDATE_ROLES_KEY] = {}
|
|
319
332
|
|
|
320
333
|
def autodiscover(self, module_name=None, verbose=True):
|
|
321
334
|
"""Autodiscovers in the auths.py file of any INSTALLED_APP."""
|
|
@@ -335,7 +348,7 @@ class SiteAuths:
|
|
|
335
348
|
except ImportError as e:
|
|
336
349
|
site_auths.registry = before_import_registry
|
|
337
350
|
if module_has_submodule(mod, module_name):
|
|
338
|
-
raise SiteAuthError(str(e))
|
|
351
|
+
raise SiteAuthError(str(e)) from e
|
|
339
352
|
except ImportError:
|
|
340
353
|
pass
|
|
341
354
|
self.verify_and_populate(app_name=app_name)
|
edc_consent/actions.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from django.contrib import messages
|
|
2
|
-
|
|
3
|
-
from edc_utils import get_utcnow
|
|
2
|
+
from django.utils import timezone
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
def verify_consent(request=None, consent_obj=None):
|
|
7
6
|
if consent_obj.is_verified:
|
|
8
7
|
return None
|
|
9
8
|
consent_obj.is_verified = True
|
|
10
|
-
consent_obj.is_verified_datetime =
|
|
9
|
+
consent_obj.is_verified_datetime = timezone.now()
|
|
11
10
|
consent_obj.verified_by = request.user.username
|
|
12
11
|
consent_obj.save(update_fields=["is_verified", "is_verified_datetime", "verified_by"])
|
|
13
12
|
return consent_obj
|
|
@@ -21,7 +20,7 @@ def unverify_consent(consent_obj=None):
|
|
|
21
20
|
return consent_obj
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
def flag_as_verified_against_paper(modeladmin, request, queryset, **kwargs):
|
|
23
|
+
def flag_as_verified_against_paper(modeladmin, request, queryset, **kwargs):
|
|
25
24
|
"""Flags instance as verified against the paper document."""
|
|
26
25
|
for consent_obj in queryset:
|
|
27
26
|
if not consent_obj.open_data_queries.count() > 0:
|
|
@@ -46,7 +45,7 @@ def flag_as_verified_against_paper(modeladmin, request, queryset, **kwargs): #
|
|
|
46
45
|
flag_as_verified_against_paper.short_description = "Verify consent against paper document"
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
def unflag_as_verified_against_paper(modeladmin, request, queryset, **kwargs):
|
|
48
|
+
def unflag_as_verified_against_paper(modeladmin, request, queryset, **kwargs):
|
|
50
49
|
"""Unflags instance as verified."""
|
|
51
50
|
for consent_obj in queryset:
|
|
52
51
|
unverify_consent(consent_obj)
|
edc_consent/auths.py
CHANGED
|
@@ -6,15 +6,21 @@ from edc_auth.utils import remove_default_model_permissions_from_edc_permissions
|
|
|
6
6
|
|
|
7
7
|
from .auth_objects import consent_codenames, navbar_tuples
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
|
|
10
|
+
def update_site_auths():
|
|
11
|
+
|
|
12
|
+
site_auths.add_post_update_func(
|
|
13
|
+
"edc_consent",
|
|
14
|
+
remove_default_model_permissions_from_edc_permissions,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
site_auths.add_custom_permissions_tuples(
|
|
18
|
+
model="edc_consent.edcpermissions", codename_tuples=navbar_tuples
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
site_auths.update_group(*consent_codenames, name=PII, no_delete=True)
|
|
22
|
+
site_auths.update_group(*consent_codenames, name=PII_VIEW, view_only=True)
|
|
23
|
+
site_auths.add_pii_model(settings.SUBJECT_CONSENT_MODEL)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
update_site_auths()
|
|
@@ -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,49 @@
|
|
|
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_consent", "0005_alter_edcpermissions_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
|
+
]
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
+
from django.utils import timezone
|
|
2
3
|
from django.utils.translation import gettext as _
|
|
3
4
|
from django_crypto_fields.fields import EncryptedTextField
|
|
4
5
|
|
|
5
6
|
from edc_constants.choices import YES_NO_NA
|
|
6
7
|
from edc_identifier.model_mixins import UniqueSubjectIdentifierModelMixin
|
|
7
|
-
from edc_utils import get_utcnow
|
|
8
8
|
|
|
9
9
|
from .. import site_consents
|
|
10
10
|
from ..consent_definition_extension import ConsentDefinitionExtension
|
|
@@ -14,11 +14,10 @@ ___all__ = ["ConsentExtensionModelMixin"]
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class ConsentExtensionModelMixin(UniqueSubjectIdentifierModelMixin, models.Model):
|
|
17
|
-
|
|
18
17
|
# declare with an FK your subject consent!
|
|
19
18
|
subject_consent = models.ForeignKey("mysubjectconsent", on_delete=models.PROTECT)
|
|
20
19
|
|
|
21
|
-
report_datetime = models.DateTimeField(default=
|
|
20
|
+
report_datetime = models.DateTimeField(default=timezone.now)
|
|
22
21
|
|
|
23
22
|
agrees_to_extension = models.CharField(
|
|
24
23
|
verbose_name=_(
|
|
@@ -35,14 +34,14 @@ class ConsentExtensionModelMixin(UniqueSubjectIdentifierModelMixin, models.Model
|
|
|
35
34
|
consent_extension_version = models.CharField(
|
|
36
35
|
verbose_name="Consent extension version",
|
|
37
36
|
max_length=10,
|
|
38
|
-
|
|
37
|
+
default="",
|
|
39
38
|
editable=False,
|
|
40
39
|
)
|
|
41
40
|
|
|
42
41
|
consent_extension_definition_name = models.CharField(
|
|
43
42
|
verbose_name="Consent extension definition",
|
|
44
43
|
max_length=50,
|
|
45
|
-
|
|
44
|
+
default="",
|
|
46
45
|
editable=False,
|
|
47
46
|
)
|
|
48
47
|
|
|
@@ -4,9 +4,9 @@ from django.db import models
|
|
|
4
4
|
class RequiresConsentFieldsModelMixin(models.Model):
|
|
5
5
|
"""See pre-save signal that checks if subject is consented"""
|
|
6
6
|
|
|
7
|
-
consent_model = models.CharField(max_length=50,
|
|
7
|
+
consent_model = models.CharField(max_length=50, default="", blank=True)
|
|
8
8
|
|
|
9
|
-
consent_version = models.CharField(max_length=10,
|
|
9
|
+
consent_version = models.CharField(max_length=10, default="", blank=True)
|
|
10
10
|
|
|
11
11
|
class Meta:
|
|
12
12
|
abstract = True
|
edc_consent/utils.py
CHANGED
edc_constants/constants.py
CHANGED
edc_crf/auths.py
CHANGED
|
@@ -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
|
(
|