From b67890d15d164c7affb2887e5737534628dc6227 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 29 Nov 2017 09:05:24 -0800 Subject: [PATCH] Auto-link column values that look like URLs Refs #153 --- datasette/app.py | 5 +++++ datasette/utils.py | 15 +++++++++++++++ tests/test_utils.py | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/datasette/app.py b/datasette/app.py index 82f2ddf2..397450f8 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -25,6 +25,7 @@ from .utils import ( escape_sqlite_table_name, filters_should_redirect, get_all_foreign_keys, + is_url, InvalidSql, path_from_row_pks, path_with_added_args, @@ -443,6 +444,10 @@ class RowTableShared(BaseView): ) elif value is None: display_value = jinja2.Markup(' ') + elif is_url(str(value).strip()): + display_value = jinja2.Markup( + '{url}'.format(url=value.strip()) + ) else: display_value = str(value) cells.append({ diff --git a/datasette/utils.py b/datasette/utils.py index e32d4f1f..2b567a05 100644 --- a/datasette/utils.py +++ b/datasette/utils.py @@ -441,3 +441,18 @@ def filters_should_redirect(special_args): ('_filter_value_{}'.format(number), None), ]) return redirect_params + + +whitespace_re = re.compile(r'\s') + + +def is_url(value): + "Must start with http:// or https:// and contain JUST a URL" + if not isinstance(value, str): + return False + if not value.startswith('http://') and not value.startswith('https://'): + return False + # Any whitespace at all is invalid + if whitespace_re.search(value): + return False + return True diff --git a/tests/test_utils.py b/tests/test_utils.py index b7645014..18ce0971 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -151,3 +151,13 @@ def test_detect_fts(): assert None is utils.detect_fts(conn, 'Dumb_Table') assert None is utils.detect_fts(conn, 'Test_View') assert 'Street_Tree_List_fts' == utils.detect_fts(conn, 'Street_Tree_List') + + +@pytest.mark.parametrize('url,expected', [ + ('http://www.google.com/', True), + ('https://example.com/', True), + ('www.google.com', False), + ('http://www.google.com/ is a search engine', False), +]) +def test_is_url(url, expected): + assert expected == utils.is_url(url)