clinicedc 2.0.7__py3-none-any.whl → 2.0.9__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.9.dist-info}/METADATA +4 -3
- {clinicedc-2.0.7.dist-info → clinicedc-2.0.9.dist-info}/RECORD +136 -137
- {clinicedc-2.0.7.dist-info → clinicedc-2.0.9.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/migrations/0036_alter_userprofile_alternate_email_and_more.py +88 -0
- 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/migrations/0038_alter_aliquot_slug_alter_box_slug_alter_boxitem_slug_and_more.py +112 -0
- 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.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -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 = (
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-22 12:31
|
|
2
|
+
|
|
3
|
+
import django.core.validators
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
("edc_auth", "0035_alter_edcpermissions_device_created_and_more"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterField(
|
|
15
|
+
model_name="userprofile",
|
|
16
|
+
name="alternate_email",
|
|
17
|
+
field=models.EmailField(
|
|
18
|
+
blank=True,
|
|
19
|
+
default="",
|
|
20
|
+
max_length=254,
|
|
21
|
+
verbose_name="Alternate email address",
|
|
22
|
+
),
|
|
23
|
+
),
|
|
24
|
+
migrations.AlterField(
|
|
25
|
+
model_name="userprofile",
|
|
26
|
+
name="clinic_label_printer",
|
|
27
|
+
field=models.CharField(
|
|
28
|
+
blank=True,
|
|
29
|
+
default="",
|
|
30
|
+
help_text='Change in <a href="/edc_label/">Edc Label Administration</a>',
|
|
31
|
+
max_length=100,
|
|
32
|
+
),
|
|
33
|
+
),
|
|
34
|
+
migrations.AlterField(
|
|
35
|
+
model_name="userprofile",
|
|
36
|
+
name="export_format",
|
|
37
|
+
field=models.CharField(
|
|
38
|
+
blank=True,
|
|
39
|
+
choices=[
|
|
40
|
+
("CSV", "CSV (delimited by pipe `|`)"),
|
|
41
|
+
(114, "Stata v10 or later"),
|
|
42
|
+
(117, "Stata v13 or later"),
|
|
43
|
+
(118, "Stata v14 or later"),
|
|
44
|
+
(119, "Stata v15 or later"),
|
|
45
|
+
],
|
|
46
|
+
default="CSV",
|
|
47
|
+
help_text="Note: requires export permissions",
|
|
48
|
+
max_length=25,
|
|
49
|
+
verbose_name="Export format",
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
migrations.AlterField(
|
|
53
|
+
model_name="userprofile",
|
|
54
|
+
name="job_title",
|
|
55
|
+
field=models.CharField(blank=True, default="", max_length=100),
|
|
56
|
+
),
|
|
57
|
+
migrations.AlterField(
|
|
58
|
+
model_name="userprofile",
|
|
59
|
+
name="lab_label_printer",
|
|
60
|
+
field=models.CharField(
|
|
61
|
+
blank=True,
|
|
62
|
+
default="",
|
|
63
|
+
help_text='Change in <a href="/edc_label/">Edc Label Administration</a>',
|
|
64
|
+
max_length=100,
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
migrations.AlterField(
|
|
68
|
+
model_name="userprofile",
|
|
69
|
+
name="mobile",
|
|
70
|
+
field=models.CharField(
|
|
71
|
+
blank=True,
|
|
72
|
+
default="",
|
|
73
|
+
help_text="e.g. +1234567890",
|
|
74
|
+
max_length=25,
|
|
75
|
+
validators=[django.core.validators.RegexValidator(regex="^\\+\\d+")],
|
|
76
|
+
),
|
|
77
|
+
),
|
|
78
|
+
migrations.AlterField(
|
|
79
|
+
model_name="userprofile",
|
|
80
|
+
name="print_server",
|
|
81
|
+
field=models.CharField(
|
|
82
|
+
blank=True,
|
|
83
|
+
default="",
|
|
84
|
+
help_text='Change in <a href="/edc_label/">Edc Label Administration</a>',
|
|
85
|
+
max_length=100,
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
]
|
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))
|