From 1ba75aeb25052bebbe5c33ef391aadbe495bd268 Mon Sep 17 00:00:00 2001 From: Martin Riese Date: Fri, 25 Oct 2024 13:26:59 -0500 Subject: [PATCH] Add field to choose filter source * Let user choose to filter conditional alert recipients by user data or user case properties * Store choice in database * Filter recipients accordingly --- corehq/messaging/scheduling/forms.py | 19 +++++++++++++++++++ .../messaging/scheduling/models/abstract.py | 4 ++++ .../scheduling_partitioned/models.py | 9 ++++++++- migrations.lock | 1 + 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/corehq/messaging/scheduling/forms.py b/corehq/messaging/scheduling/forms.py index d9a61a407f7e..eaf846c2ab91 100644 --- a/corehq/messaging/scheduling/forms.py +++ b/corehq/messaging/scheduling/forms.py @@ -55,6 +55,7 @@ from corehq.apps.groups.models import Group from corehq.apps.hqwebapp import crispy as hqcrispy from corehq.apps.hqwebapp.crispy import HQFormHelper +from corehq.apps.hqwebapp.widgets import SelectToggle from corehq.apps.locations.models import LocationType, SQLLocation from corehq.apps.reminders.util import ( get_combined_id, @@ -1344,6 +1345,18 @@ class ScheduleForm(Form): required=False, ) + use_user_case_for_filter_choices = [("false", "User Properties"), ("true", "User Case Properties")] + + use_user_case_for_filter = ChoiceField( + label=gettext_lazy("Filter on"), + required=False, + initial='ALL', + choices=use_user_case_for_filter_choices, + widget=SelectToggle( + choices=use_user_case_for_filter_choices, + ), + ) + user_data_property_name = TrimmedCharField( label=gettext_lazy("User data filter: property name"), required=False, @@ -1569,6 +1582,7 @@ def compute_initial(self, domain): result['use_user_data_filter'] = choice result['user_data_property_name'] = name result['user_data_property_value'] = value + result['use_user_case_for_filter'] = schedule.use_user_case_for_filter result['use_utc_as_default_timezone'] = schedule.use_utc_as_default_timezone if isinstance(schedule, AlertSchedule): @@ -2086,6 +2100,7 @@ def get_advanced_layout_fields(self): ), ), crispy.Div( + crispy.Field('use_user_case_for_filter'), crispy.Field('user_data_property_name'), crispy.Field('user_data_property_value'), data_bind="visible: use_user_data_filter() !== 'N'", @@ -2487,6 +2502,9 @@ def clean_occurrences(self): return validate_int(self.cleaned_data.get('occurrences'), 2) + def clean_use_user_case_for_filter(self): + return self.cleaned_data.get('use_user_case_for_filter') == 'true' + def clean_user_data_property_name(self): if self.cleaned_data.get('use_user_data_filter') == self.NO: return None @@ -2567,6 +2585,7 @@ def distill_extra_scheduling_options(self): 'location_type_filter': form_data['location_types'], 'use_utc_as_default_timezone': form_data['use_utc_as_default_timezone'], 'user_data_filter': self.distill_user_data_filter(), + 'use_user_case_for_filter': self.cleaned_data['use_user_case_for_filter'] } def distill_user_data_filter(self): diff --git a/corehq/messaging/scheduling/models/abstract.py b/corehq/messaging/scheduling/models/abstract.py index 0cb2c15cc67b..d3b8fe174cf6 100644 --- a/corehq/messaging/scheduling/models/abstract.py +++ b/corehq/messaging/scheduling/models/abstract.py @@ -92,6 +92,10 @@ class Schedule(models.Model): # type is android and whose nickname is either bob or jim. user_data_filter = jsonfield.JSONField(default=dict) + # If set to True, use the user case properties instead of the user properties + # to filter recipients + use_user_case_for_filter = models.BooleanField(default=False) + # Only applies when this Schedule is used with CaseAlertScheduleInstances or # CaseTimedScheduleInstances. # If null, this is ignored. Otherwise, it's the name of a case property which diff --git a/corehq/messaging/scheduling/scheduling_partitioned/models.py b/corehq/messaging/scheduling/scheduling_partitioned/models.py index 7d4b21615259..c6d4d6b93ca1 100644 --- a/corehq/messaging/scheduling/scheduling_partitioned/models.py +++ b/corehq/messaging/scheduling/scheduling_partitioned/models.py @@ -248,7 +248,14 @@ def passes_user_data_filter(self, contact): if not self.memoized_schedule.user_data_filter: return True - user_data = contact.get_user_data(self.domain) + if self.memoized_schedule.use_user_case_for_filter: + if contact.is_commcare_user(): + user_case = contact.memoized_usercase + else: + user_case = contact.get_usercase_by_domain(self.domain) + user_data = user_case.case_json + else: + user_data = contact.get_user_data(self.domain) for key, value in self.memoized_schedule.user_data_filter.items(): if key not in user_data: return False diff --git a/migrations.lock b/migrations.lock index 486b8e4fd0bf..645f072a0c2e 100644 --- a/migrations.lock +++ b/migrations.lock @@ -890,6 +890,7 @@ scheduling 0025_schedule_and_broadcast_deleted_on 0026_add_model_fcm_notification_content 0027_emailcontent_html_message + 0028_alertschedule_use_user_case_for_filter_and_more scheduling_partitioned 0001_initial 0002_case_schedule_instances