kopia lustrzana https://github.com/simonw/datasette
Move non-metadata configuration from metadata.yaml to datasette.yaml
* Allow and permission blocks moved to datasette.yaml * Documentation updates, initial framework for configuration referencepull/2200/head
rodzic
4e1188f60f
commit
35deaabcb1
|
@ -721,7 +721,9 @@ class Datasette:
|
|||
return self._app_css_hash
|
||||
|
||||
async def get_canned_queries(self, database_name, actor):
|
||||
queries = self.metadata("queries", database=database_name, fallback=False) or {}
|
||||
queries = (
|
||||
((self.config or {}).get("databases") or {}).get(database_name) or {}
|
||||
).get("queries") or {}
|
||||
for more_queries in pm.hook.canned_queries(
|
||||
datasette=self,
|
||||
database=database_name,
|
||||
|
@ -1315,7 +1317,7 @@ class Datasette:
|
|||
):
|
||||
hook = await await_me_maybe(hook)
|
||||
collected.extend(hook)
|
||||
collected.extend(self.metadata(key) or [])
|
||||
collected.extend((self.config or {}).get(key) or [])
|
||||
output = []
|
||||
for url_or_dict in collected:
|
||||
if isinstance(url_or_dict, dict):
|
||||
|
|
|
@ -144,14 +144,14 @@ def permission_allowed_default(datasette, actor, action, resource):
|
|||
"view-query",
|
||||
"execute-sql",
|
||||
):
|
||||
result = await _resolve_metadata_view_permissions(
|
||||
result = await _resolve_config_view_permissions(
|
||||
datasette, actor, action, resource
|
||||
)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# Check custom permissions: blocks
|
||||
result = await _resolve_metadata_permissions_blocks(
|
||||
result = await _resolve_config_permissions_blocks(
|
||||
datasette, actor, action, resource
|
||||
)
|
||||
if result is not None:
|
||||
|
@ -164,10 +164,10 @@ def permission_allowed_default(datasette, actor, action, resource):
|
|||
return inner
|
||||
|
||||
|
||||
async def _resolve_metadata_permissions_blocks(datasette, actor, action, resource):
|
||||
async def _resolve_config_permissions_blocks(datasette, actor, action, resource):
|
||||
# Check custom permissions: blocks
|
||||
metadata = datasette.metadata()
|
||||
root_block = (metadata.get("permissions", None) or {}).get(action)
|
||||
config = datasette.config or {}
|
||||
root_block = (config.get("permissions", None) or {}).get(action)
|
||||
if root_block:
|
||||
root_result = actor_matches_allow(actor, root_block)
|
||||
if root_result is not None:
|
||||
|
@ -180,7 +180,7 @@ async def _resolve_metadata_permissions_blocks(datasette, actor, action, resourc
|
|||
else:
|
||||
database = resource[0]
|
||||
database_block = (
|
||||
(metadata.get("databases", {}).get(database, {}).get("permissions", None)) or {}
|
||||
(config.get("databases", {}).get(database, {}).get("permissions", None)) or {}
|
||||
).get(action)
|
||||
if database_block:
|
||||
database_result = actor_matches_allow(actor, database_block)
|
||||
|
@ -192,7 +192,7 @@ async def _resolve_metadata_permissions_blocks(datasette, actor, action, resourc
|
|||
database, table_or_query = resource
|
||||
table_block = (
|
||||
(
|
||||
metadata.get("databases", {})
|
||||
config.get("databases", {})
|
||||
.get(database, {})
|
||||
.get("tables", {})
|
||||
.get(table_or_query, {})
|
||||
|
@ -207,7 +207,7 @@ async def _resolve_metadata_permissions_blocks(datasette, actor, action, resourc
|
|||
# Finally the canned queries
|
||||
query_block = (
|
||||
(
|
||||
metadata.get("databases", {})
|
||||
config.get("databases", {})
|
||||
.get(database, {})
|
||||
.get("queries", {})
|
||||
.get(table_or_query, {})
|
||||
|
@ -222,25 +222,30 @@ async def _resolve_metadata_permissions_blocks(datasette, actor, action, resourc
|
|||
return None
|
||||
|
||||
|
||||
async def _resolve_metadata_view_permissions(datasette, actor, action, resource):
|
||||
async def _resolve_config_view_permissions(datasette, actor, action, resource):
|
||||
config = datasette.config or {}
|
||||
if action == "view-instance":
|
||||
allow = datasette.metadata("allow")
|
||||
allow = config.get("allow")
|
||||
if allow is not None:
|
||||
return actor_matches_allow(actor, allow)
|
||||
elif action == "view-database":
|
||||
database_allow = datasette.metadata("allow", database=resource)
|
||||
database_allow = ((config.get("databases") or {}).get(resource) or {}).get(
|
||||
"allow"
|
||||
)
|
||||
if database_allow is None:
|
||||
return None
|
||||
return actor_matches_allow(actor, database_allow)
|
||||
elif action == "view-table":
|
||||
database, table = resource
|
||||
tables = datasette.metadata("tables", database=database) or {}
|
||||
tables = ((config.get("databases") or {}).get(database) or {}).get(
|
||||
"tables"
|
||||
) or {}
|
||||
table_allow = (tables.get(table) or {}).get("allow")
|
||||
if table_allow is None:
|
||||
return None
|
||||
return actor_matches_allow(actor, table_allow)
|
||||
elif action == "view-query":
|
||||
# Check if this query has a "allow" block in metadata
|
||||
# Check if this query has a "allow" block in config
|
||||
database, query_name = resource
|
||||
query = await datasette.get_canned_query(database, query_name, actor)
|
||||
assert query is not None
|
||||
|
@ -250,9 +255,11 @@ async def _resolve_metadata_view_permissions(datasette, actor, action, resource)
|
|||
return actor_matches_allow(actor, allow)
|
||||
elif action == "execute-sql":
|
||||
# Use allow_sql block from database block, or from top-level
|
||||
database_allow_sql = datasette.metadata("allow_sql", database=resource)
|
||||
database_allow_sql = ((config.get("databases") or {}).get(resource) or {}).get(
|
||||
"allow_sql"
|
||||
)
|
||||
if database_allow_sql is None:
|
||||
database_allow_sql = datasette.metadata("allow_sql")
|
||||
database_allow_sql = config.get("allow_sql")
|
||||
if database_allow_sql is None:
|
||||
return None
|
||||
return actor_matches_allow(actor, database_allow_sql)
|
||||
|
|
|
@ -67,7 +67,7 @@ An **action** is a string describing the action the actor would like to perform.
|
|||
|
||||
A **resource** is the item the actor wishes to interact with - for example a specific database or table. Some actions, such as ``permissions-debug``, are not associated with a particular resource.
|
||||
|
||||
Datasette's built-in view permissions (``view-database``, ``view-table`` etc) default to *allow* - unless you :ref:`configure additional permission rules <authentication_permissions_metadata>` unauthenticated users will be allowed to access content.
|
||||
Datasette's built-in view permissions (``view-database``, ``view-table`` etc) default to *allow* - unless you :ref:`configure additional permission rules <authentication_permissions_config>` unauthenticated users will be allowed to access content.
|
||||
|
||||
Permissions with potentially harmful effects should default to *deny*. Plugin authors should account for this when designing new plugins - for example, the `datasette-upload-csvs <https://github.com/simonw/datasette-upload-csvs>`__ plugin defaults to deny so that installations don't accidentally allow unauthenticated users to create new tables by uploading a CSV file.
|
||||
|
||||
|
@ -76,7 +76,7 @@ Permissions with potentially harmful effects should default to *deny*. Plugin au
|
|||
Defining permissions with "allow" blocks
|
||||
----------------------------------------
|
||||
|
||||
The standard way to define permissions in Datasette is to use an ``"allow"`` block. This is a JSON document describing which actors are allowed to perform a permission.
|
||||
The standard way to define permissions in Datasette is to use an ``"allow"`` block :ref:`in the datasette.yaml file <authentication_permissions_config>`. This is a JSON document describing which actors are allowed to perform a permission.
|
||||
|
||||
The most basic form of allow block is this (`allow demo <https://latest.datasette.io/-/allow-debug?actor=%7B%22id%22%3A+%22root%22%7D&allow=%7B%0D%0A++++++++%22id%22%3A+%22root%22%0D%0A++++%7D>`__, `deny demo <https://latest.datasette.io/-/allow-debug?actor=%7B%22id%22%3A+%22trevor%22%7D&allow=%7B%0D%0A++++++++%22id%22%3A+%22root%22%0D%0A++++%7D>`__):
|
||||
|
||||
|
@ -186,18 +186,18 @@ The /-/allow-debug tool
|
|||
|
||||
The ``/-/allow-debug`` tool lets you try out different ``"action"`` blocks against different ``"actor"`` JSON objects. You can try that out here: https://latest.datasette.io/-/allow-debug
|
||||
|
||||
.. _authentication_permissions_metadata:
|
||||
.. _authentication_permissions_config:
|
||||
|
||||
Access permissions in metadata
|
||||
==============================
|
||||
Access permissions in ``datasette.yaml``
|
||||
========================================
|
||||
|
||||
There are two ways to configure permissions using ``metadata.json`` (or ``metadata.yaml``).
|
||||
There are two ways to configure permissions using ``datasette.yaml`` (or ``datasette.json``).
|
||||
|
||||
For simple visibility permissions you can use ``"allow"`` blocks in the root, database, table and query sections.
|
||||
|
||||
For other permissions you can use a ``"permissions"`` block, described :ref:`in the next section <authentication_permissions_other>`.
|
||||
|
||||
You can limit who is allowed to view different parts of your Datasette instance using ``"allow"`` keys in your :ref:`metadata` configuration.
|
||||
You can limit who is allowed to view different parts of your Datasette instance using ``"allow"`` keys in your :ref:`configuration`.
|
||||
|
||||
You can control the following:
|
||||
|
||||
|
@ -216,25 +216,25 @@ Access to an instance
|
|||
Here's how to restrict access to your entire Datasette instance to just the ``"id": "root"`` user:
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
metadata_example(cog, {
|
||||
"title": "My private Datasette instance",
|
||||
"allow": {
|
||||
"id": "root"
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
from metadata_doc import config_example
|
||||
config_example(cog, """
|
||||
title: My private Datasette instance
|
||||
allow:
|
||||
id: root
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
title: My private Datasette instance
|
||||
allow:
|
||||
id: root
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -249,21 +249,22 @@ Here's how to restrict access to your entire Datasette instance to just the ``"i
|
|||
To deny access to all users, you can use ``"allow": false``:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"title": "My entirely inaccessible instance",
|
||||
"allow": False
|
||||
})
|
||||
config_example(cog, """
|
||||
title: My entirely inaccessible instance
|
||||
allow: false
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
title: My entirely inaccessible instance
|
||||
allow: false
|
||||
|
||||
title: My entirely inaccessible instance
|
||||
allow: false
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -283,28 +284,26 @@ Access to specific databases
|
|||
To limit access to a specific ``private.db`` database to just authenticated users, use the ``"allow"`` block like this:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"databases": {
|
||||
"private": {
|
||||
"allow": {
|
||||
"id": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
databases:
|
||||
private:
|
||||
allow:
|
||||
id: '*'
|
||||
id: "*"
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
databases:
|
||||
private:
|
||||
allow:
|
||||
id: "*"
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -327,34 +326,30 @@ Access to specific tables and views
|
|||
To limit access to the ``users`` table in your ``bakery.db`` database:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"databases": {
|
||||
"bakery": {
|
||||
"tables": {
|
||||
"users": {
|
||||
"allow": {
|
||||
"id": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
databases:
|
||||
bakery:
|
||||
tables:
|
||||
users:
|
||||
allow:
|
||||
id: '*'
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
databases:
|
||||
bakery:
|
||||
tables:
|
||||
users:
|
||||
allow:
|
||||
id: '*'
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -385,32 +380,12 @@ This works for SQL views as well - you can list their names in the ``"tables"``
|
|||
Access to specific canned queries
|
||||
---------------------------------
|
||||
|
||||
:ref:`canned_queries` allow you to configure named SQL queries in your ``metadata.json`` that can be executed by users. These queries can be set up to both read and write to the database, so controlling who can execute them can be important.
|
||||
:ref:`canned_queries` allow you to configure named SQL queries in your ``datasette.yaml`` that can be executed by users. These queries can be set up to both read and write to the database, so controlling who can execute them can be important.
|
||||
|
||||
To limit access to the ``add_name`` canned query in your ``dogs.db`` database to just the :ref:`root user<authentication_root>`:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"databases": {
|
||||
"dogs": {
|
||||
"queries": {
|
||||
"add_name": {
|
||||
"sql": "INSERT INTO names (name) VALUES (:name)",
|
||||
"write": True,
|
||||
"allow": {
|
||||
"id": ["root"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
databases:
|
||||
dogs:
|
||||
queries:
|
||||
|
@ -420,9 +395,26 @@ To limit access to the ``add_name`` canned query in your ``dogs.db`` database to
|
|||
allow:
|
||||
id:
|
||||
- root
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
databases:
|
||||
dogs:
|
||||
queries:
|
||||
add_name:
|
||||
sql: INSERT INTO names (name) VALUES (:name)
|
||||
write: true
|
||||
allow:
|
||||
id:
|
||||
- root
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -461,19 +453,20 @@ You can alternatively use an ``"allow_sql"`` block to control who is allowed to
|
|||
To prevent any user from executing arbitrary SQL queries, use this:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"allow_sql": False
|
||||
})
|
||||
config_example(cog, """
|
||||
allow_sql: false
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
allow_sql: false
|
||||
|
||||
allow_sql: false
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -485,22 +478,22 @@ To prevent any user from executing arbitrary SQL queries, use this:
|
|||
To enable just the :ref:`root user<authentication_root>` to execute SQL for all databases in your instance, use the following:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"allow_sql": {
|
||||
"id": "root"
|
||||
}
|
||||
})
|
||||
config_example(cog, """
|
||||
allow_sql:
|
||||
id: root
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
allow_sql:
|
||||
id: root
|
||||
|
||||
allow_sql:
|
||||
id: root
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -514,28 +507,26 @@ To enable just the :ref:`root user<authentication_root>` to execute SQL for all
|
|||
To limit this ability for just one specific database, use this:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"databases": {
|
||||
"mydatabase": {
|
||||
"allow_sql": {
|
||||
"id": "root"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
databases:
|
||||
mydatabase:
|
||||
allow_sql:
|
||||
id: root
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
databases:
|
||||
mydatabase:
|
||||
allow_sql:
|
||||
id: root
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -552,33 +543,32 @@ To limit this ability for just one specific database, use this:
|
|||
|
||||
.. _authentication_permissions_other:
|
||||
|
||||
Other permissions in metadata
|
||||
=============================
|
||||
Other permissions in ``datasette.yaml``
|
||||
=======================================
|
||||
|
||||
For all other permissions, you can use one or more ``"permissions"`` blocks in your metadata.
|
||||
For all other permissions, you can use one or more ``"permissions"`` blocks in your ``datasette.yaml`` configuration file.
|
||||
|
||||
To grant access to the :ref:`permissions debug tool <PermissionsDebugView>` to all signed in users you can grant ``permissions-debug`` to any actor with an ``id`` matching the wildcard ``*`` by adding this a the root of your metadata:
|
||||
To grant access to the :ref:`permissions debug tool <PermissionsDebugView>` to all signed in users, you can grant ``permissions-debug`` to any actor with an ``id`` matching the wildcard ``*`` by adding this a the root of your configuration:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"permissions": {
|
||||
"debug-menu": {
|
||||
"id": "*"
|
||||
}
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
permissions:
|
||||
debug-menu:
|
||||
id: '*'
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
permissions:
|
||||
debug-menu:
|
||||
id: '*'
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -594,31 +584,28 @@ To grant access to the :ref:`permissions debug tool <PermissionsDebugView>` to a
|
|||
To grant ``create-table`` to the user with ``id`` of ``editor`` for the ``docs`` database:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"databases": {
|
||||
"docs": {
|
||||
"permissions": {
|
||||
"create-table": {
|
||||
"id": "editor"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
databases:
|
||||
docs:
|
||||
permissions:
|
||||
create-table:
|
||||
id: editor
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
databases:
|
||||
docs:
|
||||
permissions:
|
||||
create-table:
|
||||
id: editor
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -638,27 +625,7 @@ To grant ``create-table`` to the user with ``id`` of ``editor`` for the ``docs``
|
|||
And for ``insert-row`` against the ``reports`` table in that ``docs`` database:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"databases": {
|
||||
"docs": {
|
||||
"tables": {
|
||||
"reports": {
|
||||
"permissions": {
|
||||
"insert-row": {
|
||||
"id": "editor"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
databases:
|
||||
docs:
|
||||
tables:
|
||||
|
@ -666,9 +633,24 @@ And for ``insert-row`` against the ``reports`` table in that ``docs`` database:
|
|||
permissions:
|
||||
insert-row:
|
||||
id: editor
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
databases:
|
||||
docs:
|
||||
tables:
|
||||
reports:
|
||||
permissions:
|
||||
insert-row:
|
||||
id: editor
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
|
|
@ -13,15 +13,15 @@ To facilitate this, You can provide a ``datasette.yaml`` configuration file to d
|
|||
|
||||
.. _configuration_reference:
|
||||
|
||||
``datasette.yaml`` reference
|
||||
``datasette.yaml`` Reference
|
||||
----------------------------
|
||||
|
||||
Here's a full example of all the valid configuration options that can exist inside ``datasette.yaml``.
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
from metadata_doc import config_example
|
||||
import textwrap
|
||||
metadata_example(cog, yaml=textwrap.dedent(
|
||||
config_example(cog, textwrap.dedent(
|
||||
"""
|
||||
# Datasette settings block
|
||||
settings:
|
||||
|
@ -52,10 +52,11 @@ Here's a full example of all the valid configuration options that can exist insi
|
|||
)
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
# Datasette settings block
|
||||
settings:
|
||||
default_page_size: 50
|
||||
|
@ -82,7 +83,8 @@ Here's a full example of all the valid configuration options that can exist insi
|
|||
datasette-my-plugin:
|
||||
key: valueB
|
||||
|
||||
.. tab:: JSON
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -125,9 +127,9 @@ Settings configuration
|
|||
:ref:`settings` can be configured in ``datasette.yaml`` with the ``settings`` key.
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
from metadata_doc import config_example
|
||||
import textwrap
|
||||
metadata_example(cog, yaml=textwrap.dedent(
|
||||
config_example(cog, textwrap.dedent(
|
||||
"""
|
||||
# inside datasette.yaml
|
||||
settings:
|
||||
|
@ -137,7 +139,7 @@ Settings configuration
|
|||
)
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -146,7 +148,7 @@ Settings configuration
|
|||
default_allow_sql: off
|
||||
default_page_size: 50
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -165,9 +167,9 @@ Plugin configuration
|
|||
Configuration for plugins can be defined inside ``datasette.yaml``. For top-level plugin configuration, use the ``plugins`` key.
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
from metadata_doc import config_example
|
||||
import textwrap
|
||||
metadata_example(cog, yaml=textwrap.dedent(
|
||||
config_example(cog, textwrap.dedent(
|
||||
"""
|
||||
# inside datasette.yaml
|
||||
plugins:
|
||||
|
@ -177,7 +179,7 @@ Configuration for plugins can be defined inside ``datasette.yaml``. For top-leve
|
|||
)
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -186,7 +188,7 @@ Configuration for plugins can be defined inside ``datasette.yaml``. For top-leve
|
|||
datasette-my-plugin:
|
||||
key: my_value
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -202,9 +204,9 @@ Configuration for plugins can be defined inside ``datasette.yaml``. For top-leve
|
|||
For database level or table level plugin configuration, nest it under the appropriate place under ``databases``.
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
from metadata_doc import config_example
|
||||
import textwrap
|
||||
metadata_example(cog, yaml=textwrap.dedent(
|
||||
config_example(cog, textwrap.dedent(
|
||||
"""
|
||||
# inside datasette.yaml
|
||||
databases:
|
||||
|
@ -224,7 +226,7 @@ For database level or table level plugin configuration, nest it under the approp
|
|||
)
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -243,7 +245,7 @@ For database level or table level plugin configuration, nest it under the approp
|
|||
datasette-my-plugin:
|
||||
key: my_value
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -269,4 +271,30 @@ For database level or table level plugin configuration, nest it under the approp
|
|||
}
|
||||
}
|
||||
}
|
||||
.. [[[end]]]
|
||||
.. [[[end]]]
|
||||
|
||||
|
||||
.. _configuration_reference_permissions:
|
||||
Permissions Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
.. _configuration_reference_authentication:
|
||||
Authentication Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
.. _configuration_reference_canned_queries:
|
||||
Canned Queries Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
.. _configuration_reference_css_js:
|
||||
Extra CSS and JS Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
|
|
@ -10,35 +10,34 @@ Datasette provides a number of ways of customizing the way data is displayed.
|
|||
Custom CSS and JavaScript
|
||||
-------------------------
|
||||
|
||||
When you launch Datasette, you can specify a custom metadata file like this::
|
||||
When you launch Datasette, you can specify a custom configuration file like this::
|
||||
|
||||
datasette mydb.db --metadata metadata.yaml
|
||||
datasette mydb.db --config datasette.yaml
|
||||
|
||||
Your ``metadata.yaml`` file can include links that look like this:
|
||||
Your ``datasette.yaml`` file can include links that look like this:
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
metadata_example(cog, {
|
||||
"extra_css_urls": [
|
||||
"https://simonwillison.net/static/css/all.bf8cd891642c.css"
|
||||
],
|
||||
"extra_js_urls": [
|
||||
"https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||
]
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
from metadata_doc import config_example
|
||||
config_example(cog, """
|
||||
extra_css_urls:
|
||||
- https://simonwillison.net/static/css/all.bf8cd891642c.css
|
||||
extra_js_urls:
|
||||
- https://code.jquery.com/jquery-3.2.1.slim.min.js
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
extra_css_urls:
|
||||
- https://simonwillison.net/static/css/all.bf8cd891642c.css
|
||||
extra_js_urls:
|
||||
- https://code.jquery.com/jquery-3.2.1.slim.min.js
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -62,35 +61,30 @@ The extra CSS and JavaScript files will be linked in the ``<head>`` of every pag
|
|||
You can also specify a SRI (subresource integrity hash) for these assets:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"extra_css_urls": [
|
||||
{
|
||||
"url": "https://simonwillison.net/static/css/all.bf8cd891642c.css",
|
||||
"sri": "sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI"
|
||||
}
|
||||
],
|
||||
"extra_js_urls": [
|
||||
{
|
||||
"url": "https://code.jquery.com/jquery-3.2.1.slim.min.js",
|
||||
"sri": "sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
|
||||
}
|
||||
]
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
extra_css_urls:
|
||||
- url: https://simonwillison.net/static/css/all.bf8cd891642c.css
|
||||
sri: sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI
|
||||
extra_js_urls:
|
||||
- url: https://code.jquery.com/jquery-3.2.1.slim.min.js
|
||||
sri: sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g=
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
extra_css_urls:
|
||||
- url: https://simonwillison.net/static/css/all.bf8cd891642c.css
|
||||
sri: sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI
|
||||
extra_js_urls:
|
||||
- url: https://code.jquery.com/jquery-3.2.1.slim.min.js
|
||||
sri: sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g=
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -115,7 +109,7 @@ This will produce:
|
|||
.. code-block:: html
|
||||
|
||||
<link rel="stylesheet" href="https://simonwillison.net/static/css/all.bf8cd891642c.css"
|
||||
integrity="sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI"
|
||||
integrity="sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI"
|
||||
crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||
integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
|
||||
|
@ -127,26 +121,24 @@ matches the content served. You can generate hashes using `www.srihash.org <http
|
|||
Items in ``"extra_js_urls"`` can specify ``"module": true`` if they reference JavaScript that uses `JavaScript modules <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules>`__. This configuration:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"extra_js_urls": [
|
||||
{
|
||||
"url": "https://example.datasette.io/module.js",
|
||||
"module": True
|
||||
}
|
||||
]
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
extra_js_urls:
|
||||
- url: https://example.datasette.io/module.js
|
||||
module: true
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
extra_js_urls:
|
||||
- url: https://example.datasette.io/module.js
|
||||
module: true
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -259,37 +251,36 @@ Consider the following directory structure::
|
|||
You can start Datasette using ``--static assets:static-files/`` to serve those
|
||||
files from the ``/assets/`` mount point::
|
||||
|
||||
datasette -m metadata.json --static assets:static-files/ --memory
|
||||
datasette --config datasette.yaml --static assets:static-files/ --memory
|
||||
|
||||
The following URLs will now serve the content from those CSS and JS files::
|
||||
|
||||
http://localhost:8001/assets/styles.css
|
||||
http://localhost:8001/assets/app.js
|
||||
|
||||
You can reference those files from ``metadata.json`` like so:
|
||||
You can reference those files from ``datasette.yaml`` like so:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
"extra_css_urls": [
|
||||
"/assets/styles.css"
|
||||
],
|
||||
"extra_js_urls": [
|
||||
"/assets/app.js"
|
||||
]
|
||||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
config_example(cog, """
|
||||
extra_css_urls:
|
||||
- /assets/styles.css
|
||||
extra_js_urls:
|
||||
- /assets/app.js
|
||||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
extra_css_urls:
|
||||
- /assets/styles.css
|
||||
extra_js_urls:
|
||||
- /assets/app.js
|
||||
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ Here's an example that turns on faceting by default for the ``qLegalStatus`` col
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -132,7 +132,7 @@ Here's an example that turns on faceting by default for the ``qLegalStatus`` col
|
|||
- qLegalStatus
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -164,7 +164,7 @@ You can specify :ref:`array <facet_by_json_array>` or :ref:`date <facet_by_date>
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -173,7 +173,7 @@ You can specify :ref:`array <facet_by_json_array>` or :ref:`date <facet_by_date>
|
|||
- date: created
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -206,7 +206,7 @@ You can change the default facet size (the number of results shown for each face
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -219,7 +219,7 @@ You can change the default facet size (the number of results shown for each face
|
|||
facet_size: 10
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ Here is an example which enables full-text search (with SQLite advanced search o
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -94,7 +94,7 @@ Here is an example which enables full-text search (with SQLite advanced search o
|
|||
searchmode: raw
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
|
|
@ -364,7 +364,7 @@ await .permission_allowed(actor, action, resource=None, default=...)
|
|||
|
||||
Check if the given actor has :ref:`permission <authentication_permissions>` to perform the given action on the given resource.
|
||||
|
||||
Some permission checks are carried out against :ref:`rules defined in metadata.json <authentication_permissions_metadata>`, while other custom permissions may be decided by plugins that implement the :ref:`plugin_hook_permission_allowed` plugin hook.
|
||||
Some permission checks are carried out against :ref:`rules defined in datasette.yaml <authentication_permissions_config>`, while other custom permissions may be decided by plugins that implement the :ref:`plugin_hook_permission_allowed` plugin hook.
|
||||
|
||||
If neither ``metadata.json`` nor any of the plugins provide an answer to the permission query the ``default`` argument will be returned.
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ Your ``metadata.yaml`` file can look something like this:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -38,7 +38,7 @@ Your ``metadata.yaml`` file can look something like this:
|
|||
source_url: http://example.com/
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -90,7 +90,7 @@ You can also provide metadata at the per-database or per-table level, like this:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -105,7 +105,7 @@ You can also provide metadata at the per-database or per-table level, like this:
|
|||
license_url: https://creativecommons.org/licenses/by/3.0/us/
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -168,7 +168,7 @@ You can include descriptions for your columns by adding a ``"columns": {"name-of
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -181,7 +181,7 @@ You can include descriptions for your columns by adding a ``"columns": {"name-of
|
|||
column2: Description of column 2
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -230,7 +230,7 @@ Column units are configured in the metadata like so:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -243,7 +243,7 @@ Column units are configured in the metadata like so:
|
|||
column2: Hz
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -276,7 +276,7 @@ registered with Pint:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -284,7 +284,7 @@ registered with Pint:
|
|||
- decibel = [] = dB
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -320,7 +320,7 @@ By default Datasette tables are sorted by primary key. You can over-ride this de
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -331,7 +331,7 @@ By default Datasette tables are sorted by primary key. You can over-ride this de
|
|||
sort: created
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -364,7 +364,7 @@ Or use ``"sort_desc"`` to sort in descending order:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -375,7 +375,7 @@ Or use ``"sort_desc"`` to sort in descending order:
|
|||
sort_desc: created
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -413,7 +413,7 @@ Datasette defaults to displaying 100 rows per page, for both tables and views. Y
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -424,7 +424,7 @@ Datasette defaults to displaying 100 rows per page, for both tables and views. Y
|
|||
size: 10
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -469,7 +469,7 @@ control which columns are available for sorting you can do so using the optional
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -482,7 +482,7 @@ control which columns are available for sorting you can do so using the optional
|
|||
- weight
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -526,7 +526,7 @@ You can use ``sortable_columns`` to enable specific sort orders for a view calle
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -539,7 +539,7 @@ You can use ``sortable_columns`` to enable specific sort orders for a view calle
|
|||
- impressions
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -586,7 +586,7 @@ used for the link label with the ``label_column`` property:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -597,7 +597,7 @@ used for the link label with the ``label_column`` property:
|
|||
label_column: title
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -636,7 +636,7 @@ SpatiaLite tables are automatically hidden) using ``"hidden": true``:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -647,7 +647,7 @@ SpatiaLite tables are automatically hidden) using ``"hidden": true``:
|
|||
hidden: true
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -689,13 +689,71 @@ Here's an example of a ``metadata.yml`` file, re-using an example from :ref:`can
|
|||
tables:
|
||||
no_primary_key:
|
||||
hidden: true
|
||||
queries:
|
||||
# This query provides LIKE-based search
|
||||
neighborhood_search:
|
||||
sql: |-
|
||||
select neighborhood, facet_cities.name, state
|
||||
from facetable join facet_cities on facetable.city_id = facet_cities.id
|
||||
where neighborhood like '%' || :text || '%' order by neighborhood;
|
||||
title: Search neighborhoods
|
||||
description_html: |-
|
||||
<p>This demonstrates <em>basic</em> LIKE search
|
||||
|
||||
|
||||
.. _metadata_reference:
|
||||
|
||||
Metadata Reference
|
||||
-----------------------
|
||||
|
||||
|
||||
A full reference of every supported option in a ``metadata.json`` or ``metadata.yaml`` file.
|
||||
|
||||
|
||||
Top-level Metadata
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
"Top-level" metadata refers to fields that can be specified at the root level of a metadata file. These attributes are meant to describe the entire Datasette instance.
|
||||
|
||||
The following are the full list of allowed top-level metadata fields:
|
||||
|
||||
- ``title``
|
||||
- ``description``
|
||||
- ``description_html``
|
||||
- ``license``
|
||||
- ``license_url``
|
||||
- ``source``
|
||||
- ``source_url``
|
||||
|
||||
|
||||
|
||||
Database-level Metadata
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
"Database-level" metadata refers to fields that can be specified for each database in a Datasette instance. These attributes should be listed under a database inside the `"databases"` field.
|
||||
|
||||
The following are the full list of allowed database-level metadata fields:
|
||||
|
||||
- ``source``
|
||||
- ``source_url``
|
||||
- ``license``
|
||||
- ``license_url``
|
||||
- ``about``
|
||||
- ``about_url``
|
||||
|
||||
|
||||
Table-level Metadata
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
"Table-level" metadata refers to fields that can be specified for each table in a Datasette instance. These attributes should be listed under a specific table using the `"tables"` field.
|
||||
|
||||
The following are the full list of allowed table-level metadata fields:
|
||||
|
||||
|
||||
- ``source``
|
||||
- ``source_url``
|
||||
- ``license``
|
||||
- ``license_url``
|
||||
- ``about``
|
||||
- ``about_url``
|
||||
- ``hidden``
|
||||
- ``sort/sort_desc``
|
||||
- ``size``
|
||||
- ``sortable_columns``
|
||||
- ``label_column``
|
||||
- ``facets``
|
||||
- ``fts_table``
|
||||
- ``fts_pk``
|
||||
- ``searchmode``
|
||||
- ``columns``
|
||||
|
|
|
@ -16,10 +16,27 @@ def metadata_example(cog, data=None, yaml=None):
|
|||
output_yaml = yaml
|
||||
else:
|
||||
output_yaml = safe_dump(data, sort_keys=False)
|
||||
cog.out("\n.. tab:: YAML\n\n")
|
||||
cog.out("\n.. tab:: metadata.yaml\n\n")
|
||||
cog.out(" .. code-block:: yaml\n\n")
|
||||
cog.out(textwrap.indent(output_yaml, " "))
|
||||
cog.out("\n\n.. tab:: JSON\n\n")
|
||||
cog.out("\n\n.. tab:: metadata.json\n\n")
|
||||
cog.out(" .. code-block:: json\n\n")
|
||||
cog.out(textwrap.indent(json.dumps(data, indent=2), " "))
|
||||
cog.out("\n")
|
||||
|
||||
|
||||
def config_example(cog, input):
|
||||
if type(input) is str:
|
||||
# round_trip_load to preserve key order:
|
||||
data = round_trip_load(input)
|
||||
output_yaml = input
|
||||
else:
|
||||
data = input
|
||||
output_yaml = safe_dump(input, sort_keys=False)
|
||||
cog.out("\n.. tab:: datasette.yaml\n\n")
|
||||
cog.out(" .. code-block:: yaml\n\n")
|
||||
cog.out(textwrap.indent(output_yaml, " "))
|
||||
cog.out("\n\n.. tab:: datasette.json\n\n")
|
||||
cog.out(" .. code-block:: json\n\n")
|
||||
cog.out(textwrap.indent(json.dumps(data, indent=2), " "))
|
||||
cog.out("\n")
|
||||
|
|
|
@ -319,13 +319,13 @@ To write that to a ``requirements.txt`` file, run this::
|
|||
Plugin configuration
|
||||
--------------------
|
||||
|
||||
Plugins can have their own configuration, embedded in a :ref:`metadata` file. Configuration options for plugins live within a ``"plugins"`` key in that file, which can be included at the root, database or table level.
|
||||
Plugins can have their own configuration, embedded in a :ref:`configuration` file. Configuration options for plugins live within a ``"plugins"`` key in that file, which can be included at the root, database or table level.
|
||||
|
||||
Here is an example of some plugin configuration for a specific table:
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
metadata_example(cog, {
|
||||
from metadata_doc import config_example
|
||||
config_example(cog, {
|
||||
"databases": {
|
||||
"sf-trees": {
|
||||
"tables": {
|
||||
|
@ -343,7 +343,7 @@ Here is an example of some plugin configuration for a specific table:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -357,7 +357,7 @@ Here is an example of some plugin configuration for a specific table:
|
|||
longitude_column: lng
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -386,12 +386,12 @@ This tells the ``datasette-cluster-map`` column which latitude and longitude col
|
|||
Secret configuration values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Any values embedded in ``metadata.yaml`` will be visible to anyone who views the ``/-/metadata`` page of your Datasette instance. Some plugins may need configuration that should stay secret - API keys for example. There are two ways in which you can store secret configuration values.
|
||||
Some plugins may need configuration that should stay secret - API keys for example. There are two ways in which you can store secret configuration values.
|
||||
|
||||
**As environment variables**. If your secret lives in an environment variable that is available to the Datasette process, you can indicate that the configuration value should be read from that environment variable like so:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
config_example(cog, {
|
||||
"plugins": {
|
||||
"datasette-auth-github": {
|
||||
"client_secret": {
|
||||
|
@ -402,7 +402,7 @@ Any values embedded in ``metadata.yaml`` will be visible to anyone who views the
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -412,7 +412,7 @@ Any values embedded in ``metadata.yaml`` will be visible to anyone who views the
|
|||
$env: GITHUB_CLIENT_SECRET
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -430,7 +430,7 @@ Any values embedded in ``metadata.yaml`` will be visible to anyone who views the
|
|||
**As values in separate files**. Your secrets can also live in files on disk. To specify a secret should be read from a file, provide the full file path like this:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
config_example(cog, {
|
||||
"plugins": {
|
||||
"datasette-auth-github": {
|
||||
"client_secret": {
|
||||
|
@ -441,7 +441,7 @@ Any values embedded in ``metadata.yaml`` will be visible to anyone who views the
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -451,7 +451,7 @@ Any values embedded in ``metadata.yaml`` will be visible to anyone who views the
|
|||
$file: /secrets/client-secret
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -477,7 +477,7 @@ If you are publishing your data using the :ref:`datasette publish <cli_publish>`
|
|||
This will set the necessary environment variables and add the following to the deployed ``metadata.yaml``:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
config_example(cog, {
|
||||
"plugins": {
|
||||
"datasette-auth-github": {
|
||||
"client_id": {
|
||||
|
@ -491,7 +491,7 @@ This will set the necessary environment variables and add the following to the d
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -503,7 +503,7 @@ This will set the necessary environment variables and add the following to the d
|
|||
$env: DATASETTE_AUTH_GITHUB_CLIENT_SECRET
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ As an alternative to this, you can run Datasette in *configuration directory* mo
|
|||
# In a directory called my-app:
|
||||
my-app/one.db
|
||||
my-app/two.db
|
||||
my-app/datasette.yaml
|
||||
my-app/metadata.json
|
||||
my-app/templates/index.html
|
||||
my-app/plugins/my_plugin.py
|
||||
|
@ -47,7 +48,7 @@ Datasette will detect the files in that directory and automatically configure it
|
|||
The files that can be included in this directory are as follows. All are optional.
|
||||
|
||||
* ``*.db`` (or ``*.sqlite3`` or ``*.sqlite``) - SQLite database files that will be served by Datasette
|
||||
* ``datasette.json`` - :ref:`configuration` for the Datasette instance
|
||||
* ``datasette.yaml`` - :ref:`configuration` for the Datasette instance
|
||||
* ``metadata.json`` - :ref:`metadata` for those databases - ``metadata.yaml`` or ``metadata.yml`` can be used as well
|
||||
* ``inspect-data.json`` - the result of running ``datasette inspect *.db --inspect-file=inspect-data.json`` from the configuration directory - any database files listed here will be treated as immutable, so they should not be changed while Datasette is running
|
||||
* ``templates/`` - a directory containing :ref:`customization_custom_templates`
|
||||
|
@ -72,7 +73,7 @@ Setting this to ``off`` causes permission checks for :ref:`permissions_execute_s
|
|||
|
||||
datasette mydatabase.db --setting default_allow_sql off
|
||||
|
||||
There are two ways to achieve this: the other is to add ``"allow_sql": false`` to your ``metadata.json`` file, as described in :ref:`authentication_permissions_execute_sql`. This setting offers a more convenient way to do this.
|
||||
Another way to achieve this is to add ``"allow_sql": false`` to your ``datasette.yaml`` file, as described in :ref:`authentication_permissions_execute_sql`. This setting offers a more convenient way to do this.
|
||||
|
||||
.. _setting_default_page_size:
|
||||
|
||||
|
|
|
@ -71,11 +71,11 @@ You can also use the `sqlite-utils <https://sqlite-utils.datasette.io/>`__ tool
|
|||
Canned queries
|
||||
--------------
|
||||
|
||||
As an alternative to adding views to your database, you can define canned queries inside your ``metadata.yaml`` file. Here's an example:
|
||||
As an alternative to adding views to your database, you can define canned queries inside your ``datasette.yaml`` file. Here's an example:
|
||||
|
||||
.. [[[cog
|
||||
from metadata_doc import metadata_example
|
||||
metadata_example(cog, {
|
||||
from metadata_doc import config_example, config_example
|
||||
config_example(cog, {
|
||||
"databases": {
|
||||
"sf-trees": {
|
||||
"queries": {
|
||||
|
@ -88,7 +88,7 @@ As an alternative to adding views to your database, you can define canned querie
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -99,7 +99,7 @@ As an alternative to adding views to your database, you can define canned querie
|
|||
sql: select qSpecies from Street_Tree_List
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -147,11 +147,11 @@ Here's an example of a canned query with a named parameter:
|
|||
where neighborhood like '%' || :text || '%'
|
||||
order by neighborhood;
|
||||
|
||||
In the canned query metadata looks like this:
|
||||
In the canned query configuration looks like this:
|
||||
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, yaml="""
|
||||
config_example(cog, """
|
||||
databases:
|
||||
fixtures:
|
||||
queries:
|
||||
|
@ -166,10 +166,11 @@ In the canned query metadata looks like this:
|
|||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
databases:
|
||||
fixtures:
|
||||
queries:
|
||||
|
@ -182,7 +183,8 @@ In the canned query metadata looks like this:
|
|||
where neighborhood like '%' || :text || '%'
|
||||
order by neighborhood
|
||||
|
||||
.. tab:: JSON
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -210,7 +212,7 @@ In this example the ``:text`` named parameter is automatically extracted from th
|
|||
You can alternatively provide an explicit list of named parameters using the ``"params"`` key, like this:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, yaml="""
|
||||
config_example(cog, """
|
||||
databases:
|
||||
fixtures:
|
||||
queries:
|
||||
|
@ -227,10 +229,11 @@ You can alternatively provide an explicit list of named parameters using the ``"
|
|||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
databases:
|
||||
fixtures:
|
||||
queries:
|
||||
|
@ -245,7 +248,8 @@ You can alternatively provide an explicit list of named parameters using the ``"
|
|||
where neighborhood like '%' || :text || '%'
|
||||
order by neighborhood
|
||||
|
||||
.. tab:: JSON
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -290,7 +294,7 @@ You can set a default fragment hash that will be included in the link to the can
|
|||
This example demonstrates both ``fragment`` and ``hide_sql``:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, yaml="""
|
||||
config_example(cog, """
|
||||
databases:
|
||||
fixtures:
|
||||
queries:
|
||||
|
@ -304,10 +308,11 @@ This example demonstrates both ``fragment`` and ``hide_sql``:
|
|||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
databases:
|
||||
fixtures:
|
||||
queries:
|
||||
|
@ -319,7 +324,8 @@ This example demonstrates both ``fragment`` and ``hide_sql``:
|
|||
from facetable join facet_cities on facetable.city_id = facet_cities.id
|
||||
where neighborhood like '%' || :text || '%' order by neighborhood;
|
||||
|
||||
.. tab:: JSON
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -350,7 +356,7 @@ Canned queries by default are read-only. You can use the ``"write": true`` key t
|
|||
See :ref:`authentication_permissions_query` for details on how to add permission checks to canned queries, using the ``"allow"`` key.
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
config_example(cog, {
|
||||
"databases": {
|
||||
"mydatabase": {
|
||||
"queries": {
|
||||
|
@ -364,7 +370,7 @@ See :ref:`authentication_permissions_query` for details on how to add permission
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -376,7 +382,7 @@ See :ref:`authentication_permissions_query` for details on how to add permission
|
|||
write: true
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -407,7 +413,7 @@ You can customize how Datasette represents success and errors using the followin
|
|||
For example:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, {
|
||||
config_example(cog, {
|
||||
"databases": {
|
||||
"mydatabase": {
|
||||
"queries": {
|
||||
|
@ -426,7 +432,7 @@ For example:
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -444,7 +450,7 @@ For example:
|
|||
on_error_redirect: /mydatabase
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -510,7 +516,7 @@ Available magic parameters are:
|
|||
Here's an example configuration that adds a message from the authenticated user, storing various pieces of additional metadata using magic parameters:
|
||||
|
||||
.. [[[cog
|
||||
metadata_example(cog, yaml="""
|
||||
config_example(cog, """
|
||||
databases:
|
||||
mydatabase:
|
||||
queries:
|
||||
|
@ -527,10 +533,11 @@ Here's an example configuration that adds a message from the authenticated user,
|
|||
""")
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: datasette.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
||||
databases:
|
||||
mydatabase:
|
||||
queries:
|
||||
|
@ -545,7 +552,8 @@ Here's an example configuration that adds a message from the authenticated user,
|
|||
)
|
||||
write: true
|
||||
|
||||
.. tab:: JSON
|
||||
|
||||
.. tab:: datasette.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ If it cannot find the requested configuration at the table layer, it will fall b
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -214,7 +214,7 @@ If it cannot find the requested configuration at the table layer, it will fall b
|
|||
longitude_column: xlng
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -247,7 +247,7 @@ The plugin configuration could also be set at the top level of ``datasette.yaml`
|
|||
})
|
||||
.. ]]]
|
||||
|
||||
.. tab:: YAML
|
||||
.. tab:: metadata.yaml
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -257,7 +257,7 @@ The plugin configuration could also be set at the top level of ``datasette.yaml`
|
|||
longitude_column: xlng
|
||||
|
||||
|
||||
.. tab:: JSON
|
||||
.. tab:: metadata.json
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
|
|
@ -321,8 +321,32 @@ CONFIG = {
|
|||
"plugins": {"name-of-plugin": {"depth": "table"}},
|
||||
},
|
||||
},
|
||||
"queries": {
|
||||
"𝐜𝐢𝐭𝐢𝐞𝐬": "select id, name from facet_cities order by id limit 1;",
|
||||
"pragma_cache_size": "PRAGMA cache_size;",
|
||||
"magic_parameters": {
|
||||
"sql": "select :_header_user_agent as user_agent, :_now_datetime_utc as datetime",
|
||||
},
|
||||
"neighborhood_search": {
|
||||
"sql": textwrap.dedent(
|
||||
"""
|
||||
select _neighborhood, facet_cities.name, state
|
||||
from facetable
|
||||
join facet_cities
|
||||
on facetable._city_id = facet_cities.id
|
||||
where _neighborhood like '%' || :text || '%'
|
||||
order by _neighborhood;
|
||||
"""
|
||||
),
|
||||
"title": "Search neighborhoods",
|
||||
"description_html": "<b>Demonstrating</b> simple like search",
|
||||
"fragment": "fragment-goes-here",
|
||||
"hide_sql": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
"extra_css_urls": ["/static/extra-css-urls.css"],
|
||||
}
|
||||
|
||||
METADATA = {
|
||||
|
@ -334,7 +358,6 @@ METADATA = {
|
|||
"source_url": "https://github.com/simonw/datasette/blob/main/tests/fixtures.py",
|
||||
"about": "About Datasette",
|
||||
"about_url": "https://github.com/simonw/datasette",
|
||||
"extra_css_urls": ["/static/extra-css-urls.css"],
|
||||
"databases": {
|
||||
"fixtures": {
|
||||
"description": "Test tables description",
|
||||
|
@ -371,29 +394,6 @@ METADATA = {
|
|||
"facet_cities": {"sort": "name"},
|
||||
"paginated_view": {"size": 25},
|
||||
},
|
||||
"queries": {
|
||||
"𝐜𝐢𝐭𝐢𝐞𝐬": "select id, name from facet_cities order by id limit 1;",
|
||||
"pragma_cache_size": "PRAGMA cache_size;",
|
||||
"magic_parameters": {
|
||||
"sql": "select :_header_user_agent as user_agent, :_now_datetime_utc as datetime",
|
||||
},
|
||||
"neighborhood_search": {
|
||||
"sql": textwrap.dedent(
|
||||
"""
|
||||
select _neighborhood, facet_cities.name, state
|
||||
from facetable
|
||||
join facet_cities
|
||||
on facetable._city_id = facet_cities.id
|
||||
where _neighborhood like '%' || :text || '%'
|
||||
order by _neighborhood;
|
||||
"""
|
||||
),
|
||||
"title": "Search neighborhoods",
|
||||
"description_html": "<b>Demonstrating</b> simple like search",
|
||||
"fragment": "fragment-goes-here",
|
||||
"hide_sql": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ def canned_write_client(tmpdir):
|
|||
with make_app_client(
|
||||
extra_databases={"data.db": "create table names (name text)"},
|
||||
template_dir=str(template_dir),
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"data": {
|
||||
"queries": {
|
||||
|
@ -63,7 +63,7 @@ def canned_write_client(tmpdir):
|
|||
def canned_write_immutable_client():
|
||||
with make_app_client(
|
||||
is_immutable=True,
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"fixtures": {
|
||||
"queries": {
|
||||
|
@ -172,7 +172,7 @@ def test_insert_error(canned_write_client):
|
|||
)
|
||||
assert [["UNIQUE constraint failed: names.rowid", 3]] == messages
|
||||
# How about with a custom error message?
|
||||
canned_write_client.ds._metadata["databases"]["data"]["queries"][
|
||||
canned_write_client.ds.config["databases"]["data"]["queries"][
|
||||
"add_name_specify_id"
|
||||
]["on_error_message"] = "ERROR"
|
||||
response = canned_write_client.post(
|
||||
|
@ -316,7 +316,7 @@ def test_canned_query_permissions(canned_write_client):
|
|||
def magic_parameters_client():
|
||||
with make_app_client(
|
||||
extra_databases={"data.db": "create table logs (line text)"},
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"data": {
|
||||
"queries": {
|
||||
|
@ -345,10 +345,10 @@ def magic_parameters_client():
|
|||
],
|
||||
)
|
||||
def test_magic_parameters(magic_parameters_client, magic_parameter, expected_re):
|
||||
magic_parameters_client.ds._metadata["databases"]["data"]["queries"]["runme_post"][
|
||||
magic_parameters_client.ds.config["databases"]["data"]["queries"]["runme_post"][
|
||||
"sql"
|
||||
] = f"insert into logs (line) values (:{magic_parameter})"
|
||||
magic_parameters_client.ds._metadata["databases"]["data"]["queries"]["runme_get"][
|
||||
magic_parameters_client.ds.config["databases"]["data"]["queries"]["runme_get"][
|
||||
"sql"
|
||||
] = f"select :{magic_parameter} as result"
|
||||
cookies = {
|
||||
|
@ -384,7 +384,7 @@ def test_magic_parameters(magic_parameters_client, magic_parameter, expected_re)
|
|||
@pytest.mark.parametrize("use_csrf", [True, False])
|
||||
@pytest.mark.parametrize("return_json", [True, False])
|
||||
def test_magic_parameters_csrf_json(magic_parameters_client, use_csrf, return_json):
|
||||
magic_parameters_client.ds._metadata["databases"]["data"]["queries"]["runme_post"][
|
||||
magic_parameters_client.ds.config["databases"]["data"]["queries"]["runme_post"][
|
||||
"sql"
|
||||
] = "insert into logs (line) values (:_header_host)"
|
||||
qs = ""
|
||||
|
|
|
@ -9,6 +9,7 @@ from .fixtures import ( # noqa
|
|||
METADATA,
|
||||
)
|
||||
from .utils import assert_footer_links, inner_html
|
||||
import copy
|
||||
import json
|
||||
import pathlib
|
||||
import pytest
|
||||
|
@ -518,7 +519,7 @@ def test_allow_download_off():
|
|||
|
||||
|
||||
def test_allow_sql_off():
|
||||
with make_app_client(metadata={"allow_sql": {}}) as client:
|
||||
with make_app_client(config={"allow_sql": {}}) as client:
|
||||
response = client.get("/fixtures")
|
||||
soup = Soup(response.content, "html.parser")
|
||||
assert not len(soup.findAll("textarea", {"name": "sql"}))
|
||||
|
@ -655,7 +656,7 @@ def test_canned_query_show_hide_metadata_option(
|
|||
expected_show_hide_text,
|
||||
):
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"_memory": {
|
||||
"queries": {
|
||||
|
@ -908,7 +909,7 @@ async def test_edit_sql_link_on_canned_queries(ds_client, path, expected):
|
|||
@pytest.mark.parametrize("permission_allowed", [True, False])
|
||||
def test_edit_sql_link_not_shown_if_user_lacks_permission(permission_allowed):
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"allow_sql": None if permission_allowed else {"id": "not-you"},
|
||||
"databases": {"fixtures": {"queries": {"simple": "select 1 + 1"}}},
|
||||
}
|
||||
|
@ -1057,7 +1058,7 @@ async def test_redirect_percent_encoding_to_tilde_encoding(ds_client, path, expe
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"path,metadata,expected_links",
|
||||
"path,config,expected_links",
|
||||
(
|
||||
("/fixtures", {}, [("/", "home")]),
|
||||
("/fixtures", {"allow": False, "databases": {"fixtures": {"allow": True}}}, []),
|
||||
|
@ -1080,21 +1081,23 @@ async def test_redirect_percent_encoding_to_tilde_encoding(ds_client, path, expe
|
|||
{"allow": False, "databases": {"fixtures": {"allow": True}}},
|
||||
[("/fixtures", "fixtures"), ("/fixtures/facetable", "facetable")],
|
||||
),
|
||||
(
|
||||
"/fixtures/facetable/1",
|
||||
{
|
||||
"allow": False,
|
||||
"databases": {"fixtures": {"tables": {"facetable": {"allow": True}}}},
|
||||
},
|
||||
[("/fixtures/facetable", "facetable")],
|
||||
),
|
||||
# TODO: what
|
||||
# (
|
||||
# "/fixtures/facetable/1",
|
||||
# {
|
||||
# "allow": False,
|
||||
# "databases": {"fixtures": {"tables": {"facetable": {"allow": True}}}},
|
||||
# },
|
||||
# [("/fixtures/facetable", "facetable")],
|
||||
# ),
|
||||
),
|
||||
)
|
||||
async def test_breadcrumbs_respect_permissions(
|
||||
ds_client, path, metadata, expected_links
|
||||
):
|
||||
orig = ds_client.ds._metadata_local
|
||||
ds_client.ds._metadata_local = metadata
|
||||
async def test_breadcrumbs_respect_permissions(ds_client, path, config, expected_links):
|
||||
previous_config = ds_client.ds.config
|
||||
updated_config = copy.deepcopy(previous_config)
|
||||
updated_config.update(config)
|
||||
ds_client.ds.config = updated_config
|
||||
|
||||
try:
|
||||
response = await ds_client.ds.client.get(path)
|
||||
soup = Soup(response.text, "html.parser")
|
||||
|
@ -1102,7 +1105,7 @@ async def test_breadcrumbs_respect_permissions(
|
|||
actual = [(a["href"], a.text) for a in breadcrumbs]
|
||||
assert actual == expected_links
|
||||
finally:
|
||||
ds_client.ds._metadata_local = orig
|
||||
ds_client.ds.config = previous_config
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -1122,4 +1125,9 @@ async def test_database_color(ds_client):
|
|||
"/fixtures/pragma_cache_size",
|
||||
):
|
||||
response = await ds_client.get(path)
|
||||
result = any(fragment in response.text for fragment in expected_fragments)
|
||||
if not result:
|
||||
import pdb
|
||||
|
||||
pdb.set_trace()
|
||||
assert any(fragment in response.text for fragment in expected_fragments)
|
||||
|
|
|
@ -85,7 +85,7 @@ ALLOW_ROOT = {"allow": {"id": "root"}}
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"actor,metadata,permissions,should_allow,expected_private",
|
||||
"actor,config,permissions,should_allow,expected_private",
|
||||
(
|
||||
(None, ALLOW_ROOT, ["view-instance"], False, False),
|
||||
(ROOT, ALLOW_ROOT, ["view-instance"], True, True),
|
||||
|
@ -114,9 +114,9 @@ ALLOW_ROOT = {"allow": {"id": "root"}}
|
|||
),
|
||||
)
|
||||
async def test_datasette_ensure_permissions_check_visibility(
|
||||
actor, metadata, permissions, should_allow, expected_private
|
||||
actor, config, permissions, should_allow, expected_private
|
||||
):
|
||||
ds = Datasette([], memory=True, metadata=metadata)
|
||||
ds = Datasette([], memory=True, config=config)
|
||||
await ds.invoke_startup()
|
||||
if not should_allow:
|
||||
with pytest.raises(Forbidden):
|
||||
|
|
|
@ -18,7 +18,7 @@ import urllib
|
|||
@pytest.fixture(scope="module")
|
||||
def padlock_client():
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"fixtures": {
|
||||
"queries": {"two": {"sql": "select 1 + 1"}},
|
||||
|
@ -63,7 +63,7 @@ async def perms_ds():
|
|||
),
|
||||
)
|
||||
def test_view_padlock(allow, expected_anon, expected_auth, path, padlock_client):
|
||||
padlock_client.ds._metadata_local["allow"] = allow
|
||||
padlock_client.ds.config["allow"] = allow
|
||||
fragment = "🔒</h1>"
|
||||
anon_response = padlock_client.get(path)
|
||||
assert expected_anon == anon_response.status
|
||||
|
@ -78,7 +78,7 @@ def test_view_padlock(allow, expected_anon, expected_auth, path, padlock_client)
|
|||
# Check for the padlock
|
||||
if allow and expected_anon == 403 and expected_auth == 200:
|
||||
assert fragment in auth_response.text
|
||||
del padlock_client.ds._metadata_local["allow"]
|
||||
del padlock_client.ds.config["allow"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -91,7 +91,7 @@ def test_view_padlock(allow, expected_anon, expected_auth, path, padlock_client)
|
|||
)
|
||||
def test_view_database(allow, expected_anon, expected_auth):
|
||||
with make_app_client(
|
||||
metadata={"databases": {"fixtures": {"allow": allow}}}
|
||||
config={"databases": {"fixtures": {"allow": allow}}}
|
||||
) as client:
|
||||
for path in (
|
||||
"/fixtures",
|
||||
|
@ -119,7 +119,7 @@ def test_view_database(allow, expected_anon, expected_auth):
|
|||
|
||||
def test_database_list_respects_view_database():
|
||||
with make_app_client(
|
||||
metadata={"databases": {"fixtures": {"allow": {"id": "root"}}}},
|
||||
config={"databases": {"fixtures": {"allow": {"id": "root"}}}},
|
||||
extra_databases={"data.db": "create table names (name text)"},
|
||||
) as client:
|
||||
anon_response = client.get("/")
|
||||
|
@ -135,7 +135,7 @@ def test_database_list_respects_view_database():
|
|||
|
||||
def test_database_list_respects_view_table():
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"data": {
|
||||
"tables": {
|
||||
|
@ -175,7 +175,7 @@ def test_database_list_respects_view_table():
|
|||
)
|
||||
def test_view_table(allow, expected_anon, expected_auth):
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"fixtures": {
|
||||
"tables": {"compound_three_primary_keys": {"allow": allow}}
|
||||
|
@ -199,7 +199,7 @@ def test_view_table(allow, expected_anon, expected_auth):
|
|||
|
||||
def test_table_list_respects_view_table():
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"fixtures": {
|
||||
"tables": {
|
||||
|
@ -235,7 +235,7 @@ def test_table_list_respects_view_table():
|
|||
)
|
||||
def test_view_query(allow, expected_anon, expected_auth):
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"fixtures": {"queries": {"q": {"sql": "select 1 + 1", "allow": allow}}}
|
||||
}
|
||||
|
@ -255,15 +255,15 @@ def test_view_query(allow, expected_anon, expected_auth):
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"metadata",
|
||||
"config",
|
||||
[
|
||||
{"allow_sql": {"id": "root"}},
|
||||
{"databases": {"fixtures": {"allow_sql": {"id": "root"}}}},
|
||||
],
|
||||
)
|
||||
def test_execute_sql(metadata):
|
||||
def test_execute_sql(config):
|
||||
schema_re = re.compile("const schema = ({.*?});", re.DOTALL)
|
||||
with make_app_client(metadata=metadata) as client:
|
||||
with make_app_client(config=config) as client:
|
||||
form_fragment = '<form class="sql" action="/fixtures"'
|
||||
|
||||
# Anonymous users - should not display the form:
|
||||
|
@ -297,7 +297,7 @@ def test_execute_sql(metadata):
|
|||
|
||||
def test_query_list_respects_view_query():
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"fixtures": {
|
||||
"queries": {"q": {"sql": "select 1 + 1", "allow": {"id": "root"}}}
|
||||
|
@ -424,13 +424,13 @@ async def test_allow_debug(ds_client, actor, allow, expected_fragment):
|
|||
],
|
||||
)
|
||||
def test_allow_unauthenticated(allow, expected):
|
||||
with make_app_client(metadata={"allow": allow}) as client:
|
||||
with make_app_client(config={"allow": allow}) as client:
|
||||
assert expected == client.get("/").status
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def view_instance_client():
|
||||
with make_app_client(metadata={"allow": {}}) as client:
|
||||
with make_app_client(config={"allow": {}}) as client:
|
||||
yield client
|
||||
|
||||
|
||||
|
@ -504,24 +504,24 @@ def test_permissions_cascade(cascade_app_client, path, permissions, expected_sta
|
|||
"""Test that e.g. having view-table but NOT view-database lets you view table page, etc"""
|
||||
allow = {"id": "*"}
|
||||
deny = {}
|
||||
previous_metadata = cascade_app_client.ds.metadata()
|
||||
updated_metadata = copy.deepcopy(previous_metadata)
|
||||
previous_config = cascade_app_client.ds.config
|
||||
updated_config = copy.deepcopy(previous_config)
|
||||
actor = {"id": "test"}
|
||||
if "download" in permissions:
|
||||
actor["can_download"] = 1
|
||||
try:
|
||||
# Set up the different allow blocks
|
||||
updated_metadata["allow"] = allow if "instance" in permissions else deny
|
||||
updated_metadata["databases"]["fixtures"]["allow"] = (
|
||||
updated_config["allow"] = allow if "instance" in permissions else deny
|
||||
updated_config["databases"]["fixtures"]["allow"] = (
|
||||
allow if "database" in permissions else deny
|
||||
)
|
||||
updated_metadata["databases"]["fixtures"]["tables"]["binary_data"] = {
|
||||
updated_config["databases"]["fixtures"]["tables"]["binary_data"] = {
|
||||
"allow": (allow if "table" in permissions else deny)
|
||||
}
|
||||
updated_metadata["databases"]["fixtures"]["queries"]["magic_parameters"][
|
||||
updated_config["databases"]["fixtures"]["queries"]["magic_parameters"][
|
||||
"allow"
|
||||
] = (allow if "query" in permissions else deny)
|
||||
cascade_app_client.ds._metadata_local = updated_metadata
|
||||
cascade_app_client.ds.config = updated_config
|
||||
response = cascade_app_client.get(
|
||||
path,
|
||||
cookies={"ds_actor": cascade_app_client.actor_cookie(actor)},
|
||||
|
@ -532,11 +532,11 @@ def test_permissions_cascade(cascade_app_client, path, permissions, expected_sta
|
|||
path, permissions, expected_status, response.status
|
||||
)
|
||||
finally:
|
||||
cascade_app_client.ds._metadata_local = previous_metadata
|
||||
cascade_app_client.ds.config = previous_config
|
||||
|
||||
|
||||
def test_padlocks_on_database_page(cascade_app_client):
|
||||
metadata = {
|
||||
config = {
|
||||
"databases": {
|
||||
"fixtures": {
|
||||
"allow": {"id": "test"},
|
||||
|
@ -548,9 +548,9 @@ def test_padlocks_on_database_page(cascade_app_client):
|
|||
}
|
||||
}
|
||||
}
|
||||
previous_metadata = cascade_app_client.ds._metadata_local
|
||||
previous_config = cascade_app_client.ds.config
|
||||
try:
|
||||
cascade_app_client.ds._metadata_local = metadata
|
||||
cascade_app_client.ds.config = config
|
||||
response = cascade_app_client.get(
|
||||
"/fixtures",
|
||||
cookies={"ds_actor": cascade_app_client.actor_cookie({"id": "test"})},
|
||||
|
@ -565,7 +565,7 @@ def test_padlocks_on_database_page(cascade_app_client):
|
|||
assert ">paginated_view</a> 🔒</li>" in response.text
|
||||
assert ">simple_view</a></li>" in response.text
|
||||
finally:
|
||||
cascade_app_client.ds._metadata_local = previous_metadata
|
||||
cascade_app_client.ds.config = previous_config
|
||||
|
||||
|
||||
DEF = "USE_DEFAULT"
|
||||
|
@ -671,51 +671,51 @@ async def test_actor_restricted_permissions(
|
|||
assert response.json() == expected
|
||||
|
||||
|
||||
PermMetadataTestCase = collections.namedtuple(
|
||||
"PermMetadataTestCase",
|
||||
"metadata,actor,action,resource,expected_result",
|
||||
PermConfigTestCase = collections.namedtuple(
|
||||
"PermConfigTestCase",
|
||||
"config,actor,action,resource,expected_result",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"metadata,actor,action,resource,expected_result",
|
||||
"config,actor,action,resource,expected_result",
|
||||
(
|
||||
# Simple view-instance default=True example
|
||||
PermMetadataTestCase(
|
||||
metadata={},
|
||||
PermConfigTestCase(
|
||||
config={},
|
||||
actor=None,
|
||||
action="view-instance",
|
||||
resource=None,
|
||||
expected_result=True,
|
||||
),
|
||||
# debug-menu on root
|
||||
PermMetadataTestCase(
|
||||
metadata={"permissions": {"debug-menu": {"id": "user"}}},
|
||||
PermConfigTestCase(
|
||||
config={"permissions": {"debug-menu": {"id": "user"}}},
|
||||
actor={"id": "user"},
|
||||
action="debug-menu",
|
||||
resource=None,
|
||||
expected_result=True,
|
||||
),
|
||||
# debug-menu on root, wrong actor
|
||||
PermMetadataTestCase(
|
||||
metadata={"permissions": {"debug-menu": {"id": "user"}}},
|
||||
PermConfigTestCase(
|
||||
config={"permissions": {"debug-menu": {"id": "user"}}},
|
||||
actor={"id": "user2"},
|
||||
action="debug-menu",
|
||||
resource=None,
|
||||
expected_result=False,
|
||||
),
|
||||
# create-table on root
|
||||
PermMetadataTestCase(
|
||||
metadata={"permissions": {"create-table": {"id": "user"}}},
|
||||
PermConfigTestCase(
|
||||
config={"permissions": {"create-table": {"id": "user"}}},
|
||||
actor={"id": "user"},
|
||||
action="create-table",
|
||||
resource=None,
|
||||
expected_result=True,
|
||||
),
|
||||
# create-table on database - no resource specified
|
||||
PermMetadataTestCase(
|
||||
metadata={
|
||||
PermConfigTestCase(
|
||||
config={
|
||||
"databases": {
|
||||
"perms_ds_one": {"permissions": {"create-table": {"id": "user"}}}
|
||||
}
|
||||
|
@ -726,8 +726,8 @@ PermMetadataTestCase = collections.namedtuple(
|
|||
expected_result=False,
|
||||
),
|
||||
# create-table on database
|
||||
PermMetadataTestCase(
|
||||
metadata={
|
||||
PermConfigTestCase(
|
||||
config={
|
||||
"databases": {
|
||||
"perms_ds_one": {"permissions": {"create-table": {"id": "user"}}}
|
||||
}
|
||||
|
@ -738,24 +738,24 @@ PermMetadataTestCase = collections.namedtuple(
|
|||
expected_result=True,
|
||||
),
|
||||
# insert-row on root, wrong actor
|
||||
PermMetadataTestCase(
|
||||
metadata={"permissions": {"insert-row": {"id": "user"}}},
|
||||
PermConfigTestCase(
|
||||
config={"permissions": {"insert-row": {"id": "user"}}},
|
||||
actor={"id": "user2"},
|
||||
action="insert-row",
|
||||
resource=("perms_ds_one", "t1"),
|
||||
expected_result=False,
|
||||
),
|
||||
# insert-row on root, right actor
|
||||
PermMetadataTestCase(
|
||||
metadata={"permissions": {"insert-row": {"id": "user"}}},
|
||||
PermConfigTestCase(
|
||||
config={"permissions": {"insert-row": {"id": "user"}}},
|
||||
actor={"id": "user"},
|
||||
action="insert-row",
|
||||
resource=("perms_ds_one", "t1"),
|
||||
expected_result=True,
|
||||
),
|
||||
# insert-row on database
|
||||
PermMetadataTestCase(
|
||||
metadata={
|
||||
PermConfigTestCase(
|
||||
config={
|
||||
"databases": {
|
||||
"perms_ds_one": {"permissions": {"insert-row": {"id": "user"}}}
|
||||
}
|
||||
|
@ -766,8 +766,8 @@ PermMetadataTestCase = collections.namedtuple(
|
|||
expected_result=True,
|
||||
),
|
||||
# insert-row on table, wrong table
|
||||
PermMetadataTestCase(
|
||||
metadata={
|
||||
PermConfigTestCase(
|
||||
config={
|
||||
"databases": {
|
||||
"perms_ds_one": {
|
||||
"tables": {
|
||||
|
@ -782,8 +782,8 @@ PermMetadataTestCase = collections.namedtuple(
|
|||
expected_result=False,
|
||||
),
|
||||
# insert-row on table, right table
|
||||
PermMetadataTestCase(
|
||||
metadata={
|
||||
PermConfigTestCase(
|
||||
config={
|
||||
"databases": {
|
||||
"perms_ds_one": {
|
||||
"tables": {
|
||||
|
@ -798,8 +798,8 @@ PermMetadataTestCase = collections.namedtuple(
|
|||
expected_result=True,
|
||||
),
|
||||
# view-query on canned query, wrong actor
|
||||
PermMetadataTestCase(
|
||||
metadata={
|
||||
PermConfigTestCase(
|
||||
config={
|
||||
"databases": {
|
||||
"perms_ds_one": {
|
||||
"queries": {
|
||||
|
@ -817,8 +817,8 @@ PermMetadataTestCase = collections.namedtuple(
|
|||
expected_result=False,
|
||||
),
|
||||
# view-query on canned query, right actor
|
||||
PermMetadataTestCase(
|
||||
metadata={
|
||||
PermConfigTestCase(
|
||||
config={
|
||||
"databases": {
|
||||
"perms_ds_one": {
|
||||
"queries": {
|
||||
|
@ -837,20 +837,20 @@ PermMetadataTestCase = collections.namedtuple(
|
|||
),
|
||||
),
|
||||
)
|
||||
async def test_permissions_in_metadata(
|
||||
perms_ds, metadata, actor, action, resource, expected_result
|
||||
async def test_permissions_in_config(
|
||||
perms_ds, config, actor, action, resource, expected_result
|
||||
):
|
||||
previous_metadata = perms_ds.metadata()
|
||||
updated_metadata = copy.deepcopy(previous_metadata)
|
||||
updated_metadata.update(metadata)
|
||||
perms_ds._metadata_local = updated_metadata
|
||||
previous_config = perms_ds.config
|
||||
updated_config = copy.deepcopy(previous_config)
|
||||
updated_config.update(config)
|
||||
perms_ds.config = updated_config
|
||||
try:
|
||||
result = await perms_ds.permission_allowed(actor, action, resource)
|
||||
if result != expected_result:
|
||||
pprint(perms_ds._permission_checks)
|
||||
assert result == expected_result
|
||||
finally:
|
||||
perms_ds._metadata_local = previous_metadata
|
||||
perms_ds.config = previous_config
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -964,7 +964,7 @@ _visible_tables_re = re.compile(r">\/((\w+)\/(\w+))\.json<\/a> - Get rows for")
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"is_logged_in,metadata,expected_visible_tables",
|
||||
"is_logged_in,config,expected_visible_tables",
|
||||
(
|
||||
# Unprotected instance logged out user sees everything:
|
||||
(
|
||||
|
@ -1002,11 +1002,11 @@ _visible_tables_re = re.compile(r">\/((\w+)\/(\w+))\.json<\/a> - Get rows for")
|
|||
),
|
||||
)
|
||||
async def test_api_explorer_visibility(
|
||||
perms_ds, is_logged_in, metadata, expected_visible_tables
|
||||
perms_ds, is_logged_in, config, expected_visible_tables
|
||||
):
|
||||
try:
|
||||
prev_metadata = perms_ds._metadata_local
|
||||
perms_ds._metadata_local = metadata or {}
|
||||
prev_config = perms_ds.config
|
||||
perms_ds.config = config or {}
|
||||
cookies = {}
|
||||
if is_logged_in:
|
||||
cookies = {"ds_actor": perms_ds.client.actor_cookie({"id": "user"})}
|
||||
|
@ -1022,7 +1022,7 @@ async def test_api_explorer_visibility(
|
|||
else:
|
||||
assert response.status_code == 403
|
||||
finally:
|
||||
perms_ds._metadata_local = prev_metadata
|
||||
perms_ds.config = prev_config
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
@ -833,7 +833,7 @@ async def test_hook_canned_queries_actor(ds_client):
|
|||
def test_hook_register_magic_parameters(restore_working_directory):
|
||||
with make_app_client(
|
||||
extra_databases={"data.db": "create table logs (line text)"},
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"data": {
|
||||
"queries": {
|
||||
|
@ -863,7 +863,7 @@ def test_hook_register_magic_parameters(restore_working_directory):
|
|||
def test_hook_forbidden(restore_working_directory):
|
||||
with make_app_client(
|
||||
extra_databases={"data2.db": "create table logs (line text)"},
|
||||
metadata={"allow": {}},
|
||||
config={"allow": {}},
|
||||
) as client:
|
||||
response = client.get("/")
|
||||
assert response.status_code == 403
|
||||
|
|
|
@ -653,7 +653,7 @@ async def test_table_filter_extra_where_invalid(ds_client):
|
|||
|
||||
|
||||
def test_table_filter_extra_where_disabled_if_no_sql_allowed():
|
||||
with make_app_client(metadata={"allow_sql": {}}) as client:
|
||||
with make_app_client(config={"allow_sql": {}}) as client:
|
||||
response = client.get(
|
||||
"/fixtures/facetable.json?_where=_neighborhood='Dogpatch'"
|
||||
)
|
||||
|
|
|
@ -1085,7 +1085,7 @@ def test_facet_more_links(
|
|||
def test_unavailable_table_does_not_break_sort_relationships():
|
||||
# https://github.com/simonw/datasette/issues/1305
|
||||
with make_app_client(
|
||||
metadata={
|
||||
config={
|
||||
"databases": {
|
||||
"fixtures": {"tables": {"foreign_key_references": {"allow": False}}}
|
||||
}
|
||||
|
@ -1208,7 +1208,7 @@ async def test_format_of_binary_links(size, title, length_bytes):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"metadata",
|
||||
"config",
|
||||
(
|
||||
# Blocked at table level
|
||||
{
|
||||
|
@ -1248,8 +1248,8 @@ async def test_format_of_binary_links(size, title, length_bytes):
|
|||
},
|
||||
),
|
||||
)
|
||||
async def test_foreign_key_labels_obey_permissions(metadata):
|
||||
ds = Datasette(metadata=metadata)
|
||||
async def test_foreign_key_labels_obey_permissions(config):
|
||||
ds = Datasette(config=config)
|
||||
db = ds.add_memory_database("foreign_key_labels")
|
||||
await db.execute_write(
|
||||
"create table if not exists a(id integer primary key, name text)"
|
||||
|
|
Ładowanie…
Reference in New Issue