Repository: cal-itp/benefits

Issue:
Update EligiblityVerifier model to support custom text content
## Background

In #317, we identified a number of user-facing text elements on various pages during the Eligibility Verification process that must be configurable based on how the user is verifying their eligibility.

A straightforward way to represent these variable text elements is store them with the `EligibilityVerifier` model instances. We'll store the text that represents the `msgid` in a `.po` language file instead of storing the actual text content directly, to maintain the app's internationalization (see also #318).

While the lines of ownership for some text content can be blurred between `EligibilityType` and `EligibilityVerifier`, for now we'll store everything with the verifier for ease of management.

## Attributes to add

Consider this list to be a starting point based on an initial read of the new UI designs. Each of these should be added as a `TextField` to the [model class](https://github.com/cal-itp/benefits/blob/dev/benefits/core/models.py#L56), and we can just update the [initial migration](https://github.com/cal-itp/benefits/blob/dev/benefits/core/migrations/0001_initial.py) since most of the new fields can't be null and we'll just rebuild the database from scratch anyway.

* [x] `selection_label`: Shown when the user is selecting from a list of verifiers
* [x] `selection_label_description`: (optional) Additional helper text shown under the main label
* [x] `instructions_content_title`: The title shown on the instructions page for the verifier
* [x] `instructions_item_name`: The name given to the verification item needed
* [x] `instructions_item_description`: The description given to the verification item needed
* [x] `instructions_blurb`: The main text blurb shown on the instructions page
* [x] `form_title`: The title of the form page
* [x] `form_content_title`: The title of the form page's content
* [x] `form_blurb`: The main text blurb shown above the form
* [x] `form_sub_label`: The label for the `sub` field on the form
* [x] `form_sub_placeholder`: The placeholder for the `sub` field on the form
* [x] `form_name_label`: The label for the `name` field on the form
* [x] `form_name_placeholder`: The placeholder for the `name` field on the form
* [x] `unverified_title`: The title of the unverified page
* [x] `unverified_content_title`: The title of the unverified page's content
* [x] `unverified_blurb`: The main text blurb shown on the unverified page

## Additional tasks

* [x] Update fixtures with new model attributes, and copy in the corresponding `msgid` from the `*.po` files


Discussion:

Resolving patch:
diff --git a/benefits/core/migrations/0001_initial.py b/benefits/core/migrations/0001_initial.py
--- a/benefits/core/migrations/0001_initial.py
+++ b/benefits/core/migrations/0001_initial.py
@@ -34,14 +34,30 @@ class Migration(migrations.Migration):
                 ("api_auth_header", models.TextField()),
                 ("api_auth_key", models.TextField()),
                 # fmt: off
-                ("sub_regex", models.TextField(help_text="A regular expression used to validate the 'sub' API field before sending to this verifier", null=True)),  # noqa: E501
-                ("name_max_length", models.PositiveSmallIntegerField(help_text="The maximum length accepted for the 'name' API field before sending to this verifier", null=True)),  # noqa: E501
+                ("form_sub_pattern", models.TextField(help_text="A regular expression used to validate the 'sub' API field before sending to this verifier", null=True)),  # noqa: E501
+                ("form_name_max_length", models.PositiveSmallIntegerField(help_text="The maximum length accepted for the 'name' API field before sending to this verifier", null=True)),  # noqa: E501
                 ("public_key", models.ForeignKey(help_text="The Verifier's public key, used to encrypt requests targeted at this Verifier and to verify signed responses from this verifier.", on_delete=models.deletion.PROTECT, related_name="+", to="core.PemData")),  # noqa: E501
                 ("jwe_cek_enc", models.TextField(help_text="The JWE-compatible Content Encryption Key (CEK) key-length and mode")),  # noqa: E501
                 ("jwe_encryption_alg", models.TextField(help_text="The JWE-compatible encryption algorithm")),
                 # fmt: on
                 ("jws_signing_alg", models.TextField(help_text="The JWS-compatible signing algorithm")),
                 ("eligibility_types", models.ManyToManyField(to="core.EligibilityType")),
+                ("selection_label", models.TextField()),
+                ("selection_label_description", models.TextField(null=True)),
+                ("instructions_content_title", models.TextField()),
+                ("instructions_item_name", models.TextField()),
+                ("instructions_item_description", models.TextField()),
+                ("instructions_blurb", models.TextField()),
+                ("form_title", models.TextField()),
+                ("form_content_title", models.TextField()),
+                ("form_blurb", models.TextField()),
+                ("form_sub_label", models.TextField()),
+                ("form_sub_placeholder", models.TextField()),
+                ("form_name_label", models.TextField()),
+                ("form_name_placeholder", models.TextField()),
+                ("unverified_title", models.TextField()),
+                ("unverified_content_title", models.TextField()),
+                ("unverified_blurb", models.TextField()),
             ],
         ),
         migrations.CreateModel(
diff --git a/benefits/core/models.py b/benefits/core/models.py
--- a/benefits/core/models.py
+++ b/benefits/core/models.py
@@ -67,8 +67,24 @@ class EligibilityVerifier(models.Model):
     jwe_cek_enc = models.TextField(help_text="The JWE-compatible Content Encryption Key (CEK) key-length and mode")
     jwe_encryption_alg = models.TextField(help_text="The JWE-compatible encryption algorithm")
     jws_signing_alg = models.TextField(help_text="The JWS-compatible signing algorithm")
-    sub_regex = models.TextField(null=True, help_text="A regular expression used to validate the 'sub' API field before sending to this verifier")  # noqa: 503
-    name_max_length = models.PositiveSmallIntegerField(null=True, help_text="The maximum length accepted for the 'name' API field before sending to this verifier")  # noqa: 503
+    selection_label = models.TextField()
+    selection_label_description = models.TextField(null=True)
+    instructions_content_title = models.TextField()
+    instructions_item_name = models.TextField()
+    instructions_item_description = models.TextField()
+    instructions_blurb = models.TextField()
+    form_title = models.TextField()
+    form_content_title = models.TextField()
+    form_blurb = models.TextField()
+    form_sub_label = models.TextField()
+    form_sub_placeholder = models.TextField()
+    form_sub_pattern = models.TextField(null=True, help_text="A regular expression used to validate the 'sub' API field before sending to this verifier")  # noqa: 503
+    form_name_label = models.TextField()
+    form_name_placeholder = models.TextField()
+    form_name_max_length = models.PositiveSmallIntegerField(null=True, help_text="The maximum length accepted for the 'name' API field before sending to this verifier")  # noqa: 503
+    unverified_title = models.TextField()
+    unverified_content_title = models.TextField()
+    unverified_blurb = models.TextField()
     # fmt: on
 
     def __str__(self):


Test patch: