mirror of
https://github.com/simonw/datasette.git
synced 2026-05-31 14:16:59 +02:00
Fix remaining base_url issues
This commit is contained in:
parent
d657fb4315
commit
1558ab7989
6 changed files with 85 additions and 56 deletions
|
|
@ -2870,19 +2870,22 @@ def wrap_view_function(view_fn, datasette):
|
|||
|
||||
|
||||
def permanent_redirect(path, forward_query_string=False, forward_rest=False):
|
||||
return wrap_view(
|
||||
lambda request, send: Response.redirect(
|
||||
def view(request, send):
|
||||
redirect_path = (
|
||||
path
|
||||
+ (request.url_vars["rest"] if forward_rest else "")
|
||||
+ (
|
||||
("?" + request.query_string)
|
||||
if forward_query_string and request.query_string
|
||||
else ""
|
||||
),
|
||||
status=301,
|
||||
),
|
||||
datasette=None,
|
||||
)
|
||||
)
|
||||
)
|
||||
route_path = request.scope.get("route_path")
|
||||
if route_path and request.path.endswith(route_path):
|
||||
redirect_path = request.path[: -len(route_path)] + redirect_path
|
||||
return Response.redirect(redirect_path, status=301)
|
||||
|
||||
return wrap_view(view, datasette=None)
|
||||
|
||||
|
||||
_curly_re = re.compile(r"({.*?})")
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
</p>
|
||||
<details open style="border: 2px solid #ccc; border-bottom: none; padding: 0.5em">
|
||||
<summary style="cursor: pointer;">GET</summary>
|
||||
<form class="core" method="get" id="api-explorer-get" style="margin-top: 0.7em">
|
||||
<form class="core" method="get" action="{{ urls.path('-/api') }}" id="api-explorer-get" style="margin-top: 0.7em">
|
||||
<div>
|
||||
<label for="path">API path:</label>
|
||||
<input type="text" id="path" name="path" style="width: 60%">
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
</details>
|
||||
<details style="border: 2px solid #ccc; padding: 0.5em">
|
||||
<summary style="cursor: pointer">POST</summary>
|
||||
<form class="core" method="post" id="api-explorer-post" style="margin-top: 0.7em">
|
||||
<form class="core" method="post" action="{{ urls.path('-/api') }}" id="api-explorer-post" style="margin-top: 0.7em">
|
||||
<div>
|
||||
<label for="path">API path:</label>
|
||||
<input type="text" id="path" name="path" style="width: 60%">
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<header class="hd"><nav>
|
||||
<p class="crumbs">
|
||||
<a href="/">home</a>
|
||||
<a href="{{ base_url }}">home</a>
|
||||
</p>
|
||||
<details class="nav-menu details-menu">
|
||||
<summary><svg aria-labelledby="nav-menu-svg-title" role="img"
|
||||
|
|
@ -22,11 +22,11 @@
|
|||
</svg></summary>
|
||||
<div class="nav-menu-inner">
|
||||
<ul>
|
||||
<li><a href="/-/databases">Databases</a></li>
|
||||
<li><a href="/-/plugins">Installed plugins</a></li>
|
||||
<li><a href="/-/versions">Version info</a></li>
|
||||
<li><a href="{{ base_url }}-/databases">Databases</a></li>
|
||||
<li><a href="{{ base_url }}-/plugins">Installed plugins</a></li>
|
||||
<li><a href="{{ base_url }}-/versions">Version info</a></li>
|
||||
</ul>
|
||||
<form class="nav-menu-logout" action="/-/logout" method="post">
|
||||
<form class="nav-menu-logout" action="{{ base_url }}-/logout" method="post">
|
||||
<button class="button-as-link">Log out</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -48,9 +48,9 @@
|
|||
<header class="hd">
|
||||
<nav>
|
||||
<p class="crumbs">
|
||||
<a href="/">home</a> /
|
||||
<a href="/fixtures">fixtures</a> /
|
||||
<a href="/fixtures/attraction_characteristic">attraction_characteristic</a>
|
||||
<a href="{{ base_url }}">home</a> /
|
||||
<a href="{{ base_url }}fixtures">fixtures</a> /
|
||||
<a href="{{ base_url }}fixtures/attraction_characteristic">attraction_characteristic</a>
|
||||
</p>
|
||||
<div class="actor">
|
||||
<strong>testuser</strong>
|
||||
|
|
@ -80,16 +80,16 @@
|
|||
<a href="https://github.com/simonw/datasette">
|
||||
About Datasette</a>
|
||||
</p>
|
||||
<h2 style="padding-left: 10px; border-left: 10px solid #9403e5"><a href="/fixtures">fixtures</a></h2>
|
||||
<h2 style="padding-left: 10px; border-left: 10px solid #9403e5"><a href="{{ base_url }}fixtures">fixtures</a></h2>
|
||||
<p>
|
||||
1,258 rows in 24 tables, 206 rows in 5 hidden tables, 4 views
|
||||
</p>
|
||||
<p><a href="/fixtures/compound_three_primary_keys" title="1001 rows">compound_three_primary_keys</a>, <a href="/fixtures/sortable" title="201 rows">sortable</a>, <a href="/fixtures/facetable" title="15 rows">facetable</a>, <a href="/fixtures/roadside_attraction_characteristics" title="5 rows">roadside_attraction_characteristics</a>, <a href="/fixtures/simple_primary_key" title="4 rows">simple_primary_key</a>, <a href="/fixtures">...</a></p>
|
||||
<h2 style="padding-left: 10px; border-left: 10px solid #8d777f"><a href="/data">data</a></h2>
|
||||
<p><a href="{{ base_url }}fixtures/compound_three_primary_keys" title="1001 rows">compound_three_primary_keys</a>, <a href="{{ base_url }}fixtures/sortable" title="201 rows">sortable</a>, <a href="{{ base_url }}fixtures/facetable" title="15 rows">facetable</a>, <a href="{{ base_url }}fixtures/roadside_attraction_characteristics" title="5 rows">roadside_attraction_characteristics</a>, <a href="{{ base_url }}fixtures/simple_primary_key" title="4 rows">simple_primary_key</a>, <a href="{{ base_url }}fixtures">...</a></p>
|
||||
<h2 style="padding-left: 10px; border-left: 10px solid #8d777f"><a href="{{ base_url }}data">data</a></h2>
|
||||
<p>
|
||||
6 rows in 2 tables
|
||||
</p>
|
||||
<p><a href="/data/names" title="6 rows">names</a>, <a href="/data/foo">foo</a></p>
|
||||
<p><a href="{{ base_url }}data/names" title="6 rows">names</a>, <a href="{{ base_url }}data/foo">foo</a></p>
|
||||
</section>
|
||||
|
||||
<h2 class="pattern-heading">.bd for /database</h2>
|
||||
|
|
@ -134,7 +134,7 @@
|
|||
<a href="https://github.com/simonw/datasette">
|
||||
About Datasette</a>
|
||||
</p>
|
||||
<form class="sql" action="/fixtures" method="get">
|
||||
<form class="sql" action="{{ base_url }}fixtures" method="get">
|
||||
<h3>Custom SQL query</h3>
|
||||
<p><textarea id="sql-editor" name="sql">select * from [123_starts_with_digits]</textarea></p>
|
||||
<p>
|
||||
|
|
@ -143,17 +143,17 @@
|
|||
</p>
|
||||
</form>
|
||||
<div class="db-table">
|
||||
<h2><a href="/fixtures/123_starts_with_digits">123_starts_with_digits</a></h2>
|
||||
<h2><a href="{{ base_url }}fixtures/123_starts_with_digits">123_starts_with_digits</a></h2>
|
||||
<p><em>content</em></p>
|
||||
<p>0 rows</p>
|
||||
</div>
|
||||
<div class="db-table">
|
||||
<h2><a href="/fixtures/Table+With+Space+In+Name">Table With Space In Name</a></h2>
|
||||
<h2><a href="{{ base_url }}fixtures/Table+With+Space+In+Name">Table With Space In Name</a></h2>
|
||||
<p><em>pk, content</em></p>
|
||||
<p>0 rows</p>
|
||||
</div>
|
||||
<div class="db-table">
|
||||
<h2><a href="/fixtures/attraction_characteristic">attraction_characteristic</a></h2>
|
||||
<h2><a href="{{ base_url }}fixtures/attraction_characteristic">attraction_characteristic</a></h2>
|
||||
<p><em>pk, name</em></p>
|
||||
<p>2 rows</p>
|
||||
</div>
|
||||
|
|
@ -202,7 +202,7 @@
|
|||
<h3>3 rows
|
||||
where characteristic_id = 2
|
||||
</h3>
|
||||
<form class="filters" action="/fixtures/roadside_attraction_characteristics" method="get">
|
||||
<form class="filters" action="{{ base_url }}fixtures/roadside_attraction_characteristics" method="get">
|
||||
<div class="search-row"><label for="_search">Search:</label><input id="_search" type="search" name="_search" value=""></div>
|
||||
<div class="filter-row">
|
||||
<div class="select-wrapper">
|
||||
|
|
@ -290,16 +290,16 @@
|
|||
<h3>2 extra where clauses</h3>
|
||||
<ul>
|
||||
|
||||
<li><code>planet_int=1</code> [<a href="/fixtures/facetable?_where=state%3D%27CA%27">remove</a>]</li>
|
||||
<li><code>planet_int=1</code> [<a href="{{ base_url }}fixtures/facetable?_where=state%3D%27CA%27">remove</a>]</li>
|
||||
|
||||
<li><code>state='CA'</code> [<a href="/fixtures/facetable?_where=planet_int%3D1">remove</a>]</li>
|
||||
<li><code>state='CA'</code> [<a href="{{ base_url }}fixtures/facetable?_where=planet_int%3D1">remove</a>]</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p><a class="not-underlined" title="select rowid, attraction_id, characteristic_id from roadside_attraction_characteristics where "characteristic_id" = :p0 order by rowid limit 101" href="/fixtures?sql=select+rowid%2C+attraction_id%2C+characteristic_id+from+roadside_attraction_characteristics+where+%22characteristic_id%22+%3D+%3Ap0+order+by+rowid+limit+101&p0=2">✎ <span class="underlined">View and edit SQL</span></a></p>
|
||||
<p><a class="not-underlined" title="select rowid, attraction_id, characteristic_id from roadside_attraction_characteristics where "characteristic_id" = :p0 order by rowid limit 101" href="{{ base_url }}fixtures?sql=select+rowid%2C+attraction_id%2C+characteristic_id+from+roadside_attraction_characteristics+where+%22characteristic_id%22+%3D+%3Ap0+order+by+rowid+limit+101&p0=2">✎ <span class="underlined">View and edit SQL</span></a></p>
|
||||
|
||||
<p class="export-links">This data as <a href="/fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on">json</a>, <a href="/fixtures/roadside_attraction_characteristics.csv?characteristic_id=2&_labels=on&_size=max">CSV</a> (<a href="#export">advanced</a>)</p>
|
||||
<p class="export-links">This data as <a href="{{ base_url }}fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on">json</a>, <a href="{{ base_url }}fixtures/roadside_attraction_characteristics.csv?characteristic_id=2&_labels=on&_size=max">CSV</a> (<a href="#export">advanced</a>)</p>
|
||||
|
||||
<p class="suggested-facets">
|
||||
Suggested facets: <a href="http://latest.datasette.io/fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=city_id&_facet=created&_facet=complex_array&_facet=tags#facet-tags">tags</a>, <a href="http://latest.datasette.io/fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=city_id&_facet=created&_facet=complex_array&_facet_date=created#facet-created">created</a> (date), <a href="http://latest.datasette.io/fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=city_id&_facet=created&_facet=complex_array&_facet_array=tags#facet-tags">tags</a> (array)
|
||||
|
|
@ -311,7 +311,7 @@
|
|||
<p class="facet-info-name">
|
||||
<strong>tags (array)</strong>
|
||||
|
||||
<a href="/fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=city_id&_facet=created" class="cross">✖</a>
|
||||
<a href="{{ base_url }}fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=city_id&_facet=created" class="cross">✖</a>
|
||||
|
||||
</p>
|
||||
<ul>
|
||||
|
|
@ -336,7 +336,7 @@
|
|||
<p class="facet-info-name">
|
||||
<strong>created</strong>
|
||||
|
||||
<a href="/fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=city_id&_facet_array=tags" class="cross">✖</a>
|
||||
<a href="{{ base_url }}fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=city_id&_facet_array=tags" class="cross">✖</a>
|
||||
|
||||
</p>
|
||||
<ul>
|
||||
|
|
@ -361,7 +361,7 @@
|
|||
<p class="facet-info-name">
|
||||
<strong>city_id</strong>
|
||||
|
||||
<a href="/fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=created&_facet_array=tags" class="cross">✖</a>
|
||||
<a href="{{ base_url }}fixtures/facetable?_where=planet_int%3D1&_where=state%3D%27CA%27&_facet=created&_facet_array=tags" class="cross">✖</a>
|
||||
|
||||
</p>
|
||||
<ul>
|
||||
|
|
@ -387,45 +387,45 @@
|
|||
Link
|
||||
</th>
|
||||
<th class="col-rowid" scope="col">
|
||||
<a href="/fixtures/roadside_attraction_characteristics?characteristic_id=2&_sort_desc=rowid" rel="nofollow">rowid ▼</a>
|
||||
<a href="{{ base_url }}fixtures/roadside_attraction_characteristics?characteristic_id=2&_sort_desc=rowid" rel="nofollow">rowid ▼</a>
|
||||
</th>
|
||||
<th class="col-attraction_id" scope="col">
|
||||
<a href="/fixtures/roadside_attraction_characteristics?characteristic_id=2&_sort=attraction_id" rel="nofollow">attraction_id</a>
|
||||
<a href="{{ base_url }}fixtures/roadside_attraction_characteristics?characteristic_id=2&_sort=attraction_id" rel="nofollow">attraction_id</a>
|
||||
</th>
|
||||
<th class="col-characteristic_id" scope="col">
|
||||
<a href="/fixtures/roadside_attraction_characteristics?characteristic_id=2&_sort=characteristic_id" rel="nofollow">characteristic_id</a>
|
||||
<a href="{{ base_url }}fixtures/roadside_attraction_characteristics?characteristic_id=2&_sort=characteristic_id" rel="nofollow">characteristic_id</a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="col-Link"><a href="/fixtures/roadside_attraction_characteristics/1">1</a></td>
|
||||
<td class="col-Link"><a href="{{ base_url }}fixtures/roadside_attraction_characteristics/1">1</a></td>
|
||||
<td class="col-rowid">1</td>
|
||||
<td class="col-attraction_id"><a href="/fixtures/roadside_attractions/1">The Mystery Spot</a> <em>1</em></td>
|
||||
<td class="col-characteristic_id"><a href="/fixtures/attraction_characteristic/2">Paranormal</a> <em>2</em></td>
|
||||
<td class="col-attraction_id"><a href="{{ base_url }}fixtures/roadside_attractions/1">The Mystery Spot</a> <em>1</em></td>
|
||||
<td class="col-characteristic_id"><a href="{{ base_url }}fixtures/attraction_characteristic/2">Paranormal</a> <em>2</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="col-Link"><a href="/fixtures/roadside_attraction_characteristics/2">2</a></td>
|
||||
<td class="col-Link"><a href="{{ base_url }}fixtures/roadside_attraction_characteristics/2">2</a></td>
|
||||
<td class="col-rowid">2</td>
|
||||
<td class="col-attraction_id"><a href="/fixtures/roadside_attractions/2">Winchester Mystery House</a> <em>2</em></td>
|
||||
<td class="col-characteristic_id"><a href="/fixtures/attraction_characteristic/2">Paranormal</a> <em>2</em></td>
|
||||
<td class="col-attraction_id"><a href="{{ base_url }}fixtures/roadside_attractions/2">Winchester Mystery House</a> <em>2</em></td>
|
||||
<td class="col-characteristic_id"><a href="{{ base_url }}fixtures/attraction_characteristic/2">Paranormal</a> <em>2</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="col-Link"><a href="/fixtures/roadside_attraction_characteristics/3">3</a></td>
|
||||
<td class="col-Link"><a href="{{ base_url }}fixtures/roadside_attraction_characteristics/3">3</a></td>
|
||||
<td class="col-rowid">3</td>
|
||||
<td class="col-attraction_id"><a href="/fixtures/roadside_attractions/4">Bigfoot Discovery Museum</a> <em>4</em></td>
|
||||
<td class="col-characteristic_id"><a href="/fixtures/attraction_characteristic/2">Paranormal</a> <em>2</em></td>
|
||||
<td class="col-attraction_id"><a href="{{ base_url }}fixtures/roadside_attractions/4">Bigfoot Discovery Museum</a> <em>4</em></td>
|
||||
<td class="col-characteristic_id"><a href="{{ base_url }}fixtures/attraction_characteristic/2">Paranormal</a> <em>2</em></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="export" class="advanced-export">
|
||||
<h3>Advanced export</h3>
|
||||
<p>JSON shape:
|
||||
<a href="/fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on">default</a>,
|
||||
<a href="/fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on&_shape=array">array</a>,
|
||||
<a href="/fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on&_shape=array&_nl=on">newline-delimited</a>
|
||||
<a href="{{ base_url }}fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on">default</a>,
|
||||
<a href="{{ base_url }}fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on&_shape=array">array</a>,
|
||||
<a href="{{ base_url }}fixtures/roadside_attraction_characteristics.json?characteristic_id=2&_labels=on&_shape=array&_nl=on">newline-delimited</a>
|
||||
</p>
|
||||
<form action="/fixtures/roadside_attraction_characteristics.csv" method="get">
|
||||
<form action="{{ base_url }}fixtures/roadside_attraction_characteristics.csv" method="get">
|
||||
<p>
|
||||
CSV options:
|
||||
<label><input type="checkbox" name="_dl"> download file</label>
|
||||
|
|
@ -445,7 +445,7 @@
|
|||
<h2 class="pattern-heading">.bd for /database/table/row</h2>
|
||||
<section class="content">
|
||||
<h1 style="padding-left: 10px; border-left: 10px solid #ff0000">roadside_attractions: 2</h1>
|
||||
<p>This data as <a href="/fixtures/roadside_attractions/2.json">json</a></p>
|
||||
<p>This data as <a href="{{ base_url }}fixtures/roadside_attractions/2.json">json</a></p>
|
||||
<table class="rows-and-columns">
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
@ -479,7 +479,7 @@
|
|||
<h2>Links from other tables</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/fixtures/roadside_attraction_characteristics?attraction_id=2">
|
||||
<a href="{{ base_url }}fixtures/roadside_attraction_characteristics?attraction_id=2">
|
||||
1 row</a>
|
||||
from attraction_id in roadside_attraction_characteristics
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -60,9 +60,11 @@ class DatabaseView(View):
|
|||
|
||||
sql = (request.args.get("sql") or "").strip()
|
||||
if sql:
|
||||
redirect_url = "/" + request.url_vars.get("database") + "/-/query"
|
||||
redirect_url = datasette.urls.database(database) + "/-/query"
|
||||
if request.url_vars.get("format"):
|
||||
redirect_url += "." + request.url_vars.get("format")
|
||||
redirect_url = path_with_format(
|
||||
path=redirect_url, format=request.url_vars.get("format")
|
||||
)
|
||||
redirect_url += "?" + request.query_string
|
||||
response = Response.redirect(redirect_url)
|
||||
if datasette.cors:
|
||||
|
|
|
|||
|
|
@ -892,14 +892,15 @@ class ApiExplorerView(BaseView):
|
|||
raise Forbidden("You do not have permission to view this instance")
|
||||
|
||||
def api_path(link):
|
||||
return "/-/api#{}".format(
|
||||
return "{}#{}".format(
|
||||
self.ds.urls.path("/-/api"),
|
||||
urllib.parse.urlencode(
|
||||
{
|
||||
key: json.dumps(value, indent=2) if key == "json" else value
|
||||
for key, value in link.items()
|
||||
if key in ("path", "method", "json")
|
||||
}
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
return await self.render(
|
||||
|
|
|
|||
|
|
@ -878,6 +878,8 @@ def test_debug_context_includes_extra_template_vars():
|
|||
"/fixtures/facetable",
|
||||
"/fixtures/facetable?_facet=state",
|
||||
"/fixtures/-/query?sql=select+1",
|
||||
"/-/api",
|
||||
"/-/patterns",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("use_prefix", (True, False))
|
||||
|
|
@ -932,7 +934,9 @@ def test_base_url_config(app_client_base_url_prefix, path, use_prefix):
|
|||
):
|
||||
# If this has been made absolute it may start http://localhost/
|
||||
if href.startswith("http://localhost/"):
|
||||
href = href[len("http://localost/") :]
|
||||
href = href[len("http://localhost") :]
|
||||
elif href.startswith(("http://", "https://")):
|
||||
continue
|
||||
assert href.startswith("/prefix/"), json.dumps(
|
||||
{
|
||||
"path": path,
|
||||
|
|
@ -966,6 +970,25 @@ def test_base_url_affects_filter_redirects(app_client_base_url_prefix):
|
|||
)
|
||||
|
||||
|
||||
def test_base_url_affects_database_sql_redirect(app_client_base_url_prefix):
|
||||
response = app_client_base_url_prefix.get(
|
||||
"/prefix/fixtures?sql=select+1", follow_redirects=False
|
||||
)
|
||||
assert response.status_code == 302
|
||||
assert response.headers["location"] == "/prefix/fixtures/-/query?sql=select+1"
|
||||
|
||||
|
||||
def test_base_url_affects_permanent_redirects():
|
||||
with make_app_client(memory=True, settings={"base_url": "/prefix/"}) as client:
|
||||
response = client.get("/prefix/-", follow_redirects=False)
|
||||
assert response.status_code == 301
|
||||
assert response.headers["location"] == "/prefix/-/"
|
||||
|
||||
response2 = client.get("/prefix/:memory:", follow_redirects=False)
|
||||
assert response2.status_code == 301
|
||||
assert response2.headers["location"] == "/prefix/_memory"
|
||||
|
||||
|
||||
def test_base_url_affects_metadata_extra_css_urls(app_client_base_url_prefix):
|
||||
html = app_client_base_url_prefix.get("/").text
|
||||
assert '<link rel="stylesheet" href="/prefix/static/extra-css-urls.css">' in html
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue