clinicedc 2.0.7__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.7.dist-info → clinicedc-2.0.8.dist-info}/METADATA +1 -1
- {clinicedc-2.0.7.dist-info → clinicedc-2.0.8.dist-info}/RECORD +134 -137
- {clinicedc-2.0.7.dist-info → clinicedc-2.0.8.dist-info}/WHEEL +1 -1
- edc_action_item/auths.py +37 -32
- edc_action_item/models/action_model_mixin.py +1 -2
- edc_action_item/models/signals.py +22 -23
- edc_action_item/site_action_items.py +5 -9
- edc_action_item/utils.py +3 -3
- edc_adverse_event/auths.py +55 -51
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
- edc_appointment/auths.py +14 -10
- edc_appointment/creators/appointment_creator.py +1 -1
- edc_appointment/creators/appointments_creator.py +1 -1
- edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -3
- edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
- edc_appointment/models/appointment.py +1 -1
- edc_appointment/utils.py +19 -24
- 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/models/user_profile.py +14 -11
- edc_auth/site_auths.py +80 -67
- edc_consent/auths.py +18 -12
- edc_constants/constants.py +1 -0
- edc_crf/auths.py +5 -0
- edc_dashboard/auths.py +10 -6
- 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/admin/data_query_admin.py +12 -11
- edc_data_manager/auths.py +37 -34
- edc_data_manager/rule/query_rule_wrapper.py +7 -7
- edc_export/archive_exporter.py +3 -2
- edc_export/auths.py +32 -28
- edc_export/model_exporter/model_exporter.py +4 -1
- edc_facility/auths.py +8 -3
- edc_facility/facility.py +8 -9
- 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_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/research_identifier.py +11 -10
- edc_identifier/simple_identifier.py +8 -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/model_mixins/requisition/requisition_model_mixin.py +6 -8
- edc_lab/models/aliquot.py +2 -2
- edc_lab/models/manifest/manifest.py +2 -2
- edc_lab/models/manifest/manifest_item.py +1 -1
- edc_lab_dashboard/auths.py +16 -11
- 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 +2 -0
- edc_label/auths.py +6 -1
- edc_label/label_template.py +8 -8
- edc_list_data/load_model_data.py +3 -3
- edc_list_data/post_migrate_signals.py +1 -1
- edc_list_data/preload_data.py +2 -2
- edc_list_data/row.py +1 -1
- edc_list_data/site_list_data.py +6 -5
- edc_locator/auths.py +18 -13
- 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/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/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/signals.py +10 -11
- edc_navbar/auths.py +18 -13
- edc_notification/auths.py +9 -4
- 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 +1 -1
- edc_notification/notification/updated_model_notification.py +2 -2
- edc_offstudy/auths.py +12 -7
- edc_pdutils/df_exporters/csv_model_exporter.py +5 -2
- edc_pharmacy/auths.py +19 -15
- edc_pharmacy/models/medication/formulation.py +5 -7
- edc_pharmacy/prescribe/create_prescription.py +3 -3
- edc_pharmacy/utils/confirm_stock.py +1 -1
- edc_pharmacy/utils/confirm_stock_at_site.py +1 -1
- edc_pharmacy/views/confirmation_at_site_view.py +6 -9
- edc_prn/admin_site.py +5 -0
- edc_prn/prn.py +10 -11
- edc_prn/urls.py +11 -0
- edc_protocol_incident/action_items.py +4 -4
- edc_protocol_incident/auths.py +27 -20
- edc_pylabels/auths.py +6 -1
- edc_qareports/auths.py +11 -7
- edc_randomization/admin.py +30 -24
- edc_randomization/auths.py +12 -7
- edc_randomization/randomizer.py +22 -20
- edc_randomization/utils.py +17 -16
- edc_refusal/auths.py +7 -2
- edc_refusal/model_mixins.py +1 -1
- edc_registration/auths.py +28 -23
- edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +13 -4
- edc_registration/models/registered_subject.py +1 -1
- edc_reportable/utils/get_reference_range_collection.py +2 -3
- edc_reportable/utils/load_data.py +1 -1
- edc_review_dashboard/auths.py +23 -18
- edc_screening/age_evaluator.py +3 -3
- edc_screening/auths.py +35 -30
- edc_screening/eligibility.py +1 -1
- edc_screening/gender_evaluator.py +1 -1
- edc_screening/model_mixins/eligibility_model_mixin.py +0 -2
- 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 -21
- edc_sites/auths.py +8 -3
- edc_subject_dashboard/auths.py +27 -22
- edc_timepoint/apps.py +0 -21
- edc_unblinding/auths.py +9 -4
- edc_utils/__init__.py +3 -1
- edc_utils/show_urls.py +29 -2
- edc_visit_schedule/auths.py +6 -1
- edc_visit_schedule/site_visit_schedules.py +2 -2
- edc_visit_tracking/models/signals.py +2 -2
- 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 -51
- edc_search/updater.py +0 -30
- edc_search/wsgi.py +0 -7
- {clinicedc-2.0.7.dist-info → clinicedc-2.0.8.dist-info}/licenses/LICENSE +0 -0
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()
|
edc_constants/constants.py
CHANGED
edc_crf/auths.py
CHANGED
edc_dashboard/auths.py
CHANGED
|
@@ -3,11 +3,15 @@ from edc_auth.utils import remove_default_model_permissions_from_edc_permissions
|
|
|
3
3
|
|
|
4
4
|
from .auth_objects import dashboard_tuples
|
|
5
5
|
|
|
6
|
-
site_auths.add_post_update_func(
|
|
7
|
-
"edc_dashboard", remove_default_model_permissions_from_edc_permissions
|
|
8
|
-
)
|
|
9
6
|
|
|
7
|
+
def update_site_auths():
|
|
8
|
+
site_auths.add_post_update_func(
|
|
9
|
+
"edc_dashboard", remove_default_model_permissions_from_edc_permissions
|
|
10
|
+
)
|
|
10
11
|
|
|
11
|
-
site_auths.add_custom_permissions_tuples(
|
|
12
|
-
|
|
13
|
-
)
|
|
12
|
+
site_auths.add_custom_permissions_tuples(
|
|
13
|
+
model="edc_dashboard.edcpermissions", codename_tuples=dashboard_tuples
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
update_site_auths()
|
edc_dashboard/url_config.py
CHANGED
|
@@ -20,12 +20,13 @@ if TYPE_CHECKING:
|
|
|
20
20
|
class UrlConfig:
|
|
21
21
|
def __init__(
|
|
22
22
|
self,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
*,
|
|
24
|
+
url_name: str,
|
|
25
|
+
namespace: str,
|
|
26
|
+
view_class: type[View | UrlRequestContextMixin],
|
|
27
|
+
label: str,
|
|
28
|
+
identifier_label: str,
|
|
29
|
+
identifier_pattern: str,
|
|
29
30
|
):
|
|
30
31
|
self.identifier_label = identifier_label
|
|
31
32
|
self.identifier_pattern = identifier_pattern
|
|
@@ -39,102 +40,108 @@ class UrlConfig:
|
|
|
39
40
|
@property
|
|
40
41
|
def dashboard_urls(self) -> list[URLPattern]:
|
|
41
42
|
"""Returns url patterns."""
|
|
42
|
-
|
|
43
|
+
return [
|
|
43
44
|
re_path(
|
|
44
|
-
"
|
|
45
|
-
"(?P
|
|
45
|
+
"{label}/"
|
|
46
|
+
"(?P<{identifier_label}>{identifier_pattern})/"
|
|
46
47
|
r"(?P<visit_schedule_name>\w+)/"
|
|
47
48
|
r"(?P<schedule_name>\w+)/"
|
|
48
49
|
r"(?P<visit_code>\w+)/"
|
|
49
|
-
r"(?P<unscheduled>\w+)/"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
r"(?P<unscheduled>\w+)/".format(
|
|
51
|
+
**dict(
|
|
52
|
+
label=self.label,
|
|
53
|
+
identifier_label=self.identifier_label,
|
|
54
|
+
identifier_pattern=self.identifier_pattern,
|
|
55
|
+
)
|
|
56
|
+
),
|
|
55
57
|
self.view_class.as_view(),
|
|
56
58
|
name=self.url_name,
|
|
57
59
|
),
|
|
58
60
|
re_path(
|
|
59
|
-
"
|
|
60
|
-
"(?P
|
|
61
|
+
"{label}/"
|
|
62
|
+
"(?P<{identifier_label}>{identifier_pattern})/"
|
|
61
63
|
r"(?P<visit_schedule_name>\w+)/"
|
|
62
64
|
r"(?P<schedule_name>\w+)/"
|
|
63
|
-
r"(?P<visit_code>\w+)/"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
r"(?P<visit_code>\w+)/".format(
|
|
66
|
+
**dict(
|
|
67
|
+
label=self.label,
|
|
68
|
+
identifier_label=self.identifier_label,
|
|
69
|
+
identifier_pattern=self.identifier_pattern,
|
|
70
|
+
)
|
|
68
71
|
),
|
|
69
72
|
self.view_class.as_view(),
|
|
70
73
|
name=self.url_name,
|
|
71
74
|
),
|
|
72
75
|
re_path(
|
|
73
|
-
"
|
|
74
|
-
"(?P
|
|
75
|
-
"(?P<appointment
|
|
76
|
+
"{label}/"
|
|
77
|
+
"(?P<{identifier_label}>{identifier_pattern})/"
|
|
78
|
+
"(?P<appointment>{uuid_pattern})/"
|
|
76
79
|
r"(?P<scanning>\d)/"
|
|
77
|
-
r"(?P<error>\d)/"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
r"(?P<error>\d)/".format(
|
|
81
|
+
**dict(
|
|
82
|
+
label=self.label,
|
|
83
|
+
identifier_label=self.identifier_label,
|
|
84
|
+
identifier_pattern=self.identifier_pattern,
|
|
85
|
+
uuid_pattern=UUID_PATTERN.pattern,
|
|
86
|
+
)
|
|
83
87
|
),
|
|
84
88
|
self.view_class.as_view(),
|
|
85
89
|
name=self.url_name,
|
|
86
90
|
),
|
|
87
91
|
re_path(
|
|
88
|
-
"
|
|
89
|
-
"(?P
|
|
90
|
-
"(?P<appointment
|
|
91
|
-
r"(?P<reason>\w+)/"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
"{label}/"
|
|
93
|
+
"(?P<{identifier_label}>{identifier_pattern})/"
|
|
94
|
+
"(?P<appointment>{uuid_pattern})/"
|
|
95
|
+
r"(?P<reason>\w+)/".format(
|
|
96
|
+
**dict(
|
|
97
|
+
label=self.label,
|
|
98
|
+
identifier_label=self.identifier_label,
|
|
99
|
+
identifier_pattern=self.identifier_pattern,
|
|
100
|
+
uuid_pattern=UUID_PATTERN.pattern,
|
|
101
|
+
)
|
|
97
102
|
),
|
|
98
103
|
self.view_class.as_view(),
|
|
99
104
|
name=self.url_name,
|
|
100
105
|
),
|
|
101
106
|
re_path(
|
|
102
|
-
"
|
|
103
|
-
"(?P
|
|
104
|
-
"(?P<appointment
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
"{label}/"
|
|
108
|
+
"(?P<{identifier_label}>{identifier_pattern})/"
|
|
109
|
+
"(?P<appointment>{uuid_pattern})/".format(
|
|
110
|
+
**dict(
|
|
111
|
+
label=self.label,
|
|
112
|
+
identifier_label=self.identifier_label,
|
|
113
|
+
identifier_pattern=self.identifier_pattern,
|
|
114
|
+
uuid_pattern=UUID_PATTERN.pattern,
|
|
115
|
+
)
|
|
110
116
|
),
|
|
111
117
|
self.view_class.as_view(),
|
|
112
118
|
name=self.url_name,
|
|
113
119
|
),
|
|
114
120
|
re_path(
|
|
115
|
-
"
|
|
116
|
-
"(?P
|
|
117
|
-
r"(?P<schedule_name>\w+)/"
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
"{label}/"
|
|
122
|
+
"(?P<{identifier_label}>{identifier_pattern})/"
|
|
123
|
+
r"(?P<schedule_name>\w+)/".format(
|
|
124
|
+
**dict(
|
|
125
|
+
label=self.label,
|
|
126
|
+
identifier_label=self.identifier_label,
|
|
127
|
+
identifier_pattern=self.identifier_pattern,
|
|
128
|
+
)
|
|
122
129
|
),
|
|
123
130
|
self.view_class.as_view(),
|
|
124
131
|
name=self.url_name,
|
|
125
132
|
),
|
|
126
133
|
re_path(
|
|
127
|
-
"
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
"{label}/(?P<{identifier_label}>{identifier_pattern})/".format(
|
|
135
|
+
**dict(
|
|
136
|
+
label=self.label,
|
|
137
|
+
identifier_label=self.identifier_label,
|
|
138
|
+
identifier_pattern=self.identifier_pattern,
|
|
139
|
+
)
|
|
132
140
|
),
|
|
133
141
|
self.view_class.as_view(),
|
|
134
142
|
name=self.url_name,
|
|
135
143
|
),
|
|
136
144
|
]
|
|
137
|
-
return urlpatterns
|
|
138
145
|
|
|
139
146
|
@property
|
|
140
147
|
def listboard_urls(self) -> list[URLPattern]:
|
|
@@ -142,52 +149,54 @@ class UrlConfig:
|
|
|
142
149
|
|
|
143
150
|
configs = [(listboard_url, listboard_view_class, label), (), ...]
|
|
144
151
|
"""
|
|
145
|
-
|
|
152
|
+
return [
|
|
146
153
|
re_path(
|
|
147
|
-
"
|
|
148
|
-
r"(?P<page>\d+)/"
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
"{label}/(?P<{identifier_label}>{identifier_pattern})/"
|
|
155
|
+
r"(?P<page>\d+)/".format(
|
|
156
|
+
**dict(
|
|
157
|
+
label=self.label,
|
|
158
|
+
identifier_label=self.identifier_label,
|
|
159
|
+
identifier_pattern=self.identifier_pattern,
|
|
160
|
+
)
|
|
153
161
|
),
|
|
154
162
|
self.view_class.as_view(),
|
|
155
163
|
name=self.url_name,
|
|
156
164
|
),
|
|
157
165
|
re_path(
|
|
158
|
-
"
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
"{label}/(?P<{identifier_label}>{identifier_pattern})/".format(
|
|
167
|
+
**dict(
|
|
168
|
+
label=self.label,
|
|
169
|
+
identifier_label=self.identifier_label,
|
|
170
|
+
identifier_pattern=self.identifier_pattern,
|
|
171
|
+
)
|
|
163
172
|
),
|
|
164
173
|
self.view_class.as_view(),
|
|
165
174
|
name=self.url_name,
|
|
166
175
|
),
|
|
167
176
|
re_path(
|
|
168
|
-
r"
|
|
177
|
+
r"{label}/(?P<page>\d+)/".format(**dict(label=self.label)),
|
|
169
178
|
self.view_class.as_view(),
|
|
170
179
|
name=self.url_name,
|
|
171
180
|
),
|
|
172
181
|
re_path(
|
|
173
|
-
r"
|
|
182
|
+
r"{label}/".format(**dict(label=self.label)),
|
|
174
183
|
self.view_class.as_view(),
|
|
175
184
|
name=self.url_name,
|
|
176
185
|
),
|
|
177
186
|
]
|
|
178
|
-
return urlpatterns
|
|
179
187
|
|
|
180
188
|
@property
|
|
181
189
|
def review_listboard_urls(self) -> list[URLPattern]:
|
|
182
190
|
url_patterns = [
|
|
183
191
|
re_path(
|
|
184
|
-
"
|
|
185
|
-
"(?P<appointment
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
"{label}/(?P<{identifier_label}>{identifier_pattern})/"
|
|
193
|
+
"(?P<appointment>{uuid_pattern})/".format(
|
|
194
|
+
**dict(
|
|
195
|
+
label=self.label,
|
|
196
|
+
identifier_label=self.identifier_label,
|
|
197
|
+
identifier_pattern=self.identifier_pattern,
|
|
198
|
+
uuid_pattern=UUID_PATTERN.pattern,
|
|
199
|
+
)
|
|
191
200
|
),
|
|
192
201
|
self.view_class.as_view(),
|
|
193
202
|
name=self.url_name,
|
edc_dashboard/url_names.py
CHANGED
|
@@ -3,11 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class AlreadyRegistered(Exception):
|
|
6
|
+
class AlreadyRegistered(Exception): # noqa: N818
|
|
7
7
|
pass
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class InvalidDashboardUrlName(Exception):
|
|
10
|
+
class InvalidDashboardUrlName(Exception): # noqa: N818
|
|
11
11
|
pass
|
|
12
12
|
|
|
13
13
|
|
|
@@ -16,12 +16,12 @@ class UrlNames:
|
|
|
16
16
|
registry: dict[str, str] = field(default_factory=dict)
|
|
17
17
|
|
|
18
18
|
def register(
|
|
19
|
-
self, name: str = None, url: str = None, namespace: str | None = None
|
|
19
|
+
self, name: str | None = None, url: str | None = None, namespace: str | None = None
|
|
20
20
|
) -> None:
|
|
21
21
|
name = name or url
|
|
22
22
|
complete_url = f"{namespace}:{url}" if namespace else url
|
|
23
23
|
if name in self.registry:
|
|
24
|
-
raise AlreadyRegistered(f"Url already registered. Got {
|
|
24
|
+
raise AlreadyRegistered(f"Url already registered. Got {complete_url}.")
|
|
25
25
|
self.registry.update({name: complete_url})
|
|
26
26
|
|
|
27
27
|
def register_from_dict(self, **urldata: str) -> None:
|
|
@@ -30,10 +30,11 @@ class UrlRequestContextMixin:
|
|
|
30
30
|
@classmethod
|
|
31
31
|
def urls(
|
|
32
32
|
cls,
|
|
33
|
-
|
|
34
|
-
label: str
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
*,
|
|
34
|
+
label: str,
|
|
35
|
+
identifier_pattern: str,
|
|
36
|
+
namespace: str | None = None,
|
|
37
|
+
identifier_label: str | None = None,
|
|
37
38
|
) -> list[URLPattern]:
|
|
38
39
|
label = (
|
|
39
40
|
label
|
|
@@ -62,5 +63,5 @@ class UrlRequestContextMixin:
|
|
|
62
63
|
f"Url name not defined in url_names. "
|
|
63
64
|
f"Expected one of {url_names.registry}. Got {e}. "
|
|
64
65
|
f"Hint: check if dashboard middleware is loaded."
|
|
65
|
-
)
|
|
66
|
+
) from e
|
|
66
67
|
return url_data
|
|
@@ -45,7 +45,7 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
|
|
|
45
45
|
|
|
46
46
|
locked_column_template_name = "edc_data_manager/columns/locked.html"
|
|
47
47
|
|
|
48
|
-
status_column_context = {
|
|
48
|
+
status_column_context = { # noqa: RUF012
|
|
49
49
|
"NEW": NEW,
|
|
50
50
|
"OPEN": OPEN,
|
|
51
51
|
"FEEDBACK": FEEDBACK,
|
|
@@ -61,13 +61,13 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
|
|
|
61
61
|
|
|
62
62
|
actions = (toggle_dm_status,)
|
|
63
63
|
|
|
64
|
-
radio_fields = {
|
|
64
|
+
radio_fields = { # noqa: RUF012
|
|
65
65
|
"status": admin.VERTICAL,
|
|
66
66
|
"site_response_status": admin.VERTICAL,
|
|
67
67
|
"query_priority": admin.VERTICAL,
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
autocomplete_fields =
|
|
70
|
+
autocomplete_fields = (
|
|
71
71
|
"sender",
|
|
72
72
|
"recipients",
|
|
73
73
|
"data_dictionaries",
|
|
@@ -75,7 +75,7 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
|
|
|
75
75
|
"visit_schedule",
|
|
76
76
|
"registered_subject",
|
|
77
77
|
"dm_user",
|
|
78
|
-
|
|
78
|
+
)
|
|
79
79
|
|
|
80
80
|
list_display = (
|
|
81
81
|
"wrapped_title",
|
|
@@ -201,11 +201,10 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
|
|
|
201
201
|
wrapped_title.short_description = "Title"
|
|
202
202
|
|
|
203
203
|
def formfield_for_manytomany(self, db_field, request, **kwargs):
|
|
204
|
-
if db_field.name == "data_dictionaries":
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
)
|
|
204
|
+
if db_field.name == "data_dictionaries" and request.GET.get("title"):
|
|
205
|
+
kwargs["queryset"] = DataDictionary.objects.filter(
|
|
206
|
+
model_verbose_name=request.GET.get("title")
|
|
207
|
+
)
|
|
209
208
|
return super().formfield_for_manytomany(db_field, request, **kwargs)
|
|
210
209
|
|
|
211
210
|
def query_dates(self, obj):
|
|
@@ -332,7 +331,8 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
|
|
|
332
331
|
"missed_visit",
|
|
333
332
|
"auto_resolved",
|
|
334
333
|
"registered_subject",
|
|
335
|
-
|
|
334
|
+
*action_fields,
|
|
335
|
+
)
|
|
336
336
|
if not request.user.groups.filter(name=DATA_MANAGER):
|
|
337
337
|
extra_fields = (
|
|
338
338
|
"data_dictionaries",
|
|
@@ -350,10 +350,11 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
|
|
|
350
350
|
"title",
|
|
351
351
|
"visit_code_sequence",
|
|
352
352
|
"visit_schedule",
|
|
353
|
+
*extra_fields,
|
|
353
354
|
)
|
|
354
355
|
if not obj:
|
|
355
356
|
extra_fields = tuple(f for f in extra_fields if f != "registered_subject")
|
|
356
|
-
return fields
|
|
357
|
+
return *fields, *extra_fields
|
|
357
358
|
|
|
358
359
|
def get_subject_dashboard_url_kwargs(self, obj):
|
|
359
360
|
def get_opts():
|
edc_data_manager/auths.py
CHANGED
|
@@ -18,45 +18,48 @@ from .auth_objects import (
|
|
|
18
18
|
data_manager,
|
|
19
19
|
)
|
|
20
20
|
|
|
21
|
-
site_auths.add_custom_permissions_tuples(
|
|
22
|
-
model="edc_data_manager.edcpermissions", codename_tuples=custom_codename_tuples
|
|
23
|
-
)
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
22
|
+
def update_site_auths():
|
|
23
|
+
site_auths.add_custom_permissions_tuples(
|
|
24
|
+
model="edc_data_manager.edcpermissions", codename_tuples=custom_codename_tuples
|
|
25
|
+
)
|
|
29
26
|
|
|
27
|
+
site_auths.add_custom_permissions_tuples(
|
|
28
|
+
model="edc_data_manager.edcpermissions",
|
|
29
|
+
codename_tuples=[("edc_data_manager.special_bypassmodelform", "Can bypass modelform")],
|
|
30
|
+
)
|
|
30
31
|
|
|
31
|
-
# groups
|
|
32
|
-
site_auths.add_group(*data_manager, name=DATA_MANAGER)
|
|
33
|
-
site_auths.add_group(*data_manager, name=DATA_QUERY_VIEW, view_only=True)
|
|
32
|
+
# groups
|
|
33
|
+
site_auths.add_group(*data_manager, name=DATA_MANAGER)
|
|
34
|
+
site_auths.add_group(*data_manager, name=DATA_QUERY_VIEW, view_only=True)
|
|
34
35
|
|
|
35
|
-
site_auths.add_group(*data_manager, name=DATA_QUERY, view_only=True)
|
|
36
|
-
site_auths.update_group("edc_data_manager.change_dataquery", name=DATA_QUERY)
|
|
36
|
+
site_auths.add_group(*data_manager, name=DATA_QUERY, view_only=True)
|
|
37
|
+
site_auths.update_group("edc_data_manager.change_dataquery", name=DATA_QUERY)
|
|
37
38
|
|
|
38
|
-
site_auths.add_group(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
39
|
+
site_auths.add_group(
|
|
40
|
+
"edc_data_manager.export_datadictionary",
|
|
41
|
+
"edc_data_manager.export_dataquery",
|
|
42
|
+
"edc_data_manager.export_queryrule",
|
|
43
|
+
name=DATA_MANAGER_EXPORT,
|
|
44
|
+
)
|
|
44
45
|
|
|
45
|
-
site_auths.add_group(*data_manager, name=DATA_MANAGER_SUPER)
|
|
46
|
-
site_auths.update_group("edc_data_manager.change_dataquery", name=DATA_MANAGER_SUPER)
|
|
47
|
-
site_auths.update_group(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
46
|
+
site_auths.add_group(*data_manager, name=DATA_MANAGER_SUPER)
|
|
47
|
+
site_auths.update_group("edc_data_manager.change_dataquery", name=DATA_MANAGER_SUPER)
|
|
48
|
+
site_auths.update_group(
|
|
49
|
+
"edc_data_manager.export_datadictionary",
|
|
50
|
+
"edc_data_manager.export_dataquery",
|
|
51
|
+
"edc_data_manager.export_queryrule",
|
|
52
|
+
"edc_data_manager.special_bypassmodelform",
|
|
53
|
+
"edc_data_manager.change_dataquery",
|
|
54
|
+
name=DATA_MANAGER_SUPER,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# roles
|
|
58
|
+
site_auths.add_role(CELERY_MANAGER, DATA_MANAGER, name=DATA_MANAGER_ROLE)
|
|
59
|
+
site_auths.add_role(DATA_QUERY, name=SITE_DATA_MANAGER_ROLE)
|
|
60
|
+
site_auths.update_role(DATA_QUERY, name=CLINICIAN_ROLE)
|
|
61
|
+
site_auths.update_role(DATA_QUERY, name=NURSE_ROLE)
|
|
62
|
+
site_auths.update_role(DATA_QUERY, name=CLINICIAN_SUPER_ROLE)
|
|
55
63
|
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
site_auths.add_role(CELERY_MANAGER, DATA_MANAGER, name=DATA_MANAGER_ROLE)
|
|
59
|
-
site_auths.add_role(DATA_QUERY, name=SITE_DATA_MANAGER_ROLE)
|
|
60
|
-
site_auths.update_role(DATA_QUERY, name=CLINICIAN_ROLE)
|
|
61
|
-
site_auths.update_role(DATA_QUERY, name=NURSE_ROLE)
|
|
62
|
-
site_auths.update_role(DATA_QUERY, name=CLINICIAN_SUPER_ROLE)
|
|
65
|
+
update_site_auths()
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from decimal import Decimal
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from tqdm import tqdm
|
|
8
8
|
|
|
@@ -17,12 +17,12 @@ if TYPE_CHECKING:
|
|
|
17
17
|
class QueryRuleWrapper:
|
|
18
18
|
def __init__(
|
|
19
19
|
self,
|
|
20
|
-
query_rule_obj: QueryRule = None,
|
|
21
|
-
subject_identifiers: list[
|
|
22
|
-
visit_schedule_obj: QueryVisitSchedule = None,
|
|
23
|
-
timepoint: Decimal = None,
|
|
24
|
-
entry_status: str = None,
|
|
25
|
-
now: datetime = None,
|
|
20
|
+
query_rule_obj: QueryRule | None = None,
|
|
21
|
+
subject_identifiers: list[str] | None = None,
|
|
22
|
+
visit_schedule_obj: QueryVisitSchedule | None = None,
|
|
23
|
+
timepoint: Decimal | None = None,
|
|
24
|
+
entry_status: str | None = None,
|
|
25
|
+
now: datetime | None = None,
|
|
26
26
|
verbose: bool | None = None,
|
|
27
27
|
):
|
|
28
28
|
self.now = now
|
edc_export/archive_exporter.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from tempfile import mkdtemp
|
|
4
5
|
from typing import TYPE_CHECKING
|
|
5
6
|
|
|
@@ -17,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
17
18
|
from django.contrib.auth.models import User
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
class ArchiveExporterNothingExported(Exception):
|
|
21
|
+
class ArchiveExporterNothingExported(Exception): # noqa: N818
|
|
21
22
|
pass
|
|
22
23
|
|
|
23
24
|
|
|
@@ -56,7 +57,7 @@ class ArchiveExporter:
|
|
|
56
57
|
for model in models:
|
|
57
58
|
csv_exporter = self.csv_exporter_cls(
|
|
58
59
|
model=model,
|
|
59
|
-
export_folder=tmp_folder,
|
|
60
|
+
export_folder=Path(tmp_folder),
|
|
60
61
|
decrypt=decrypt,
|
|
61
62
|
site_ids=sites.get_site_ids_for_user(
|
|
62
63
|
user=user, site_id=sites.get_current_site().site_id
|