mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
URLify URLs in custom SQL queries, closes #298
This commit is contained in:
parent
3955771fea
commit
581b4c97ee
3 changed files with 47 additions and 12 deletions
|
|
@ -26,7 +26,7 @@
|
||||||
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
||||||
|
|
||||||
<form class="sql" action="/{{ database }}-{{ database_hash }}{% if canned_query %}/{{ canned_query }}{% endif %}" method="get">
|
<form class="sql" action="/{{ database }}-{{ database_hash }}{% if canned_query %}/{{ canned_query }}{% endif %}" method="get">
|
||||||
<h3>Custom SQL query{% if rows %} returning {% if truncated %}more than {% endif %}{{ "{:,}".format(rows|length) }} row{% if rows|length == 1 %}{% else %}s{% endif %}{% endif %}</h3>
|
<h3>Custom SQL query{% if display_rows %} returning {% if truncated %}more than {% endif %}{{ "{:,}".format(display_rows|length) }} row{% if display_rows|length == 1 %}{% else %}s{% endif %}{% endif %}</h3>
|
||||||
{% if editable and config.allow_sql %}
|
{% if editable and config.allow_sql %}
|
||||||
<p><textarea name="sql">{% if query and query.sql %}{{ query.sql }}{% else %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}</textarea></p>
|
<p><textarea name="sql">{% if query and query.sql %}{{ query.sql }}{% else %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}</textarea></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
<p><input type="submit" value="Run SQL"></p>
|
<p><input type="submit" value="Run SQL"></p>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% if rows %}
|
{% if display_rows %}
|
||||||
<p class="export-links">This data as <a href="{{ url_json }}">JSON</a>, <a href="{{ url_csv }}">CSV</a></p>
|
<p class="export-links">This data as <a href="{{ url_json }}">JSON</a>, <a href="{{ url_csv }}">CSV</a></p>
|
||||||
<table class="rows-and-columns">
|
<table class="rows-and-columns">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for row in rows %}
|
{% for row in display_rows %}
|
||||||
<tr>
|
<tr>
|
||||||
{% for column, td in zip(columns, row) %}
|
{% for column, td in zip(columns, row) %}
|
||||||
<td class="col-{{ column|to_css_class }}">{% if td == None %}{{ " "|safe }}{% else %}{{ td }}{% endif %}</td>
|
<td class="col-{{ column|to_css_class }}">{% if td == None %}{{ " "|safe }}{% else %}{{ td }}{% endif %}</td>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import sqlite3
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
import jinja2
|
||||||
import pint
|
import pint
|
||||||
from sanic import response
|
from sanic import response
|
||||||
from sanic.exceptions import NotFound
|
from sanic.exceptions import NotFound
|
||||||
|
|
@ -17,6 +18,7 @@ from datasette.utils import (
|
||||||
InterruptedError,
|
InterruptedError,
|
||||||
InvalidSql,
|
InvalidSql,
|
||||||
LimitedWriter,
|
LimitedWriter,
|
||||||
|
is_url,
|
||||||
path_from_row_pks,
|
path_from_row_pks,
|
||||||
path_with_added_args,
|
path_with_added_args,
|
||||||
path_with_format,
|
path_with_format,
|
||||||
|
|
@ -485,21 +487,40 @@ class BaseView(RenderMixin):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def extra_template():
|
||||||
|
display_rows = []
|
||||||
|
for row in results.rows:
|
||||||
|
display_row = []
|
||||||
|
for value in row:
|
||||||
|
display_value = value
|
||||||
|
if value in ("", None):
|
||||||
|
display_value = jinja2.Markup(" ")
|
||||||
|
elif is_url(str(value).strip()):
|
||||||
|
display_value = jinja2.Markup(
|
||||||
|
'<a href="{url}">{url}</a>'.format(
|
||||||
|
url=jinja2.escape(value.strip())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
display_row.append(display_value)
|
||||||
|
display_rows.append(display_row)
|
||||||
|
return {
|
||||||
|
"display_rows": display_rows,
|
||||||
|
"database_hash": hash,
|
||||||
|
"custom_sql": True,
|
||||||
|
"named_parameter_values": named_parameter_values,
|
||||||
|
"editable": editable,
|
||||||
|
"canned_query": canned_query,
|
||||||
|
"metadata": metadata,
|
||||||
|
"config": self.ds.config,
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"database": name,
|
"database": name,
|
||||||
"rows": results.rows,
|
"rows": results.rows,
|
||||||
"truncated": results.truncated,
|
"truncated": results.truncated,
|
||||||
"columns": columns,
|
"columns": columns,
|
||||||
"query": {"sql": sql, "params": params},
|
"query": {"sql": sql, "params": params},
|
||||||
}, {
|
}, extra_template, templates
|
||||||
"database_hash": hash,
|
|
||||||
"custom_sql": True,
|
|
||||||
"named_parameter_values": named_parameter_values,
|
|
||||||
"editable": editable,
|
|
||||||
"canned_query": canned_query,
|
|
||||||
"metadata": metadata,
|
|
||||||
"config": self.ds.config,
|
|
||||||
}, templates
|
|
||||||
|
|
||||||
|
|
||||||
def convert_specific_columns_to_json(rows, columns, json_cols):
|
def convert_specific_columns_to_json(rows, columns, json_cols):
|
||||||
|
|
|
||||||
|
|
@ -793,3 +793,17 @@ def test_advanced_export_box(app_client, path, has_object, has_stream, has_expan
|
||||||
# "expand labels" option
|
# "expand labels" option
|
||||||
if has_expand:
|
if has_expand:
|
||||||
assert "expand labels" in str(div)
|
assert "expand labels" in str(div)
|
||||||
|
|
||||||
|
|
||||||
|
def test_urlify_custom_queries(app_client):
|
||||||
|
path = "/fixtures?" + urllib.parse.urlencode({
|
||||||
|
"sql": "select ('https://twitter.com/' || 'simonw') as user_url;"
|
||||||
|
})
|
||||||
|
response = app_client.get(path)
|
||||||
|
assert response.status == 200
|
||||||
|
soup = Soup(response.body, "html.parser")
|
||||||
|
assert '''<td class="col-user_url">
|
||||||
|
<a href="https://twitter.com/simonw">
|
||||||
|
https://twitter.com/simonw
|
||||||
|
</a>
|
||||||
|
</td>''' == soup.find("td", {"class": "col-user_url"}).prettify().strip()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue