Skip to content

Commit

Permalink
Merge pull request #8378 from cfpb/tccp/detail-jinja
Browse files Browse the repository at this point in the history
TCCP: Render card contact info using Python
  • Loading branch information
chosak authored May 8, 2024
2 parents 043a2c0 + c694921 commit fdf5a92
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 31 deletions.
31 changes: 3 additions & 28 deletions cfgov/tccp/jinja2/tccp/card.html
Original file line number Diff line number Diff line change
Expand Up @@ -132,34 +132,9 @@ <h1>{{ card.product_name }}</h1>
</ul>
{% endif %}
</div>
<div class="o-contact-info">
{% if card.website_for_consumer %}
{# Some issuers submitted more than one URL for a card, always
separated by a space. To catch those, we'll make a list and
render a link for each URL. #}
{% set urls = card.website_for_consumer.split() %}
{% for url in urls %}
{# TODO: Make this into a custom filter instead of rpartition #}
{% with value = {
"url": url,
"text": url.rpartition("//")[-1].partition("/")[0]
| replace('www.', '')}
%}
{% include "v1/includes/molecules/contact-hyperlink.html" %}
{% endwith %}
{% endfor %}
{% endif %}
{% if card.telephone_number_for_consumers %}
{# TODO: Make this into a custom filter instead of this terribleness #}
{% set phone_number = card.telephone_number_for_consumers | replace('-', '') | replace('(', '') | replace(')', '') | replace(' ', '') %}
{% if phone_number.startswith('1') %}
{% set phone_number = phone_number[1:] %}
{% endif %}
{% with value = {"phones": [{"number": phone_number}]} %}
{% include "v1/includes/molecules/contact-phone.html" %}
{% endwith %}
{% endif %}
</div>

{{ render_contact_info(card) }}

{% if not card.top_25_institution %}
<div class="u-mt30">
{# TODO: Maybe unify this content with the card list version? #}
Expand Down
13 changes: 13 additions & 0 deletions cfgov/tccp/jinja2/tccp/includes/contact_info.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% if urls or phone_numbers -%}
<div class="o-contact-info">
{% for value in urls %}
{%- include "v1/includes/molecules/contact-hyperlink.html" -%}
{% endfor %}

{% for phone_number in phone_numbers %}
{% with value = {"phones": [{"number": phone_number}]} %}
{%- include "v1/includes/molecules/contact-phone.html" -%}
{% endwith %}
{%- endfor %}
</div>
{%- endif %}
61 changes: 61 additions & 0 deletions cfgov/tccp/jinja2tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import re
from urllib.parse import urlparse

from django.template.loader import render_to_string
from django.utils.safestring import mark_safe


# Contact website schemes must be either http or https.
_valid_website_scheme = re.compile(r"https?")


# Contact website hosts must have at least one . in them.
_valid_website_netloc = re.compile(r".+\..+")


# We strip www. from the beginning of displayed URLs.
_leading_www = re.compile(r"^www\.")


def _format_contact_website(url):
parsed_url = urlparse(url)

if _valid_website_scheme.match(
parsed_url.scheme or ""
) and _valid_website_netloc.match(parsed_url.netloc or ""):
return {"url": url, "text": _leading_www.sub("", parsed_url.netloc)}
else:
return {
"text": url,
}


def _format_contact_phone_number(phone_number):
phone_number = "".join(
c for c in phone_number if c.isalpha() or c.isdigit()
)
return phone_number[phone_number.startswith("1") :]


def _format_contact_info(card):
def fmt_list(format_fn, value):
return list(map(format_fn, (value or "").split()))

return {
"urls": fmt_list(
_format_contact_website, card["website_for_consumer"]
),
"phone_numbers": fmt_list(
_format_contact_phone_number,
card["telephone_number_for_consumers"],
),
}


def render_contact_info(card):
return mark_safe(
render_to_string(
"tccp/includes/contact_info.html",
_format_contact_info(card),
)
)
85 changes: 85 additions & 0 deletions cfgov/tccp/tests/test_jinja2tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import re

from django.test import SimpleTestCase

from tccp.jinja2tags import (
_format_contact_phone_number,
_format_contact_website,
render_contact_info,
)


class FormatContactPhoneNumberTests(SimpleTestCase):
def test_phone_number_formatting(self):
for value, expected in [
("FOOBAR", "FOOBAR"),
("888-FOO-BAR", "888FOOBAR"),
("18885551234", "8885551234"),
("(800) 555-1234", "8005551234"),
]:
with self.subTest(value=value, expected=expected):
self.assertEqual(_format_contact_phone_number(value), expected)


class FormatContactWebsiteTests(SimpleTestCase):
def test_website_formatting(self):
for value, expected in [
(
"http://example.com",
{"text": "example.com", "url": "http://example.com"},
),
(
"https://example.com",
{"text": "example.com", "url": "https://example.com"},
),
(
"https://www.example.com",
{
"text": "example.com",
"url": "https://www.example.com",
},
),
(
"https://subdomain.example.com",
{
"text": "subdomain.example.com",
"url": "https://subdomain.example.com",
},
),
(
"https://example.com/path/",
{
"text": "example.com",
"url": "https://example.com/path/",
},
),
(
"invalid://example.com",
{
"text": "invalid://example.com",
},
),
(
"example.com",
{
"text": "example.com",
},
),
]:
with self.subTest(value=value, expected=expected):
self.assertEqual(_format_contact_website(value), expected)


class TestRenderContactInfo(SimpleTestCase):
def test_render(self):
html = render_contact_info(
{
"website_for_consumer": "https://example.com foo.com",
"telephone_number_for_consumers": "212-555-1234",
}
)

self.assertEqual(len(re.findall("m-contact-hyperlink", html)), 2)
self.assertIn('<a href="https://example.com">', html)
self.assertNotIn('<a href="foo.com">', html)
self.assertEqual(len(re.findall("m-contact-phone", html)), 1)
2 changes: 2 additions & 0 deletions cfgov/tccp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from .filter_backend import CardSurveyDataFilterBackend
from .filterset import CardSurveyDataFilterSet
from .forms import LandingPageForm
from .jinja2tags import render_contact_info
from .models import CardSurveyData
from .serializers import CardSurveyDataListSerializer, CardSurveyDataSerializer
from .situations import Situation, SituationFeatures, SituationSpeedBumps
Expand Down Expand Up @@ -232,6 +233,7 @@ def retrieve(self, request, *args, **kwargs):
"apr_rating_lookup": dict(enums.PurchaseAPRRatings),
"state_lookup": dict(enums.StateChoices),
"rewards_lookup": dict(enums.RewardsChoices),
"render_contact_info": render_contact_info,
}
)

Expand Down
6 changes: 3 additions & 3 deletions cfgov/v1/jinja2/v1/includes/molecules/contact-hyperlink.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
Web
</span>
<p>
<a href="{{ value.url }}">
{{ value.text | default( value.url, true ) }}
</a>
{% if value.url %}<a href="{{ value.url }}">{% endif %}
{{- value.text | default( value.url, true ) -}}
{% if value.url %}</a>{% endif %}
</p>
</div>

0 comments on commit fdf5a92

Please sign in to comment.