diff --git a/network-api/networkapi/wagtailpages/fields.py b/network-api/networkapi/wagtailpages/fields.py index 6360be8cbf8..23455a9b15f 100644 --- a/network-api/networkapi/wagtailpages/fields.py +++ b/network-api/networkapi/wagtailpages/fields.py @@ -1,6 +1,39 @@ from django.db import models +class ExtendedBoolean(models.CharField): + """ + TODO: unify this with the ExtendedYesNoField below. Because this would + introduce a superclass hierarchy change, and Django is notoriously + bad at those, this is a separate task. + + See https://github.com/mozilla/foundation.mozilla.org/issues/6929 + """ + + description = "Yes, No, Unknown" + + choice_list = [ + ('Yes', 'Yes'), + ('No', 'No'), + ('U', 'Unknown'), + ] + + default_choice = 'U' + + def __init__(self, *args, **kwargs): + kwargs['choices'] = self.choice_list + kwargs['default'] = self.default_choice + kwargs['max_length'] = 3 + super().__init__(*args, **kwargs) + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + del kwargs['choices'] + del kwargs['default'] + del kwargs['max_length'] + return name, path, args, kwargs + + class ExtendedYesNoField(models.CharField): description = "Yes, No, Not Applicable, or Can’t Determine" diff --git a/network-api/networkapi/wagtailpages/migrations/0019_fix_software_fields_part_1.py b/network-api/networkapi/wagtailpages/migrations/0019_fix_software_fields_part_1.py new file mode 100644 index 00000000000..697a7467e39 --- /dev/null +++ b/network-api/networkapi/wagtailpages/migrations/0019_fix_software_fields_part_1.py @@ -0,0 +1,55 @@ +# Generated by Django 3.1.11 on 2021-06-23 21:40 + +from django.db import migrations +import networkapi.wagtailpages.fields + + +def update_software_product_fields(apps, schema_editor): + SoftwareProductPage = apps.get_model("wagtailpages", "SoftwareProductPage") + + # ExtendedBoolean is char(3), so the original boolean + # values True/False become the string values 'tru'/'fal'. + + for product in SoftwareProductPage.objects.all(): + if product.easy_to_learn_and_use == 'tru': + product.easy_to_learn_and_use = 'Yes' + + if product.easy_to_learn_and_use == 'fal': + product.easy_to_learn_and_use = 'No' + + if product.easy_to_learn_and_use == None: + product.easy_to_learn_and_use = 'U' + + if product.medical_privacy_compliant == 'tru': + product.medical_privacy_compliant = 'Yes' + + if product.medical_privacy_compliant == 'fal': + product.medical_privacy_compliant = 'No' + + if product.medical_privacy_compliant == None: + product.medical_privacy_compliant = 'U' + + product.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailpages', '0018_translation_mixin_migration_for_cta_models'), + ] + + operations = [ + migrations.AlterField( + model_name='softwareproductpage', + name='easy_to_learn_and_use', + field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Is it easy to learn & use the features?', null=True, default='U'), + ), + migrations.AlterField( + model_name='softwareproductpage', + name='medical_privacy_compliant', + field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Compliant with US medical privacy laws?', null=True, default='U'), + ), + migrations.RunPython( + code=update_software_product_fields + ), + ] diff --git a/network-api/networkapi/wagtailpages/migrations/0020_fix_software_fields_part_2.py b/network-api/networkapi/wagtailpages/migrations/0020_fix_software_fields_part_2.py new file mode 100644 index 00000000000..cdc867d1b69 --- /dev/null +++ b/network-api/networkapi/wagtailpages/migrations/0020_fix_software_fields_part_2.py @@ -0,0 +1,24 @@ +# Generated by Django 3.1.11 on 2021-06-23 22:05 + +from django.db import migrations +import networkapi.wagtailpages.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailpages', '0019_fix_software_fields_part_1'), + ] + + operations = [ + migrations.AlterField( + model_name='softwareproductpage', + name='easy_to_learn_and_use', + field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Is it easy to learn & use the features?'), + ), + migrations.AlterField( + model_name='softwareproductpage', + name='medical_privacy_compliant', + field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Compliant with US medical privacy laws?'), + ), + ] diff --git a/network-api/networkapi/wagtailpages/pagemodels/products.py b/network-api/networkapi/wagtailpages/pagemodels/products.py index 8c94dad7ecf..6cadf498563 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/products.py +++ b/network-api/networkapi/wagtailpages/pagemodels/products.py @@ -28,7 +28,7 @@ from wagtail_airtable.mixins import AirtableMixin -from networkapi.wagtailpages.fields import ExtendedYesNoField +from networkapi.wagtailpages.fields import ExtendedBoolean, ExtendedYesNoField from networkapi.wagtailpages.pagemodels.mixin.foundation_metadata import ( FoundationMetadataPageMixin ) @@ -898,11 +898,8 @@ class SoftwareProductPage(ProductPage): max_length=5000, blank=True ) - # NullBooleanField is deprecated as of Django 3.1. - # We're using it here primarily for a data migration, but we should - # move to BooleanField as soon as it's safe to do so with the content we have - medical_privacy_compliant = models.BooleanField( - null=True, + + medical_privacy_compliant = ExtendedBoolean( help_text='Compliant with US medical privacy laws?' ) @@ -917,11 +914,8 @@ class SoftwareProductPage(ProductPage): max_length=5000, blank=True ) - # NullBooleanField is deprecated as of Django 3.1. - # We're using it here primarily for a data migration, but we should - # move to BooleanField as soon as it's safe to do so with the content we have - easy_to_learn_and_use = models.BooleanField( - null=True, + + easy_to_learn_and_use = ExtendedBoolean( help_text='Is it easy to learn & use the features?', ) diff --git a/network-api/networkapi/wagtailpages/templates/fragments/software_product_privacy.html b/network-api/networkapi/wagtailpages/templates/fragments/software_product_privacy.html index b46b4836f7a..8afa89f0b3c 100644 --- a/network-api/networkapi/wagtailpages/templates/fragments/software_product_privacy.html +++ b/network-api/networkapi/wagtailpages/templates/fragments/software_product_privacy.html @@ -8,5 +8,5 @@ {% include "./product_criterion.html" with label=handles_recordings_how value=product.handles_recordings_how %} {% endif %} -{% include "./product_criterion.html" with label=recording_alert value=product.recording_alert|extended_yes_no help=product.recording_alert_helptext %} -{% include "./product_criterion.html" with label=medical_privacy_compliant value=product.medical_privacy_compliant|yes_no help=product.medical_privacy_compliant_helptext %} +{% include "./product_criterion.html" with label=recording_alert value=product.recording_alert|extended_yes_no help=product.recording_alert_helptext %} +{% include "./product_criterion.html" with label=medical_privacy_compliant value=product.medical_privacy_compliant|extended_boolean help=product.medical_privacy_compliant_helptext %} diff --git a/network-api/networkapi/wagtailpages/templatetags/bg_selector_tags.py b/network-api/networkapi/wagtailpages/templatetags/bg_selector_tags.py index 1c098bd2c22..e30608062ce 100644 --- a/network-api/networkapi/wagtailpages/templatetags/bg_selector_tags.py +++ b/network-api/networkapi/wagtailpages/templatetags/bg_selector_tags.py @@ -9,13 +9,22 @@ def yes_no(value): """Converts nullish boolean to yes or no string""" if value is False: return gettext('No') - if value is True: return gettext('Yes') - return gettext('Unknown') +@register.filter +def extended_boolean(value): + if value == 'Yes': + return gettext('Yes') + if value == 'No': + return gettext('No') + if value == 'U': + return gettext('Unknown') + return value + + @register.filter def extended_yes_no(value): """Converts quad-state to human readable string"""