Skip to content

Commit e481845

Browse files
Replace footer links with cfpb-link
1 parent e33c147 commit e481845

9 files changed

Lines changed: 259 additions & 248 deletions

File tree

.yarn/cache/@cfpb-cfpb-design-system-npm-5.7.0-2afd374dcd-0b7a50e91d.zip renamed to .yarn/cache/@cfpb-cfpb-design-system-npm-5.8.0-0f0a011bab-d50ad25928.zip

2.51 MB
Binary file not shown.

cfgov/core/middleware.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111

1212
from wagtail.rich_text import expand_db_html
1313

14-
from core.utils import add_link_markup, get_body_html, get_link_tags
14+
from core.utils import (
15+
add_cfpb_link_markup,
16+
add_link_markup,
17+
get_body_html,
18+
get_cfpb_link_tags,
19+
get_link_tags,
20+
)
1521

1622

1723
class DownstreamCacheControlMiddleware:
@@ -52,6 +58,12 @@ def parse_links(html, request_path=None, encoding=None):
5258
if tag_with_markup:
5359
expanded_html = expanded_html.replace(tag, tag_with_markup)
5460

61+
cfpb_link_tags = get_cfpb_link_tags(body_html)
62+
for tag in cfpb_link_tags:
63+
tag_with_markup = add_cfpb_link_markup(tag, request_path)
64+
if tag_with_markup:
65+
expanded_html = expanded_html.replace(tag, tag_with_markup)
66+
5567
return expanded_html
5668

5769

cfgov/core/tests/test_utils.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
ASK_CFPB_LINKS,
88
NON_CFPB_LINKS,
99
UNSAFE_CHARACTERS,
10+
add_cfpb_link_markup,
1011
add_link_markup,
1112
extract_answers_from_request,
1213
format_file_size,
1314
get_body_html,
15+
get_cfpb_link_tags,
1416
get_link_tags,
1517
make_safe,
1618
text_matches_href,
@@ -77,6 +79,61 @@ def test_format_file_size_terabytes(self):
7779
self.assertEqual(format_file_size(1024 * 9000000000), "8 TB")
7880

7981

82+
class CfpbLinkUtilsTests(SimpleTestCase):
83+
def test_get_cfpb_link_tags(self):
84+
self.assertEqual(
85+
get_cfpb_link_tags(
86+
'outer <cfpb-link><a href="">inner</a></cfpb-link>'
87+
),
88+
['<cfpb-link><a href="">inner</a></cfpb-link>'],
89+
)
90+
91+
def test_add_cfpb_link_markup_invalid(self):
92+
tag = "not a valid tag"
93+
path = "/about-us/blog/"
94+
self.assertIsNone(add_cfpb_link_markup(tag, path))
95+
96+
def test_add_cfpb_link_markup_anchor(self):
97+
tag = '<cfpb-link><a href="/about-us/blog/#anchor">bar</a></cfpb-link>'
98+
path = "/about-us/blog/"
99+
self.assertEqual(
100+
add_cfpb_link_markup(tag, path),
101+
'<cfpb-link><a href="#anchor">bar</a></cfpb-link>',
102+
)
103+
104+
def check_external_cfpb_link(self, url):
105+
tag = f'<cfpb-link><a href="{url}">foo</a></cfpb-link>'
106+
path = "/about-us/blog/"
107+
108+
expected_html = (
109+
'<cfpb-link link-variant="external>'
110+
f'<a href="{url}">foo</a></cfpb-link>'
111+
)
112+
expected_tag = BeautifulSoup(expected_html, "html.parser")
113+
114+
self.assertEqual(add_cfpb_link_markup(tag, path), str(expected_tag))
115+
116+
def check_download_cfpb_link(self, url):
117+
tag = f'<cfpb-link><a href="{url}">foo</a></cfpb-link>'
118+
path = "/about-us/blog/"
119+
120+
expected_html = (
121+
'<cfpb-link link-variant="download">'
122+
f'<a href="{url}">foo</a></cfpb-link>'
123+
)
124+
expected_tag = BeautifulSoup(expected_html, "html.parser")
125+
126+
self.assertEqual(add_cfpb_link_markup(tag, path), str(expected_tag))
127+
128+
def test_usa_gov(self):
129+
url = "https://www.usa.gov"
130+
self.check_external_cfpb_link(url)
131+
132+
def test_test_pdf(self):
133+
url = "test.pdf"
134+
self.check_download_cfpb_link(url)
135+
136+
80137
class LinkUtilsTests(SimpleTestCase):
81138
@classmethod
82139
def setUpClass(cls):
@@ -138,6 +195,12 @@ def test_get_link_tags_spacing(self):
138195
],
139196
)
140197

198+
def test_get_link_tags_does_not_match_wc(self):
199+
self.assertEqual(
200+
get_link_tags('outer <cfpb-link><a href="">inner</a></cfpb-link>'),
201+
[],
202+
)
203+
141204
def test_add_link_markup_invalid(self):
142205
tag = "not a valid tag"
143206
path = "/about-us/blog/"

cfgov/core/utils.py

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
# Match <a…>…</a>
6060
A_TAG_RE = re.compile(TAG_RE.format(tag_name="a"))
6161

62+
# Match <cfpb-link>…</cfpb-link>
63+
CFPB_LINK_TAG_RE = re.compile(TAG_RE.format(tag_name="cfpb-link"))
64+
6265
# If a link contains these elements, it should *not* get an icon
6366
ICONLESS_LINK_CHILD_ELEMENTS = [
6467
"img",
@@ -90,6 +93,8 @@
9093

9194
MAX_CHARS = 75
9295

96+
BEAUTIFUL_SOUP_PARSER = "html.parser"
97+
9398

9499
def make_safe(term):
95100
for char in UNSAFE_CHARACTERS:
@@ -128,7 +133,18 @@ def get_body_html(html):
128133

129134

130135
def get_link_tags(html):
131-
return A_TAG_RE.findall(html)
136+
without_components = re.sub(
137+
r"<cfpb-link\b[^>]*>.*?</cfpb-link>",
138+
"",
139+
html,
140+
flags=re.DOTALL | re.IGNORECASE,
141+
)
142+
links = A_TAG_RE.findall(without_components)
143+
return links
144+
145+
146+
def get_cfpb_link_tags(html):
147+
return CFPB_LINK_TAG_RE.findall(html)
132148

133149

134150
def text_matches_href(text, href):
@@ -177,6 +193,42 @@ def normalize(url):
177193
return normalize((text or "").strip()) == normalize((href or "").strip())
178194

179195

196+
def add_cfpb_link_markup(tag, request_path):
197+
"""Add necessary attributes to the given cfpb-link.
198+
199+
Return cfpb-link if modified.
200+
"""
201+
soup = BeautifulSoup(tag, BEAUTIFUL_SOUP_PARSER)
202+
tag = soup.find("cfpb-link")
203+
204+
if tag is None:
205+
return None
206+
207+
a_tag = tag.find("a")
208+
href = a_tag["href"]
209+
210+
if request_path is not None:
211+
# Strips the path of the current page from hrefs that are internal page
212+
# anchor links.
213+
# TODO: Remove that functionality when we get to Wagtail>=2.7, which
214+
# adds the ability to create anchor links.
215+
in_page_anchor_pattern = request_path + "#"
216+
if a_tag["href"].startswith(in_page_anchor_pattern):
217+
# Strip current path from in-page anchor links
218+
a_tag["href"] = href.replace(request_path, "")
219+
return str(tag)
220+
221+
if NON_CFPB_LINKS.match(href):
222+
# Sets the icon to indicate you're leaving consumerfinance.gov
223+
tag["link-variant"] = "external"
224+
225+
elif DOWNLOAD_LINKS.search(href):
226+
# Sets the icon to indicate you're downloading a file
227+
tag["link-variant"] = "download"
228+
229+
return str(tag)
230+
231+
180232
def add_link_markup(tag, request_path):
181233
"""Add necessary markup to the given link and return if modified.
182234
@@ -190,7 +242,7 @@ def add_link_markup(tag, request_path):
190242
"""
191243
icon = False
192244

193-
soup = BeautifulSoup(tag, "html.parser")
245+
soup = BeautifulSoup(tag, BEAUTIFUL_SOUP_PARSER)
194246
tag = soup.find("a", href=True)
195247

196248
if tag is None:
@@ -252,7 +304,7 @@ def add_link_markup(tag, request_path):
252304
icon_classes = {"class": LINK_ICON_TEXT_CLASSES}
253305
spans = tag.findAll("span", icon_classes)
254306

255-
icon_soup = BeautifulSoup(svg_icon(icon), "html.parser")
307+
icon_soup = BeautifulSoup(svg_icon(icon), BEAUTIFUL_SOUP_PARSER)
256308

257309
# If this is an <a class="a-btn"> tag without a span inside, we want to
258310
# add proper markup so that the link appears as a button with the icon on

0 commit comments

Comments
 (0)