truncate_cells_html now affects URLs too, refs #1805

This commit is contained in:
Simon Willison 2022-09-06 16:50:43 -07:00
commit d0737e4de5
8 changed files with 68 additions and 14 deletions

View file

@ -1167,3 +1167,13 @@ def resolve_routes(routes, path):
if match is not None:
return match, view
return None, None
def truncate_url(url, length):
if (not length) or (len(url) <= length):
return url
bits = url.rsplit(".", 1)
if len(bits) == 2 and 1 <= len(bits[1]) <= 4 and "/" not in bits[1]:
rest, ext = bits
return rest[: length - 1 - len(ext)] + "…." + ext
return url[: length - 1] + ""

View file

@ -20,6 +20,7 @@ from datasette.utils import (
path_with_format,
path_with_removed_args,
sqlite3,
truncate_url,
InvalidSql,
)
from datasette.utils.asgi import AsgiFileDownload, NotFound, Response, Forbidden
@ -371,6 +372,7 @@ class QueryView(DataView):
async def extra_template():
display_rows = []
truncate_cells = self.ds.setting("truncate_cells_html")
for row in results.rows if results else []:
display_row = []
for column, value in zip(results.columns, row):
@ -396,9 +398,12 @@ class QueryView(DataView):
if value in ("", None):
display_value = Markup("&nbsp;")
elif is_url(str(display_value).strip()):
display_value = Markup(
'<a href="{url}">{url}</a>'.format(
url=escape(value.strip())
display_value = markupsafe.Markup(
'<a href="{url}">{truncated_url}</a>'.format(
url=markupsafe.escape(value.strip()),
truncated_url=markupsafe.escape(
truncate_url(value.strip(), truncate_cells)
),
)
)
elif isinstance(display_value, bytes):

View file

@ -24,6 +24,7 @@ from datasette.utils import (
path_with_removed_args,
path_with_replaced_args,
to_css_class,
truncate_url,
urlsafe_components,
value_as_boolean,
)
@ -966,8 +967,11 @@ async def display_columns_and_rows(
display_value = markupsafe.Markup("&nbsp;")
elif is_url(str(value).strip()):
display_value = markupsafe.Markup(
'<a href="{url}">{url}</a>'.format(
url=markupsafe.escape(value.strip())
'<a href="{url}">{truncated_url}</a>'.format(
url=markupsafe.escape(value.strip()),
truncated_url=markupsafe.escape(
truncate_url(value.strip(), truncate_cells)
),
)
)
elif column in table_metadata.get("units", {}) and value != "":

View file

@ -598,23 +598,24 @@ CREATE TABLE roadside_attractions (
pk integer primary key,
name text,
address text,
url text,
latitude real,
longitude real
);
INSERT INTO roadside_attractions VALUES (
1, "The Mystery Spot", "465 Mystery Spot Road, Santa Cruz, CA 95065",
1, "The Mystery Spot", "465 Mystery Spot Road, Santa Cruz, CA 95065", "https://www.mysteryspot.com/",
37.0167, -122.0024
);
INSERT INTO roadside_attractions VALUES (
2, "Winchester Mystery House", "525 South Winchester Boulevard, San Jose, CA 95128",
2, "Winchester Mystery House", "525 South Winchester Boulevard, San Jose, CA 95128", "https://winchestermysteryhouse.com/",
37.3184, -121.9511
);
INSERT INTO roadside_attractions VALUES (
3, "Burlingame Museum of PEZ Memorabilia", "214 California Drive, Burlingame, CA 94010",
3, "Burlingame Museum of PEZ Memorabilia", "214 California Drive, Burlingame, CA 94010", null,
37.5793, -122.3442
);
INSERT INTO roadside_attractions VALUES (
4, "Bigfoot Discovery Museum", "5497 Highway 9, Felton, CA 95018",
4, "Bigfoot Discovery Museum", "5497 Highway 9, Felton, CA 95018", "https://www.bigfootdiscoveryproject.com/",
37.0414, -122.0725
);

View file

@ -339,7 +339,7 @@ def test_database_page(app_client):
},
{
"name": "roadside_attractions",
"columns": ["pk", "name", "address", "latitude", "longitude"],
"columns": ["pk", "name", "address", "url", "latitude", "longitude"],
"primary_keys": ["pk"],
"count": 4,
"hidden": False,

View file

@ -615,11 +615,12 @@ def test_table_through(app_client):
response = app_client.get(
'/fixtures/roadside_attractions.json?_through={"table":"roadside_attraction_characteristics","column":"characteristic_id","value":"1"}'
)
assert [
assert response.json["rows"] == [
[
3,
"Burlingame Museum of PEZ Memorabilia",
"214 California Drive, Burlingame, CA 94010",
None,
37.5793,
-122.3442,
],
@ -627,13 +628,15 @@ def test_table_through(app_client):
4,
"Bigfoot Discovery Museum",
"5497 Highway 9, Felton, CA 95018",
"https://www.bigfootdiscoveryproject.com/",
37.0414,
-122.0725,
],
] == response.json["rows"]
]
assert (
'where roadside_attraction_characteristics.characteristic_id = "1"'
== response.json["human_description_en"]
response.json["human_description_en"]
== 'where roadside_attraction_characteristics.characteristic_id = "1"'
)

View file

@ -69,6 +69,17 @@ def test_table_cell_truncation():
td.string
for td in table.findAll("td", {"class": "col-neighborhood-b352a7"})
]
# URLs should be truncated too
response2 = client.get("/fixtures/roadside_attractions")
assert response2.status == 200
table = Soup(response2.body, "html.parser").find("table")
tds = table.findAll("td", {"class": "col-url"})
assert [str(td) for td in tds] == [
'<td class="col-url type-str"><a href="https://www.mysteryspot.com/">http…</a></td>',
'<td class="col-url type-str"><a href="https://winchestermysteryhouse.com/">http…</a></td>',
'<td class="col-url type-none">\xa0</td>',
'<td class="col-url type-str"><a href="https://www.bigfootdiscoveryproject.com/">http…</a></td>',
]
def test_add_filter_redirects(app_client):

View file

@ -626,3 +626,23 @@ def test_tilde_encoding(original, expected):
assert actual == expected
# And test round-trip
assert original == utils.tilde_decode(actual)
@pytest.mark.parametrize(
"url,length,expected",
(
("https://example.com/", 5, "http…"),
("https://example.com/foo/bar", 15, "https://exampl…"),
("https://example.com/foo/bar/baz.jpg", 30, "https://example.com/foo/ba….jpg"),
# Extensions longer than 4 characters are not treated specially:
("https://example.com/foo/bar/baz.jpeg2", 30, "https://example.com/foo/bar/b…"),
(
"https://example.com/foo/bar/baz.jpeg2",
None,
"https://example.com/foo/bar/baz.jpeg2",
),
),
)
def test_truncate_url(url, length, expected):
actual = utils.truncate_url(url, length)
assert actual == expected