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.

Files changed (142) hide show
  1. {clinicedc-2.0.7.dist-info → clinicedc-2.0.9.dist-info}/METADATA +4 -3
  2. {clinicedc-2.0.7.dist-info → clinicedc-2.0.9.dist-info}/RECORD +136 -137
  3. {clinicedc-2.0.7.dist-info → clinicedc-2.0.9.dist-info}/WHEEL +1 -1
  4. edc_action_item/auths.py +37 -32
  5. edc_action_item/models/action_model_mixin.py +1 -2
  6. edc_action_item/models/signals.py +22 -23
  7. edc_action_item/site_action_items.py +5 -9
  8. edc_action_item/utils.py +3 -3
  9. edc_adverse_event/auths.py +55 -51
  10. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
  11. edc_appointment/auths.py +14 -10
  12. edc_appointment/creators/appointment_creator.py +1 -1
  13. edc_appointment/creators/appointments_creator.py +1 -1
  14. edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -3
  15. edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
  16. edc_appointment/models/appointment.py +1 -1
  17. edc_appointment/utils.py +19 -24
  18. edc_auth/auth_objects/__init__.py +2 -20
  19. edc_auth/auth_objects/default_groups.py +13 -11
  20. edc_auth/auth_objects/default_roles.py +26 -24
  21. edc_auth/auth_updater/auth_updater.py +13 -2
  22. edc_auth/auth_updater/group_updater.py +12 -10
  23. edc_auth/auth_updater/role_updater.py +2 -2
  24. edc_auth/constants.py +10 -0
  25. edc_auth/import_users.py +3 -3
  26. edc_auth/migrations/0036_alter_userprofile_alternate_email_and_more.py +88 -0
  27. edc_auth/models/user_profile.py +14 -11
  28. edc_auth/site_auths.py +80 -67
  29. edc_consent/auths.py +18 -12
  30. edc_constants/constants.py +1 -0
  31. edc_crf/auths.py +5 -0
  32. edc_dashboard/auths.py +10 -6
  33. edc_dashboard/url_config.py +92 -83
  34. edc_dashboard/url_names.py +4 -4
  35. edc_dashboard/view_mixins/url_request_context_mixin.py +6 -5
  36. edc_data_manager/admin/data_query_admin.py +12 -11
  37. edc_data_manager/auths.py +37 -34
  38. edc_data_manager/rule/query_rule_wrapper.py +7 -7
  39. edc_export/archive_exporter.py +3 -2
  40. edc_export/auths.py +32 -28
  41. edc_export/model_exporter/model_exporter.py +4 -1
  42. edc_facility/auths.py +8 -3
  43. edc_facility/facility.py +8 -9
  44. edc_form_label/custom_label_condition.py +11 -8
  45. edc_form_label/form_label.py +1 -1
  46. edc_form_runners/auths.py +11 -6
  47. edc_form_validators/applicable_field_validator.py +7 -6
  48. edc_form_validators/base_form_validator.py +8 -9
  49. edc_form_validators/other_specify_field_validator.py +2 -8
  50. edc_form_validators/required_field_validator.py +19 -16
  51. edc_identifier/research_identifier.py +11 -10
  52. edc_identifier/simple_identifier.py +8 -2
  53. edc_lab/auths.py +26 -23
  54. edc_lab/lab/aliquot_creator.py +5 -8
  55. edc_lab/lab/primary_aliquot.py +14 -5
  56. edc_lab/migrations/0038_alter_aliquot_slug_alter_box_slug_alter_boxitem_slug_and_more.py +112 -0
  57. edc_lab/model_mixins/requisition/requisition_model_mixin.py +6 -8
  58. edc_lab/models/aliquot.py +2 -2
  59. edc_lab/models/manifest/manifest.py +2 -2
  60. edc_lab/models/manifest/manifest_item.py +1 -1
  61. edc_lab_dashboard/auths.py +16 -11
  62. edc_lab_results/calculate_missing.py +8 -8
  63. edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +2 -2
  64. edc_lab_results/get_summary.py +26 -25
  65. edc_lab_results/model_mixins/blood_result_model_mixin.py +2 -0
  66. edc_label/auths.py +6 -1
  67. edc_label/label_template.py +8 -8
  68. edc_list_data/load_model_data.py +3 -3
  69. edc_list_data/post_migrate_signals.py +1 -1
  70. edc_list_data/preload_data.py +2 -2
  71. edc_list_data/row.py +1 -1
  72. edc_list_data/site_list_data.py +6 -5
  73. edc_locator/auths.py +18 -13
  74. edc_metadata/auths.py +11 -7
  75. edc_metadata/metadata/metadata.py +1 -1
  76. edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
  77. edc_metadata/metadata_rules/metadata_rule_evaluator.py +5 -3
  78. edc_metadata/metadata_rules/rule.py +2 -3
  79. edc_metadata/metadata_rules/rule_evaluator.py +1 -1
  80. edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +7 -4
  81. edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +5 -2
  82. edc_metadata/models/signals.py +10 -11
  83. edc_navbar/auths.py +18 -13
  84. edc_notification/auths.py +9 -4
  85. edc_notification/notification/graded_event_notification.py +2 -2
  86. edc_notification/notification/model_notification.py +3 -30
  87. edc_notification/notification/new_model_notification.py +1 -1
  88. edc_notification/notification/notification.py +1 -1
  89. edc_notification/notification/updated_model_notification.py +2 -2
  90. edc_offstudy/auths.py +12 -7
  91. edc_pdutils/df_exporters/csv_model_exporter.py +5 -2
  92. edc_pharmacy/auths.py +19 -15
  93. edc_pharmacy/models/medication/formulation.py +5 -7
  94. edc_pharmacy/prescribe/create_prescription.py +3 -3
  95. edc_pharmacy/utils/confirm_stock.py +1 -1
  96. edc_pharmacy/utils/confirm_stock_at_site.py +1 -1
  97. edc_pharmacy/views/confirmation_at_site_view.py +6 -9
  98. edc_prn/admin_site.py +5 -0
  99. edc_prn/prn.py +10 -11
  100. edc_prn/urls.py +11 -0
  101. edc_protocol_incident/action_items.py +4 -4
  102. edc_protocol_incident/auths.py +27 -20
  103. edc_pylabels/auths.py +6 -1
  104. edc_qareports/auths.py +11 -7
  105. edc_randomization/admin.py +30 -24
  106. edc_randomization/auths.py +12 -7
  107. edc_randomization/randomizer.py +22 -20
  108. edc_randomization/utils.py +17 -16
  109. edc_refusal/auths.py +7 -2
  110. edc_refusal/model_mixins.py +1 -1
  111. edc_registration/auths.py +28 -23
  112. edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +13 -4
  113. edc_registration/models/registered_subject.py +1 -1
  114. edc_reportable/utils/get_reference_range_collection.py +2 -3
  115. edc_reportable/utils/load_data.py +1 -1
  116. edc_review_dashboard/auths.py +23 -18
  117. edc_screening/age_evaluator.py +3 -3
  118. edc_screening/auths.py +35 -30
  119. edc_screening/eligibility.py +1 -1
  120. edc_screening/gender_evaluator.py +1 -1
  121. edc_screening/model_mixins/eligibility_model_mixin.py +0 -2
  122. edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
  123. edc_screening/screening_eligibility.py +2 -4
  124. edc_screening/utils.py +9 -9
  125. edc_search/generate_slug.py +26 -0
  126. edc_search/model_mixins.py +10 -21
  127. edc_sites/auths.py +8 -3
  128. edc_subject_dashboard/auths.py +27 -22
  129. edc_timepoint/apps.py +0 -21
  130. edc_unblinding/auths.py +9 -4
  131. edc_utils/__init__.py +3 -1
  132. edc_utils/show_urls.py +29 -2
  133. edc_visit_schedule/auths.py +6 -1
  134. edc_visit_schedule/site_visit_schedules.py +2 -2
  135. edc_visit_tracking/models/signals.py +2 -2
  136. edc_form_label/models.py +0 -0
  137. edc_search/constants.py +0 -1
  138. edc_search/models.py +0 -0
  139. edc_search/search_slug.py +0 -51
  140. edc_search/updater.py +0 -30
  141. edc_search/wsgi.py +0 -7
  142. {clinicedc-2.0.7.dist-info → clinicedc-2.0.9.dist-info}/licenses/LICENSE +0 -0
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 default_groups, default_pii_models, default_roles
13
-
14
-
15
- class AlreadyRegistered(Exception):
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
- "groups": default_groups,
100
- "roles": default_roles,
101
- "update_groups": {},
102
- "update_roles": {},
103
- "custom_permissions_tuples": {},
104
- "pre_update_funcs": [],
105
- "post_update_funcs": [],
106
- "pii_models": default_pii_models,
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
- "groups": {},
112
- "roles": {},
113
- "update_groups": {},
114
- "update_roles": {},
115
- "custom_permissions_tuples": {},
116
- "pre_update_funcs": [],
117
- "post_update_funcs": [],
118
- "pii_models": [],
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
- "groups": {k: [] for k in registry.get("groups")},
125
- "roles": {k: [] for k in self.registry.get("roles")},
126
- "update_groups": {},
127
- "update_roles": {},
128
- "custom_permissions_tuples": {},
129
- "pre_update_funcs": [],
130
- "post_update_funcs": [],
131
- "pii_models": [],
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["pre_update_funcs"].append(func)
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["post_update_funcs"].append((app_label, func))
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["pii_models"]:
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["pii_models"].append(model_name)
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["groups"]:
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["groups"].update({name: codenames_or_func})
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["roles"]:
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["roles"].update({name: group_names})
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 "update_groups"
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 "update_roles"
210
+ key = key or UPDATE_ROLES_KEY
201
211
  group_names = list(set(group_names))
202
- existing_group_names = deepcopy(self.registry[key].get(name)) or []
203
- existing_group_names = list(set(existing_group_names))
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["custom_permissions_tuples"][model]
222
+ self.registry[CUSTOM_PERMISSIONS_TUPLES_KEY][model]
213
223
  except KeyError:
214
- self.registry["custom_permissions_tuples"].update({model: []})
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["custom_permissions_tuples"][model]:
217
- self.registry["custom_permissions_tuples"][model].append(codename_tuple)
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["roles"]
277
+ return self.registry[ROLES_KEY]
267
278
 
268
279
  @property
269
280
  def groups(self):
270
- return self.registry["groups"]
281
+ return self.registry[GROUPS_KEY]
271
282
 
272
283
  @property
273
284
  def pii_models(self):
274
- return self.registry["pii_models"]
285
+ return self.registry[PII_MODELS_KEY]
275
286
 
276
287
  @property
277
288
  def pre_update_funcs(self):
278
- return self.registry["pre_update_funcs"]
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["post_update_funcs"]
293
+ return self.registry[POST_UPDATE_FUNCS_KEY]
283
294
 
284
295
  @property
285
296
  def custom_permissions_tuples(self):
286
- return self.registry["custom_permissions_tuples"]
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["update_groups"].items():
298
- if name not in self.registry["groups"]:
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="groups")
308
- for name, group_names in self.registry["update_roles"].items():
309
- if name not in self.registry["roles"]:
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="roles")
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/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
- site_auths.add_post_update_func(
10
- "edc_consent",
11
- remove_default_model_permissions_from_edc_permissions,
12
- )
13
-
14
- site_auths.add_custom_permissions_tuples(
15
- model="edc_consent.edcpermissions", codename_tuples=navbar_tuples
16
- )
17
-
18
- site_auths.update_group(*consent_codenames, name=PII, no_delete=True)
19
- site_auths.update_group(*consent_codenames, name=PII_VIEW, view_only=True)
20
- site_auths.add_pii_model(settings.SUBJECT_CONSENT_MODEL)
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()
@@ -135,6 +135,7 @@ NOT_SURE = "not_sure"
135
135
  NOT_TESTED = "not_tested"
136
136
  NO_EXAM = "NO_EXAM"
137
137
  NO_UNCONFIRMED = "no_unconfirmed"
138
+ NULL_STRING = ""
138
139
  OBSERVATION = "observation"
139
140
  OK = "OK"
140
141
  OFF_STUDY = "off study"
edc_crf/auths.py CHANGED
@@ -0,0 +1,5 @@
1
+ def update_site_auths():
2
+ return None
3
+
4
+
5
+ update_site_auths()
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
- model="edc_dashboard.edcpermissions", codename_tuples=dashboard_tuples
13
- )
12
+ site_auths.add_custom_permissions_tuples(
13
+ model="edc_dashboard.edcpermissions", codename_tuples=dashboard_tuples
14
+ )
15
+
16
+
17
+ update_site_auths()
@@ -20,12 +20,13 @@ if TYPE_CHECKING:
20
20
  class UrlConfig:
21
21
  def __init__(
22
22
  self,
23
- url_name: str = None,
24
- namespace: str = None,
25
- view_class: type[View | UrlRequestContextMixin] = None,
26
- label: str = None,
27
- identifier_label: str = None,
28
- identifier_pattern: str = None,
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
- urlpatterns = [
43
+ return [
43
44
  re_path(
44
- "%(label)s/"
45
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
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
- "label": self.label,
52
- "identifier_label": self.identifier_label,
53
- "identifier_pattern": self.identifier_pattern,
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
- "%(label)s/"
60
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
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
- % dict(
65
- label=self.label,
66
- identifier_label=self.identifier_label,
67
- identifier_pattern=self.identifier_pattern,
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
- "%(label)s/"
74
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
75
- "(?P<appointment>%(uuid_pattern)s)/"
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
- % dict(
79
- label=self.label,
80
- identifier_label=self.identifier_label,
81
- identifier_pattern=self.identifier_pattern,
82
- uuid_pattern=UUID_PATTERN.pattern,
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
- "%(label)s/"
89
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
90
- "(?P<appointment>%(uuid_pattern)s)/"
91
- r"(?P<reason>\w+)/"
92
- % dict(
93
- label=self.label,
94
- identifier_label=self.identifier_label,
95
- identifier_pattern=self.identifier_pattern,
96
- uuid_pattern=UUID_PATTERN.pattern,
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
- "%(label)s/"
103
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
104
- "(?P<appointment>%(uuid_pattern)s)/"
105
- % dict(
106
- label=self.label,
107
- identifier_label=self.identifier_label,
108
- identifier_pattern=self.identifier_pattern,
109
- uuid_pattern=UUID_PATTERN.pattern,
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
- "%(label)s/"
116
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
117
- r"(?P<schedule_name>\w+)/"
118
- % dict(
119
- label=self.label,
120
- identifier_label=self.identifier_label,
121
- identifier_pattern=self.identifier_pattern,
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
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
128
- % dict(
129
- label=self.label,
130
- identifier_label=self.identifier_label,
131
- identifier_pattern=self.identifier_pattern,
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
- urlpatterns = [
152
+ return [
146
153
  re_path(
147
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
148
- r"(?P<page>\d+)/"
149
- % dict(
150
- label=self.label,
151
- identifier_label=self.identifier_label,
152
- identifier_pattern=self.identifier_pattern,
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
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
159
- % dict(
160
- label=self.label,
161
- identifier_label=self.identifier_label,
162
- identifier_pattern=self.identifier_pattern,
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"%(label)s/(?P<page>\d+)/" % dict(label=self.label),
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"%(label)s/" % dict(label=self.label),
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
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
185
- "(?P<appointment>%(uuid_pattern)s)/"
186
- % dict(
187
- label=self.label,
188
- identifier_label=self.identifier_label,
189
- identifier_pattern=self.identifier_pattern,
190
- uuid_pattern=UUID_PATTERN.pattern,
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,
@@ -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 {name}.")
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: