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
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.utils.text import slugify
|
|
4
|
+
from django_crypto_fields.utils import get_encrypted_field_names
|
|
5
|
+
|
|
6
|
+
SLUG_SEP = "|"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def generate_slug(obj, fields) -> str | None:
|
|
10
|
+
"""Returns a slug of the char values of the fields
|
|
11
|
+
listed on the models get_search_slug_fields() method.
|
|
12
|
+
|
|
13
|
+
Excludes any encrypted fields if listed.
|
|
14
|
+
"""
|
|
15
|
+
slug = None
|
|
16
|
+
if obj and fields:
|
|
17
|
+
values = []
|
|
18
|
+
for field in (f for f in fields if f not in get_encrypted_field_names(obj)):
|
|
19
|
+
v = obj
|
|
20
|
+
for f in field.split("."):
|
|
21
|
+
v = getattr(v, f)
|
|
22
|
+
if isinstance(v, str):
|
|
23
|
+
values.append(v[:50]) # truncate value
|
|
24
|
+
slugs = [slugify(v) for v in list(set(values)) if v]
|
|
25
|
+
slug = SLUG_SEP.join(slugs)[:250]
|
|
26
|
+
return slug
|
edc_search/model_mixins.py
CHANGED
|
@@ -1,42 +1,31 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
+
from tqdm import tqdm
|
|
2
3
|
|
|
3
|
-
from .
|
|
4
|
+
from .generate_slug import generate_slug
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class SearchSlugManager(models.Manager):
|
|
7
|
-
search_slug_updater_cls = SearchSlugUpdater
|
|
8
|
-
search_slug_field_name = "slug"
|
|
9
|
-
|
|
10
8
|
def update_search_slugs(self) -> None:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
)
|
|
15
|
-
setattr(obj, self.search_slug_field_name, updater.slug)
|
|
16
|
-
obj.save_base(update_fields=[self.search_slug_field_name])
|
|
9
|
+
qs = self.all()
|
|
10
|
+
for obj in tqdm(qs, total=qs.count()):
|
|
11
|
+
obj.slug = generate_slug(obj, obj.get_search_slug_fields()) or ""
|
|
12
|
+
obj.save_base(update_fields=["slug"])
|
|
17
13
|
|
|
18
14
|
|
|
19
15
|
class SearchSlugModelMixin(models.Model):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def get_search_slug_fields(self) -> tuple[str] | None:
|
|
24
|
-
return None
|
|
16
|
+
def get_search_slug_fields(self) -> tuple[str, ...]:
|
|
17
|
+
return ()
|
|
25
18
|
|
|
26
19
|
slug = models.CharField(
|
|
27
20
|
max_length=250,
|
|
28
21
|
default="",
|
|
29
22
|
editable=False,
|
|
30
23
|
db_index=True,
|
|
31
|
-
help_text="
|
|
24
|
+
help_text="Hold slug field values for quick search. Excludes encrypted fields",
|
|
32
25
|
)
|
|
33
26
|
|
|
34
27
|
def save(self, *args, **kwargs):
|
|
35
|
-
|
|
36
|
-
fields=self.get_search_slug_fields(), model_obj=self
|
|
37
|
-
)
|
|
38
|
-
self.search_slug_warning = updater.warning
|
|
39
|
-
self.slug = updater.slug
|
|
28
|
+
self.slug = generate_slug(self, self.get_search_slug_fields()) or ""
|
|
40
29
|
super().save(*args, **kwargs)
|
|
41
30
|
|
|
42
31
|
class Meta:
|
edc_sites/auths.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
from edc_auth.site_auths import site_auths
|
|
2
2
|
from edc_auth.utils import remove_default_model_permissions_from_edc_permissions
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
|
|
5
|
+
def update_site_auths() -> None:
|
|
6
|
+
site_auths.add_post_update_func(
|
|
7
|
+
"edc_sites", remove_default_model_permissions_from_edc_permissions
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
update_site_auths()
|
edc_subject_dashboard/auths.py
CHANGED
|
@@ -7,30 +7,35 @@ from edc_auth.constants import (
|
|
|
7
7
|
from edc_auth.site_auths import site_auths
|
|
8
8
|
from edc_auth.utils import remove_default_model_permissions_from_edc_permissions
|
|
9
9
|
|
|
10
|
-
site_auths.add_post_update_func(
|
|
11
|
-
"edc_subject_dashboard", remove_default_model_permissions_from_edc_permissions
|
|
12
|
-
)
|
|
13
|
-
|
|
14
10
|
SUBJECT_VIEW = "SUBJECT_VIEW"
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
|
|
13
|
+
def update_site_auths() -> None:
|
|
14
|
+
site_auths.add_post_update_func(
|
|
15
|
+
"edc_subject_dashboard", remove_default_model_permissions_from_edc_permissions
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
site_auths.add_custom_permissions_tuples(
|
|
19
|
+
model="edc_subject_dashboard.edcpermissions",
|
|
20
|
+
codename_tuples=(
|
|
21
|
+
(
|
|
22
|
+
"edc_subject_dashboard.view_subject_listboard",
|
|
23
|
+
"Can access subject listboard",
|
|
24
|
+
),
|
|
25
|
+
("edc_subject_dashboard.nav_subject_section", "Can access nav_subject_section"),
|
|
22
26
|
),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
site_auths.add_group(
|
|
30
|
+
"edc_subject_dashboard.view_subject_listboard",
|
|
31
|
+
"edc_subject_dashboard.nav_subject_section",
|
|
32
|
+
name=SUBJECT_VIEW,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
site_auths.update_role(SUBJECT_VIEW, name=CLINICIAN_ROLE)
|
|
36
|
+
site_auths.update_role(SUBJECT_VIEW, name=NURSE_ROLE)
|
|
37
|
+
site_auths.update_role(SUBJECT_VIEW, name=CLINICIAN_SUPER_ROLE)
|
|
38
|
+
site_auths.update_role(SUBJECT_VIEW, name=AUDITOR_ROLE)
|
|
26
39
|
|
|
27
|
-
site_auths.add_group(
|
|
28
|
-
"edc_subject_dashboard.view_subject_listboard",
|
|
29
|
-
"edc_subject_dashboard.nav_subject_section",
|
|
30
|
-
name=SUBJECT_VIEW,
|
|
31
|
-
)
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
site_auths.update_role(SUBJECT_VIEW, name=NURSE_ROLE)
|
|
35
|
-
site_auths.update_role(SUBJECT_VIEW, name=CLINICIAN_SUPER_ROLE)
|
|
36
|
-
site_auths.update_role(SUBJECT_VIEW, name=AUDITOR_ROLE)
|
|
41
|
+
update_site_auths()
|
edc_timepoint/apps.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
|
|
3
3
|
from django.apps import AppConfig as DjangoAppConfig
|
|
4
|
-
from django.conf import settings
|
|
5
4
|
|
|
6
5
|
from edc_appointment.constants import COMPLETE_APPT
|
|
7
6
|
|
|
@@ -35,23 +34,3 @@ class AppConfig(DjangoAppConfig):
|
|
|
35
34
|
for model in self.timepoints:
|
|
36
35
|
sys.stdout.write(f" * '{model}' is a timepoint model.\n")
|
|
37
36
|
sys.stdout.write(f" Done loading {self.verbose_name}.\n")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if settings.APP_NAME == "edc_timepoint":
|
|
41
|
-
from dateutil.relativedelta import FR, MO, SA, SU, TH, TU, WE
|
|
42
|
-
|
|
43
|
-
from edc_facility.apps import AppConfig as BaseEdcFacilityAppConfig
|
|
44
|
-
|
|
45
|
-
class EdcFacilityAppConfig(BaseEdcFacilityAppConfig):
|
|
46
|
-
definitions = {
|
|
47
|
-
"7-day-clinic": dict(
|
|
48
|
-
days=[MO, TU, WE, TH, FR, SA, SU],
|
|
49
|
-
slots=[100, 100, 100, 100, 100, 100, 100],
|
|
50
|
-
),
|
|
51
|
-
"5-day-clinic": dict(days=[MO, TU, WE, TH, FR], slots=[100, 100, 100, 100, 100]),
|
|
52
|
-
"3-day-clinic": dict(
|
|
53
|
-
days=[TU, WE, TH],
|
|
54
|
-
slots=[100, 100, 100],
|
|
55
|
-
best_effort_available_datetime=True,
|
|
56
|
-
),
|
|
57
|
-
}
|
edc_unblinding/auths.py
CHANGED
|
@@ -9,7 +9,12 @@ from .auth_objects import (
|
|
|
9
9
|
unblinding_reviewers,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
site_auths.
|
|
15
|
-
site_auths.
|
|
12
|
+
|
|
13
|
+
def update_site_auths() -> None:
|
|
14
|
+
site_auths.add_group(*unblinding_requestors, name=UNBLINDING_REQUESTORS)
|
|
15
|
+
site_auths.add_group(*unblinding_reviewers, name=UNBLINDING_REVIEWERS)
|
|
16
|
+
site_auths.add_role(UNBLINDING_REQUESTORS, name=UNBLINDING_REQUESTORS_ROLE)
|
|
17
|
+
site_auths.add_role(UNBLINDING_REVIEWERS, name=UNBLINDING_REVIEWERS_ROLE)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
update_site_auths()
|
edc_utils/__init__.py
CHANGED
|
@@ -8,7 +8,7 @@ from .get_static_file import get_static_file
|
|
|
8
8
|
from .get_uuid import get_uuid
|
|
9
9
|
from .message_in_queue import message_in_queue
|
|
10
10
|
from .round_up import round_half_away_from_zero, round_half_up, round_up
|
|
11
|
-
from .show_urls import show_url_names, show_urls
|
|
11
|
+
from .show_urls import show_namespaces, show_url_names, show_urls, show_urls_from_patterns
|
|
12
12
|
from .text import (
|
|
13
13
|
convert_from_camel,
|
|
14
14
|
convert_php_dateformat,
|
|
@@ -48,8 +48,10 @@ __all__ = [
|
|
|
48
48
|
"round_half_up",
|
|
49
49
|
"round_up",
|
|
50
50
|
"safe_allowed_chars",
|
|
51
|
+
"show_namespaces",
|
|
51
52
|
"show_url_names",
|
|
52
53
|
"show_urls",
|
|
54
|
+
"show_urls_from_patterns",
|
|
53
55
|
"to_local",
|
|
54
56
|
"to_utc",
|
|
55
57
|
"truncate_string",
|
edc_utils/show_urls.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# https://github.com/django-extensions/django-extensions/blob/master/django_extensions/management/commands/show_urls.py
|
|
3
3
|
|
|
4
4
|
from django.core.exceptions import ViewDoesNotExist
|
|
5
|
-
from django.urls import URLPattern, URLResolver
|
|
5
|
+
from django.urls import URLPattern, URLResolver, get_resolver
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class RegexURLPattern:
|
|
@@ -21,7 +21,26 @@ def describe_pattern(p):
|
|
|
21
21
|
return str(p.pattern)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def
|
|
24
|
+
def show_namespaces():
|
|
25
|
+
"""Returns a list of all registered URL namespaces."""
|
|
26
|
+
resolver = get_resolver()
|
|
27
|
+
return list(resolver.namespace_dict.keys())
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def show_urls():
|
|
31
|
+
"""Return a list of all URL patterns in the project."""
|
|
32
|
+
urls = []
|
|
33
|
+
resolver = get_resolver()
|
|
34
|
+
url_patterns = resolver.url_patterns
|
|
35
|
+
for pattern in url_patterns:
|
|
36
|
+
try:
|
|
37
|
+
urls.append(f"URL: {pattern.pattern} -> View: {pattern.callback.__name__}")
|
|
38
|
+
except AttributeError:
|
|
39
|
+
urls.append(f"URL: {pattern.pattern}")
|
|
40
|
+
return urls
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def show_urls_from_patterns(urlpatterns, base="", namespace=None, search=None):
|
|
25
44
|
urls = extract_views_from_urlpatterns(urlpatterns, base=base, namespace=namespace)
|
|
26
45
|
if search:
|
|
27
46
|
return [url[1] for url in urls if search in url[1]]
|
|
@@ -29,6 +48,14 @@ def show_urls(urlpatterns, base="", namespace=None, search=None):
|
|
|
29
48
|
|
|
30
49
|
|
|
31
50
|
def show_url_names(urlpatterns, base="", namespace=None, search=None):
|
|
51
|
+
"""Returns a list of url names.
|
|
52
|
+
|
|
53
|
+
For example:
|
|
54
|
+
resolver = get_resolver()
|
|
55
|
+
url_patterns = resolver.url_patterns
|
|
56
|
+
pprint(show_url_names(url_patterns))
|
|
57
|
+
"""
|
|
58
|
+
|
|
32
59
|
urls = extract_views_from_urlpatterns(urlpatterns, base=base, namespace=namespace)
|
|
33
60
|
if search:
|
|
34
61
|
return [url[2] for url in urls if search in url[2]]
|
edc_visit_schedule/auths.py
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
from edc_auth.constants import EVERYONE
|
|
2
2
|
from edc_auth.site_auths import site_auths
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
def update_site_auths() -> None:
|
|
6
|
+
site_auths.update_group("edc_visit_schedule.view_subjectschedulehistory", name=EVERYONE)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
update_site_auths()
|
|
@@ -163,10 +163,10 @@ class SiteVisitSchedules:
|
|
|
163
163
|
for schedule in visit_schedule.schedules.values():
|
|
164
164
|
try:
|
|
165
165
|
model_name = getattr(schedule, attr)
|
|
166
|
-
except (AttributeError, TypeError):
|
|
166
|
+
except (AttributeError, TypeError) as e:
|
|
167
167
|
raise SiteVisitScheduleError(
|
|
168
168
|
f"Invalid attr for Schedule. See {schedule}. Got {attr}."
|
|
169
|
-
)
|
|
169
|
+
) from e
|
|
170
170
|
if model_name and model_name == model:
|
|
171
171
|
ret.append([visit_schedule, schedule])
|
|
172
172
|
if not ret:
|
|
@@ -51,8 +51,8 @@ def subject_visit_missed_on_post_delete(sender, instance, using, **kwargs) -> No
|
|
|
51
51
|
instance.related_visit.reason = SCHEDULED
|
|
52
52
|
instance.related_visit.reason_unscheduled = NOT_APPLICABLE
|
|
53
53
|
instance.related_visit.info_source = PATIENT
|
|
54
|
-
instance.related_visit.info_source_other =
|
|
55
|
-
instance.related_visit.comment =
|
|
54
|
+
instance.related_visit.info_source_other = ""
|
|
55
|
+
instance.related_visit.comment = ""
|
|
56
56
|
instance.related_visit.modified = instance.modified
|
|
57
57
|
instance.related_visit.user_modified = instance.user_modified
|
|
58
58
|
instance.related_visit.save_base(
|
edc_form_label/models.py
DELETED
|
File without changes
|
edc_search/constants.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
SEARCH_SLUG_SEP = "|"
|
edc_search/models.py
DELETED
|
File without changes
|
edc_search/search_slug.py
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import sys
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
|
-
|
|
6
|
-
from django.apps import apps as django_apps
|
|
7
|
-
from django.core.management.color import color_style
|
|
8
|
-
from django.utils.text import slugify
|
|
9
|
-
from django_crypto_fields.fields import BaseField
|
|
10
|
-
|
|
11
|
-
from .constants import SEARCH_SLUG_SEP
|
|
12
|
-
|
|
13
|
-
style = color_style()
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from edc_model.models import BaseUuidModel
|
|
16
|
-
|
|
17
|
-
from .model_mixins import SearchSlugModelMixin
|
|
18
|
-
|
|
19
|
-
class Model(SearchSlugModelMixin, BaseUuidModel):
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class SearchSlug:
|
|
24
|
-
def __init__(
|
|
25
|
-
self, obj: Model | SearchSlugModelMixin = None, fields: tuple[str] | None = None
|
|
26
|
-
):
|
|
27
|
-
self.warning = None
|
|
28
|
-
self.slug = ""
|
|
29
|
-
self.model_cls = None
|
|
30
|
-
self.fields = None
|
|
31
|
-
if obj and fields:
|
|
32
|
-
self.model_cls = django_apps.get_model(obj._meta.label_lower)
|
|
33
|
-
self.fields = self.get_safe_fields(fields)
|
|
34
|
-
values = []
|
|
35
|
-
for field in fields:
|
|
36
|
-
value = obj
|
|
37
|
-
for f in field.split("."):
|
|
38
|
-
value = getattr(value, f)
|
|
39
|
-
values.append(value)
|
|
40
|
-
slugs = [slugify(item or "") for item in values]
|
|
41
|
-
slug = SEARCH_SLUG_SEP.join(slugs)
|
|
42
|
-
if len(slug) > 250:
|
|
43
|
-
self.warning = f"Warning! Search slug string exceeds 250 chars. See {obj!r}\n"
|
|
44
|
-
sys.stdout.write(style.WARNING(self.warning))
|
|
45
|
-
self.slug = slug[:250]
|
|
46
|
-
|
|
47
|
-
def get_safe_fields(self, fields) -> tuple[str]:
|
|
48
|
-
encrypted_fields = tuple(
|
|
49
|
-
[fld.name for fld in self.model_cls._meta.fields if isinstance(fld, BaseField)]
|
|
50
|
-
)
|
|
51
|
-
return tuple([f for f in fields if f not in encrypted_fields])
|
edc_search/updater.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
from .search_slug import SearchSlug
|
|
6
|
-
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from edc_model.models import BaseUuidModel
|
|
9
|
-
|
|
10
|
-
from .model_mixins import SearchSlugModelMixin
|
|
11
|
-
|
|
12
|
-
class Model(SearchSlugModelMixin, BaseUuidModel):
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class SearchSlugDuplicateFields(Exception): # noqa: N818
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class SearchSlugUpdater:
|
|
21
|
-
search_slug_cls = SearchSlug
|
|
22
|
-
|
|
23
|
-
def __init__(self, fields: tuple[str], model_obj: Model | SearchSlugModelMixin = None):
|
|
24
|
-
if len(fields) > len(list(set(fields))):
|
|
25
|
-
raise SearchSlugDuplicateFields(
|
|
26
|
-
f"Duplicate search slug fields detected. Got {fields}. See {self!r}"
|
|
27
|
-
)
|
|
28
|
-
search_slug = self.search_slug_cls(obj=model_obj, fields=fields)
|
|
29
|
-
self.warning = search_slug.warning
|
|
30
|
-
self.slug = search_slug.slug
|
edc_search/wsgi.py
DELETED
|
File without changes
|