Skip to content

Commit

Permalink
Switch to tilde-encoded table names, refs #62
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Apr 24, 2024
1 parent f167036 commit 5bc7680
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 18 deletions.
7 changes: 4 additions & 3 deletions datasette_edit_schema/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datasette import hookimpl
from datasette.events import CreateTableEvent, AlterTableEvent, DropTableEvent
from datasette.utils.asgi import Response, NotFound, Forbidden
from datasette.utils import sqlite3
from datasette.utils import sqlite3, tilde_decode, tilde_encode
from urllib.parse import quote_plus, unquote_plus
import sqlite_utils
import textwrap
Expand Down Expand Up @@ -40,7 +40,7 @@ async def inner():
return [
{
"href": datasette.urls.path(
"/-/edit-schema/{}/{}".format(database, quote_plus(table))
"/-/edit-schema/{}/{}".format(database, tilde_encode(table))
),
"label": "Edit table schema",
"description": "Rename the table, add and remove columns...",
Expand Down Expand Up @@ -307,7 +307,7 @@ def create_the_table(conn):


async def edit_schema_table(request, datasette):
table = unquote_plus(request.url_vars["table"])
table = tilde_decode(request.url_vars["table"])
databases = get_databases(datasette)
database_name = request.url_vars["database"]

Expand Down Expand Up @@ -619,6 +619,7 @@ def get_columns_and_schema_and_fks_and_pks_and_indexes(conn):
"can_rename_table": await can_rename_table(
datasette, request.actor, database_name, table
),
"tilde_encode": tilde_encode,
},
request=request,
)
Expand Down
16 changes: 8 additions & 8 deletions datasette_edit_schema/templates/edit_schema_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,20 @@
{% endblock %}

{% block content %}
<h1>Edit table <a href="{{ base_url }}{{ database.name|quote_plus }}/{{ table|quote_plus }}">{{ database.name }}/{{ table }}</a></h1>
<h1>Edit table <a href="{{ base_url }}{{ database.name|quote_plus }}/{{ tilde_encode(table) }}">{{ database.name }}/{{ table }}</a></h1>

{% if can_rename_table %}
<h2>Rename table</h2>

<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<p><label>New name&nbsp; <input type="text" name="name"></label>
<input type="hidden" name="rename_table" value="1">
<input type="submit" value="Rename">
</form>
{% endif %}

<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
<h2>Change existing columns</h2>
<ul class="sortable-columns">
{% for column in columns %}
Expand Down Expand Up @@ -134,7 +134,7 @@ <h2>Change existing columns</h2>

<h2>Add a column</h2>

<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<input type="hidden" name="add_column" value="1">
<p><label>Name &nbsp;<input type="text" name="name"></label>
Expand All @@ -156,7 +156,7 @@ <h2>Update foreign key relationships</h2>
}
</style>

<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<input type="hidden" name="action" value="update_foreign_keys">
<table class="foreign-key-options">
Expand All @@ -180,7 +180,7 @@ <h2>{% if is_rowid_table %}Set a primary key{% else %}Change the primary key{% e

<p>The primary key column uniquely identifies each row in the table.</p>

<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<input type="hidden" name="action" value="update_primary_key">
<label for="primary_key">Primary key column &nbsp;</label>
Expand All @@ -201,7 +201,7 @@ <h2>Table indexes</h2>

<p>Indexes can speed up filter and sort operations against indexed columns.</p>

<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
{% if non_primary_key_columns %}
<p><label for="id_add_index_column">
Expand Down Expand Up @@ -233,7 +233,7 @@ <h3>Existing indexes</h3>
{% if can_drop_table %}
<h2>Drop table</h2>

<form id="drop-table-form" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<form id="drop-table-form" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<input type="hidden" name="drop_table" value="1">
<input type="submit" class="button-red" value="Drop this table">
Expand Down
15 changes: 15 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ def db_and_path(tmpdir):
db["has_indexes"].create_index(
["name"], index_name="name_unique_index", unique=True
)
db["animal.name/with/slashes"].insert(
{
"id": 1,
"name": "Sirocco",
"species": 582,
},
pk="id",
)
db["table.name/with/slashes.categories"].insert(
{
"id": 582,
"name": "Kākāpō",
},
pk="id",
)

return db, path

Expand Down
37 changes: 30 additions & 7 deletions tests/test_edit_schema.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datasette.app import Datasette
from datasette.utils import tilde_encode
from datasette_edit_schema.utils import (
potential_foreign_keys,
get_primary_keys,
Expand Down Expand Up @@ -41,8 +42,9 @@ async def test_csrf_required(db_path):
("user_with_no_perms", False),
),
)
@pytest.mark.parametrize("table", ("creatures", "animal.name/with/slashes"))
@pytest.mark.asyncio
async def test_table_actions(permission_plugin, ds, actor_id, should_allow):
async def test_table_actions(permission_plugin, ds, actor_id, should_allow, table):
ds._rules_allow = [
Rule(
actor_id="user_with_edit_schema",
Expand All @@ -60,9 +62,13 @@ async def test_table_actions(permission_plugin, ds, actor_id, should_allow):
cookies = None
if actor_id:
cookies = {"ds_actor": ds.sign({"a": {"id": actor_id}}, "actor")}
response = await ds.client.get("/data/creatures", cookies=cookies)
response = await ds.client.get(
ds.urls.table(database="data", table=table), cookies=cookies
)
assert response.status_code == 200
fragment = '<a href="/-/edit-schema/data/creatures">Edit table schema'
fragment = '<a href="/-/edit-schema/data/{}">Edit table schema'.format(
tilde_encode(table)
)
if should_allow:
# Should have table action
assert fragment in response.text
Expand Down Expand Up @@ -1065,20 +1071,37 @@ def test_potential_primary_keys_primary_key_only_table():
"Index dropped: name_unique_index",
[{"columns": ["name"], "name": "name_index", "unique": 0}],
),
# Test for table with surprising characters in its name
(
"animal.name/with/slashes",
{"add_index": "1", "add_index_column": "species"},
"Index added on species",
[
{
"name": "idx_animal.name/with/slashes_species",
"columns": ["species"],
"unique": 0,
}
],
),
),
)
async def test_add_remove_index(
db_path, table, post_data, expected_message, expected_indexes
):
ds = Datasette([db_path])
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
csrftoken = (
await ds.client.get("/-/edit-schema/data/{}".format(table), cookies=cookies)
).cookies["ds_csrftoken"]
get_response = await ds.client.get(
"/-/edit-schema/data/{}".format(tilde_encode(table)), cookies=cookies
)
assert get_response.status_code == 200
csrftoken = get_response.cookies["ds_csrftoken"]
cookies["ds_csrftoken"] = csrftoken
post_data["csrftoken"] = csrftoken
response = await ds.client.post(
"/-/edit-schema/data/{}".format(table), cookies=cookies, data=post_data
"/-/edit-schema/data/{}".format(tilde_encode(table)),
cookies=cookies,
data=post_data,
)
assert response.status_code == 302
messages = ds.unsign(response.cookies["ds_messages"], "messages")
Expand Down

1 comment on commit 5bc7680

@simonw
Copy link
Owner Author

@simonw simonw commented on 5bc7680 Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also closes #61

Please sign in to comment.