datasette-edit-schema 0.8a2__tar.gz → 0.8a5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/PKG-INFO +12 -18
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/README.md +7 -13
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/__init__.py +47 -24
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/templates/edit_schema_table.html +13 -12
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema.egg-info/PKG-INFO +12 -18
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema.egg-info/requires.txt +1 -1
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/pyproject.toml +5 -6
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/tests/test_edit_schema.py +23 -17
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/LICENSE +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/static/draggable.1.0.0-beta.11.bundle.js +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/static/draggable.1.0.0-beta.11.bundle.min.js +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/templates/edit_schema_create_table.html +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/templates/edit_schema_database.html +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/templates/edit_schema_index.html +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/utils.py +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema.egg-info/SOURCES.txt +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema.egg-info/dependency_links.txt +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema.egg-info/entry_points.txt +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema.egg-info/top_level.txt +0 -0
- {datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/setup.cfg +0 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: datasette-edit-schema
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8a5
|
|
4
4
|
Summary: Datasette plugin for modifying table schemas
|
|
5
5
|
Author: Simon Willison
|
|
6
|
-
License: Apache-2.0
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
7
|
Project-URL: Homepage, https://datasette.io/plugins/datasette-edit-schema
|
|
8
8
|
Project-URL: Changelog, https://github.com/simonw/datasette-edit-schema/releases
|
|
9
9
|
Project-URL: Issues, https://github.com/simonw/datasette-edit-schema/issues
|
|
10
10
|
Project-URL: CI, https://github.com/simonw/datasette-edit-schema/actions
|
|
11
11
|
Classifier: Framework :: Datasette
|
|
12
|
-
|
|
13
|
-
Requires-Python: >=3.8
|
|
12
|
+
Requires-Python: >=3.10
|
|
14
13
|
Description-Content-Type: text/markdown
|
|
15
14
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: datasette>=1.
|
|
15
|
+
Requires-Dist: datasette>=1.0a21
|
|
17
16
|
Requires-Dist: sqlite-utils>=3.35
|
|
18
17
|
Provides-Extra: test
|
|
19
18
|
Requires-Dist: pytest; extra == "test"
|
|
20
19
|
Requires-Dist: pytest-asyncio; extra == "test"
|
|
21
20
|
Requires-Dist: beautifulsoup4; extra == "test"
|
|
22
21
|
Requires-Dist: html5lib; extra == "test"
|
|
22
|
+
Dynamic: license-file
|
|
23
23
|
|
|
24
24
|
# datasette-edit-schema
|
|
25
25
|
|
|
@@ -61,21 +61,15 @@ By default only [the root actor](https://datasette.readthedocs.io/en/stable/auth
|
|
|
61
61
|
|
|
62
62
|
## Permissions
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
This plugin registers an `edit-schema` action that applies to databases. Granting that action gives an actor access to every feature in the UI. Instances launched with `datasette --root` automatically allow the signed-in root actor to perform this action.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
All permission checks now call `datasette.allowed()` with `DatabaseResource` or `TableResource` objects, so they work seamlessly with Datasette’s `permission_resources_sql()` hook and configuration-based permission rules. Plugins such as [datasette-permissions-sql](https://github.com/simonw/datasette-permissions-sql) can continue to be used to grant access to the write interface.
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
For finer control you can combine Datasette’s built-in actions:
|
|
69
69
|
|
|
70
|
-
- `
|
|
71
|
-
- `
|
|
72
|
-
- `
|
|
73
|
-
|
|
74
|
-
You can instead use more finely-grained permissions from the default Datasette permissions collection:
|
|
75
|
-
|
|
76
|
-
- `create-table` allows users to create a new table. The `resource` will be the name of the database.
|
|
77
|
-
- `drop-table` allows users to drop a table. The `resource` will be a tuple of `(database_name, table_name)`.
|
|
78
|
-
- `alter-table` allows users to alter a table. The `resource` will be a tuple of `(database_name, table_name)`.
|
|
70
|
+
- `create-table` allows users to create a new table (database-level resource).
|
|
71
|
+
- `drop-table` allows users to drop a table (table-level resource).
|
|
72
|
+
- `alter-table` allows users to alter a table (table-level resource).
|
|
79
73
|
|
|
80
74
|
To rename a table a user must have both `drop-table` permission for that table and `create-table` permission for that database.
|
|
81
75
|
|
|
@@ -38,21 +38,15 @@ By default only [the root actor](https://datasette.readthedocs.io/en/stable/auth
|
|
|
38
38
|
|
|
39
39
|
## Permissions
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
This plugin registers an `edit-schema` action that applies to databases. Granting that action gives an actor access to every feature in the UI. Instances launched with `datasette --root` automatically allow the signed-in root actor to perform this action.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
All permission checks now call `datasette.allowed()` with `DatabaseResource` or `TableResource` objects, so they work seamlessly with Datasette’s `permission_resources_sql()` hook and configuration-based permission rules. Plugins such as [datasette-permissions-sql](https://github.com/simonw/datasette-permissions-sql) can continue to be used to grant access to the write interface.
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
For finer control you can combine Datasette’s built-in actions:
|
|
46
46
|
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
49
|
-
- `
|
|
50
|
-
|
|
51
|
-
You can instead use more finely-grained permissions from the default Datasette permissions collection:
|
|
52
|
-
|
|
53
|
-
- `create-table` allows users to create a new table. The `resource` will be the name of the database.
|
|
54
|
-
- `drop-table` allows users to drop a table. The `resource` will be a tuple of `(database_name, table_name)`.
|
|
55
|
-
- `alter-table` allows users to alter a table. The `resource` will be a tuple of `(database_name, table_name)`.
|
|
47
|
+
- `create-table` allows users to create a new table (database-level resource).
|
|
48
|
+
- `drop-table` allows users to drop a table (table-level resource).
|
|
49
|
+
- `alter-table` allows users to alter a table (table-level resource).
|
|
56
50
|
|
|
57
51
|
To rename a table a user must have both `drop-table` permission for that table and `create-table` permission for that database.
|
|
58
52
|
|
|
@@ -103,4 +97,4 @@ pip install -e '.[test]'
|
|
|
103
97
|
To run the tests:
|
|
104
98
|
```bash
|
|
105
99
|
pytest
|
|
106
|
-
```
|
|
100
|
+
```
|
{datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema/__init__.py
RENAMED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from datasette import hookimpl
|
|
2
2
|
from datasette.events import CreateTableEvent, AlterTableEvent, DropTableEvent
|
|
3
|
+
from datasette.permissions import Action
|
|
4
|
+
from datasette.resources import DatabaseResource, TableResource
|
|
3
5
|
from datasette.utils.asgi import Response, NotFound, Forbidden
|
|
4
6
|
from datasette.utils import sqlite3, tilde_decode, tilde_encode
|
|
5
7
|
from urllib.parse import quote_plus, unquote_plus
|
|
@@ -22,14 +24,14 @@ FOREIGN_KEY_DETECTION_LIMIT = 10_000
|
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
@hookimpl
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
def register_actions(datasette):
|
|
28
|
+
return [
|
|
29
|
+
Action(
|
|
30
|
+
name="edit-schema",
|
|
31
|
+
description="Edit database schemas",
|
|
32
|
+
resource_class=DatabaseResource,
|
|
33
|
+
)
|
|
34
|
+
]
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
@hookimpl
|
|
@@ -51,25 +53,36 @@ def table_actions(datasette, actor, database, table):
|
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
async def can_create_table(datasette, actor, database):
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
database_resource = DatabaseResource(database)
|
|
57
|
+
if await datasette.allowed(
|
|
58
|
+
actor=actor,
|
|
59
|
+
action="edit-schema",
|
|
60
|
+
resource=database_resource,
|
|
56
61
|
):
|
|
57
62
|
return True
|
|
58
63
|
# Or maybe they have create-table
|
|
59
|
-
if await datasette.
|
|
60
|
-
actor
|
|
64
|
+
if await datasette.allowed(
|
|
65
|
+
actor=actor,
|
|
66
|
+
action="create-table",
|
|
67
|
+
resource=database_resource,
|
|
61
68
|
):
|
|
62
69
|
return True
|
|
63
70
|
return False
|
|
64
71
|
|
|
65
72
|
|
|
66
73
|
async def can_alter_table(datasette, actor, database, table):
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
database_resource = DatabaseResource(database)
|
|
75
|
+
if await datasette.allowed(
|
|
76
|
+
actor=actor,
|
|
77
|
+
action="edit-schema",
|
|
78
|
+
resource=database_resource,
|
|
69
79
|
):
|
|
70
80
|
return True
|
|
71
|
-
|
|
72
|
-
|
|
81
|
+
table_resource = TableResource(database, table)
|
|
82
|
+
if await datasette.allowed(
|
|
83
|
+
actor=actor,
|
|
84
|
+
action="alter-table",
|
|
85
|
+
resource=table_resource,
|
|
73
86
|
):
|
|
74
87
|
return True
|
|
75
88
|
return False
|
|
@@ -84,13 +97,19 @@ async def can_rename_table(datasette, actor, database, table):
|
|
|
84
97
|
|
|
85
98
|
|
|
86
99
|
async def can_drop_table(datasette, actor, database, table):
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
database_resource = DatabaseResource(database)
|
|
101
|
+
if await datasette.allowed(
|
|
102
|
+
actor=actor,
|
|
103
|
+
action="edit-schema",
|
|
104
|
+
resource=database_resource,
|
|
89
105
|
):
|
|
90
106
|
return True
|
|
91
107
|
# Or maybe they have drop-table
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
table_resource = TableResource(database, table)
|
|
109
|
+
if await datasette.allowed(
|
|
110
|
+
actor=actor,
|
|
111
|
+
action="drop-table",
|
|
112
|
+
resource=table_resource,
|
|
94
113
|
):
|
|
95
114
|
return True
|
|
96
115
|
return False
|
|
@@ -148,8 +167,10 @@ def get_databases(datasette):
|
|
|
148
167
|
|
|
149
168
|
|
|
150
169
|
async def check_permissions(datasette, request, database):
|
|
151
|
-
if not await datasette.
|
|
152
|
-
request.actor,
|
|
170
|
+
if not await datasette.allowed(
|
|
171
|
+
actor=request.actor,
|
|
172
|
+
action="edit-schema",
|
|
173
|
+
resource=DatabaseResource(database),
|
|
153
174
|
):
|
|
154
175
|
raise Forbidden("Permission denied for edit-schema")
|
|
155
176
|
|
|
@@ -160,8 +181,10 @@ async def edit_schema_index(datasette, request):
|
|
|
160
181
|
allowed_databases = [
|
|
161
182
|
name
|
|
162
183
|
for name in database_names
|
|
163
|
-
if await datasette.
|
|
164
|
-
request.actor,
|
|
184
|
+
if await datasette.allowed(
|
|
185
|
+
actor=request.actor,
|
|
186
|
+
action="edit-schema",
|
|
187
|
+
resource=DatabaseResource(name),
|
|
165
188
|
)
|
|
166
189
|
]
|
|
167
190
|
if not allowed_databases:
|
|
@@ -14,13 +14,14 @@ html body input[type="search"] {
|
|
|
14
14
|
font-size: 1em;
|
|
15
15
|
font-family: Helvetica, sans-serif;
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
background-color: red;
|
|
19
|
-
border-color: red;
|
|
20
|
-
}
|
|
21
|
-
body form .button-small {
|
|
17
|
+
input[type=submit].button-small {
|
|
22
18
|
font-size: 0.7em;
|
|
23
19
|
}
|
|
20
|
+
form input[type=submit].button-red {
|
|
21
|
+
background: red;
|
|
22
|
+
border-color: rgb(171, 112, 112);
|
|
23
|
+
}
|
|
24
|
+
|
|
24
25
|
select {
|
|
25
26
|
border: 1px solid #ccc;
|
|
26
27
|
border-radius: 3px;
|
|
@@ -91,7 +92,7 @@ html body label {
|
|
|
91
92
|
{% if can_rename_table %}
|
|
92
93
|
<h2>Rename table</h2>
|
|
93
94
|
|
|
94
|
-
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
95
|
+
<form class="core" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
95
96
|
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
|
|
96
97
|
<p><label>New name <input type="text" name="name"></label>
|
|
97
98
|
<input type="hidden" name="rename_table" value="1">
|
|
@@ -99,7 +100,7 @@ html body label {
|
|
|
99
100
|
</form>
|
|
100
101
|
{% endif %}
|
|
101
102
|
|
|
102
|
-
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
103
|
+
<form class="core" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
103
104
|
<h2>Change existing columns</h2>
|
|
104
105
|
<ul class="sortable-columns">
|
|
105
106
|
{% for column in columns %}
|
|
@@ -134,7 +135,7 @@ html body label {
|
|
|
134
135
|
|
|
135
136
|
<h2>Add a column</h2>
|
|
136
137
|
|
|
137
|
-
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
138
|
+
<form class="core" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
138
139
|
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
|
|
139
140
|
<input type="hidden" name="add_column" value="1">
|
|
140
141
|
<p><label>Name <input type="text" name="name"></label>
|
|
@@ -156,7 +157,7 @@ table.foreign-key-options td {
|
|
|
156
157
|
}
|
|
157
158
|
</style>
|
|
158
159
|
|
|
159
|
-
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
160
|
+
<form class="core" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
160
161
|
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
|
|
161
162
|
<input type="hidden" name="action" value="update_foreign_keys">
|
|
162
163
|
<table class="foreign-key-options">
|
|
@@ -180,7 +181,7 @@ table.foreign-key-options td {
|
|
|
180
181
|
|
|
181
182
|
<p>The primary key column uniquely identifies each row in the table.</p>
|
|
182
183
|
|
|
183
|
-
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
184
|
+
<form class="core" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
184
185
|
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
|
|
185
186
|
<input type="hidden" name="action" value="update_primary_key">
|
|
186
187
|
<label for="primary_key">Primary key column </label>
|
|
@@ -201,7 +202,7 @@ table.foreign-key-options td {
|
|
|
201
202
|
|
|
202
203
|
<p>Indexes can speed up filter and sort operations against indexed columns.</p>
|
|
203
204
|
|
|
204
|
-
<form action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
205
|
+
<form class="core" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
205
206
|
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
|
|
206
207
|
{% if non_primary_key_columns %}
|
|
207
208
|
<p><label for="id_add_index_column">
|
|
@@ -233,7 +234,7 @@ table.foreign-key-options td {
|
|
|
233
234
|
{% if can_drop_table %}
|
|
234
235
|
<h2>Drop table</h2>
|
|
235
236
|
|
|
236
|
-
<form id="drop-table-form" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
237
|
+
<form class="core" id="drop-table-form" action="{{ base_url }}-/edit-schema/{{ database.name|quote_plus }}/{{ tilde_encode(table) }}" method="post">
|
|
237
238
|
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
|
|
238
239
|
<input type="hidden" name="drop_table" value="1">
|
|
239
240
|
<input type="submit" class="button-red" value="Drop this table">
|
{datasette_edit_schema-0.8a2 → datasette_edit_schema-0.8a5}/datasette_edit_schema.egg-info/PKG-INFO
RENAMED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: datasette-edit-schema
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8a5
|
|
4
4
|
Summary: Datasette plugin for modifying table schemas
|
|
5
5
|
Author: Simon Willison
|
|
6
|
-
License: Apache-2.0
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
7
|
Project-URL: Homepage, https://datasette.io/plugins/datasette-edit-schema
|
|
8
8
|
Project-URL: Changelog, https://github.com/simonw/datasette-edit-schema/releases
|
|
9
9
|
Project-URL: Issues, https://github.com/simonw/datasette-edit-schema/issues
|
|
10
10
|
Project-URL: CI, https://github.com/simonw/datasette-edit-schema/actions
|
|
11
11
|
Classifier: Framework :: Datasette
|
|
12
|
-
|
|
13
|
-
Requires-Python: >=3.8
|
|
12
|
+
Requires-Python: >=3.10
|
|
14
13
|
Description-Content-Type: text/markdown
|
|
15
14
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: datasette>=1.
|
|
15
|
+
Requires-Dist: datasette>=1.0a21
|
|
17
16
|
Requires-Dist: sqlite-utils>=3.35
|
|
18
17
|
Provides-Extra: test
|
|
19
18
|
Requires-Dist: pytest; extra == "test"
|
|
20
19
|
Requires-Dist: pytest-asyncio; extra == "test"
|
|
21
20
|
Requires-Dist: beautifulsoup4; extra == "test"
|
|
22
21
|
Requires-Dist: html5lib; extra == "test"
|
|
22
|
+
Dynamic: license-file
|
|
23
23
|
|
|
24
24
|
# datasette-edit-schema
|
|
25
25
|
|
|
@@ -61,21 +61,15 @@ By default only [the root actor](https://datasette.readthedocs.io/en/stable/auth
|
|
|
61
61
|
|
|
62
62
|
## Permissions
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
This plugin registers an `edit-schema` action that applies to databases. Granting that action gives an actor access to every feature in the UI. Instances launched with `datasette --root` automatically allow the signed-in root actor to perform this action.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
All permission checks now call `datasette.allowed()` with `DatabaseResource` or `TableResource` objects, so they work seamlessly with Datasette’s `permission_resources_sql()` hook and configuration-based permission rules. Plugins such as [datasette-permissions-sql](https://github.com/simonw/datasette-permissions-sql) can continue to be used to grant access to the write interface.
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
For finer control you can combine Datasette’s built-in actions:
|
|
69
69
|
|
|
70
|
-
- `
|
|
71
|
-
- `
|
|
72
|
-
- `
|
|
73
|
-
|
|
74
|
-
You can instead use more finely-grained permissions from the default Datasette permissions collection:
|
|
75
|
-
|
|
76
|
-
- `create-table` allows users to create a new table. The `resource` will be the name of the database.
|
|
77
|
-
- `drop-table` allows users to drop a table. The `resource` will be a tuple of `(database_name, table_name)`.
|
|
78
|
-
- `alter-table` allows users to alter a table. The `resource` will be a tuple of `(database_name, table_name)`.
|
|
70
|
+
- `create-table` allows users to create a new table (database-level resource).
|
|
71
|
+
- `drop-table` allows users to drop a table (table-level resource).
|
|
72
|
+
- `alter-table` allows users to alter a table (table-level resource).
|
|
79
73
|
|
|
80
74
|
To rename a table a user must have both `drop-table` permission for that table and `create-table` permission for that database.
|
|
81
75
|
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datasette-edit-schema"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.8a5"
|
|
4
4
|
description = "Datasette plugin for modifying table schemas"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{name = "Simon Willison"}]
|
|
7
|
-
license =
|
|
7
|
+
license = "Apache-2.0"
|
|
8
8
|
classifiers=[
|
|
9
|
-
"Framework :: Datasette"
|
|
10
|
-
"License :: OSI Approved :: Apache Software License"
|
|
9
|
+
"Framework :: Datasette"
|
|
11
10
|
]
|
|
12
|
-
requires-python = ">=3.
|
|
11
|
+
requires-python = ">=3.10"
|
|
13
12
|
dependencies = [
|
|
14
|
-
"datasette>=1.
|
|
13
|
+
"datasette>=1.0a21",
|
|
15
14
|
"sqlite-utils>=3.35",
|
|
16
15
|
]
|
|
17
16
|
|
|
@@ -22,9 +22,15 @@ def get_last_event(datasette):
|
|
|
22
22
|
return events[-1]
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def root_datasette(*args, **kwargs):
|
|
26
|
+
ds = Datasette(*args, **kwargs)
|
|
27
|
+
ds.root_enabled = True
|
|
28
|
+
return ds
|
|
29
|
+
|
|
30
|
+
|
|
25
31
|
@pytest.mark.asyncio
|
|
26
32
|
async def test_csrf_required(db_path):
|
|
27
|
-
ds =
|
|
33
|
+
ds = root_datasette([db_path])
|
|
28
34
|
response = await ds.client.post(
|
|
29
35
|
"/edit-schema/data/creatures",
|
|
30
36
|
data={"drop_table": "1"},
|
|
@@ -78,7 +84,7 @@ async def test_table_actions(permission_plugin, ds, actor_id, should_allow, tabl
|
|
|
78
84
|
|
|
79
85
|
@pytest.mark.asyncio
|
|
80
86
|
async def test_post_without_operation_raises_error(db_path):
|
|
81
|
-
ds =
|
|
87
|
+
ds = root_datasette([db_path])
|
|
82
88
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
83
89
|
# Get a csrftoken
|
|
84
90
|
csrftoken = (
|
|
@@ -104,7 +110,7 @@ async def test_post_without_operation_raises_error(db_path):
|
|
|
104
110
|
),
|
|
105
111
|
)
|
|
106
112
|
async def test_drop_table(permission_plugin, db_path, actor_id, should_allow):
|
|
107
|
-
ds =
|
|
113
|
+
ds = root_datasette([db_path], pdb=True)
|
|
108
114
|
ds._rules_allow = [
|
|
109
115
|
Rule(
|
|
110
116
|
actor_id="user_with_edit_schema",
|
|
@@ -174,7 +180,7 @@ async def test_drop_table(permission_plugin, db_path, actor_id, should_allow):
|
|
|
174
180
|
[("text", str), ("integer", int), ("real", float), ("blob", bytes)],
|
|
175
181
|
)
|
|
176
182
|
async def test_add_column(db_path, col_type, expected_type):
|
|
177
|
-
ds =
|
|
183
|
+
ds = root_datasette([db_path])
|
|
178
184
|
db = sqlite_utils.Database(db_path)
|
|
179
185
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
180
186
|
table = db["creatures"]
|
|
@@ -218,7 +224,7 @@ async def test_add_column(db_path, col_type, expected_type):
|
|
|
218
224
|
],
|
|
219
225
|
)
|
|
220
226
|
async def test_add_column_errors(db_path, name, type, expected_error):
|
|
221
|
-
ds =
|
|
227
|
+
ds = root_datasette([db_path])
|
|
222
228
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
223
229
|
csrftoken = (
|
|
224
230
|
await ds.client.get("/-/edit-schema/data/creatures", cookies=cookies)
|
|
@@ -345,7 +351,7 @@ async def test_add_column_errors(db_path, name, type, expected_error):
|
|
|
345
351
|
async def test_transform_table(
|
|
346
352
|
db_path, action, post_data, expected_columns_dict, expected_order, expected_message
|
|
347
353
|
):
|
|
348
|
-
ds =
|
|
354
|
+
ds = root_datasette([db_path])
|
|
349
355
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
350
356
|
db = sqlite_utils.Database(db_path)
|
|
351
357
|
table = db["creatures"]
|
|
@@ -378,7 +384,7 @@ async def test_transform_table(
|
|
|
378
384
|
@pytest.mark.asyncio
|
|
379
385
|
async def test_drop_column_from_table_that_is_part_of_a_view(db_path):
|
|
380
386
|
# https://github.com/simonw/datasette-edit-schema/issues/35
|
|
381
|
-
ds =
|
|
387
|
+
ds = root_datasette([db_path], pdb=True)
|
|
382
388
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
383
389
|
db = sqlite_utils.Database(db_path)
|
|
384
390
|
db.create_view("creatures_view", "select * from creatures")
|
|
@@ -407,7 +413,7 @@ async def test_drop_column_from_table_that_is_part_of_a_view(db_path):
|
|
|
407
413
|
|
|
408
414
|
@pytest.mark.asyncio
|
|
409
415
|
async def test_static_assets(db_path):
|
|
410
|
-
ds =
|
|
416
|
+
ds = root_datasette([db_path])
|
|
411
417
|
for path in (
|
|
412
418
|
"/-/static-plugins/datasette-edit-schema/draggable.1.0.0-beta.11.bundle.min.js",
|
|
413
419
|
):
|
|
@@ -421,7 +427,7 @@ async def test_static_assets(db_path):
|
|
|
421
427
|
)
|
|
422
428
|
async def test_permission_edit_schema(db_path, path):
|
|
423
429
|
# root user has edit-schema which allows access to all
|
|
424
|
-
ds =
|
|
430
|
+
ds = root_datasette([db_path])
|
|
425
431
|
someuser_cookies = {"ds_actor": ds.sign({"a": {"id": "someuser"}}, "actor")}
|
|
426
432
|
root_cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
427
433
|
response = await ds.client.get(path)
|
|
@@ -615,7 +621,7 @@ async def test_table_form_contains_schema(permission_plugin, ds):
|
|
|
615
621
|
],
|
|
616
622
|
)
|
|
617
623
|
async def test_rename_table(db_path, new_name, should_work, expected_message):
|
|
618
|
-
ds =
|
|
624
|
+
ds = root_datasette([db_path])
|
|
619
625
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
620
626
|
csrftoken = (
|
|
621
627
|
await ds.client.get("/-/edit-schema/data/creatures", cookies=cookies)
|
|
@@ -674,7 +680,7 @@ async def test_rename_table(db_path, new_name, should_work, expected_message):
|
|
|
674
680
|
),
|
|
675
681
|
)
|
|
676
682
|
async def test_breadcrumbs(db_path, path, expected_breadcrumbs):
|
|
677
|
-
ds =
|
|
683
|
+
ds = root_datasette([db_path])
|
|
678
684
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
679
685
|
response = await ds.client.get(path, cookies=cookies)
|
|
680
686
|
assert response.status_code == 200
|
|
@@ -696,7 +702,7 @@ def test_potential_foreign_keys(db):
|
|
|
696
702
|
@pytest.mark.asyncio
|
|
697
703
|
async def test_edit_form_shows_suggestions(db_path):
|
|
698
704
|
# Test for suggested foreign keys and primary keys
|
|
699
|
-
ds =
|
|
705
|
+
ds = root_datasette([db_path])
|
|
700
706
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
701
707
|
response = await ds.client.get("/-/edit-schema/data/museums", cookies=cookies)
|
|
702
708
|
assert response.status_code == 200
|
|
@@ -767,7 +773,7 @@ async def test_edit_form_shows_suggestions(db_path):
|
|
|
767
773
|
@pytest.mark.asyncio
|
|
768
774
|
async def test_edit_form_for_empty_table(db_path):
|
|
769
775
|
# https://github.com/simonw/datasette-edit-schema/issues/38
|
|
770
|
-
ds =
|
|
776
|
+
ds = root_datasette([db_path])
|
|
771
777
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
772
778
|
response = await ds.client.get("/-/edit-schema/data/empty_table", cookies=cookies)
|
|
773
779
|
assert response.status_code == 200
|
|
@@ -859,7 +865,7 @@ async def test_edit_form_for_empty_table(db_path):
|
|
|
859
865
|
async def test_edit_keys(
|
|
860
866
|
db_path, table, post_data, expected_fks, expected_pk, expected_message
|
|
861
867
|
):
|
|
862
|
-
ds =
|
|
868
|
+
ds = root_datasette([db_path])
|
|
863
869
|
# Grab a csrftoken
|
|
864
870
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
865
871
|
csrftoken_r = await ds.client.get(
|
|
@@ -951,7 +957,7 @@ def get_options(soup, name):
|
|
|
951
957
|
),
|
|
952
958
|
)
|
|
953
959
|
async def test_create_table(db_path, post_data, expected_message, expected_schema):
|
|
954
|
-
ds =
|
|
960
|
+
ds = root_datasette([db_path])
|
|
955
961
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
956
962
|
csrftoken_r = await ds.client.get("/-/edit-schema/data/-/create", cookies=cookies)
|
|
957
963
|
csrftoken = csrftoken_r.cookies["ds_csrftoken"]
|
|
@@ -1107,7 +1113,7 @@ def test_potential_primary_keys_primary_key_only_table():
|
|
|
1107
1113
|
async def test_add_remove_index(
|
|
1108
1114
|
db_path, table, post_data, expected_message, expected_indexes
|
|
1109
1115
|
):
|
|
1110
|
-
ds =
|
|
1116
|
+
ds = root_datasette([db_path])
|
|
1111
1117
|
cookies = {"ds_actor": ds.sign({"a": {"id": "root"}}, "actor")}
|
|
1112
1118
|
get_response = await ds.client.get(
|
|
1113
1119
|
"/-/edit-schema/data/{}".format(tilde_encode(table)), cookies=cookies
|
|
@@ -1144,7 +1150,7 @@ async def test_database_and_table_level_permissions(tmp_path):
|
|
|
1144
1150
|
sales_db["notes"].insert({"id": 1, "note": "Hello"}, pk="id")
|
|
1145
1151
|
sales_db["not_allowed"].insert({"id": 1}, pk="id")
|
|
1146
1152
|
|
|
1147
|
-
ds =
|
|
1153
|
+
ds = root_datasette(
|
|
1148
1154
|
[marketing_path, sales_path],
|
|
1149
1155
|
config={
|
|
1150
1156
|
"databases": {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|